diff options
1811 files changed, 72243 insertions, 34805 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index bc56cba21b..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Bug report -about: Report a bug in Godot -title: '' -labels: '' -assignees: '' - ---- -<!-- Please search existing issues for potential duplicates before filing yours: -https://github.com/godotengine/godot/issues?q=is%3Aissue ---> - -**Godot version:** -<!-- Specify commit hash if using non-official build. --> - - -**OS/device including version:** -<!-- Specify GPU model, drivers, and the backend (GLES2, GLES3, Vulkan) if graphics-related. --> - - -**Issue description:** -<!-- What happened, and what was expected. --> - - -**Steps to reproduce:** - - -**Minimal reproduction project:** -<!-- A small Godot project which reproduces the issue. Drag and drop a zip archive to upload it. --> diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..43ba5ef357 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,56 @@ +name: Bug report +description: Report a bug in Godot +body: + +- type: markdown + attributes: + value: | + - Read our [CONTRIBUTING.md guide](CONTRIBUTING.md#reporting-bugs) on reporting bugs. + - Write a descriptive issue title above. + - Search [open](https://github.com/godotengine/godot/issues) and [closed](https://github.com/godotengine/godot/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported. + - Verify that you are using a [supported Godot version](https://docs.godotengine.org/en/stable/about/release_policy.html). + +- type: input + attributes: + label: Godot version + description: > + Specify the Git commit hash if using a development or non-official build. + If you use a custom build, please test if your issue is reproducible in official builds too. + placeholder: 3.3.stable, 4.0.dev (3041becc6) + validations: + required: true + +- type: input + attributes: + label: System information + description: | + Specify the OS version, and when relevant hardware information. + For graphics-related issues, specify the GPU model, driver version, and the rendering backend (GLES2, GLES3, Vulkan). + placeholder: Windows 10, GLES3, Intel HD Graphics 620 (27.20.100.9616) + validations: + required: true + +- type: textarea + attributes: + label: Issue description + description: | + Describe your issue briefly. What doesn't work, and how do you expect it to work instead? + You can include images or videos with drag and drop, and format code blocks or logs with <code>```</code> tags. + validations: + required: true + +- type: textarea + attributes: + label: Steps to reproduce + description: | + List of steps or sample code that reproduces the issue. Having reproducible issues is a prerequisite for contributors to be able to solve them. + If you include a minimal reproduction project below, you can detail how to use it here. + validations: + required: true + +- type: textarea + attributes: + label: Minimal reproduction project + description: | + A small Godot project which reproduces the issue. Highly recommended to speed up troubleshooting. + Drag and drop a ZIP archive to upload it. diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index 2dad253288..63930aa9e2 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -6,7 +6,6 @@ env: GODOT_BASE_BRANCH: master SCONSFLAGS: platform=android verbose=yes warnings=extra werror=yes debug_symbols=no --jobs=2 module_text_server_fb_enabled=yes SCONS_CACHE_LIMIT: 4096 - ANDROID_NDK_VERSION: 21.4.7075529 jobs: android-template: @@ -29,10 +28,6 @@ jobs: with: java-version: 8 - - name: Install Android NDK - run: | - sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install 'ndk;${{env.ANDROID_NDK_VERSION}}' - # Upload cache on completion and check it out now - name: Load .scons_cache directory id: android-template-cache @@ -64,7 +59,6 @@ jobs: - name: Compilation env: SCONS_CACHE: ${{github.workspace}}/.scons_cache/ - ANDROID_NDK_ROOT: /usr/local/lib/android/sdk/ndk/${{env.ANDROID_NDK_VERSION}}/ run: | scons target=release tools=no android_arch=armv7 scons target=release tools=no android_arch=arm64v8 diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index b4bbaaacb1..ace1ce3fec 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -26,7 +26,7 @@ jobs: - name: Configure dependencies run: | sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \ - libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm + libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libdbus-1-dev libudev-dev libxi-dev libxrandr-dev yasm # Upload cache on completion and check it out now - name: Load .scons_cache directory @@ -111,7 +111,7 @@ jobs: - name: Configure dependencies run: | sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \ - libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm \ + libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libdbus-1-dev libudev-dev libxi-dev libxrandr-dev yasm \ xvfb wget unzip # Upload cache on completion and check it out now @@ -204,7 +204,7 @@ jobs: - name: Configure dependencies run: | sudo apt-get install build-essential pkg-config libx11-dev libxcursor-dev \ - libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libudev-dev libxi-dev libxrandr-dev yasm + libxinerama-dev libgl1-mesa-dev libglu-dev libasound2-dev libpulse-dev libdbus-1-dev libudev-dev libxi-dev libxrandr-dev yasm # Upload cache on completion and check it out now - name: Load .scons_cache directory @@ -27,6 +27,7 @@ generous deed immortalized in the next stable release of Godot Engine. ## Bronze sponsors + Ben Nolan Brandon Lamb Garry Newman Gordon MacPherson @@ -44,12 +45,12 @@ generous deed immortalized in the next stable release of Godot Engine. Andrew Dunai Angry Skull anti666 - Ben Nolan blurp CD Christian Baune Christoffer Sundbom Christopher Montesano + Daniel Edwards Darrin Massena David Mydlarz Digital Grows @@ -61,10 +62,12 @@ generous deed immortalized in the next stable release of Godot Engine. Hein-Pieter van Braam Jasper Brooks Javary Co. + Jay Sistar Jeffery Chiu John G Gentzel Jonah Stich Justin Arnold + Justo Delgado Baudà Kamil Brzezinski Marcel Kräml Marek Belski @@ -103,12 +106,11 @@ generous deed immortalized in the next stable release of Godot Engine. David Gehrig David Snopek Don B + Ealthy Studio Ed Morley Ellen Poe Florian Rämisch - Forge Gamejunkey - Hoojib Jakub Grzesik Javier Roman Joan Fons @@ -128,25 +130,26 @@ generous deed immortalized in the next stable release of Godot Engine. m kaersten Monster Vial Officine Pixel S.n.c. + Petrus Prinsloo Rene Retro Village Rob Messick Roland Fredenhagen Ronan Zeegers - Sandro Jenny Sarksus Scott B Sean segfault-god Sergey Sofox + Stephen Molyneaux Taylor Ritenour Tom Langwaldt Tricky Fat Cat tukon + Vagabond Arcade Vitaliy Sapronenko William Wold - xagonist Xeno Coliseum Zaven Muradyan @@ -160,13 +163,13 @@ generous deed immortalized in the next stable release of Godot Engine. Andrew Cunningham Antanas Paskauskas Antoni Batchelli + Arch Henderson III Arisaka Mayuki Arthur S. Muszynski Ben Botwin - Björn Hjorth Brandon Hawkinson Caleb Sizemore - Can Eris + Cameron Connolly Charlie Whitfield Chase Taranto Chelsea Hash @@ -177,8 +180,10 @@ generous deed immortalized in the next stable release of Godot Engine. Craig Ostrin Craig Smith Cristopher + CzechBlueBear D dan didenko + Daniel Tebbutt Darrian Little Dennis Belfrage Dev To be curious @@ -188,22 +193,26 @@ generous deed immortalized in the next stable release of Godot Engine. Donn Eddy Easypete Edgar Sun + Eric Eric Brand Eugenio Hugo Salgüero Jáñez EXUREI flesk foxydevloper + Fransiska F S Gabrielius VaiÅ¡kÅ«nas Gary Hulst gavlig General Chicken + Geoffroy Warin GGGames.org Guilherme Felipe de C. G. da Silva Harvey Fong Heath Hayes Horváth Péter Hu Hund + Hunter Barabas Jake Burga James Couzens Jan Sælid @@ -212,7 +221,6 @@ generous deed immortalized in the next stable release of Godot Engine. Jeppe Zapp Jesús Chicharro Joel Fivat - Joel Höglund Johnathan Kupferer John Knight Jose Malheiro @@ -224,10 +232,10 @@ generous deed immortalized in the next stable release of Godot Engine. Juan T Chen Juan Velandia Judd + Julián Absatz Julian Todd Juraj Móza JUSTIN CARROLL - Justo Delgado Baudà Kelteseth kickmaniac kinfox @@ -239,6 +247,7 @@ generous deed immortalized in the next stable release of Godot Engine. leetNightshade Leo Fidel R Liban Liam Smyth + Luca Vazzano Luc-Frédéric Langis MadScientistCarl Marcus Dobler @@ -247,7 +256,7 @@ generous deed immortalized in the next stable release of Godot Engine. Martin Eigel Martin Kotz Martin Soucek - Matt Eunson + matt Matt Greene Matthias Toepp medecau @@ -271,24 +280,24 @@ generous deed immortalized in the next stable release of Godot Engine. Pete Goodwin Peter Richmond Petr Malac - Petrus Prinsloo PhaineOfCatz pl Raymond Harris - Raz A + Renato Fontes Rene Tailleur Rhodochrone Ricardo Alcantara Rob Robert Larnach + Robert McDermott Robert Willes Rob McInroy Rocknight Studios Rodrigo Favarete + Romeo Disca Ronnie Ashlock Ronny Mühle Ryan Scott - Ryszard Sommefeldt Samuel Judd Sean Morgan Sebastian Hutter @@ -303,12 +312,16 @@ generous deed immortalized in the next stable release of Godot Engine. Stephan Hennion Steven Landow Stoned Xander + Super Izzo Sven F. Thomas Bjarnelöf Thomas Kurz Tim Howard Tobias Bocanegra Todd Smith + Torbulous + toto bibi + Troy Kinsella Turntsnaco tweaklab Valryia @@ -326,6 +339,7 @@ generous deed immortalized in the next stable release of Godot Engine. 1D_Inc Abraham Haskins + Actual_Dio Adam Adam Brunnmeier Adam Carr @@ -337,7 +351,6 @@ generous deed immortalized in the next stable release of Godot Engine. Adisibio Adrien de Pierres Agar3s - Giovanny Beltrán - Agustinus Arya Ahmet Kalyoncu Aidan O'Flannagain Aki Mimoto @@ -348,16 +361,19 @@ generous deed immortalized in the next stable release of Godot Engine. AleMax Alessandro Senese Alexander Erlemann + Alexander Ravenheart Alexander Ryndin Alexander Walter (SilvanuZ) Alexandre Beaudoin + Alex Chan alex clavelle + alex raeside Alex (Well Done Games) - alks Allan Davis Allen Schade + Aloehart + Amanda Anders Marstein Kruke - Andreas Krampitz Andre Stackhouse andrew james morris Andrew Mansuetti @@ -365,7 +381,6 @@ generous deed immortalized in the next stable release of Godot Engine. Ano Nim Anthony Avina Anton Bouwer - aomimezura11 Arch Toasty Arda Erol Armin Preiml @@ -374,14 +389,17 @@ generous deed immortalized in the next stable release of Godot Engine. Ashley Claymore Astier Mickael Aubrey Falconer + Audun Borgersen aurelien condomines AzulCrescent Balázs Batári Bartosz Bielecki Benedikt + Benoit Jauvin-Girard Ben Vercammen Bernd Jänichen Bernhard Werner + Bill Thibault Bjarne Voigtländer Black Block blackjacksike @@ -401,7 +419,6 @@ generous deed immortalized in the next stable release of Godot Engine. Cameron Meyer Carlos Cejudo Carl van der Geest - Carwyn Edwards Cas Brugman Casey Cassidy James @@ -409,7 +426,6 @@ generous deed immortalized in the next stable release of Godot Engine. Chad Steadman Charles Alston Chris Chapin - Chris Jagusch Chris Langford Christian Clavet Christian Mauduit @@ -422,13 +438,15 @@ generous deed immortalized in the next stable release of Godot Engine. Clay Heaton Cody Parker Conall O + Conner Lane + Corchari + Craig Maloney Craig Post - CzechBlueBear Daniel Cheney Daniel Johnson - DanielMaximiano Daren Scot Wilson Dave Walker + David Baker David Bôle David May David Maziarka @@ -465,6 +483,7 @@ generous deed immortalized in the next stable release of Godot Engine. Felix Bohmann Flaredown Forty Doubleu + Francisco Garcia Florez Francois Holland Frank Game Endeavor @@ -476,13 +495,13 @@ generous deed immortalized in the next stable release of Godot Engine. Greg Olson Greyson Richey Grid + Grominet Guillaume Audirac Guillaume Pham Ngoc Guldoman - Gustavo Loureiro dos Reis Hal A - helija Heribert Hirth + Hoojib Houdini Blueprints Hunter Jones Ian Williams @@ -491,7 +510,7 @@ generous deed immortalized in the next stable release of Godot Engine. Ivan Nikolaev iveks Jackson Harmer - Jacob + Jacob D Jaguar Jaime Ruiz-Borau Vizárraga Jake D @@ -499,19 +518,25 @@ generous deed immortalized in the next stable release of Godot Engine. Jako Danar James James A F Manley + James Gary + James Guardino James Quincy James Thomas Jamie Massey + Janis Skuja Jan Vetulani JARKKO PARVIAINEN Jason Bolton Jason Malcolm-Herzmark Jason Uechi Jeff Hungerford + Jeffrey Berube Jennifer Graves Jesse Dubay - Jhon Adams + Jim Engstrand Joe Klemmer + Joel Höglund + John Bruce John Gabriel Jonah Branch Jonas @@ -524,6 +549,7 @@ generous deed immortalized in the next stable release of Godot Engine. Jon Bonazza Jon Oakes Jon Sully + Jordan West Jordy Goodridge Jorge Antunes Jorge Araya Navarro @@ -552,15 +578,19 @@ generous deed immortalized in the next stable release of Godot Engine. Kenneth Lee Kent Jofur Ketafuki + Kevin van Rooijen Kiri Jolly Kjetil Haugland Konstantin Goncharov + Krishna Nadoor Kristian Nygaard Jensen + Kronarq KsyTek Games - kt kycho + Kyle Burnett Kyle Jacobs Kyuppin + Lady Grach Lasse le Dous Laurent CHEA Laurent Tréguier @@ -585,7 +615,6 @@ generous deed immortalized in the next stable release of Godot Engine. Martin Holas Martin Trbola Marvin - MatÄ›j Drábek Mathieu Matt Edwards Matthew Booe @@ -594,13 +623,16 @@ generous deed immortalized in the next stable release of Godot Engine. Max Fiedler Maxime Blade Maxwell + Mecha Kaiju X Melissa Mears Merlyn Morgan-Graham mewin Michael Michael Bruce-Lockhart Michael Haney + Michael Morrison MichaÅ‚ Skwarek + Michel Candries MidoriBunn 'tis BS Mikayla Mike @@ -613,6 +645,7 @@ generous deed immortalized in the next stable release of Godot Engine. Molinghu Molly Jameson MoltenGears + Morwyn MrAZIE Mrjemandem Nathan Fish @@ -623,7 +656,9 @@ generous deed immortalized in the next stable release of Godot Engine. Neil Wang Nerdforge Nerdyninja + Nicholas La Roux Nicholas Orlowski + Nick Eldrenkamp Nick Macholl Niclas Eriksen Nicolas Goll-Perrier @@ -640,6 +675,7 @@ generous deed immortalized in the next stable release of Godot Engine. Omar Delarosa Oriol Muñoz Princep Oscar Domingo + Pascal Patrick Brock Patrick Nafarrete Paul Gieske @@ -650,7 +686,6 @@ generous deed immortalized in the next stable release of Godot Engine. Philip Cohoe Philip Ludington (MrPhil) Pierre Caye - Piotr Góral pj Point08 Preethi Vaidyanathan @@ -659,12 +694,15 @@ generous deed immortalized in the next stable release of Godot Engine. Rad Cat Rafa Laguna Raffaele Aramo + Rainer Amler + Rami Hanano RAMupgrade Remi Rampin Rémi Verschelde Reneator Riccardo Marini Richard Ivánek + Richard Néveri Riley Robert Farr (Larington) Rob Ruana @@ -677,13 +715,13 @@ generous deed immortalized in the next stable release of Godot Engine. Ryan Groom Sam Caulfield Sam Edson - Samuele Zolfanelli - Scott D. Yelich Scott Longley Sean Lynch Sebastian Michailidis SeongWan Kim Sergey + SeungJong k + Shaidak Shane Shane Sicienski Shane Spoor @@ -692,10 +730,11 @@ generous deed immortalized in the next stable release of Godot Engine. Simon Jonas Larsen Simon Schoenenberger Simon Wenner + sirn Skalli smbe19 smo1704 - soft circles + Solene Waked Squirrel Stéphane Roussel Steve Cloete @@ -712,13 +751,16 @@ generous deed immortalized in the next stable release of Godot Engine. thomas Thomas Bechtold Thomas Detoy - Thomas Hermansen Thomas Horwath + Tianren Qin + Till1805 Tim Drumheller Tim Erskine Tim Gleason Timothy B. MacDonald + Title Plinsut TMoney + Toadile Tobias Bradtke Tom Coxon Toni Duran @@ -758,6 +800,7 @@ generous deed immortalized in the next stable release of Godot Engine. Yegor Smirnov Zak Stephens è•æƒŸå… + éƒæ™¨ç…œ ## Bronze donors diff --git a/SConstruct b/SConstruct index f8e3a68edd..8b37bb8285 100644 --- a/SConstruct +++ b/SConstruct @@ -4,10 +4,12 @@ EnsureSConsVersion(3, 0, 0) EnsurePythonVersion(3, 5) # System +import atexit import glob import os import pickle import sys +import time from collections import OrderedDict # Local @@ -25,6 +27,8 @@ active_platform_ids = [] platform_exporters = [] platform_apis = [] +time_at_start = time.time() + for x in sorted(glob.glob("platform/*")): if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"): continue @@ -551,11 +555,10 @@ if selected_platform in platform_list: if env["target"] == "release": if env["tools"]: - print("Tools can only be built with targets 'debug' and 'release_debug'.") + print("Error: The editor can only be built with `target=debug` or `target=release_debug`.") Exit(255) suffix += ".opt" env.Append(CPPDEFINES=["NDEBUG"]) - elif env["target"] == "release_debug": if env["tools"]: suffix += ".opt.tools" @@ -563,8 +566,14 @@ if selected_platform in platform_list: suffix += ".opt.debug" else: if env["tools"]: + print( + "Note: Building a debug binary (which will run slowly). Use `target=release_debug` to build an optimized release binary." + ) suffix += ".tools" else: + print( + "Note: Building a debug binary (which will run slowly). Use `target=release` to build an optimized release binary." + ) suffix += ".debug" if env["arch"] != "": @@ -743,3 +752,12 @@ if "env" in locals(): # TODO: replace this with `env.Dump(format="json")` # once we start requiring SCons 4.0 as min version. methods.dump(env) + + +def print_elapsed_time(): + elapsed_time_sec = round(time.time() - time_at_start, 3) + time_ms = round((elapsed_time_sec % 1) * 1000) + print(f"[Time elapsed: {time.strftime('%H:%M:%S', time.gmtime(elapsed_time_sec))}.{time_ms:03}]") + + +atexit.register(print_elapsed_time) diff --git a/core/SCsub b/core/SCsub index e3ba46be02..d9167b8f83 100644 --- a/core/SCsub +++ b/core/SCsub @@ -186,6 +186,7 @@ SConscript("io/SCsub") SConscript("debugger/SCsub") SConscript("input/SCsub") SConscript("variant/SCsub") +SConscript("extension/SCsub") SConscript("object/SCsub") SConscript("templates/SCsub") SConscript("string/SCsub") diff --git a/core/config/engine.cpp b/core/config/engine.cpp index c43e32868c..ad31966a65 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -190,6 +190,14 @@ bool Engine::is_validation_layers_enabled() const { return use_validation_layers; } +void Engine::set_print_error_messages(bool p_enabled) { + _print_error_enabled = p_enabled; +} + +bool Engine::is_printing_error_messages() const { + return _print_error_enabled; +} + void Engine::add_singleton(const Singleton &p_singleton) { singletons.push_back(p_singleton); singleton_ptrs[p_singleton.name] = p_singleton.ptr; @@ -228,13 +236,14 @@ Engine::Engine() { singleton = this; } -Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr) : +Engine::Singleton::Singleton(const StringName &p_name, Object *p_ptr, const StringName &p_class_name) : name(p_name), - ptr(p_ptr) { + ptr(p_ptr), + class_name(p_class_name) { #ifdef DEBUG_ENABLED - Reference *ref = Object::cast_to<Reference>(p_ptr); - if (ref && !ref->is_referenced()) { - WARN_PRINT("You must use Ref<> to ensure the lifetime of a Reference object intended to be used as a singleton."); + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); + if (rc && !rc->is_referenced()) { + WARN_PRINT("You must use Ref<> to ensure the lifetime of a RefCounted object intended to be used as a singleton."); } #endif } diff --git a/core/config/engine.h b/core/config/engine.h index 276da1c7ea..970cfb03e8 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -41,7 +41,8 @@ public: struct Singleton { StringName name; Object *ptr; - Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr); + StringName class_name; //used for binding generation hinting + Singleton(const StringName &p_name = StringName(), Object *p_ptr = nullptr, const StringName &p_class_name = StringName()); }; private: @@ -100,6 +101,9 @@ public: void set_time_scale(float p_scale); float get_time_scale() const; + void set_print_error_messages(bool p_enabled); + bool is_printing_error_messages() const; + void set_frame_delay(uint32_t p_msec); uint32_t get_frame_delay() const; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 53d13f7429..ac4e0db5b7 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -33,11 +33,11 @@ #include "core/core_bind.h" #include "core/core_string_names.h" #include "core/input/input_map.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_network.h" #include "core/io/file_access_pack.h" #include "core/io/marshalls.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" @@ -62,7 +62,7 @@ String ProjectSettings::localize_path(const String &p_path) const { } if (p_path.begins_with("res://") || p_path.begins_with("user://") || - (p_path.is_abs_path() && !p_path.begins_with(resource_path))) { + (p_path.is_absolute_path() && !p_path.begins_with(resource_path))) { return p_path.simplify_path(); } @@ -248,7 +248,7 @@ struct _VCSort { String name; Variant::Type type; int order; - int flags; + uint32_t flags; bool operator<(const _VCSort &p_vcs) const { return order == p_vcs.order ? name < p_vcs.name : order < p_vcs.order; } }; @@ -711,8 +711,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str file->store_32(count + 1); //store how many properties are saved, add one for custom featuers, which must always go first String key = CoreStringNames::get_singleton()->_custom_features; - file->store_32(key.length()); - file->store_string(key); + file->store_pascal_string(key); int len; err = encode_variant(p_custom_features, nullptr, len, false); @@ -749,8 +748,7 @@ Error ProjectSettings::_save_settings_binary(const String &p_file, const Map<Str value = get(key); } - file->store_32(key.length()); - file->store_string(key); + file->store_pascal_string(key); int len; err = encode_variant(value, nullptr, len, true); @@ -1102,7 +1100,7 @@ ProjectSettings::ProjectSettings() { if (Engine::get_singleton()->has_singleton("GodotSharp")) { extensions.push_back("cs"); } - extensions.push_back("shader"); + extensions.push_back("gdshader"); GLOBAL_DEF("editor/run/main_run_args", ""); @@ -1116,6 +1114,8 @@ ProjectSettings::ProjectSettings() { // Keep the enum values in sync with the `DisplayServer::ScreenOrientation` enum. custom_prop_info["display/window/handheld/orientation"] = PropertyInfo(Variant::INT, "display/window/handheld/orientation", PROPERTY_HINT_ENUM, "Landscape,Portrait,Reverse Landscape,Reverse Portrait,Sensor Landscape,Sensor Portrait,Sensor"); + // Keep the enum values in sync with the `DisplayServer::VSyncMode` enum. + custom_prop_info["display/window/vsync/vsync_mode"] = PropertyInfo(Variant::INT, "display/window/vsync/vsync_mode", PROPERTY_HINT_ENUM, "Disabled,Enabled,Adaptive,Mailbox"); custom_prop_info["rendering/driver/threads/thread_model"] = PropertyInfo(Variant::INT, "rendering/driver/threads/thread_model", PROPERTY_HINT_ENUM, "Single-Unsafe,Single-Safe,Multi-Threaded"); GLOBAL_DEF("physics/2d/run_on_thread", false); GLOBAL_DEF("physics/3d/run_on_thread", false); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index ed4387a1b9..a3349444c4 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -35,35 +35,12 @@ #include "core/debugger/engine_debugger.h" #include "core/io/file_access_compressed.h" #include "core/io/file_access_encrypted.h" -#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" #include "core/os/keyboard.h" #include "core/os/os.h" -/** - * Time constants borrowed from loc_time.h - */ -#define EPOCH_YR 1970 /* EPOCH = Jan 1 1970 00:00:00 */ -#define SECS_DAY (24L * 60L * 60L) -#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) -#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365) -#define SECOND_KEY "second" -#define MINUTE_KEY "minute" -#define HOUR_KEY "hour" -#define DAY_KEY "day" -#define MONTH_KEY "month" -#define YEAR_KEY "year" -#define WEEKDAY_KEY "weekday" -#define DST_KEY "dst" - -/// Table of number of days in each month (for regular year and leap year) -static const unsigned int MONTH_DAYS_TABLE[2][12] = { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } -}; - ////// _ResourceLoader ////// _ResourceLoader *_ResourceLoader::singleton = nullptr; @@ -322,197 +299,6 @@ uint64_t _OS::get_static_memory_peak_usage() const { return OS::get_singleton()->get_static_memory_peak_usage(); } -/** - * Get current datetime with consideration for utc and - * dst - */ -Dictionary _OS::get_datetime(bool utc) const { - Dictionary dated = get_date(utc); - Dictionary timed = get_time(utc); - - List<Variant> keys; - timed.get_key_list(&keys); - - for (int i = 0; i < keys.size(); i++) { - dated[keys[i]] = timed[keys[i]]; - } - - return dated; -} - -Dictionary _OS::get_date(bool utc) const { - OS::Date date = OS::get_singleton()->get_date(utc); - Dictionary dated; - dated[YEAR_KEY] = date.year; - dated[MONTH_KEY] = date.month; - dated[DAY_KEY] = date.day; - dated[WEEKDAY_KEY] = date.weekday; - dated[DST_KEY] = date.dst; - return dated; -} - -Dictionary _OS::get_time(bool utc) const { - OS::Time time = OS::get_singleton()->get_time(utc); - Dictionary timed; - timed[HOUR_KEY] = time.hour; - timed[MINUTE_KEY] = time.min; - timed[SECOND_KEY] = time.sec; - return timed; -} - -/** - * Get an epoch time value from a dictionary of time values - * @p datetime must be populated with the following keys: - * day, hour, minute, month, second, year. (dst is ignored). - * - * You can pass the output from - * get_datetime_from_unix_time directly into this function - * - * @param datetime dictionary of date and time values to convert - * - * @return epoch calculated - */ -int64_t _OS::get_unix_time_from_datetime(Dictionary datetime) const { - // if datetime is an empty Dictionary throws an error - ERR_FAIL_COND_V_MSG(datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); - - // Bunch of conversion constants - static const unsigned int SECONDS_PER_MINUTE = 60; - static const unsigned int MINUTES_PER_HOUR = 60; - static const unsigned int HOURS_PER_DAY = 24; - static const unsigned int SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE; - static const unsigned int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY; - - // Get all time values from the dictionary, set to zero if it doesn't exist. - // Risk incorrect calculation over throwing errors - unsigned int second = ((datetime.has(SECOND_KEY)) ? static_cast<unsigned int>(datetime[SECOND_KEY]) : 0); - unsigned int minute = ((datetime.has(MINUTE_KEY)) ? static_cast<unsigned int>(datetime[MINUTE_KEY]) : 0); - unsigned int hour = ((datetime.has(HOUR_KEY)) ? static_cast<unsigned int>(datetime[HOUR_KEY]) : 0); - unsigned int day = ((datetime.has(DAY_KEY)) ? static_cast<unsigned int>(datetime[DAY_KEY]) : 1); - unsigned int month = ((datetime.has(MONTH_KEY)) ? static_cast<unsigned int>(datetime[MONTH_KEY]) : 1); - unsigned int year = ((datetime.has(YEAR_KEY)) ? static_cast<unsigned int>(datetime[YEAR_KEY]) : 1970); - - /// How many days come before each month (0-12) - static const unsigned short int DAYS_PAST_THIS_YEAR_TABLE[2][13] = { - /* Normal years. */ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, - /* Leap years. */ - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } - }; - - ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + "."); - ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); - ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); - ERR_FAIL_COND_V_MSG(year == 0, 0, "Years before 1 AD are not supported. Value passed: " + itos(year) + "."); - ERR_FAIL_COND_V_MSG(month > 12 || month == 0, 0, "Invalid month value of: " + itos(month) + "."); - // Do this check after month is tested as valid - unsigned int days_in_month = MONTH_DAYS_TABLE[LEAPYEAR(year)][month - 1]; - ERR_FAIL_COND_V_MSG(day == 0 || day > days_in_month, 0, "Invalid day value of: " + itos(day) + ". It should be comprised between 1 and " + itos(days_in_month) + " for month " + itos(month) + "."); - - // Calculate all the seconds from months past in this year - uint64_t SECONDS_FROM_MONTHS_PAST_THIS_YEAR = DAYS_PAST_THIS_YEAR_TABLE[LEAPYEAR(year)][month - 1] * SECONDS_PER_DAY; - - int64_t SECONDS_FROM_YEARS_PAST = 0; - if (year >= EPOCH_YR) { - for (unsigned int iyear = EPOCH_YR; iyear < year; iyear++) { - SECONDS_FROM_YEARS_PAST += YEARSIZE(iyear) * SECONDS_PER_DAY; - } - } else { - for (unsigned int iyear = EPOCH_YR - 1; iyear >= year; iyear--) { - SECONDS_FROM_YEARS_PAST -= YEARSIZE(iyear) * SECONDS_PER_DAY; - } - } - - int64_t epoch = - second + - minute * SECONDS_PER_MINUTE + - hour * SECONDS_PER_HOUR + - // Subtract 1 from day, since the current day isn't over yet - // and we cannot count all 24 hours. - (day - 1) * SECONDS_PER_DAY + - SECONDS_FROM_MONTHS_PAST_THIS_YEAR + - SECONDS_FROM_YEARS_PAST; - return epoch; -} - -/** - * Get a dictionary of time values when given epoch time - * - * Dictionary Time values will be a union if values from #get_time - * and #get_date dictionaries (with the exception of dst = - * day light standard time, as it cannot be determined from epoch) - * - * @param unix_time_val epoch time to convert - * - * @return dictionary of date and time values - */ -Dictionary _OS::get_datetime_from_unix_time(int64_t unix_time_val) const { - OS::Date date; - OS::Time time; - - long dayclock, dayno; - int year = EPOCH_YR; - - if (unix_time_val >= 0) { - dayno = unix_time_val / SECS_DAY; - dayclock = unix_time_val % SECS_DAY; - /* day 0 was a thursday */ - date.weekday = static_cast<OS::Weekday>((dayno + 4) % 7); - while (dayno >= YEARSIZE(year)) { - dayno -= YEARSIZE(year); - year++; - } - } else { - dayno = (unix_time_val - SECS_DAY + 1) / SECS_DAY; - dayclock = unix_time_val - dayno * SECS_DAY; - date.weekday = static_cast<OS::Weekday>(((dayno % 7) + 11) % 7); - do { - year--; - dayno += YEARSIZE(year); - } while (dayno < 0); - } - - time.sec = dayclock % 60; - time.min = (dayclock % 3600) / 60; - time.hour = dayclock / 3600; - date.year = year; - - size_t imonth = 0; - - while ((unsigned long)dayno >= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]) { - dayno -= MONTH_DAYS_TABLE[LEAPYEAR(year)][imonth]; - imonth++; - } - - /// Add 1 to month to make sure months are indexed starting at 1 - date.month = static_cast<OS::Month>(imonth + 1); - - date.day = dayno + 1; - - Dictionary timed; - timed[HOUR_KEY] = time.hour; - timed[MINUTE_KEY] = time.min; - timed[SECOND_KEY] = time.sec; - timed[YEAR_KEY] = date.year; - timed[MONTH_KEY] = date.month; - timed[DAY_KEY] = date.day; - timed[WEEKDAY_KEY] = date.weekday; - - return timed; -} - -Dictionary _OS::get_time_zone_info() const { - OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info(); - Dictionary infod; - infod["bias"] = info.bias; - infod["name"] = info.name; - return infod; -} - -double _OS::get_unix_time() const { - return OS::get_singleton()->get_unix_time(); -} - /** This method uses a signed argument for better error reporting as it's used from the scripting API. */ void _OS::delay_usec(int p_usec) const { ERR_FAIL_COND_MSG( @@ -529,14 +315,6 @@ void _OS::delay_msec(int p_msec) const { OS::get_singleton()->delay_usec(int64_t(p_msec) * 1000); } -uint32_t _OS::get_ticks_msec() const { - return OS::get_singleton()->get_ticks_msec(); -} - -uint64_t _OS::get_ticks_usec() const { - return OS::get_singleton()->get_ticks_usec(); -} - bool _OS::can_use_threads() const { return OS::get_singleton()->can_use_threads(); } @@ -643,6 +421,25 @@ String _OS::get_user_data_dir() const { return OS::get_singleton()->get_user_data_dir(); } +String _OS::get_external_data_dir() const { + return OS::get_singleton()->get_external_data_dir(); +} + +String _OS::get_config_dir() const { + // Exposed as `get_config_dir()` instead of `get_config_path()` for consistency with other exposed OS methods. + return OS::get_singleton()->get_config_path(); +} + +String _OS::get_data_dir() const { + // Exposed as `get_data_dir()` instead of `get_data_path()` for consistency with other exposed OS methods. + return OS::get_singleton()->get_data_path(); +} + +String _OS::get_cache_dir() const { + // Exposed as `get_cache_dir()` instead of `get_cache_path()` for consistency with other exposed OS methods. + return OS::get_singleton()->get_cache_path(); +} + bool _OS::is_debug_build() const { #ifdef DEBUG_ENABLED return true; @@ -712,18 +509,8 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_name"), &_OS::get_name); ClassDB::bind_method(D_METHOD("get_cmdline_args"), &_OS::get_cmdline_args); - ClassDB::bind_method(D_METHOD("get_datetime", "utc"), &_OS::get_datetime, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_date", "utc"), &_OS::get_date, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_time", "utc"), &_OS::get_time, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_time_zone_info"), &_OS::get_time_zone_info); - ClassDB::bind_method(D_METHOD("get_unix_time"), &_OS::get_unix_time); - ClassDB::bind_method(D_METHOD("get_datetime_from_unix_time", "unix_time_val"), &_OS::get_datetime_from_unix_time); - ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime", "datetime"), &_OS::get_unix_time_from_datetime); - ClassDB::bind_method(D_METHOD("delay_usec", "usec"), &_OS::delay_usec); ClassDB::bind_method(D_METHOD("delay_msec", "msec"), &_OS::delay_msec); - ClassDB::bind_method(D_METHOD("get_ticks_msec"), &_OS::get_ticks_msec); - ClassDB::bind_method(D_METHOD("get_ticks_usec"), &_OS::get_ticks_usec); ClassDB::bind_method(D_METHOD("get_locale"), &_OS::get_locale); ClassDB::bind_method(D_METHOD("get_model_name"), &_OS::get_model_name); @@ -743,7 +530,11 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_static_memory_peak_usage"), &_OS::get_static_memory_peak_usage); ClassDB::bind_method(D_METHOD("get_user_data_dir"), &_OS::get_user_data_dir); + ClassDB::bind_method(D_METHOD("get_external_data_dir"), &_OS::get_external_data_dir); ClassDB::bind_method(D_METHOD("get_system_dir", "dir"), &_OS::get_system_dir); + ClassDB::bind_method(D_METHOD("get_config_dir"), &_OS::get_config_dir); + ClassDB::bind_method(D_METHOD("get_data_dir"), &_OS::get_data_dir); + ClassDB::bind_method(D_METHOD("get_cache_dir"), &_OS::get_cache_dir); ClassDB::bind_method(D_METHOD("get_unique_id"), &_OS::get_unique_id); ClassDB::bind_method(D_METHOD("print_all_textures_by_size"), &_OS::print_all_textures_by_size); @@ -2059,17 +1850,17 @@ bool _ClassDB::is_parent_class(const StringName &p_class, const StringName &p_in return ClassDB::is_parent_class(p_class, p_inherits); } -bool _ClassDB::can_instance(const StringName &p_class) const { - return ClassDB::can_instance(p_class); +bool _ClassDB::can_instantiate(const StringName &p_class) const { + return ClassDB::can_instantiate(p_class); } -Variant _ClassDB::instance(const StringName &p_class) const { - Object *obj = ClassDB::instance(p_class); +Variant _ClassDB::instantiate(const StringName &p_class) const { + Object *obj = ClassDB::instantiate(p_class); if (!obj) { return Variant(); } - Reference *r = Object::cast_to<Reference>(obj); + RefCounted *r = Object::cast_to<RefCounted>(obj); if (r) { return REF(r); } else { @@ -2193,8 +1984,8 @@ void _ClassDB::_bind_methods() { ClassDB::bind_method(D_METHOD("get_parent_class", "class"), &_ClassDB::get_parent_class); ClassDB::bind_method(D_METHOD("class_exists", "class"), &_ClassDB::class_exists); ClassDB::bind_method(D_METHOD("is_parent_class", "class", "inherits"), &_ClassDB::is_parent_class); - ClassDB::bind_method(D_METHOD("can_instance", "class"), &_ClassDB::can_instance); - ClassDB::bind_method(D_METHOD("instance", "class"), &_ClassDB::instance); + ClassDB::bind_method(D_METHOD("can_instantiate", "class"), &_ClassDB::can_instantiate); + ClassDB::bind_method(D_METHOD("instantiate", "class"), &_ClassDB::instantiate); ClassDB::bind_method(D_METHOD("class_has_signal", "class", "signal"), &_ClassDB::has_signal); ClassDB::bind_method(D_METHOD("class_get_signal", "class", "signal"), &_ClassDB::get_signal); @@ -2320,6 +2111,14 @@ bool _Engine::is_editor_hint() const { return Engine::get_singleton()->is_editor_hint(); } +void _Engine::set_print_error_messages(bool p_enabled) { + Engine::get_singleton()->set_print_error_messages(p_enabled); +} + +bool _Engine::is_printing_error_messages() const { + return Engine::get_singleton()->is_printing_error_messages(); +} + void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_iterations_per_second", "iterations_per_second"), &_Engine::set_iterations_per_second); ClassDB::bind_method(D_METHOD("get_iterations_per_second"), &_Engine::get_iterations_per_second); @@ -2354,7 +2153,11 @@ void _Engine::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editor_hint", "enabled"), &_Engine::set_editor_hint); ClassDB::bind_method(D_METHOD("is_editor_hint"), &_Engine::is_editor_hint); + ClassDB::bind_method(D_METHOD("set_print_error_messages", "enabled"), &_Engine::set_print_error_messages); + ClassDB::bind_method(D_METHOD("is_printing_error_messages"), &_Engine::is_printing_error_messages); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_hint"), "set_editor_hint", "is_editor_hint"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "print_error_messages"), "set_print_error_messages", "is_printing_error_messages"); ADD_PROPERTY(PropertyInfo(Variant::INT, "iterations_per_second"), "set_iterations_per_second", "get_iterations_per_second"); ADD_PROPERTY(PropertyInfo(Variant::INT, "target_fps"), "set_target_fps", "get_target_fps"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_scale"), "set_time_scale", "get_time_scale"); @@ -2363,80 +2166,6 @@ void _Engine::_bind_methods() { _Engine *_Engine::singleton = nullptr; -////// _JSON ////// - -void JSONParseResult::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_error"), &JSONParseResult::get_error); - ClassDB::bind_method(D_METHOD("get_error_string"), &JSONParseResult::get_error_string); - ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParseResult::get_error_line); - ClassDB::bind_method(D_METHOD("get_result"), &JSONParseResult::get_result); - - ClassDB::bind_method(D_METHOD("set_error", "error"), &JSONParseResult::set_error); - ClassDB::bind_method(D_METHOD("set_error_string", "error_string"), &JSONParseResult::set_error_string); - ClassDB::bind_method(D_METHOD("set_error_line", "error_line"), &JSONParseResult::set_error_line); - ClassDB::bind_method(D_METHOD("set_result", "result"), &JSONParseResult::set_result); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "error", PROPERTY_HINT_NONE, "Error", PROPERTY_USAGE_CLASS_IS_ENUM), "set_error", "get_error"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "error_string"), "set_error_string", "get_error_string"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "error_line"), "set_error_line", "get_error_line"); - ADD_PROPERTY(PropertyInfo(Variant::NIL, "result", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_result", "get_result"); -} - -void JSONParseResult::set_error(Error p_error) { - error = p_error; -} - -Error JSONParseResult::get_error() const { - return error; -} - -void JSONParseResult::set_error_string(const String &p_error_string) { - error_string = p_error_string; -} - -String JSONParseResult::get_error_string() const { - return error_string; -} - -void JSONParseResult::set_error_line(int p_error_line) { - error_line = p_error_line; -} - -int JSONParseResult::get_error_line() const { - return error_line; -} - -void JSONParseResult::set_result(const Variant &p_result) { - result = p_result; -} - -Variant JSONParseResult::get_result() const { - return result; -} - -void _JSON::_bind_methods() { - ClassDB::bind_method(D_METHOD("print", "value", "indent", "sort_keys"), &_JSON::print, DEFVAL(String()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("parse", "json"), &_JSON::parse); -} - -String _JSON::print(const Variant &p_value, const String &p_indent, bool p_sort_keys) { - return JSON::print(p_value, p_indent, p_sort_keys); -} - -Ref<JSONParseResult> _JSON::parse(const String &p_json) { - Ref<JSONParseResult> result; - result.instance(); - - result->error = JSON::parse(p_json, result->result, result->error_string, result->error_line); - - if (result->error != OK) { - ERR_PRINT(vformat("Error parsing JSON at line %s: %s", result->error_line, result->error_string)); - } - return result; -} - -_JSON *_JSON::singleton = nullptr; - ////// _EngineDebugger ////// void _EngineDebugger::_bind_methods() { diff --git a/core/core_bind.h b/core/core_bind.h index d05353bf0f..673dbe32c4 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -32,11 +32,11 @@ #define CORE_BIND_H #include "core/io/compression.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/os/semaphore.h" #include "core/os/thread.h" @@ -199,14 +199,6 @@ public: void set_use_file_access_save_and_swap(bool p_enable); - Dictionary get_date(bool utc) const; - Dictionary get_time(bool utc) const; - Dictionary get_datetime(bool utc) const; - Dictionary get_datetime_from_unix_time(int64_t unix_time_val) const; - int64_t get_unix_time_from_datetime(Dictionary datetime) const; - Dictionary get_time_zone_info() const; - double get_unix_time() const; - uint64_t get_static_memory_usage() const; uint64_t get_static_memory_peak_usage() const; @@ -237,6 +229,10 @@ public: String get_system_dir(SystemDir p_dir) const; String get_user_data_dir() const; + String get_external_data_dir() const; + String get_config_dir() const; + String get_data_dir() const; + String get_cache_dir() const; Error set_thread_name(const String &p_name); Thread::ID get_thread_caller_id() const; @@ -352,8 +348,8 @@ public: _Geometry3D() { singleton = this; } }; -class _File : public Reference { - GDCLASS(_File, Reference); +class _File : public RefCounted { + GDCLASS(_File, RefCounted); FileAccess *f = nullptr; bool big_endian = false; @@ -454,8 +450,8 @@ public: VARIANT_ENUM_CAST(_File::ModeFlags); VARIANT_ENUM_CAST(_File::CompressionMode); -class _Directory : public Reference { - GDCLASS(_Directory, Reference); +class _Directory : public RefCounted { + GDCLASS(_Directory, RefCounted); DirAccess *d; bool dir_open = false; @@ -524,8 +520,8 @@ public: ~_Marshalls() { singleton = nullptr; } }; -class _Mutex : public Reference { - GDCLASS(_Mutex, Reference); +class _Mutex : public RefCounted { + GDCLASS(_Mutex, RefCounted); Mutex mutex; static void _bind_methods(); @@ -536,8 +532,8 @@ public: void unlock(); }; -class _Semaphore : public Reference { - GDCLASS(_Semaphore, Reference); +class _Semaphore : public RefCounted { + GDCLASS(_Semaphore, RefCounted); Semaphore semaphore; static void _bind_methods(); @@ -548,8 +544,8 @@ public: void post(); }; -class _Thread : public Reference { - GDCLASS(_Thread, Reference); +class _Thread : public RefCounted { + GDCLASS(_Thread, RefCounted); protected: Variant ret; @@ -589,8 +585,8 @@ public: StringName get_parent_class(const StringName &p_class) const; bool class_exists(const StringName &p_class) const; bool is_parent_class(const StringName &p_class, const StringName &p_inherits) const; - bool can_instance(const StringName &p_class) const; - Variant instance(const StringName &p_class) const; + bool can_instantiate(const StringName &p_class) const; + Variant instantiate(const StringName &p_class) const; bool has_signal(StringName p_class, StringName p_signal) const; Dictionary get_signal(StringName p_class, StringName p_signal) const; @@ -660,55 +656,10 @@ public: void set_editor_hint(bool p_enabled); bool is_editor_hint() const; - _Engine() { singleton = this; } -}; - -class _JSON; - -class JSONParseResult : public Reference { - GDCLASS(JSONParseResult, Reference); - - friend class _JSON; - - Error error; - String error_string; - int error_line = -1; - - Variant result; - -protected: - static void _bind_methods(); - -public: - void set_error(Error p_error); - Error get_error() const; - - void set_error_string(const String &p_error_string); - String get_error_string() const; - - void set_error_line(int p_error_line); - int get_error_line() const; + void set_print_error_messages(bool p_enabled); + bool is_printing_error_messages() const; - void set_result(const Variant &p_result); - Variant get_result() const; - - JSONParseResult() {} -}; - -class _JSON : public Object { - GDCLASS(_JSON, Object); - -protected: - static void _bind_methods(); - static _JSON *singleton; - -public: - static _JSON *get_singleton() { return singleton; } - - String print(const Variant &p_value, const String &p_indent = "", bool p_sort_keys = false); - Ref<JSONParseResult> parse(const String &p_json); - - _JSON() { singleton = this; } + _Engine() { singleton = this; } }; class _EngineDebugger : public Object { diff --git a/core/core_constants.cpp b/core/core_constants.cpp index a0a41015dc..0aad21276a 100644 --- a/core/core_constants.cpp +++ b/core/core_constants.cpp @@ -106,10 +106,6 @@ static Vector<_CoreConstant> _global_constants; VARIANT_ENUM_CAST(Key); VARIANT_ENUM_CAST(KeyModifierMask); -VARIANT_ENUM_CAST(MouseButton); -VARIANT_ENUM_CAST(JoyButton); -VARIANT_ENUM_CAST(JoyAxis); -VARIANT_ENUM_CAST(MIDIMessage); void register_global_constants() { BIND_CORE_ENUM_CONSTANT(SIDE_LEFT); @@ -512,7 +508,6 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_NONE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_RANGE); - BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_RANGE); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_ENUM); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_EXP_EASING); BIND_CORE_ENUM_CONSTANT(PROPERTY_HINT_LENGTH); @@ -580,10 +575,10 @@ void register_global_constants() { BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_VECTOR3I", Variant::VECTOR3I); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM2D", Variant::TRANSFORM2D); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_PLANE", Variant::PLANE); - BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUAT", Variant::QUAT); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_QUATERNION", Variant::QUATERNION); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_AABB", Variant::AABB); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_BASIS", Variant::BASIS); - BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM", Variant::TRANSFORM); + BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_TRANSFORM3D", Variant::TRANSFORM3D); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_COLOR", Variant::COLOR); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_STRING_NAME", Variant::STRING_NAME); BIND_CORE_ENUM_CONSTANT_CUSTOM("TYPE_NODE_PATH", Variant::NODE_PATH); diff --git a/core/crypto/aes_context.h b/core/crypto/aes_context.h index cc00b18fd2..2f8422f537 100644 --- a/core/crypto/aes_context.h +++ b/core/crypto/aes_context.h @@ -32,10 +32,10 @@ #define AES_CONTEXT_H #include "core/crypto/crypto_core.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class AESContext : public Reference { - GDCLASS(AESContext, Reference); +class AESContext : public RefCounted { + GDCLASS(AESContext, RefCounted); public: enum Mode { diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index 9438fcfea5..a46f42949d 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -35,7 +35,7 @@ #include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class CryptoKey : public Resource { GDCLASS(CryptoKey, Resource); @@ -67,8 +67,8 @@ public: virtual Error save(String p_path) = 0; }; -class HMACContext : public Reference { - GDCLASS(HMACContext, Reference); +class HMACContext : public RefCounted { + GDCLASS(HMACContext, RefCounted); protected: static void _bind_methods(); @@ -82,10 +82,11 @@ public: virtual PackedByteArray finish() = 0; HMACContext() {} + virtual ~HMACContext() {} }; -class Crypto : public Reference { - GDCLASS(Crypto, Reference); +class Crypto : public RefCounted { + GDCLASS(Crypto, RefCounted); protected: static void _bind_methods(); diff --git a/core/crypto/crypto_core.h b/core/crypto/crypto_core.h index 27b380e838..7a2f4df589 100644 --- a/core/crypto/crypto_core.h +++ b/core/crypto/crypto_core.h @@ -31,7 +31,7 @@ #ifndef CRYPTO_CORE_H #define CRYPTO_CORE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class CryptoCore { public: diff --git a/core/crypto/hashing_context.h b/core/crypto/hashing_context.h index 892a48a4e8..31521a147c 100644 --- a/core/crypto/hashing_context.h +++ b/core/crypto/hashing_context.h @@ -31,10 +31,10 @@ #ifndef HASHING_CONTEXT_H #define HASHING_CONTEXT_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class HashingContext : public Reference { - GDCLASS(HashingContext, Reference); +class HashingContext : public RefCounted { + GDCLASS(HashingContext, RefCounted); public: enum HashType { diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp index 39113eda14..ea5e32203c 100644 --- a/core/debugger/remote_debugger_peer.cpp +++ b/core/debugger/remote_debugger_peer.cpp @@ -84,7 +84,7 @@ RemoteDebuggerPeerTCP::RemoteDebuggerPeerTCP(Ref<StreamPeerTCP> p_tcp) { thread.start(_thread_func, this); #endif } else { - tcp_client.instance(); + tcp_client.instantiate(); } } diff --git a/core/debugger/remote_debugger_peer.h b/core/debugger/remote_debugger_peer.h index 652e2d9d20..8cba53a81c 100644 --- a/core/debugger/remote_debugger_peer.h +++ b/core/debugger/remote_debugger_peer.h @@ -32,12 +32,12 @@ #define REMOTE_DEBUGGER_PEER_H #include "core/io/stream_peer_tcp.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/os/thread.h" #include "core/string/ustring.h" -class RemoteDebuggerPeer : public Reference { +class RemoteDebuggerPeer : public RefCounted { protected: int max_queued_messages = 4096; diff --git a/core/extension/SCsub b/core/extension/SCsub new file mode 100644 index 0000000000..a3a54250c1 --- /dev/null +++ b/core/extension/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import("env") + +env_extension = env.Clone() + +env_extension.add_source_files(env.core_sources, "*.cpp") diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp new file mode 100644 index 0000000000..3c132a619d --- /dev/null +++ b/core/extension/extension_api_dump.cpp @@ -0,0 +1,805 @@ +/*************************************************************************/ +/* extension_api_dump.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "extension_api_dump.h" +#include "core/config/engine.h" +#include "core/core_constants.h" +#include "core/io/file_access.h" +#include "core/io/json.h" +#include "core/templates/pair.h" +#include "core/version.h" + +#ifdef TOOLS_ENABLED + +Dictionary NativeExtensionAPIDump::generate_extension_api() { + Dictionary api_dump; + + { + //header + Dictionary header; + header["version_major"] = VERSION_MAJOR; + header["version_minor"] = VERSION_MINOR; +#if VERSION_PATCH + header["version_patch"] = VERSION_PATCH; +#else + header["version_patch"] = 0; +#endif + header["version_status"] = VERSION_STATUS; + header["version_build"] = VERSION_BUILD; + header["version_full_name"] = VERSION_FULL_NAME; + + api_dump["header"] = header; + } + + const uint32_t vec3_elems = 3; + const uint32_t ptrsize_32 = 4; + const uint32_t ptrsize_64 = 4; + static const char *build_config_name[4] = { "float_32", "float_64", "double_32", "double_64" }; + + { + //type sizes + struct { + Variant::Type type; + uint32_t size_32_bits_real_float; + uint32_t size_64_bits_real_float; + uint32_t size_32_bits_real_double; + uint32_t size_64_bits_real_double; + } type_size_array[Variant::VARIANT_MAX + 1] = { + { Variant::NIL, 0, 0, 0, 0 }, + { Variant::BOOL, sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t), sizeof(uint32_t) }, + { Variant::INT, sizeof(int64_t), sizeof(int64_t), sizeof(int64_t), sizeof(int64_t) }, + { Variant::FLOAT, sizeof(double), sizeof(double), sizeof(double), sizeof(double) }, + { Variant::STRING, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::VECTOR2, 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, + { Variant::VECTOR2I, 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, + { Variant::RECT2, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) }, + { Variant::RECT2I, 4 * sizeof(int32_t), 4 * sizeof(int32_t), 4 * sizeof(int32_t), 4 * sizeof(int32_t) }, + { Variant::VECTOR3, vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, + { Variant::VECTOR3I, 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t), 3 * sizeof(int32_t) }, + { Variant::TRANSFORM2D, 6 * sizeof(float), 6 * sizeof(float), 6 * sizeof(double), 6 * sizeof(double) }, + { Variant::PLANE, (vec3_elems + 1) * sizeof(float), (vec3_elems + 1) * sizeof(float), (vec3_elems + 1) * sizeof(double), (vec3_elems + 1) * sizeof(double) }, + { Variant::QUATERNION, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) }, + { Variant::AABB, (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(float), (vec3_elems * 2) * sizeof(double), (vec3_elems * 2) * sizeof(double) }, + { Variant::BASIS, (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) }, + { Variant::TRANSFORM3D, (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(float), (vec3_elems * 4) * sizeof(double), (vec3_elems * 4) * sizeof(double) }, + { Variant::COLOR, 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(float) }, + { Variant::STRING_NAME, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::NODE_PATH, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::RID, sizeof(uint64_t), sizeof(uint64_t), sizeof(uint64_t), sizeof(uint64_t) }, + { Variant::OBJECT, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::CALLABLE, sizeof(Callable), sizeof(Callable), sizeof(Callable), sizeof(Callable) }, //harcoded align + { Variant::SIGNAL, sizeof(Signal), sizeof(Signal), sizeof(Signal), sizeof(Signal) }, //harcoded align + { Variant::DICTIONARY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_BYTE_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_INT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_INT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_FLOAT32_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_FLOAT64_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_STRING_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_VECTOR2_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_VECTOR3_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::PACKED_COLOR_ARRAY, ptrsize_32, ptrsize_64, ptrsize_32, ptrsize_64 }, + { Variant::VARIANT_MAX, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(float) * 4, sizeof(uint64_t) + sizeof(double) * 4, sizeof(uint64_t) + sizeof(double) * 4 }, + }; + + Array core_type_sizes; + + for (int i = 0; i < 4; i++) { + Dictionary d; + d["build_configuration"] = build_config_name[i]; + Array sizes; + for (int j = 0; j < Variant::VARIANT_MAX; j++) { + Variant::Type t = type_size_array[j].type; + String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t); + Dictionary d2; + d2["name"] = name; + uint32_t size; + switch (i) { + case 0: + size = type_size_array[j].size_32_bits_real_float; + break; + case 1: + size = type_size_array[j].size_64_bits_real_float; + break; + case 2: + size = type_size_array[j].size_32_bits_real_double; + break; + case 3: + size = type_size_array[j].size_64_bits_real_double; + break; + } + d2["size"] = size; + sizes.push_back(d2); + } + d["sizes"] = sizes; + core_type_sizes.push_back(d); + } + api_dump["builtin_class_sizes"] = core_type_sizes; + } + + { + //member offsets sizes + struct { + Variant::Type type; + const char *member; + uint32_t offset_32_bits_real_float; + uint32_t offset_64_bits_real_float; + uint32_t offset_32_bits_real_double; + uint32_t offset_64_bits_real_double; + } member_offset_array[] = { + { Variant::VECTOR2, "x", 0, 0, 0, 0 }, + { Variant::VECTOR2, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, + { Variant::VECTOR2I, "x", 0, 0, 0, 0 }, + { Variant::VECTOR2I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) }, + { Variant::RECT2, "position", 0, 0, 0, 0 }, + { Variant::RECT2, "size", 2 * sizeof(Vector2), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, + { Variant::RECT2I, "position", 0, 0, 0, 0 }, + { Variant::RECT2I, "size", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, + { Variant::VECTOR3, "x", 0, 0, 0, 0 }, + { Variant::VECTOR3, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, + { Variant::VECTOR3, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, + { Variant::VECTOR3I, "x", 0, 0, 0, 0 }, + { Variant::VECTOR3I, "y", sizeof(int32_t), sizeof(int32_t), sizeof(int32_t), sizeof(int32_t) }, + { Variant::VECTOR3I, "z", 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t), 2 * sizeof(int32_t) }, + { Variant::TRANSFORM2D, "x", 0, 0, 0, 0 }, + { Variant::TRANSFORM2D, "y", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, + { Variant::TRANSFORM2D, "origin", 4 * sizeof(float), 4 * sizeof(float), 4 * sizeof(double), 4 * sizeof(double) }, + { Variant::PLANE, "normal", 0, 0, 0, 0 }, + { Variant::PLANE, "d", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, + { Variant::QUATERNION, "x", 0, 0, 0, 0 }, + { Variant::QUATERNION, "y", sizeof(float), sizeof(float), sizeof(double), sizeof(double) }, + { Variant::QUATERNION, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(double), 2 * sizeof(double) }, + { Variant::QUATERNION, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(double), 3 * sizeof(double) }, + { Variant::AABB, "position", 0, 0, 0, 0 }, + { Variant::AABB, "size", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, + //rememer that basis vectors are flipped! + { Variant::BASIS, "x", 0, 0, 0, 0 }, + { Variant::BASIS, "y", vec3_elems * sizeof(float), vec3_elems * sizeof(float), vec3_elems * sizeof(double), vec3_elems * sizeof(double) }, + { Variant::BASIS, "z", vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(float), vec3_elems * 2 * sizeof(double), vec3_elems * 2 * sizeof(double) }, + { Variant::TRANSFORM3D, "basis", 0, 0, 0, 0 }, + { Variant::TRANSFORM3D, "origin", (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(float), (vec3_elems * 3) * sizeof(double), (vec3_elems * 3) * sizeof(double) }, + { Variant::COLOR, "x", 0, 0, 0, 0 }, + { Variant::COLOR, "y", sizeof(float), sizeof(float), sizeof(float), sizeof(float) }, + { Variant::COLOR, "z", 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float), 2 * sizeof(float) }, + { Variant::COLOR, "w", 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float), 3 * sizeof(float) }, + { Variant::NIL, nullptr, 0, 0, 0, 0 }, + }; + + Array core_type_member_offsets; + + for (int i = 0; i < 4; i++) { + Dictionary d; + d["build_configuration"] = build_config_name[i]; + Array type_offsets; + uint32_t idx = 0; + + Variant::Type last_type = Variant::NIL; + + Dictionary d2; + Array members; + + while (true) { + Variant::Type t = member_offset_array[idx].type; + if (t != last_type) { + if (last_type != Variant::NIL) { + d2["members"] = members; + type_offsets.push_back(d2); + } + if (t == Variant::NIL) { + break; + } + + String name = t == Variant::VARIANT_MAX ? String("Variant") : Variant::get_type_name(t); + d2 = Dictionary(); + members = Array(); + d2["name"] = name; + last_type = t; + } + Dictionary d3; + uint32_t offset; + switch (i) { + case 0: + offset = member_offset_array[idx].offset_32_bits_real_float; + break; + case 1: + offset = member_offset_array[idx].offset_64_bits_real_float; + break; + case 2: + offset = member_offset_array[idx].offset_32_bits_real_double; + break; + case 3: + offset = member_offset_array[idx].offset_64_bits_real_double; + break; + } + d3["member"] = member_offset_array[idx].member; + d3["offset"] = offset; + members.push_back(d3); + idx++; + } + d["classes"] = type_offsets; + core_type_member_offsets.push_back(d); + } + api_dump["builtin_class_member_offsets"] = core_type_member_offsets; + } + + { + // global enums and constants + Array constants; + Map<String, List<Pair<String, int>>> enum_list; + + for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) { + int value = CoreConstants::get_global_constant_value(i); + String enum_name = CoreConstants::get_global_constant_enum(i); + String name = CoreConstants::get_global_constant_name(i); + if (enum_name != String()) { + enum_list[enum_name].push_back(Pair<String, int>(name, value)); + } else { + Dictionary d; + d["name"] = name; + d["value"] = value; + constants.push_back(d); + } + } + + api_dump["global_constants"] = constants; + + Array enums; + for (Map<String, List<Pair<String, int>>>::Element *E = enum_list.front(); E; E = E->next()) { + Dictionary d1; + d1["name"] = E->key(); + Array values; + for (List<Pair<String, int>>::Element *F = E->get().front(); F; F = F->next()) { + Dictionary d2; + d2["name"] = F->get().first; + d2["value"] = F->get().second; + values.push_back(d2); + } + d1["values"] = values; + enums.push_back(d1); + } + + api_dump["global_enums"] = enums; + } + { + Array utility_funcs; + + List<StringName> utility_func_names; + Variant::get_utility_function_list(&utility_func_names); + + for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) { + StringName name = E->get(); + Dictionary func; + func["name"] = String(name); + if (Variant::has_utility_function_return_value(name)) { + Variant::Type rt = Variant::get_utility_function_return_type(name); + func["return_type"] = rt == Variant::NIL ? String("Variant") : Variant::get_type_name(rt); + } + switch (Variant::get_utility_function_type(name)) { + case Variant::UTILITY_FUNC_TYPE_MATH: + func["category"] = "math"; + break; + case Variant::UTILITY_FUNC_TYPE_RANDOM: + func["category"] = "random"; + break; + case Variant::UTILITY_FUNC_TYPE_GENERAL: + func["category"] = "general"; + break; + } + bool vararg = Variant::is_utility_function_vararg(name); + func["is_vararg"] = Variant::is_utility_function_vararg(name); + func["hash"] = Variant::get_utility_function_hash(name); + Array arguments; + int argcount = Variant::get_utility_function_argument_count(name); + for (int i = 0; i < argcount; i++) { + Dictionary arg; + String argname = vararg ? "arg" + itos(i + 1) : Variant::get_utility_function_argument_name(name, i); + arg["name"] = argname; + Variant::Type argtype = Variant::get_utility_function_argument_type(name, i); + arg["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype); + //no default value support in utility functions + arguments.push_back(arg); + } + + if (arguments.size()) { + func["arguments"] = arguments; + } + + utility_funcs.push_back(func); + } + + api_dump["utility_functions"] = utility_funcs; + } + + { + // builtin types + + Array builtins; + + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + if (i == Variant::OBJECT) { + continue; + } + + Variant::Type type = Variant::Type(i); + + Dictionary d; + d["name"] = Variant::get_type_name(type); + if (Variant::has_indexing(type)) { + Variant::Type index_type = Variant::get_indexed_element_type(type); + d["indexing_return_type"] = index_type == Variant::NIL ? String("Variant") : Variant::get_type_name(index_type); + } + + { + //members + Array members; + + List<StringName> member_names; + Variant::get_member_list(type, &member_names); + for (List<StringName>::Element *E = member_names.front(); E; E = E->next()) { + StringName member_name = E->get(); + Dictionary d2; + d2["name"] = String(member_name); + d2["type"] = Variant::get_type_name(Variant::get_member_type(type, member_name)); + members.push_back(d2); + } + if (members.size()) { + d["members"] = members; + } + } + { + //constants + Array constants; + + List<StringName> constant_names; + Variant::get_constants_for_type(type, &constant_names); + for (List<StringName>::Element *E = constant_names.front(); E; E = E->next()) { + StringName constant_name = E->get(); + Dictionary d2; + d2["name"] = String(constant_name); + Variant constant = Variant::get_constant_value(type, constant_name); + d2["type"] = Variant::get_type_name(constant.get_type()); + d2["value"] = constant.get_construct_string(); + constants.push_back(d2); + } + if (constants.size()) { + d["constants"] = constants; + } + } + { + //operators + Array operators; + + for (int j = 0; j < Variant::VARIANT_MAX; j++) { + for (int k = 0; k < Variant::OP_MAX; k++) { + Variant::Type rt = Variant::get_operator_return_type(Variant::Operator(k), type, Variant::Type(j)); + if (rt != Variant::NIL) { + Dictionary d2; + d2["name"] = Variant::get_operator_name(Variant::Operator(k)); + if (k != Variant::OP_NEGATE && k != Variant::OP_POSITIVE && k != Variant::OP_NOT && k != Variant::OP_BIT_NEGATE) { + d2["right_type"] = Variant::get_type_name(Variant::Type(j)); + } + operators.push_back(d2); + } + } + } + if (operators.size()) { + d["operators"] = operators; + } + } + { + //methods + Array methods; + + List<StringName> method_names; + Variant::get_builtin_method_list(type, &method_names); + for (List<StringName>::Element *E = method_names.front(); E; E = E->next()) { + StringName method_name = E->get(); + Dictionary d2; + d2["name"] = String(method_name); + if (Variant::has_builtin_method_return_value(type, method_name)) { + Variant::Type ret_type = Variant::get_builtin_method_return_type(type, method_name); + d2["return_type"] = ret_type == Variant::NIL ? String("Variant") : Variant::get_type_name(ret_type); + } + d2["is_vararg"] = Variant::is_builtin_method_vararg(type, method_name); + d2["is_const"] = Variant::is_builtin_method_const(type, method_name); + d2["is_static"] = Variant::is_builtin_method_static(type, method_name); + d2["hash"] = Variant::get_builtin_method_hash(type, method_name); + + Vector<Variant> default_args = Variant::get_builtin_method_default_arguments(type, method_name); + + Array arguments; + int argcount = Variant::get_builtin_method_argument_count(type, method_name); + for (int j = 0; j < argcount; j++) { + Dictionary d3; + d3["name"] = Variant::get_builtin_method_argument_name(type, method_name, j); + Variant::Type argtype = Variant::get_builtin_method_argument_type(type, method_name, j); + d3["type"] = argtype == Variant::NIL ? String("Variant") : Variant::get_type_name(argtype); + + if (j >= (argcount - default_args.size())) { + int dargidx = j - (argcount - default_args.size()); + d3["default_value"] = default_args[dargidx].get_construct_string(); + } + arguments.push_back(d3); + } + + if (arguments.size()) { + d2["arguments"] = arguments; + } + + methods.push_back(d2); + } + if (methods.size()) { + d["methods"] = methods; + } + } + { + //constructors + Array constructors; + + for (int j = 0; j < Variant::get_constructor_count(type); j++) { + Dictionary d2; + d2["index"] = j; + + Array arguments; + int argcount = Variant::get_constructor_argument_count(type, j); + for (int k = 0; k < argcount; k++) { + Dictionary d3; + d3["name"] = Variant::get_constructor_argument_name(type, j, k); + d3["type"] = Variant::get_type_name(Variant::get_constructor_argument_type(type, j, k)); + arguments.push_back(d3); + } + if (arguments.size()) { + d2["arguments"] = arguments; + } + constructors.push_back(d2); + } + + if (constructors.size()) { + d["constructors"] = constructors; + } + } + + builtins.push_back(d); + } + + api_dump["builtin_classes"] = builtins; + } + + { + // classes + Array classes; + + List<StringName> class_list; + + ClassDB::get_class_list(&class_list); + + class_list.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = class_list.front(); E; E = E->next()) { + Dictionary d; + StringName class_name = E->get(); + d["name"] = String(class_name); + d["is_refcounted"] = ClassDB::is_parent_class(class_name, "RefCounted"); + d["is_instantiable"] = ClassDB::can_instantiate(class_name); + StringName parent_class = ClassDB::get_parent_class(class_name); + if (parent_class != StringName()) { + d["inherits"] = String(parent_class); + } + + { + ClassDB::APIType api = ClassDB::get_api_type(class_name); + static const char *api_type[5] = { "core", "editor", "extension", "editor_extension" }; + d["api_type"] = api_type[api]; + } + + { + //constants + Array constants; + List<String> constant_list; + ClassDB::get_integer_constant_list(class_name, &constant_list, true); + for (List<String>::Element *F = constant_list.front(); F; F = F->next()) { + StringName enum_name = ClassDB::get_integer_constant_enum(class_name, F->get()); + if (enum_name != StringName()) { + continue; //enums will be handled on their own + } + + Dictionary d2; + d2["name"] = String(F->get()); + d2["value"] = ClassDB::get_integer_constant(class_name, F->get()); + + constants.push_back(d2); + } + + if (constants.size()) { + d["constants"] = constants; + } + } + { + //enum + Array enums; + List<StringName> enum_list; + ClassDB::get_enum_list(class_name, &enum_list, true); + for (List<StringName>::Element *F = enum_list.front(); F; F = F->next()) { + Dictionary d2; + d2["name"] = String(F->get()); + + Array values; + List<StringName> enum_constant_list; + ClassDB::get_enum_constants(class_name, F->get(), &enum_constant_list, true); + for (List<StringName>::Element *G = enum_constant_list.front(); G; G = G->next()) { + Dictionary d3; + d3["name"] = String(G->get()); + d3["value"] = ClassDB::get_integer_constant(class_name, G->get()); + values.push_back(d3); + } + + d2["values"] = values; + + enums.push_back(d2); + } + + if (enums.size()) { + d["enums"] = enums; + } + } + { + //methods + Array methods; + List<MethodInfo> method_list; + ClassDB::get_method_list(class_name, &method_list, true); + for (List<MethodInfo>::Element *F = method_list.front(); F; F = F->next()) { + StringName method_name = F->get().name; + if (F->get().flags & METHOD_FLAG_VIRTUAL) { + //virtual method + const MethodInfo &mi = F->get(); + Dictionary d2; + d2["name"] = String(method_name); + d2["is_const"] = (F->get().flags & METHOD_FLAG_CONST) ? true : false; + d2["is_vararg"] = false; + d2["is_virtual"] = true; + // virtual functions have no hash since no MethodBind is involved + bool has_return = mi.return_val.type != Variant::NIL || (mi.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT); + Array arguments; + for (int i = (has_return ? -1 : 0); i < mi.arguments.size(); i++) { + PropertyInfo pinfo = i == -1 ? mi.return_val : mi.arguments[i]; + Dictionary d3; + + if (i >= 0) { + d3["name"] = pinfo.name; + } + if (pinfo.class_name != StringName()) { + d3["type"] = String(pinfo.class_name); + } else { + Variant::Type type = pinfo.type; + if (type == Variant::NIL) { + d3["type"] = "Variant"; + } else { + d3["type"] = Variant::get_type_name(type); + } + } + + if (i == -1) { + d2["return_value"] = d3; + } else { + arguments.push_back(d3); + } + } + + if (arguments.size()) { + d2["arguments"] = arguments; + } + + methods.push_back(d2); + + } else if (F->get().name.begins_with("_")) { + //hidden method, ignore + + } else { + Dictionary d2; + d2["name"] = String(method_name); + + MethodBind *method = ClassDB::get_method(class_name, method_name); + if (!method) { + continue; + } + + d2["is_const"] = method->is_const(); + d2["is_vararg"] = method->is_vararg(); + d2["is_virtual"] = false; + d2["hash"] = method->get_hash(); + + Vector<Variant> default_args = method->get_default_arguments(); + + Array arguments; + for (int i = (method->has_return() ? -1 : 0); i < method->get_argument_count(); i++) { + PropertyInfo pinfo = i == -1 ? method->get_return_info() : method->get_argument_info(i); + Dictionary d3; + + if (i >= 0) { + d3["name"] = pinfo.name; + } + if (pinfo.class_name != StringName()) { + d3["type"] = String(pinfo.class_name); + } else { + Variant::Type type = pinfo.type; + if (type == Variant::NIL) { + d3["type"] = "Variant"; + } else { + d3["type"] = Variant::get_type_name(type); + } + } + + if (method->get_argument_meta(i) > 0) { + static const char *argmeta[11] = { "none", "int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "double" }; + d3["meta"] = argmeta[method->get_argument_meta(i)]; + } + + if (i >= 0 && i >= (method->get_argument_count() - default_args.size())) { + int dargidx = i - (method->get_argument_count() - default_args.size()); + d3["default_value"] = default_args[dargidx].get_construct_string(); + } + + if (i == -1) { + d2["return_value"] = d3; + } else { + arguments.push_back(d3); + } + } + + if (arguments.size()) { + d2["arguments"] = arguments; + } + + methods.push_back(d2); + } + } + + if (methods.size()) { + d["methods"] = methods; + } + } + + { + //signals + Array signals; + List<MethodInfo> signal_list; + ClassDB::get_signal_list(class_name, &signal_list, true); + for (List<MethodInfo>::Element *F = signal_list.front(); F; F = F->next()) { + StringName signal_name = F->get().name; + Dictionary d2; + d2["name"] = String(signal_name); + + Array arguments; + + for (int i = 0; i < F->get().arguments.size(); i++) { + Dictionary d3; + d3["name"] = F->get().arguments[i].name; + Variant::Type type = F->get().arguments[i].type; + if (F->get().arguments[i].class_name != StringName()) { + d3["type"] = String(F->get().arguments[i].class_name); + } else if (type == Variant::NIL) { + d3["type"] = "Variant"; + } else { + d3["type"] = Variant::get_type_name(type); + } + arguments.push_back(d3); + } + if (arguments.size()) { + d2["arguments"] = arguments; + } + + signals.push_back(d2); + } + + if (signals.size()) { + d["signals"] = signals; + } + } + { + //properties + Array properties; + List<PropertyInfo> property_list; + ClassDB::get_property_list(class_name, &property_list, true); + for (List<PropertyInfo>::Element *F = property_list.front(); F; F = F->next()) { + if (F->get().usage & PROPERTY_USAGE_CATEGORY || F->get().usage & PROPERTY_USAGE_GROUP || F->get().usage & PROPERTY_USAGE_SUBGROUP) { + continue; //not real properties + } + if (F->get().name.begins_with("_")) { + continue; //hidden property + } + StringName property_name = F->get().name; + Dictionary d2; + d2["name"] = String(property_name); + + if (F->get().class_name != StringName()) { + d2["type"] = String(F->get().class_name); + } else if (F->get().type == Variant::NIL && F->get().usage & PROPERTY_USAGE_NIL_IS_VARIANT) { + d2["type"] = "Variant"; + } else { + d2["type"] = Variant::get_type_name(F->get().type); + } + + d2["setter"] = ClassDB::get_property_setter(class_name, F->get().name); + d2["getter"] = ClassDB::get_property_getter(class_name, F->get().name); + d2["index"] = ClassDB::get_property_index(class_name, F->get().name); + properties.push_back(d2); + } + + if (properties.size()) { + d["properties"] = properties; + } + } + + classes.push_back(d); + } + + api_dump["classes"] = classes; + } + + { + // singletons + + Array singletons; + List<Engine::Singleton> singleton_list; + Engine::get_singleton()->get_singletons(&singleton_list); + + for (List<Engine::Singleton>::Element *E = singleton_list.front(); E; E = E->next()) { + const Engine::Singleton &s = E->get(); + Dictionary d; + d["name"] = s.name; + if (s.class_name != StringName()) { + d["type"] = String(s.class_name); + } else { + d["type"] = String(s.ptr->get_class()); + } + singletons.push_back(d); + } + + if (singletons.size()) { + api_dump["singletons"] = singletons; + } + } + + return api_dump; +} + +void NativeExtensionAPIDump::generate_extension_json_file(const String &p_path) { + Dictionary api = generate_extension_api(); + Ref<JSON> json; + json.instantiate(); + + String text = json->stringify(api, "\t", false); + FileAccessRef fa = FileAccess::open(p_path, FileAccess::WRITE); + CharString cs = text.ascii(); + fa->store_buffer((const uint8_t *)cs.ptr(), cs.length()); + fa->close(); +} +#endif diff --git a/scene/2d/y_sort.h b/core/extension/extension_api_dump.h index 7d36ee3391..a7825c10a9 100644 --- a/scene/2d/y_sort.h +++ b/core/extension/extension_api_dump.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* y_sort.h */ +/* extension_api_dump.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef Y_SORT_H -#define Y_SORT_H +#ifndef API_DUMP_H +#define API_DUMP_H -#include "scene/2d/node_2d.h" +#include "core/extension/native_extension.h" -class YSort : public Node2D { - GDCLASS(YSort, Node2D); - bool sort_enabled = true; - static void _bind_methods(); +#ifdef TOOLS_ENABLED +class NativeExtensionAPIDump { public: - void set_sort_enabled(bool p_enabled); - bool is_sort_enabled() const; - YSort(); + static Dictionary generate_extension_api(); + static void generate_extension_json_file(const String &p_path); }; +#endif -#endif // Y_SORT_H +#endif // API_DUMP_H diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp new file mode 100644 index 0000000000..8f68b8d848 --- /dev/null +++ b/core/extension/gdnative_interface.cpp @@ -0,0 +1,694 @@ +/*************************************************************************/ +/* gdnative_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "gdnative_interface.h" + +#include "core/config/engine.h" +#include "core/object/class_db.h" +#include "core/os/memory.h" +#include "core/variant/variant.h" +#include "core/version.h" + +// Memory Functions +static void *gdnative_alloc(size_t p_size) { + return memalloc(p_size); +} + +static void *gdnative_realloc(void *p_mem, size_t p_size) { + return memrealloc(p_mem, p_size); +} + +static void gdnative_free(void *p_mem) { + memfree(p_mem); +} + +// Helper print functions. +static void gdnative_print_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) { + _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_ERROR); +} +static void gdnative_print_warning(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) { + _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_WARNING); +} +static void gdnative_print_script_error(const char *p_description, const char *p_function, const char *p_file, int32_t p_line) { + _err_print_error(p_function, p_file, p_line, p_description, ERR_HANDLER_SCRIPT); +} + +// Variant functions + +static void gdnative_variant_new_copy(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src) { + memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant(*reinterpret_cast<Variant *>(p_src))); +} +static void gdnative_variant_new_nil(GDNativeVariantPtr r_dest) { + memnew_placement(reinterpret_cast<Variant *>(r_dest), Variant); +} +static void gdnative_variant_destroy(GDNativeVariantPtr p_self) { + reinterpret_cast<Variant *>(p_self)->~Variant(); +} + +// variant type + +#define memnew_placement_custom(m_placement, m_class, m_constr) _post_initialize(new (m_placement, sizeof(m_class), "") m_constr) + +static void gdnative_variant_call(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) { + Variant *self = (Variant *)p_self; + const StringName *method = (const StringName *)p_method; + const Variant **args = (const Variant **)p_args; + Variant ret; + Callable::CallError error; + self->call(*method, args, p_argcount, ret, error); + memnew_placement_custom(r_return, Variant, Variant(ret)); + + if (r_error) { + r_error->error = (GDNativeCallErrorType)(error.error); + r_error->argument = error.argument; + r_error->expected = error.expected; + } +} + +static void gdnative_variant_call_static(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argcount, GDNativeVariantPtr r_return, GDNativeCallError *r_error) { + Variant::Type type = (Variant::Type)p_type; + const StringName *method = (const StringName *)p_method; + const Variant **args = (const Variant **)p_args; + Variant ret; + Callable::CallError error; + Variant::call_static(type, *method, args, p_argcount, ret, error); + memnew_placement_custom(r_return, Variant, Variant(ret)); + + if (r_error) { + r_error->error = (GDNativeCallErrorType)error.error; + r_error->argument = error.argument; + r_error->expected = error.expected; + } +} + +static void gdnative_variant_evaluate(GDNativeVariantOperator p_op, const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_return, GDNativeBool *r_valid) { + Variant::Operator op = (Variant::Operator)p_op; + const Variant *a = (const Variant *)p_a; + const Variant *b = (const Variant *)p_b; + Variant *ret = (Variant *)r_return; + bool valid; + Variant::evaluate(op, *a, *b, *ret, valid); + *r_valid = valid; +} + +static void gdnative_variant_set(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) { + Variant *self = (Variant *)p_self; + const Variant *key = (const Variant *)p_key; + const Variant *value = (const Variant *)p_value; + + bool valid; + self->set(*key, *value, &valid); + *r_valid = valid; +} + +static void gdnative_variant_set_named(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) { + Variant *self = (Variant *)p_self; + const StringName *key = (const StringName *)p_key; + const Variant *value = (const Variant *)p_value; + + bool valid; + self->set_named(*key, *value, valid); + *r_valid = valid; +} + +static void gdnative_variant_set_keyed(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid) { + Variant *self = (Variant *)p_self; + const Variant *key = (const Variant *)p_key; + const Variant *value = (const Variant *)p_value; + + bool valid; + self->set_keyed(*key, *value, valid); + *r_valid = valid; +} + +static void gdnative_variant_set_indexed(GDNativeVariantPtr p_self, GDNativeInt p_index, const GDNativeVariantPtr p_value, GDNativeBool *r_valid, GDNativeBool *r_oob) { + Variant *self = (Variant *)p_self; + const Variant *value = (const Variant *)p_value; + + bool valid; + bool oob; + self->set_indexed(p_index, value, valid, oob); + *r_valid = valid; + *r_oob = oob; +} + +static void gdnative_variant_get(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + const Variant *key = (const Variant *)p_key; + + bool valid; + memnew_placement_custom(r_ret, Variant, Variant(self->get(*key, &valid))); + *r_valid = valid; +} + +static void gdnative_variant_get_named(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + const StringName *key = (const StringName *)p_key; + + bool valid; + memnew_placement_custom(r_ret, Variant, Variant(self->get_named(*key, valid))); + *r_valid = valid; +} + +static void gdnative_variant_get_keyed(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + const Variant *key = (const Variant *)p_key; + + bool valid; + memnew_placement_custom(r_ret, Variant, Variant(self->get_keyed(*key, valid))); + *r_valid = valid; +} + +static void gdnative_variant_get_indexed(const GDNativeVariantPtr p_self, GDNativeInt p_index, GDNativeVariantPtr r_ret, GDNativeBool *r_valid, GDNativeBool *r_oob) { + const Variant *self = (const Variant *)p_self; + + bool valid; + bool oob; + memnew_placement_custom(r_ret, Variant, Variant(self->get_indexed(p_index, valid, oob))); + *r_valid = valid; + *r_oob = oob; +} + +/// Iteration. +static GDNativeBool gdnative_variant_iter_init(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + Variant *iter = (Variant *)r_iter; + + bool valid; + bool ret = self->iter_init(*iter, valid); + *r_valid = valid; + return ret; +} + +static GDNativeBool gdnative_variant_iter_next(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + Variant *iter = (Variant *)r_iter; + + bool valid; + bool ret = self->iter_next(*iter, valid); + *r_valid = valid; + return ret; +} + +static void gdnative_variant_iter_get(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + Variant *iter = (Variant *)r_iter; + + bool valid; + memnew_placement_custom(r_ret, Variant, Variant(self->iter_next(*iter, valid))); + *r_valid = valid; +} + +/// Variant functions. +static GDNativeBool gdnative_variant_hash_compare(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other) { + const Variant *self = (const Variant *)p_self; + const Variant *other = (const Variant *)p_other; + return self->hash_compare(*other); +} + +static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self) { + const Variant *self = (const Variant *)p_self; + return self->booleanize(); +} + +static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) { + const Variant *a = (const Variant *)p_a; + const Variant *b = (const Variant *)p_b; + memnew_placement(r_dst, Variant); + Variant::blend(*a, *b, p_c, *(Variant *)r_dst); +} + +static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) { + const Variant *a = (const Variant *)p_a; + const Variant *b = (const Variant *)p_b; + memnew_placement(r_dst, Variant); + Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst); +} + +static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) { + const Variant *self = (const Variant *)p_self; + memnew_placement_custom(r_ret, Variant, Variant(self->duplicate(p_deep))); +} + +static void gdnative_variant_stringify(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret) { + const Variant *self = (const Variant *)p_self; + memnew_placement_custom(r_ret, String, String(*self)); +} + +static GDNativeVariantType gdnative_variant_get_type(const GDNativeVariantPtr p_self) { + const Variant *self = (const Variant *)p_self; + return (GDNativeVariantType)self->get_type(); +} + +static GDNativeBool gdnative_variant_has_method(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method) { + const Variant *self = (const Variant *)p_self; + const StringName *method = (const StringName *)p_method; + return self->has_method(*method); +} + +static GDNativeBool gdnative_variant_has_member(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member) { + return Variant::has_member((Variant::Type)p_type, *((const StringName *)p_member)); +} + +static GDNativeBool gdnative_variant_has_key(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeBool *r_valid) { + const Variant *self = (const Variant *)p_self; + const Variant *key = (const Variant *)p_key; + bool valid; + return self->has_key(*key, valid); + *r_valid = valid; +} + +static void gdnative_variant_get_type_name(GDNativeVariantType p_type, GDNativeStringPtr r_ret) { + String name = Variant::get_type_name((Variant::Type)p_type); + memnew_placement_custom(r_ret, String, String(name)); +} + +static GDNativeBool gdnative_variant_can_convert(GDNativeVariantType p_from, GDNativeVariantType p_to) { + return Variant::can_convert((Variant::Type)p_from, (Variant::Type)p_to); +} + +static GDNativeBool gdnative_variant_can_convert_strict(GDNativeVariantType p_from, GDNativeVariantType p_to) { + return Variant::can_convert_strict((Variant::Type)p_from, (Variant::Type)p_to); +} + +// ptrcalls +static GDNativePtrOperatorEvaluator gdnative_variant_get_ptr_operator_evaluator(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b) { + return (GDNativePtrOperatorEvaluator)Variant::get_ptr_operator_evaluator(Variant::Operator(p_operator), Variant::Type(p_type_a), Variant::Type(p_type_b)); +} +static GDNativePtrBuiltInMethod gdnative_variant_get_ptr_builtin_method(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash) { + StringName method = p_method; + uint32_t hash = Variant::get_builtin_method_hash(Variant::Type(p_type), method); + if (hash != p_hash) { + ERR_PRINT_ONCE("Error getting method " + String(method) + ", hash mismatch."); + return nullptr; + } + + return (GDNativePtrBuiltInMethod)Variant::get_ptr_builtin_method(Variant::Type(p_type), method); +} +static GDNativePtrConstructor gdnative_variant_get_ptr_constructor(GDNativeVariantType p_type, int32_t p_constructor) { + return (GDNativePtrConstructor)Variant::get_ptr_constructor(Variant::Type(p_type), p_constructor); +} +static void gdnative_variant_construct(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error) { + memnew_placement(p_base, Variant); + + Callable::CallError error; + Variant::construct(Variant::Type(p_type), *(Variant *)p_base, (const Variant **)p_args, p_argument_count, error); + + if (r_error) { + r_error->error = (GDNativeCallErrorType)(error.error); + r_error->argument = error.argument; + r_error->expected = error.expected; + } +} +static GDNativePtrSetter gdnative_variant_get_ptr_setter(GDNativeVariantType p_type, const char *p_member) { + return (GDNativePtrSetter)Variant::get_member_ptr_setter(Variant::Type(p_type), p_member); +} +static GDNativePtrGetter gdnative_variant_get_ptr_getter(GDNativeVariantType p_type, const char *p_member) { + return (GDNativePtrGetter)Variant::get_member_ptr_getter(Variant::Type(p_type), p_member); +} +static GDNativePtrIndexedSetter gdnative_variant_get_ptr_indexed_setter(GDNativeVariantType p_type) { + return (GDNativePtrIndexedSetter)Variant::get_member_ptr_indexed_setter(Variant::Type(p_type)); +} +static GDNativePtrIndexedGetter gdnative_variant_get_ptr_indexed_getter(GDNativeVariantType p_type) { + return (GDNativePtrIndexedGetter)Variant::get_member_ptr_indexed_getter(Variant::Type(p_type)); +} +static GDNativePtrKeyedSetter gdnative_variant_get_ptr_keyed_setter(GDNativeVariantType p_type) { + return (GDNativePtrKeyedSetter)Variant::get_member_ptr_keyed_setter(Variant::Type(p_type)); +} +static GDNativePtrKeyedGetter gdnative_variant_get_ptr_keyed_getter(GDNativeVariantType p_type) { + return (GDNativePtrKeyedGetter)Variant::get_member_ptr_keyed_getter(Variant::Type(p_type)); +} +static GDNativePtrKeyedChecker gdnative_variant_get_ptr_keyed_checker(GDNativeVariantType p_type) { + return (GDNativePtrKeyedChecker)Variant::get_member_ptr_keyed_checker(Variant::Type(p_type)); +} +static void gdnative_variant_get_constant_value(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret) { + memnew_placement_custom(r_ret, Variant, Variant(Variant::get_constant_value(Variant::Type(p_type), p_constant))); +} +static GDNativePtrUtilityFunction gdnative_variant_get_ptr_utility_function(const char *p_function, GDNativeInt p_hash) { + StringName function = p_function; + uint32_t hash = Variant::get_utility_function_hash(function); + if (hash != p_hash) { + ERR_PRINT_ONCE("Error getting utility function " + String(function) + ", hash mismatch."); + return nullptr; + } + return (GDNativePtrUtilityFunction)Variant::get_ptr_utility_function(function); +} + +//string helpers + +static void gdnative_string_new_with_latin1_chars(GDNativeStringPtr r_dest, const char *p_contents) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + *dest = String(p_contents); +} + +static void gdnative_string_new_with_utf8_chars(GDNativeStringPtr r_dest, const char *p_contents) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + dest->parse_utf8(p_contents); +} + +static void gdnative_string_new_with_utf16_chars(GDNativeStringPtr r_dest, const char16_t *p_contents) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + dest->parse_utf16(p_contents); +} + +static void gdnative_string_new_with_utf32_chars(GDNativeStringPtr r_dest, const char32_t *p_contents) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + *dest = String((const char32_t *)p_contents); +} + +static void gdnative_string_new_with_wide_chars(GDNativeStringPtr r_dest, const wchar_t *p_contents) { + String *dest = (String *)r_dest; + if (sizeof(wchar_t) == 2) { + // wchar_t is 16 bit, parse. + memnew_placement(dest, String); + dest->parse_utf16((const char16_t *)p_contents); + } else { + // wchar_t is 32 bit, copy. + memnew_placement(dest, String); + *dest = String((const char32_t *)p_contents); + } +} + +static void gdnative_string_new_with_latin1_chars_and_len(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + *dest = String(p_contents, p_size); +} + +static void gdnative_string_new_with_utf8_chars_and_len(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + dest->parse_utf8(p_contents, p_size); +} + +static void gdnative_string_new_with_utf16_chars_and_len(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + dest->parse_utf16(p_contents, p_size); +} + +static void gdnative_string_new_with_utf32_chars_and_len(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size) { + String *dest = (String *)r_dest; + memnew_placement(dest, String); + *dest = String((const char32_t *)p_contents, p_size); +} + +static void gdnative_string_new_with_wide_chars_and_len(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size) { + String *dest = (String *)r_dest; + if (sizeof(wchar_t) == 2) { + // wchar_t is 16 bit, parse. + memnew_placement(dest, String); + dest->parse_utf16((const char16_t *)p_contents, p_size); + } else { + // wchar_t is 32 bit, copy. + memnew_placement(dest, String); + *dest = String((const char32_t *)p_contents, p_size); + } +} + +static GDNativeInt gdnative_string_to_latin1_chars(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length) { + String *self = (String *)p_self; + CharString cs = self->ascii(true); + GDNativeInt len = cs.length(); + if (r_text) { + const char *s_text = cs.ptr(); + for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) { + r_text[i] = s_text[i]; + } + } + return len; +} +static GDNativeInt gdnative_string_to_utf8_chars(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length) { + String *self = (String *)p_self; + CharString cs = self->utf8(); + GDNativeInt len = cs.length(); + if (r_text) { + const char *s_text = cs.ptr(); + for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) { + r_text[i] = s_text[i]; + } + } + return len; +} +static GDNativeInt gdnative_string_to_utf16_chars(const GDNativeStringPtr p_self, char16_t *r_text, GDNativeInt p_max_write_length) { + String *self = (String *)p_self; + Char16String cs = self->utf16(); + GDNativeInt len = cs.length(); + if (r_text) { + const char16_t *s_text = cs.ptr(); + for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) { + r_text[i] = s_text[i]; + } + } + return len; +} +static GDNativeInt gdnative_string_to_utf32_chars(const GDNativeStringPtr p_self, char32_t *r_text, GDNativeInt p_max_write_length) { + String *self = (String *)p_self; + GDNativeInt len = self->length(); + if (r_text) { + const char32_t *s_text = self->ptr(); + for (GDNativeInt i = 0; i < MIN(len, p_max_write_length); i++) { + r_text[i] = s_text[i]; + } + } + return len; +} +static GDNativeInt gdnative_string_to_wide_chars(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length) { + if (sizeof(wchar_t) == 4) { + return gdnative_string_to_utf32_chars(p_self, (char32_t *)r_text, p_max_write_length); + } else { + return gdnative_string_to_utf16_chars(p_self, (char16_t *)r_text, p_max_write_length); + } +} + +static char32_t *gdnative_string_operator_index(GDNativeStringPtr p_self, GDNativeInt p_index) { + String *self = (String *)p_self; + ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr); + return &self->ptrw()[p_index]; +} + +static const char32_t *gdnative_string_operator_index_const(const GDNativeStringPtr p_self, GDNativeInt p_index) { + const String *self = (const String *)p_self; + ERR_FAIL_INDEX_V(p_index, self->length() + 1, nullptr); + return &self->ptr()[p_index]; +} + +/* OBJECT API */ + +static void gdnative_object_method_bind_ptrcall(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr p_ret) { + MethodBind *mb = (MethodBind *)p_method_bind; + Object *o = (Object *)p_instance; + mb->ptrcall(o, (const void **)p_args, p_ret); +} + +static void gdnative_object_destroy(GDNativeObjectPtr p_o) { + memdelete((Object *)p_o); +} + +static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) { + return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name)); +} + +static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_instance, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks) { + Object *o = (Object *)p_instance; + return o->get_instance_binding(p_token, p_callbacks); +} + +static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) { + return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id)); +} + +static GDNativeObjectPtr gdnative_object_cast_to(const GDNativeObjectPtr p_object, void *p_class_tag) { + if (!p_object) { + return nullptr; + } + Object *o = (Object *)p_object; + + return o->is_class_ptr(p_class_tag) ? (GDNativeObjectPtr)o : (GDNativeObjectPtr) nullptr; +} + +static GDObjectInstanceID gdnative_object_get_instance_id(const GDNativeObjectPtr p_object) { + const Object *o = (const Object *)p_object; + return (GDObjectInstanceID)o->get_instance_id(); +} + +static GDNativeMethodBindPtr gdnative_classdb_get_method_bind(const char *p_classname, const char *p_methodname, GDNativeInt p_hash) { + MethodBind *mb = ClassDB::get_method(StringName(p_classname), StringName(p_methodname)); + ERR_FAIL_COND_V(!mb, nullptr); + if (mb->get_hash() != p_hash) { + ERR_PRINT_ONCE("Hash mismatch for method '" + String(p_classname) + "." + String(p_methodname) + "'."); + return nullptr; + } + // MethodBind *mb = ClassDB::get_method("Node", "get_name"); + return (GDNativeMethodBindPtr)mb; +} + +static GDNativeClassConstructor gdnative_classdb_get_constructor(const char *p_classname) { + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(StringName(p_classname)); + if (class_info) { + return (GDNativeClassConstructor)class_info->creation_func; + } + return nullptr; +} + +static void *gdnative_classdb_get_class_tag(const char *p_classname) { + ClassDB::ClassInfo *class_info = ClassDB::classes.getptr(p_classname); + return class_info ? class_info->class_ptr : nullptr; +} + +void gdnative_setup_interface(GDNativeInterface *p_interface) { + GDNativeInterface &gdni = *p_interface; + + gdni.version_major = VERSION_MAJOR; + gdni.version_minor = VERSION_MINOR; +#if VERSION_PATCH + gdni.version_patch = VERSION_PATCH; +#else + gdni.version_patch = 0; +#endif + gdni.version_string = VERSION_FULL_NAME; + + /* GODOT CORE */ + + gdni.mem_alloc = gdnative_alloc; + gdni.mem_realloc = gdnative_realloc; + gdni.mem_free = gdnative_free; + + gdni.print_error = gdnative_print_error; + gdni.print_warning = gdnative_print_warning; + gdni.print_script_error = gdnative_print_script_error; + + /* GODOT VARIANT */ + + // variant general + gdni.variant_new_copy = gdnative_variant_new_copy; + gdni.variant_new_nil = gdnative_variant_new_nil; + gdni.variant_destroy = gdnative_variant_destroy; + + gdni.variant_call = gdnative_variant_call; + gdni.variant_call_static = gdnative_variant_call_static; + gdni.variant_evaluate = gdnative_variant_evaluate; + gdni.variant_set = gdnative_variant_set; + gdni.variant_set_named = gdnative_variant_set_named; + gdni.variant_set_keyed = gdnative_variant_set_keyed; + gdni.variant_set_indexed = gdnative_variant_set_indexed; + gdni.variant_get = gdnative_variant_get; + gdni.variant_get_named = gdnative_variant_get_named; + gdni.variant_get_keyed = gdnative_variant_get_keyed; + gdni.variant_get_indexed = gdnative_variant_get_indexed; + gdni.variant_iter_init = gdnative_variant_iter_init; + gdni.variant_iter_next = gdnative_variant_iter_next; + gdni.variant_iter_get = gdnative_variant_iter_get; + gdni.variant_hash_compare = gdnative_variant_hash_compare; + gdni.variant_booleanize = gdnative_variant_booleanize; + gdni.variant_blend = gdnative_variant_blend; + gdni.variant_interpolate = gdnative_variant_interpolate; + gdni.variant_duplicate = gdnative_variant_duplicate; + gdni.variant_stringify = gdnative_variant_stringify; + + gdni.variant_get_type = gdnative_variant_get_type; + gdni.variant_has_method = gdnative_variant_has_method; + gdni.variant_has_member = gdnative_variant_has_member; + gdni.variant_has_key = gdnative_variant_has_key; + gdni.variant_get_type_name = gdnative_variant_get_type_name; + gdni.variant_can_convert = gdnative_variant_can_convert; + gdni.variant_can_convert_strict = gdnative_variant_can_convert_strict; + + //ptrcalls +#if 0 + GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type); + GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type); +#endif + + gdni.variant_get_ptr_operator_evaluator = gdnative_variant_get_ptr_operator_evaluator; + gdni.variant_get_ptr_builtin_method = gdnative_variant_get_ptr_builtin_method; + gdni.variant_get_ptr_constructor = gdnative_variant_get_ptr_constructor; + gdni.variant_construct = gdnative_variant_construct; + gdni.variant_get_ptr_setter = gdnative_variant_get_ptr_setter; + gdni.variant_get_ptr_getter = gdnative_variant_get_ptr_getter; + gdni.variant_get_ptr_indexed_setter = gdnative_variant_get_ptr_indexed_setter; + gdni.variant_get_ptr_indexed_getter = gdnative_variant_get_ptr_indexed_getter; + gdni.variant_get_ptr_keyed_setter = gdnative_variant_get_ptr_keyed_setter; + gdni.variant_get_ptr_keyed_getter = gdnative_variant_get_ptr_keyed_getter; + gdni.variant_get_ptr_keyed_checker = gdnative_variant_get_ptr_keyed_checker; + gdni.variant_get_constant_value = gdnative_variant_get_constant_value; + gdni.variant_get_ptr_utility_function = gdnative_variant_get_ptr_utility_function; + + // extra utilities + + gdni.string_new_with_latin1_chars = gdnative_string_new_with_latin1_chars; + gdni.string_new_with_utf8_chars = gdnative_string_new_with_utf8_chars; + gdni.string_new_with_utf16_chars = gdnative_string_new_with_utf16_chars; + gdni.string_new_with_utf32_chars = gdnative_string_new_with_utf32_chars; + gdni.string_new_with_wide_chars = gdnative_string_new_with_wide_chars; + gdni.string_new_with_latin1_chars_and_len = gdnative_string_new_with_latin1_chars_and_len; + gdni.string_new_with_utf8_chars_and_len = gdnative_string_new_with_utf8_chars_and_len; + gdni.string_new_with_utf16_chars_and_len = gdnative_string_new_with_utf16_chars_and_len; + gdni.string_new_with_utf32_chars_and_len = gdnative_string_new_with_utf32_chars_and_len; + gdni.string_new_with_wide_chars_and_len = gdnative_string_new_with_wide_chars_and_len; + gdni.string_to_latin1_chars = gdnative_string_to_latin1_chars; + gdni.string_to_utf8_chars = gdnative_string_to_utf8_chars; + gdni.string_to_utf16_chars = gdnative_string_to_utf16_chars; + gdni.string_to_utf32_chars = gdnative_string_to_utf32_chars; + gdni.string_to_wide_chars = gdnative_string_to_wide_chars; + gdni.string_operator_index = gdnative_string_operator_index; + gdni.string_operator_index_const = gdnative_string_operator_index_const; + + /* OBJECT */ + + gdni.object_method_bind_ptrcall = gdnative_object_method_bind_ptrcall; + gdni.object_destroy = gdnative_object_destroy; + gdni.global_get_singleton = gdnative_global_get_singleton; + gdni.object_get_instance_binding = gdnative_object_get_instance_binding; + + gdni.object_cast_to = gdnative_object_cast_to; + gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id; + gdni.object_get_instance_id = gdnative_object_get_instance_id; + + /* CLASSDB */ + + gdni.classdb_get_constructor = gdnative_classdb_get_constructor; + gdni.classdb_get_method_bind = gdnative_classdb_get_method_bind; + gdni.classdb_get_class_tag = gdnative_classdb_get_class_tag; + + /* CLASSDB EXTENSION */ + + //these are filled by implementation, since it will want to keep track of registered classes + gdni.classdb_register_extension_class = nullptr; + gdni.classdb_register_extension_class_method = nullptr; + gdni.classdb_register_extension_class_integer_constant = nullptr; + gdni.classdb_register_extension_class_property = nullptr; + gdni.classdb_register_extension_class_signal = nullptr; + gdni.classdb_unregister_extension_class = nullptr; +} diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h new file mode 100644 index 0000000000..c1ebb3e76a --- /dev/null +++ b/core/extension/gdnative_interface.h @@ -0,0 +1,438 @@ +/*************************************************************************/ +/* gdnative_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef GDNATIVE_INTERFACE_H +#define GDNATIVE_INTERFACE_H + +/* This is a C class header, you can copy it and use it directly in your own binders. + * Together with the JSON file, you should be able to generate any binder. + */ + +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* VARIANT TYPES */ + +typedef enum { + GDNATIVE_VARIANT_TYPE_NIL, + + /* atomic types */ + GDNATIVE_VARIANT_TYPE_BOOL, + GDNATIVE_VARIANT_TYPE_INT, + GDNATIVE_VARIANT_TYPE_FLOAT, + GDNATIVE_VARIANT_TYPE_STRING, + + /* math types */ + GDNATIVE_VARIANT_TYPE_VECTOR2, + GDNATIVE_VARIANT_TYPE_VECTOR2I, + GDNATIVE_VARIANT_TYPE_RECT2, + GDNATIVE_VARIANT_TYPE_RECT2I, + GDNATIVE_VARIANT_TYPE_VECTOR3, + GDNATIVE_VARIANT_TYPE_VECTOR3I, + GDNATIVE_VARIANT_TYPE_TRANSFORM2D, + GDNATIVE_VARIANT_TYPE_PLANE, + GDNATIVE_VARIANT_TYPE_QUATERNION, + GDNATIVE_VARIANT_TYPE_AABB, + GDNATIVE_VARIANT_TYPE_BASIS, + GDNATIVE_VARIANT_TYPE_TRANSFORM3D, + + /* misc types */ + GDNATIVE_VARIANT_TYPE_COLOR, + GDNATIVE_VARIANT_TYPE_STRING_NAME, + GDNATIVE_VARIANT_TYPE_NODE_PATH, + GDNATIVE_VARIANT_TYPE_RID, + GDNATIVE_VARIANT_TYPE_OBJECT, + GDNATIVE_VARIANT_TYPE_CALLABLE, + GDNATIVE_VARIANT_TYPE_SIGNAL, + GDNATIVE_VARIANT_TYPE_DICTIONARY, + GDNATIVE_VARIANT_TYPE_ARRAY, + + /* typed arrays */ + GDNATIVE_VARIANT_TYPE_PACKED_BYTE_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_INT32_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_INT64_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_FLOAT32_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_FLOAT64_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_STRING_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_VECTOR2_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_VECTOR3_ARRAY, + GDNATIVE_VARIANT_TYPE_PACKED_COLOR_ARRAY, + + GDNATIVE_VARIANT_TYPE_VARIANT_MAX +} GDNativeVariantType; + +typedef enum { + /* comparison */ + GDNATIVE_VARIANT_OP_EQUAL, + GDNATIVE_VARIANT_OP_NOT_EQUAL, + GDNATIVE_VARIANT_OP_LESS, + GDNATIVE_VARIANT_OP_LESS_EQUAL, + GDNATIVE_VARIANT_OP_GREATER, + GDNATIVE_VARIANT_OP_GREATER_EQUAL, + /* mathematic */ + GDNATIVE_VARIANT_OP_ADD, + GDNATIVE_VARIANT_OP_SUBTRACT, + GDNATIVE_VARIANT_OP_MULTIPLY, + GDNATIVE_VARIANT_OP_DIVIDE, + GDNATIVE_VARIANT_OP_NEGATE, + GDNATIVE_VARIANT_OP_POSITIVE, + GDNATIVE_VARIANT_OP_MODULE, + /* bitwise */ + GDNATIVE_VARIANT_OP_SHIFT_LEFT, + GDNATIVE_VARIANT_OP_SHIFT_RIGHT, + GDNATIVE_VARIANT_OP_BIT_AND, + GDNATIVE_VARIANT_OP_BIT_OR, + GDNATIVE_VARIANT_OP_BIT_XOR, + GDNATIVE_VARIANT_OP_BIT_NEGATE, + /* logic */ + GDNATIVE_VARIANT_OP_AND, + GDNATIVE_VARIANT_OP_OR, + GDNATIVE_VARIANT_OP_XOR, + GDNATIVE_VARIANT_OP_NOT, + /* containment */ + GDNATIVE_VARIANT_OP_IN, + GDNATIVE_VARIANT_OP_MAX + +} GDNativeVariantOperator; + +typedef void *GDNativeVariantPtr; +typedef void *GDNativeStringNamePtr; +typedef void *GDNativeStringPtr; +typedef void *GDNativeObjectPtr; +typedef void *GDNativeTypePtr; +typedef void *GDNativeMethodBindPtr; +typedef int64_t GDNativeInt; +typedef uint32_t GDNativeBool; +typedef uint64_t GDObjectInstanceID; + +/* VARIANT DATA I/O */ + +typedef enum { + NATIVE_CALL_OK, + NATIVE_CALL_ERROR_INVALID_METHOD, + NATIVE_CALL_ERROR_INVALID_ARGUMENT, /* expected is variant type */ + NATIVE_CALL_ERROR_TOO_MANY_ARGUMENTS, /* expected is number of arguments */ + NATIVE_CALL_ERROR_TOO_FEW_ARGUMENTS, /* expected is number of arguments */ + NATIVE_CALL_ERROR_INSTANCE_IS_NULL, + +} GDNativeCallErrorType; + +typedef struct { + GDNativeCallErrorType error; + int32_t argument; + int32_t expected; +} GDNativeCallError; + +typedef void (*GDNativeVariantFromTypeConstructorFunc)(GDNativeVariantPtr, GDNativeTypePtr); +typedef void (*GDNativeTypeFromVariantConstructorFunc)(GDNativeTypePtr, GDNativeVariantPtr); +typedef void (*GDNativePtrOperatorEvaluator)(const GDNativeTypePtr p_left, const GDNativeTypePtr p_right, GDNativeTypePtr r_result); +typedef void (*GDNativePtrBuiltInMethod)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args, GDNativeTypePtr r_return, int p_argument_count); +typedef void (*GDNativePtrConstructor)(GDNativeTypePtr p_base, const GDNativeTypePtr *p_args); +typedef void (*GDNativePtrSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_value); +typedef void (*GDNativePtrGetter)(const GDNativeTypePtr p_base, GDNativeTypePtr r_value); +typedef void (*GDNativePtrIndexedSetter)(GDNativeTypePtr p_base, GDNativeInt p_index, const GDNativeTypePtr p_value); +typedef void (*GDNativePtrIndexedGetter)(const GDNativeTypePtr p_base, GDNativeInt p_index, GDNativeTypePtr r_value); +typedef void (*GDNativePtrKeyedSetter)(GDNativeTypePtr p_base, const GDNativeTypePtr p_key, const GDNativeTypePtr p_value); +typedef void (*GDNativePtrKeyedGetter)(const GDNativeTypePtr p_base, const GDNativeTypePtr p_key, GDNativeTypePtr r_value); +typedef uint32_t (*GDNativePtrKeyedChecker)(const GDNativeVariantPtr p_base, const GDNativeVariantPtr p_key); +typedef void (*GDNativePtrUtilityFunction)(GDNativeTypePtr r_return, const GDNativeTypePtr *p_arguments, int p_argument_count); + +typedef GDNativeObjectPtr (*GDNativeClassConstructor)(); + +typedef void *(*GDNativeInstanceBindingCreateCallback)(void *p_token, void *p_instance); +typedef void (*GDNativeInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding); +typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_instance, GDNativeBool p_reference); + +struct GDNativeInstanceBindingCallbacks { + GDNativeInstanceBindingCreateCallback create_callback; + GDNativeInstanceBindingFreeCallback free_callback; + GDNativeInstanceBindingReferenceCallback reference_callback; +}; + +/* EXTENSION CLASSES */ + +typedef void *GDExtensionClassInstancePtr; + +typedef GDNativeBool (*GDNativeExtensionClassSet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value); +typedef GDNativeBool (*GDNativeExtensionClassGet)(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret); + +typedef struct { + uint32_t type; + const char *name; + const char *class_name; + uint32_t hint; + const char *hint_string; + uint32_t usage; +} GDNativePropertyInfo; + +typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); +typedef void (*GDNativeExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list); +typedef void (*GDNativeExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what); +typedef const char *(*GDNativeExtensionClassToString)(GDExtensionClassInstancePtr p_instance); +typedef void (*GDNativeExtensionClassReference)(GDExtensionClassInstancePtr p_instance); +typedef void (*GDNativeExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance); +typedef void (*GDNativeExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret); +typedef GDExtensionClassInstancePtr (*GDNativeExtensionClassCreateInstance)(void *p_userdata); +typedef void (*GDNativeExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance); +typedef GDNativeExtensionClassCallVirtual (*GDNativeExtensionClassGetVirtual)(void *p_userdata, const char *p_name); + +typedef struct { + GDNativeExtensionClassSet set_func; + GDNativeExtensionClassGet get_func; + GDNativeExtensionClassGetPropertyList get_property_list_func; + GDNativeExtensionClassFreePropertyList free_property_list_func; + GDNativeExtensionClassNotification notification_func; + GDNativeExtensionClassToString to_string_func; + GDNativeExtensionClassReference reference_func; + GDNativeExtensionClassUnreference unreference_func; + GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ + GDNativeExtensionClassFreeInstance free_instance_func; /* this one is mandatory */ + GDNativeExtensionClassGetVirtual get_firtual_func; + void *class_userdata; +} GDNativeExtensionClassCreationInfo; + +typedef void *GDNativeExtensionClassLibraryPtr; + +typedef const GDNativePropertyInfo *(*GDNativeExtensionClassGetPropertyList)(GDExtensionClassInstancePtr p_instance, uint32_t *r_count); + +/* Method */ + +typedef enum { + GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL = 1, + GDNATIVE_EXTENSION_METHOD_FLAG_EDITOR = 2, + GDNATIVE_EXTENSION_METHOD_FLAG_NOSCRIPT = 4, + GDNATIVE_EXTENSION_METHOD_FLAG_CONST = 8, + GDNATIVE_EXTENSION_METHOD_FLAG_REVERSE = 16, /* used for events */ + GDNATIVE_EXTENSION_METHOD_FLAG_VIRTUAL = 32, + GDNATIVE_EXTENSION_METHOD_FLAG_FROM_SCRIPT = 64, + GDNATIVE_EXTENSION_METHOD_FLAG_VARARG = 128, + GDNATIVE_EXTENSION_METHOD_FLAG_STATIC = 256, + GDNATIVE_EXTENSION_METHOD_FLAGS_DEFAULT = GDNATIVE_EXTENSION_METHOD_FLAG_NORMAL, +} GDNativeExtensionClassMethodFlags; + +typedef enum { + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_NONE, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT16, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT32, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT64, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT8, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT16, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT32, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_UINT64, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_FLOAT, + GDNATIVE_EXTENSION_METHOD_ARGUMENT_METADATA_REAL_IS_DOUBLE +} GDNativeExtensionClassMethodArgumentMetadata; + +typedef void (*GDNativeExtensionClassMethodCall)(GDExtensionClassInstancePtr p_instance, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error); +typedef void (*GDNativeExtensionClassMethodPtrCall)(GDExtensionClassInstancePtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret); + +/* passing -1 as argument in the following functions refers to the return type */ +typedef GDNativeVariantType (*GDNativeExtensionClassMethodGetArgumentType)(void *p_method_userdata, int32_t p_argument); +typedef void (*GDNativeExtensionClassMethodGetArgumentInfo)(void *p_method_userdata, int32_t p_argument, GDNativePropertyInfo *r_info); +typedef GDNativeExtensionClassMethodArgumentMetadata (*GDNativeExtensionClassMethodGetArgumentMetadata)(void *p_method_userdata, int32_t p_argument); + +typedef struct { + const char *name; + void *method_userdata; + GDNativeExtensionClassMethodCall call_func; + GDNativeExtensionClassMethodPtrCall ptrcall_func; + uint32_t method_flags; /* GDNativeExtensionClassMethodFlags */ + uint32_t argument_count; + GDNativeBool has_return_value; + GDNativeExtensionClassMethodGetArgumentType get_argument_type_func; + GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; /* name and hint information for the argument can be omitted in release builds. Class name should always be present if it applies. */ + GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func; + uint32_t default_argument_count; + GDNativeVariantPtr *default_arguments; +} GDNativeExtensionClassMethodInfo; + +/* INTERFACE */ + +typedef struct { + uint32_t version_major; + uint32_t version_minor; + uint32_t version_patch; + const char *version_string; + + /* GODOT CORE */ + void *(*mem_alloc)(size_t p_bytes); + void *(*mem_realloc)(void *p_ptr, size_t p_bytes); + void (*mem_free)(void *p_ptr); + + void (*print_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line); + void (*print_warning)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line); + void (*print_script_error)(const char *p_description, const char *p_function, const char *p_file, int32_t p_line); + + /* GODOT VARIANT */ + + /* variant general */ + void (*variant_new_copy)(GDNativeVariantPtr r_dest, const GDNativeVariantPtr p_src); + void (*variant_new_nil)(GDNativeVariantPtr r_dest); + void (*variant_destroy)(GDNativeVariantPtr p_self); + + /* variant type */ + void (*variant_call)(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error); + void (*variant_call_static)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_method, const GDNativeVariantPtr *p_args, const GDNativeInt p_argument_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error); + void (*variant_evaluate)(GDNativeVariantOperator p_op, const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_return, GDNativeBool *r_valid); + void (*variant_set)(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid); + void (*variant_set_named)(GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid); + void (*variant_set_keyed)(GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, const GDNativeVariantPtr p_value, GDNativeBool *r_valid); + void (*variant_set_indexed)(GDNativeVariantPtr p_self, GDNativeInt p_index, const GDNativeVariantPtr p_value, GDNativeBool *r_valid, GDNativeBool *r_oob); + void (*variant_get)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid); + void (*variant_get_named)(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid); + void (*variant_get_keyed)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeVariantPtr r_ret, GDNativeBool *r_valid); + void (*variant_get_indexed)(const GDNativeVariantPtr p_self, GDNativeInt p_index, GDNativeVariantPtr r_ret, GDNativeBool *r_valid, GDNativeBool *r_oob); + GDNativeBool (*variant_iter_init)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid); + GDNativeBool (*variant_iter_next)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeBool *r_valid); + void (*variant_iter_get)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_iter, GDNativeVariantPtr r_ret, GDNativeBool *r_valid); + GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other); + GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self); + void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst); + void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst); + void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep); + void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret); + + GDNativeVariantType (*variant_get_type)(const GDNativeVariantPtr p_self); + GDNativeBool (*variant_has_method)(const GDNativeVariantPtr p_self, const GDNativeStringNamePtr p_method); + GDNativeBool (*variant_has_member)(GDNativeVariantType p_type, const GDNativeStringNamePtr p_member); + GDNativeBool (*variant_has_key)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_key, GDNativeBool *r_valid); + void (*variant_get_type_name)(GDNativeVariantType p_type, GDNativeStringPtr r_name); + GDNativeBool (*variant_can_convert)(GDNativeVariantType p_from, GDNativeVariantType p_to); + GDNativeBool (*variant_can_convert_strict)(GDNativeVariantType p_from, GDNativeVariantType p_to); + + /* ptrcalls */ + GDNativeVariantFromTypeConstructorFunc (*get_variant_from_type_constructor)(GDNativeVariantType p_type); + GDNativeTypeFromVariantConstructorFunc (*get_variant_to_type_constructor)(GDNativeVariantType p_type); + GDNativePtrOperatorEvaluator (*variant_get_ptr_operator_evaluator)(GDNativeVariantOperator p_operator, GDNativeVariantType p_type_a, GDNativeVariantType p_type_b); + GDNativePtrBuiltInMethod (*variant_get_ptr_builtin_method)(GDNativeVariantType p_type, const char *p_method, GDNativeInt p_hash); + GDNativePtrConstructor (*variant_get_ptr_constructor)(GDNativeVariantType p_type, int32_t p_constructor); + void (*variant_construct)(GDNativeVariantType p_type, GDNativeVariantPtr p_base, const GDNativeVariantPtr *p_args, int32_t p_argument_count, GDNativeCallError *r_error); + GDNativePtrSetter (*variant_get_ptr_setter)(GDNativeVariantType p_type, const char *p_member); + GDNativePtrGetter (*variant_get_ptr_getter)(GDNativeVariantType p_type, const char *p_member); + GDNativePtrIndexedSetter (*variant_get_ptr_indexed_setter)(GDNativeVariantType p_type); + GDNativePtrIndexedGetter (*variant_get_ptr_indexed_getter)(GDNativeVariantType p_type); + GDNativePtrKeyedSetter (*variant_get_ptr_keyed_setter)(GDNativeVariantType p_type); + GDNativePtrKeyedGetter (*variant_get_ptr_keyed_getter)(GDNativeVariantType p_type); + GDNativePtrKeyedChecker (*variant_get_ptr_keyed_checker)(GDNativeVariantType p_type); + void (*variant_get_constant_value)(GDNativeVariantType p_type, const char *p_constant, GDNativeVariantPtr r_ret); + GDNativePtrUtilityFunction (*variant_get_ptr_utility_function)(const char *p_function, GDNativeInt p_hash); + + /* extra utilities */ + + void (*string_new_with_latin1_chars)(GDNativeStringPtr r_dest, const char *p_contents); + void (*string_new_with_utf8_chars)(GDNativeStringPtr r_dest, const char *p_contents); + void (*string_new_with_utf16_chars)(GDNativeStringPtr r_dest, const char16_t *p_contents); + void (*string_new_with_utf32_chars)(GDNativeStringPtr r_dest, const char32_t *p_contents); + void (*string_new_with_wide_chars)(GDNativeStringPtr r_dest, const wchar_t *p_contents); + void (*string_new_with_latin1_chars_and_len)(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size); + void (*string_new_with_utf8_chars_and_len)(GDNativeStringPtr r_dest, const char *p_contents, const GDNativeInt p_size); + void (*string_new_with_utf16_chars_and_len)(GDNativeStringPtr r_dest, const char16_t *p_contents, const GDNativeInt p_size); + void (*string_new_with_utf32_chars_and_len)(GDNativeStringPtr r_dest, const char32_t *p_contents, const GDNativeInt p_size); + void (*string_new_with_wide_chars_and_len)(GDNativeStringPtr r_dest, const wchar_t *p_contents, const GDNativeInt p_size); + /* Information about the following functions: + * - The return value is the resulting encoded string length. + * - The length returned is in characters, not in bytes. It also does not include a trailing zero. + * - These functions also do not write trailing zero, If you need it, write it yourself at the position indicated by the length (and make sure to allocate it). + * - Passing NULL in r_text means only the length is computed (again, without including trailing zero). + * - p_max_write_length argument is in characters, not bytes. It will be ignored if r_text is NULL. + * - p_max_write_length argument does not affect the return value, it's only to cap write length. + */ + GDNativeInt (*string_to_latin1_chars)(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length); + GDNativeInt (*string_to_utf8_chars)(const GDNativeStringPtr p_self, char *r_text, GDNativeInt p_max_write_length); + GDNativeInt (*string_to_utf16_chars)(const GDNativeStringPtr p_self, char16_t *r_text, GDNativeInt p_max_write_length); + GDNativeInt (*string_to_utf32_chars)(const GDNativeStringPtr p_self, char32_t *r_text, GDNativeInt p_max_write_length); + GDNativeInt (*string_to_wide_chars)(const GDNativeStringPtr p_self, wchar_t *r_text, GDNativeInt p_max_write_length); + char32_t *(*string_operator_index)(GDNativeStringPtr p_self, GDNativeInt p_index); + const char32_t *(*string_operator_index_const)(const GDNativeStringPtr p_self, GDNativeInt p_index); + + /* OBJECT */ + + void (*object_method_bind_ptrcall)(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret); + void (*object_destroy)(GDNativeObjectPtr p_o); + GDNativeObjectPtr (*global_get_singleton)(const char *p_name); + void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks); + + GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag); + GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id); + GDObjectInstanceID (*object_get_instance_id)(const GDNativeObjectPtr p_object); + + /* CLASSDB */ + + GDNativeClassConstructor (*classdb_get_constructor)(const char *p_classname); + GDNativeMethodBindPtr (*classdb_get_method_bind)(const char *p_classname, const char *p_methodname, GDNativeInt p_hash); + void *(*classdb_get_class_tag)(const char *p_classname); + + /* CLASSDB EXTENSION */ + + void (*classdb_register_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs); + void (*classdb_register_extension_class_method)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info); + void (*classdb_register_extension_class_integer_constant)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_enum_name, const char *p_class_name, const char *p_constant_name, uint32_t p_constant_value); + void (*classdb_register_extension_class_property)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter); + void (*classdb_register_extension_class_signal)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count); + void (*classdb_unregister_extension_class)(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); /* Unregistering a parent class before a class that inherits it will result in failure. Inheritors must be unregistered first. */ +} GDNativeInterface; + +/* INITIALIZATION */ + +typedef enum { + GDNATIVE_INITIALIZATION_CORE, + GDNATIVE_INITIALIZATION_SERVERS, + GDNATIVE_INITIALIZATION_SCENE, + GDNATIVE_INITIALIZATION_EDITOR, +} GDNativeInitializationLevel; + +typedef struct { + /* Minimum initialization level required. + * If Core or Servers, the extension needs editor or game restart to take effect */ + GDNativeInitializationLevel minimum_initialization_level; + /* Up to the user to supply when initializing */ + void *userdata; + /* This function will be called multiple times for each initialization level. */ + void (*initialize)(void *userdata, GDNativeInitializationLevel p_level); + void (*deinitialize)(void *userdata, GDNativeInitializationLevel p_level); +} GDNativeInitialization; + +/* Define a C function prototype that implements the function below and expose it to dlopen() (or similar). + * It will be called on initialization. The name must be an unique one specified in the .gdextension config file. + */ + +typedef GDNativeBool (*GDNativeInitializationFunction)(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp new file mode 100644 index 0000000000..65718a7507 --- /dev/null +++ b/core/extension/native_extension.cpp @@ -0,0 +1,411 @@ +/*************************************************************************/ +/* native_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "native_extension.h" +#include "core/io/config_file.h" +#include "core/object/class_db.h" +#include "core/object/method_bind.h" +#include "core/os/os.h" + +class NativeExtensionMethodBind : public MethodBind { + GDNativeExtensionClassMethodCall call_func; + GDNativeExtensionClassMethodPtrCall ptrcall_func; + GDNativeExtensionClassMethodGetArgumentType get_argument_type_func; + GDNativeExtensionClassMethodGetArgumentInfo get_argument_info_func; + GDNativeExtensionClassMethodGetArgumentMetadata get_argument_metadata_func; + void *method_userdata; + bool vararg; + +protected: + virtual Variant::Type _gen_argument_type(int p_arg) const { + return Variant::Type(get_argument_type_func(method_userdata, p_arg)); + } + virtual PropertyInfo _gen_argument_type_info(int p_arg) const { + GDNativePropertyInfo pinfo; + get_argument_info_func(method_userdata, p_arg, &pinfo); + PropertyInfo ret; + ret.type = Variant::Type(pinfo.type); + ret.name = pinfo.name; + ret.class_name = pinfo.class_name; + ret.hint = PropertyHint(pinfo.hint); + ret.usage = pinfo.usage; + ret.class_name = pinfo.class_name; + return ret; + } + +public: + virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const { + return GodotTypeInfo::Metadata(get_argument_metadata_func(method_userdata, p_arg)); + } + + virtual Variant call(Object *p_object, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + Variant ret; + GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance(); + GDNativeCallError ce; + call_func(extension_instance, (const GDNativeVariantPtr *)p_args, p_arg_count, (GDNativeVariantPtr)&ret, &ce); + r_error.error = Callable::CallError::Error(ce.error); + r_error.argument = ce.argument; + r_error.expected = ce.expected; + return ret; + } + virtual void ptrcall(Object *p_object, const void **p_args, void *r_ret) { + ERR_FAIL_COND_MSG(vararg, "Vararg methods don't have ptrcall support. This is most likely an engine bug."); + GDExtensionClassInstancePtr extension_instance = p_object->_get_extension_instance(); + ptrcall_func(extension_instance, (const GDNativeTypePtr *)p_args, (GDNativeTypePtr)r_ret); + } + + virtual bool is_vararg() const { + return false; + } + NativeExtensionMethodBind(const GDNativeExtensionClassMethodInfo *p_method_info) { + method_userdata = p_method_info->method_userdata; + call_func = p_method_info->call_func; + ptrcall_func = p_method_info->ptrcall_func; + get_argument_type_func = p_method_info->get_argument_type_func; + get_argument_info_func = p_method_info->get_argument_info_func; + get_argument_metadata_func = p_method_info->get_argument_metadata_func; + + vararg = p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_VARARG; + + _set_returns(p_method_info->has_return_value); + _set_const(p_method_info->method_flags & GDNATIVE_EXTENSION_METHOD_FLAG_CONST); +#ifdef DEBUG_METHODS_ENABLED + _generate_argument_types(p_method_info->argument_count); +#endif + set_argument_count(p_method_info->argument_count); + } +}; + +static GDNativeInterface gdnative_interface; + +void NativeExtension::_register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs) { + NativeExtension *self = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + ERR_FAIL_COND_MSG(String(class_name).is_valid_identifier(), "Attempt to register extension clas '" + class_name + "', which is not a valid class identifier."); + ERR_FAIL_COND_MSG(ClassDB::class_exists(class_name), "Attempt to register extension class '" + class_name + "', which appears to be already registered."); + + Extension *parent_extension = nullptr; + StringName parent_class_name = p_parent_class_name; + + if (self->extension_classes.has(parent_class_name)) { + parent_extension = &self->extension_classes[parent_class_name]; + } else if (ClassDB::class_exists(parent_class_name)) { + if (ClassDB::get_api_type(parent_class_name) == ClassDB::API_EXTENSION || ClassDB::get_api_type(parent_class_name) == ClassDB::API_EDITOR_EXTENSION) { + ERR_PRINT("Unimplemented yet"); + //inheriting from another extension + } else { + //inheriting from engine class + } + } else { + ERR_FAIL_MSG("Attempt to register an extension class '" + String(class_name) + "' using non-existing parent class '" + String(parent_class_name) + "'"); + } + + self->extension_classes[class_name] = Extension(); + + Extension *extension = &self->extension_classes[class_name]; + + if (parent_extension) { + extension->native_extension.parent = &parent_extension->native_extension; + parent_extension->native_extension.children.push_back(&extension->native_extension); + } + + extension->native_extension.parent_class_name = parent_class_name; + extension->native_extension.class_name = class_name; + extension->native_extension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR; + extension->native_extension.set = p_extension_funcs->set_func; + extension->native_extension.get = p_extension_funcs->get_func; + extension->native_extension.get_property_list = p_extension_funcs->get_property_list_func; + extension->native_extension.free_property_list = p_extension_funcs->free_property_list_func; + extension->native_extension.notification = p_extension_funcs->notification_func; + extension->native_extension.to_string = p_extension_funcs->to_string_func; + extension->native_extension.reference = p_extension_funcs->reference_func; + extension->native_extension.unreference = p_extension_funcs->unreference_func; + extension->native_extension.class_userdata = p_extension_funcs->class_userdata; + extension->native_extension.create_instance = p_extension_funcs->create_instance_func; + extension->native_extension.free_instance = p_extension_funcs->free_instance_func; + + ClassDB::register_extension_class(&extension->native_extension); +} +void NativeExtension::_register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info) { + NativeExtension *self = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + StringName method_name = p_method_info->name; + ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension method '" + String(method_name) + "' for unexisting class '" + class_name + "'."); + + //Extension *extension = &self->extension_classes[class_name]; + + NativeExtensionMethodBind *method = memnew(NativeExtensionMethodBind(p_method_info)); + + ClassDB::bind_method_custom(class_name, method); +} +void NativeExtension::_register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, uint32_t p_constant_value) { + NativeExtension *self = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension constant '" + String(p_constant_name) + "' for unexisting class '" + class_name + "'."); + + //Extension *extension = &self->extension_classes[class_name]; + + ClassDB::bind_integer_constant(class_name, p_enum_name, p_constant_name, p_constant_value); +} +void NativeExtension::_register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter) { + NativeExtension *self = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension class property '" + String(p_info->name) + "' for unexisting class '" + class_name + "'."); + + //Extension *extension = &self->extension_classes[class_name]; + PropertyInfo pinfo; + pinfo.type = Variant::Type(p_info->type); + pinfo.name = p_info->name; + pinfo.class_name = p_info->class_name; + pinfo.hint = PropertyHint(p_info->hint); + pinfo.hint_string = p_info->hint_string; + pinfo.usage = p_info->usage; + + ClassDB::add_property(class_name, pinfo, p_setter, p_getter); +} + +void NativeExtension::_register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count) { + NativeExtension *self = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to register extension class signal '" + String(p_signal_name) + "' for unexisting class '" + class_name + "'."); + + MethodInfo s; + s.name = p_signal_name; + for (int i = 0; i < p_argument_count; i++) { + PropertyInfo arg; + arg.type = Variant::Type(p_argument_info[i].type); + arg.name = p_argument_info[i].name; + arg.class_name = p_argument_info[i].class_name; + arg.hint = PropertyHint(p_argument_info[i].hint); + arg.hint_string = p_argument_info[i].hint_string; + arg.usage = p_argument_info[i].usage; + s.arguments.push_back(arg); + } + ClassDB::add_signal(class_name, s); +} + +void NativeExtension::_unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name) { + NativeExtension *self = (NativeExtension *)p_library; + + StringName class_name = p_class_name; + ERR_FAIL_COND_MSG(self->extension_classes.has(class_name), "Attempt to unregister unexisting extension class '" + class_name + "'."); + Extension *ext = &self->extension_classes[class_name]; + ERR_FAIL_COND_MSG(ext->native_extension.children.size(), "Attempt to unregister class '" + class_name + "' while other extension classes inherit from it."); + + ClassDB::unregister_extension_class(class_name); + if (ext->native_extension.parent != nullptr) { + ext->native_extension.parent->children.erase(&ext->native_extension); + } + self->extension_classes.erase(class_name); +} + +Error NativeExtension::open_library(const String &p_path, const String &p_entry_symbol) { + Error err = OS::get_singleton()->open_dynamic_library(p_path, library, true); + if (err != OK) { + return err; + } + + void *entry_funcptr = nullptr; + + err = OS::get_singleton()->get_dynamic_library_symbol_handle(library, p_entry_symbol, entry_funcptr, false); + + if (err != OK) { + OS::get_singleton()->close_dynamic_library(library); + return err; + } + + GDNativeInitializationFunction initialization_function = (GDNativeInitializationFunction)entry_funcptr; + + initialization_function(&gdnative_interface, this, &initialization); + level_initialized = -1; + return OK; +} + +void NativeExtension::close_library() { + ERR_FAIL_COND(library == nullptr); + OS::get_singleton()->close_dynamic_library(library); + + library = nullptr; +} + +bool NativeExtension::is_library_open() const { + return library != nullptr; +} + +NativeExtension::InitializationLevel NativeExtension::get_minimum_library_initialization_level() const { + ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE); + return InitializationLevel(initialization.minimum_initialization_level); +} +void NativeExtension::initialize_library(InitializationLevel p_level) { + ERR_FAIL_COND(library == nullptr); + ERR_FAIL_COND(p_level <= int32_t(level_initialized)); + + level_initialized = int32_t(p_level); + + ERR_FAIL_COND(initialization.initialize == nullptr); + + initialization.initialize(initialization.userdata, GDNativeInitializationLevel(p_level)); +} +void NativeExtension::deinitialize_library(InitializationLevel p_level) { + ERR_FAIL_COND(library == nullptr); + ERR_FAIL_COND(p_level > int32_t(level_initialized)); + + level_initialized = int32_t(p_level) - 1; + initialization.deinitialize(initialization.userdata, GDNativeInitializationLevel(p_level)); +} + +void NativeExtension::_bind_methods() { + ClassDB::bind_method(D_METHOD("open_library", "path", "entry_symbol"), &NativeExtension::open_library); + ClassDB::bind_method(D_METHOD("close_library"), &NativeExtension::close_library); + ClassDB::bind_method(D_METHOD("is_library_open"), &NativeExtension::is_library_open); + + ClassDB::bind_method(D_METHOD("get_minimum_library_initialization_level"), &NativeExtension::get_minimum_library_initialization_level); + ClassDB::bind_method(D_METHOD("initialize_library", "level"), &NativeExtension::initialize_library); + + BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_CORE); + BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SERVERS); + BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_SCENE); + BIND_ENUM_CONSTANT(INITIALIZATION_LEVEL_EDITOR); +} + +NativeExtension::NativeExtension() { +} + +NativeExtension::~NativeExtension() { + if (library != nullptr) { + close_library(); + } +} + +extern void gdnative_setup_interface(GDNativeInterface *p_interface); + +void NativeExtension::initialize_native_extensions() { + gdnative_setup_interface(&gdnative_interface); + + gdnative_interface.classdb_register_extension_class = _register_extension_class; + gdnative_interface.classdb_register_extension_class_method = _register_extension_class_method; + gdnative_interface.classdb_register_extension_class_integer_constant = _register_extension_class_integer_constant; + gdnative_interface.classdb_register_extension_class_property = _register_extension_class_property; + gdnative_interface.classdb_register_extension_class_signal = _register_extension_class_signal; + gdnative_interface.classdb_unregister_extension_class = _unregister_extension_class; +} + +RES NativeExtensionResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + Ref<ConfigFile> config; + config.instantiate(); + + Error err = config->load(p_path); + + if (r_error) { + *r_error = err; + } + + if (err != OK) { + return RES(); + } + + if (!config->has_section_key("configuration", "entry_symbol")) { + if (r_error) { + *r_error = ERR_INVALID_DATA; + } + return RES(); + } + + String entry_symbol = config->get_value("configuration", "entry_symbol"); + + List<String> libraries; + + config->get_section_keys("libraries", &libraries); + + String library_path; + + for (List<String>::Element *E = libraries.front(); E; E = E->next()) { + Vector<String> tags = E->get().split("."); + bool all_tags_met = true; + for (int i = 0; i < tags.size(); i++) { + String tag = tags[i].strip_edges(); + if (!OS::get_singleton()->has_feature(tag)) { + all_tags_met = false; + break; + } + } + + if (all_tags_met) { + library_path = config->get_value("libraries", E->get()); + break; + } + } + + if (library_path != String()) { + if (r_error) { + *r_error = ERR_FILE_NOT_FOUND; + } + return RES(); + } + + if (!library_path.is_resource_file()) { + library_path = p_path.get_base_dir().plus_file(library_path); + } + + Ref<NativeExtension> lib; + lib.instantiate(); + err = lib->open_library(library_path, entry_symbol); + + if (r_error) { + *r_error = err; + } + + if (err != OK) { + return RES(); + } + + return lib; +} + +void NativeExtensionResourceLoader::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("gdextension"); +} + +bool NativeExtensionResourceLoader::handles_type(const String &p_type) const { + return p_type == "NativeExtension"; +} + +String NativeExtensionResourceLoader::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "gdextension") { + return "NativeExtension"; + } + return ""; +} diff --git a/core/extension/native_extension.h b/core/extension/native_extension.h new file mode 100644 index 0000000000..0a23848eb2 --- /dev/null +++ b/core/extension/native_extension.h @@ -0,0 +1,94 @@ +/*************************************************************************/ +/* native_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef NATIVE_EXTENSION_H +#define NATIVE_EXTENSION_H + +#include "core/extension/gdnative_interface.h" +#include "core/io/resource_loader.h" +#include "core/object/ref_counted.h" + +class NativeExtension : public RefCounted { + GDCLASS(NativeExtension, RefCounted) + + void *library = nullptr; // pointer if valid, + + struct Extension { + ObjectNativeExtension native_extension; + }; + + Map<StringName, Extension> extension_classes; + + static void _register_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_parent_class_name, const GDNativeExtensionClassCreationInfo *p_extension_funcs); + static void _register_extension_class_method(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativeExtensionClassMethodInfo *p_method_info); + static void _register_extension_class_integer_constant(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_enum_name, const char *p_constant_name, uint32_t p_constant_value); + static void _register_extension_class_property(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const GDNativePropertyInfo *p_info, const char *p_setter, const char *p_getter); + static void _register_extension_class_signal(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name, const char *p_signal_name, const GDNativePropertyInfo *p_argument_info, GDNativeInt p_argument_count); + static void _unregister_extension_class(const GDNativeExtensionClassLibraryPtr p_library, const char *p_class_name); + + GDNativeInitialization initialization; + int32_t level_initialized = -1; + +protected: + static void _bind_methods(); + +public: + Error open_library(const String &p_path, const String &p_entry_symbol); + void close_library(); + + enum InitializationLevel { + INITIALIZATION_LEVEL_CORE, + INITIALIZATION_LEVEL_SERVERS, + INITIALIZATION_LEVEL_SCENE, + INITIALIZATION_LEVEL_EDITOR, + }; + + bool is_library_open() const; + + InitializationLevel get_minimum_library_initialization_level() const; + void initialize_library(InitializationLevel p_level); + void deinitialize_library(InitializationLevel p_level); + + static void initialize_native_extensions(); + NativeExtension(); + ~NativeExtension(); +}; + +VARIANT_ENUM_CAST(NativeExtension::InitializationLevel) + +class NativeExtensionResourceLoader : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual void get_recognized_extensions(List<String> *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; +}; + +#endif // NATIVEEXTENSION_H diff --git a/core/extension/native_extension_manager.cpp b/core/extension/native_extension_manager.cpp new file mode 100644 index 0000000000..7be2593845 --- /dev/null +++ b/core/extension/native_extension_manager.cpp @@ -0,0 +1,130 @@ +/*************************************************************************/ +/* native_extension_manager.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "native_extension_manager.h" + +NativeExtensionManager::LoadStatus NativeExtensionManager::load_extension(const String &p_path) { + if (native_extension_map.has(p_path)) { + return LOAD_STATUS_ALREADY_LOADED; + } + Ref<NativeExtension> extension = ResourceLoader::load(p_path); + if (extension.is_null()) { + return LOAD_STATUS_FAILED; + } + + if (level >= 0) { //already initialized up to some level + int32_t minimum_level = extension->get_minimum_library_initialization_level(); + if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) { + return LOAD_STATUS_NEEDS_RESTART; + } + //initialize up to current level + for (int32_t i = minimum_level; i < level; i++) { + extension->initialize_library(NativeExtension::InitializationLevel(level)); + } + } + native_extension_map[p_path] = extension; + return LOAD_STATUS_OK; +} + +NativeExtensionManager::LoadStatus NativeExtensionManager::reload_extension(const String &p_path) { + return LOAD_STATUS_OK; //TODO +} +NativeExtensionManager::LoadStatus NativeExtensionManager::unload_extension(const String &p_path) { + if (!native_extension_map.has(p_path)) { + return LOAD_STATUS_NOT_LOADED; + } + + Ref<NativeExtension> extension = native_extension_map[p_path]; + + if (level >= 0) { //already initialized up to some level + int32_t minimum_level = extension->get_minimum_library_initialization_level(); + if (minimum_level < MIN(level, NativeExtension::INITIALIZATION_LEVEL_SCENE)) { + return LOAD_STATUS_NEEDS_RESTART; + } + //initialize up to current level + for (int32_t i = level; i >= minimum_level; i--) { + extension->deinitialize_library(NativeExtension::InitializationLevel(level)); + } + } + native_extension_map.erase(p_path); + return LOAD_STATUS_OK; +} +Vector<String> NativeExtensionManager::get_loaded_extensions() const { + Vector<String> ret; + for (const Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) { + ret.push_back(E->key()); + } + return ret; +} +Ref<NativeExtension> NativeExtensionManager::get_extension(const String &p_path) { + Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.find(p_path); + ERR_FAIL_COND_V(!E, Ref<NativeExtension>()); + return E->get(); +} + +void NativeExtensionManager::initialize_extensions(NativeExtension::InitializationLevel p_level) { + ERR_FAIL_COND(int32_t(p_level) - 1 != level); + for (Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) { + E->get()->initialize_library(p_level); + } + level = p_level; +} + +void NativeExtensionManager::deinitialize_extensions(NativeExtension::InitializationLevel p_level) { + ERR_FAIL_COND(int32_t(p_level) != level); + for (Map<String, Ref<NativeExtension>>::Element *E = native_extension_map.front(); E; E = E->next()) { + E->get()->deinitialize_library(p_level); + } + level = int32_t(p_level) - 1; +} + +NativeExtensionManager *NativeExtensionManager::get_singleton() { + return singleton; +} +void NativeExtensionManager::_bind_methods() { + ClassDB::bind_method(D_METHOD("load_extension", "path"), &NativeExtensionManager::load_extension); + ClassDB::bind_method(D_METHOD("reload_extension", "path"), &NativeExtensionManager::reload_extension); + ClassDB::bind_method(D_METHOD("unload_extension", "path"), &NativeExtensionManager::unload_extension); + ClassDB::bind_method(D_METHOD("get_loaded_extensions"), &NativeExtensionManager::get_loaded_extensions); + ClassDB::bind_method(D_METHOD("get_extension", "path"), &NativeExtensionManager::get_extension); + + BIND_ENUM_CONSTANT(LOAD_STATUS_OK); + BIND_ENUM_CONSTANT(LOAD_STATUS_FAILED); + BIND_ENUM_CONSTANT(LOAD_STATUS_ALREADY_LOADED); + BIND_ENUM_CONSTANT(LOAD_STATUS_NOT_LOADED); + BIND_ENUM_CONSTANT(LOAD_STATUS_NEEDS_RESTART); +} + +NativeExtensionManager *NativeExtensionManager::singleton = nullptr; + +NativeExtensionManager::NativeExtensionManager() { + ERR_FAIL_COND(singleton != nullptr); + singleton = this; +} diff --git a/core/extension/native_extension_manager.h b/core/extension/native_extension_manager.h new file mode 100644 index 0000000000..78465bd5cf --- /dev/null +++ b/core/extension/native_extension_manager.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* native_extension_manager.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef NATIVE_EXTENSION_MANAGER_H +#define NATIVE_EXTENSION_MANAGER_H + +#include "core/extension/native_extension.h" + +class NativeExtensionManager : public Object { + GDCLASS(NativeExtensionManager, Object); + + int32_t level = -1; + Map<String, Ref<NativeExtension>> native_extension_map; + + static void _bind_methods(); + + static NativeExtensionManager *singleton; + +public: + enum LoadStatus { + LOAD_STATUS_OK, + LOAD_STATUS_FAILED, + LOAD_STATUS_ALREADY_LOADED, + LOAD_STATUS_NOT_LOADED, + LOAD_STATUS_NEEDS_RESTART, + }; + + LoadStatus load_extension(const String &p_path); + LoadStatus reload_extension(const String &p_path); + LoadStatus unload_extension(const String &p_path); + Vector<String> get_loaded_extensions() const; + Ref<NativeExtension> get_extension(const String &p_path); + + void initialize_extensions(NativeExtension::InitializationLevel p_level); + void deinitialize_extensions(NativeExtension::InitializationLevel p_level); + + static NativeExtensionManager *get_singleton(); + + NativeExtensionManager(); +}; + +VARIANT_ENUM_CAST(NativeExtensionManager::LoadStatus) + +#endif // NATIVEEXTENSIONMANAGER_H diff --git a/core/input/input.cpp b/core/input/input.cpp index 6e98b596d7..a712394b35 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -227,7 +227,7 @@ bool Input::is_key_pressed(int p_keycode) const { return keys_pressed.has(p_keycode); } -bool Input::is_mouse_button_pressed(int p_button) const { +bool Input::is_mouse_button_pressed(MouseButton p_button) const { _THREAD_SAFE_METHOD_ return (mouse_button_mask & (1 << (p_button - 1))) != 0; } @@ -236,7 +236,7 @@ static int _combine_device(int p_value, int p_device) { return p_value | (p_device << 20); } -bool Input::is_joy_button_pressed(int p_device, int p_button) const { +bool Input::is_joy_button_pressed(int p_device, JoyButton p_button) const { _THREAD_SAFE_METHOD_ return joy_buttons_pressed.has(_combine_device(p_button, p_device)); } @@ -352,7 +352,7 @@ Vector2 Input::get_vector(const StringName &p_negative_x, const StringName &p_po return vector; } -float Input::get_joy_axis(int p_device, int p_axis) const { +float Input::get_joy_axis(int p_device, JoyAxis p_axis) const { _THREAD_SAFE_METHOD_ int c = _combine_device(p_axis, p_device); if (_joy_axis.has(c)) { @@ -433,7 +433,7 @@ void Input::joy_connection_changed(int p_idx, bool p_connected, String p_name, S joy_buttons_pressed.erase(c); } for (int i = 0; i < JOY_AXIS_MAX; i++) { - set_joy_axis(p_idx, i, 0.0f); + set_joy_axis(p_idx, (JoyAxis)i, 0.0f); } } joy_names[p_idx] = js; @@ -488,9 +488,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (mb.is_valid()) { if (mb->is_pressed()) { - mouse_button_mask |= (1 << (mb->get_button_index() - 1)); + mouse_button_mask |= (MouseButton)(1 << (mb->get_button_index() - 1)); } else { - mouse_button_mask &= ~(1 << (mb->get_button_index() - 1)); + mouse_button_mask &= (MouseButton) ~(1 << (mb->get_button_index() - 1)); } Point2 pos = mb->get_global_position(); @@ -500,7 +500,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mb->get_button_index() == 1) { Ref<InputEventScreenTouch> touch_event; - touch_event.instance(); + touch_event.instantiate(); touch_event->set_pressed(mb->is_pressed()); touch_event->set_position(mb->get_position()); event_dispatch_function(touch_event); @@ -517,7 +517,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (event_dispatch_function && emulate_touch_from_mouse && !p_is_emulated && mm->get_button_mask() & 1) { Ref<InputEventScreenDrag> drag_event; - drag_event.instance(); + drag_event.instantiate(); drag_event->set_position(mm->get_position()); drag_event->set_relative(mm->get_relative()); @@ -555,7 +555,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (translate) { Ref<InputEventMouseButton> button_event; - button_event.instance(); + button_event.instantiate(); button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); button_event->set_position(st->get_position()); @@ -563,9 +563,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em button_event->set_pressed(st->is_pressed()); button_event->set_button_index(MOUSE_BUTTON_LEFT); if (st->is_pressed()) { - button_event->set_button_mask(mouse_button_mask | (1 << (MOUSE_BUTTON_LEFT - 1))); + button_event->set_button_mask(MouseButton(mouse_button_mask | MOUSE_BUTTON_MASK_LEFT)); } else { - button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1))); + button_event->set_button_mask(MouseButton(mouse_button_mask & ~MOUSE_BUTTON_MASK_LEFT)); } _parse_input_event_impl(button_event, true); @@ -582,7 +582,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) { Ref<InputEventMouseMotion> motion_event; - motion_event.instance(); + motion_event.instantiate(); motion_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); motion_event->set_position(sd->get_position()); @@ -644,7 +644,7 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em } } -void Input::set_joy_axis(int p_device, int p_axis, float p_value) { +void Input::set_joy_axis(int p_device, JoyAxis p_axis, float p_value) { _THREAD_SAFE_METHOD_ int c = _combine_device(p_axis, p_device); _joy_axis[c] = p_value; @@ -787,14 +787,14 @@ void Input::ensure_touch_mouse_raised() { mouse_from_touch_index = -1; Ref<InputEventMouseButton> button_event; - button_event.instance(); + button_event.instantiate(); button_event->set_device(InputEvent::DEVICE_ID_TOUCH_MOUSE); button_event->set_position(mouse_pos); button_event->set_global_position(mouse_pos); button_event->set_pressed(false); button_event->set_button_index(MOUSE_BUTTON_LEFT); - button_event->set_button_mask(mouse_button_mask & ~(1 << (MOUSE_BUTTON_LEFT - 1))); + button_event->set_button_mask(MouseButton(mouse_button_mask & ~MOUSE_BUTTON_MASK_LEFT)); _parse_input_event_impl(button_event, true); } @@ -821,7 +821,7 @@ void Input::set_default_cursor_shape(CursorShape p_shape) { // The default shape is set in Viewport::_gui_input_event. To instantly // see the shape in the viewport we need to trigger a mouse motion event. Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_position(mouse_pos); mm->set_global_position(mouse_pos); parse_input_event(mm); @@ -882,7 +882,7 @@ void Input::set_event_dispatch_function(EventDispatchFunc p_function) { event_dispatch_function = p_function; } -void Input::joy_button(int p_device, int p_button, bool p_pressed) { +void Input::joy_button(int p_device, JoyButton p_button, bool p_pressed) { _THREAD_SAFE_METHOD_; Joypad &joy = joy_names[p_device]; //printf("got button %i, mapping is %i\n", p_button, joy.mapping); @@ -898,17 +898,17 @@ void Input::joy_button(int p_device, int p_button, bool p_pressed) { JoyEvent map = _get_mapped_button_event(map_db[joy.mapping], p_button); if (map.type == TYPE_BUTTON) { - _button_event(p_device, map.index, p_pressed); + _button_event(p_device, (JoyButton)map.index, p_pressed); return; } if (map.type == TYPE_AXIS) { - _axis_event(p_device, map.index, p_pressed ? map.value : 0.0); + _axis_event(p_device, (JoyAxis)map.index, p_pressed ? map.value : 0.0); } // no event? } -void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) { +void Input::joy_axis(int p_device, JoyAxis p_axis, const JoyAxisValue &p_value) { _THREAD_SAFE_METHOD_; ERR_FAIL_INDEX(p_axis, JOY_AXIS_MAX); @@ -949,7 +949,7 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) { // Button already pressed or released; so ignore. return; } - _button_event(p_device, map.index, pressed); + _button_event(p_device, (JoyButton)map.index, pressed); // Ensure opposite D-Pad button is also released. switch (map.index) { @@ -981,7 +981,7 @@ void Input::joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value) { } if (map.type == TYPE_AXIS) { - _axis_event(p_device, map.index, map.value); + _axis_event(p_device, (JoyAxis)map.index, map.value); return; } //printf("invalid mapping\n"); @@ -993,24 +993,24 @@ void Input::joy_hat(int p_device, int p_val) { JoyEvent map[HAT_MAX]; - map[HAT_UP].type = TYPE_BUTTON; - map[HAT_UP].index = JOY_BUTTON_DPAD_UP; - map[HAT_UP].value = 0; + map[HatDir::HAT_UP].type = TYPE_BUTTON; + map[HatDir::HAT_UP].index = JOY_BUTTON_DPAD_UP; + map[HatDir::HAT_UP].value = 0; - map[HAT_RIGHT].type = TYPE_BUTTON; - map[HAT_RIGHT].index = JOY_BUTTON_DPAD_RIGHT; - map[HAT_RIGHT].value = 0; + map[HatDir::HAT_RIGHT].type = TYPE_BUTTON; + map[HatDir::HAT_RIGHT].index = JOY_BUTTON_DPAD_RIGHT; + map[HatDir::HAT_RIGHT].value = 0; - map[HAT_DOWN].type = TYPE_BUTTON; - map[HAT_DOWN].index = JOY_BUTTON_DPAD_DOWN; - map[HAT_DOWN].value = 0; + map[HatDir::HAT_DOWN].type = TYPE_BUTTON; + map[HatDir::HAT_DOWN].index = JOY_BUTTON_DPAD_DOWN; + map[HatDir::HAT_DOWN].value = 0; - map[HAT_LEFT].type = TYPE_BUTTON; - map[HAT_LEFT].index = JOY_BUTTON_DPAD_LEFT; - map[HAT_LEFT].value = 0; + map[HatDir::HAT_LEFT].type = TYPE_BUTTON; + map[HatDir::HAT_LEFT].index = JOY_BUTTON_DPAD_LEFT; + map[HatDir::HAT_LEFT].value = 0; if (joy.mapping != -1) { - _get_mapped_hat_events(map_db[joy.mapping], 0, map); + _get_mapped_hat_events(map_db[joy.mapping], (HatDir)0, map); } int cur_val = joy_names[p_device].hat_current; @@ -1018,10 +1018,10 @@ void Input::joy_hat(int p_device, int p_val) { for (int hat_direction = 0, hat_mask = 1; hat_direction < HAT_MAX; hat_direction++, hat_mask <<= 1) { if ((p_val & hat_mask) != (cur_val & hat_mask)) { if (map[hat_direction].type == TYPE_BUTTON) { - _button_event(p_device, map[hat_direction].index, p_val & hat_mask); + _button_event(p_device, (JoyButton)map[hat_direction].index, p_val & hat_mask); } if (map[hat_direction].type == TYPE_AXIS) { - _axis_event(p_device, map[hat_direction].index, (p_val & hat_mask) ? map[hat_direction].value : 0.0); + _axis_event(p_device, (JoyAxis)map[hat_direction].index, (p_val & hat_mask) ? map[hat_direction].value : 0.0); } } } @@ -1029,9 +1029,9 @@ void Input::joy_hat(int p_device, int p_val) { joy_names[p_device].hat_current = p_val; } -void Input::_button_event(int p_device, int p_index, bool p_pressed) { +void Input::_button_event(int p_device, JoyButton p_index, bool p_pressed) { Ref<InputEventJoypadButton> ievent; - ievent.instance(); + ievent.instantiate(); ievent->set_device(p_device); ievent->set_button_index(p_index); ievent->set_pressed(p_pressed); @@ -1039,9 +1039,9 @@ void Input::_button_event(int p_device, int p_index, bool p_pressed) { parse_input_event(ievent); } -void Input::_axis_event(int p_device, int p_axis, float p_value) { +void Input::_axis_event(int p_device, JoyAxis p_axis, float p_value) { Ref<InputEventJoypadMotion> ievent; - ievent.instance(); + ievent.instantiate(); ievent->set_device(p_device); ievent->set_axis(p_axis); ievent->set_axis_value(p_value); @@ -1049,7 +1049,7 @@ void Input::_axis_event(int p_device, int p_axis, float p_value) { parse_input_event(ievent); } -Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button) { +Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button) { JoyEvent event; event.type = TYPE_MAX; @@ -1085,7 +1085,7 @@ Input::JoyEvent Input::_get_mapped_button_event(const JoyDeviceMapping &mapping, return event; } -Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value) { +Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value) { JoyEvent event; event.type = TYPE_MAX; @@ -1156,23 +1156,23 @@ Input::JoyEvent Input::_get_mapped_axis_event(const JoyDeviceMapping &mapping, i return event; } -void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[]) { +void Input::_get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[]) { for (int i = 0; i < mapping.bindings.size(); i++) { const JoyBinding binding = mapping.bindings[i]; if (binding.inputType == TYPE_HAT && binding.input.hat.hat == p_hat) { int hat_direction; switch (binding.input.hat.hat_mask) { - case HAT_MASK_UP: - hat_direction = HAT_UP; + case HatMask::HAT_MASK_UP: + hat_direction = HatDir::HAT_UP; break; - case HAT_MASK_RIGHT: - hat_direction = HAT_RIGHT; + case HatMask::HAT_MASK_RIGHT: + hat_direction = HatDir::HAT_RIGHT; break; - case HAT_MASK_DOWN: - hat_direction = HAT_DOWN; + case HatMask::HAT_MASK_DOWN: + hat_direction = HatDir::HAT_DOWN; break; - case HAT_MASK_LEFT: - hat_direction = HAT_LEFT; + case HatMask::HAT_MASK_LEFT: + hat_direction = HatDir::HAT_LEFT; break; default: ERR_PRINT_ONCE("Joypad button mapping error."); @@ -1300,11 +1300,11 @@ void Input::parse_mapping(String p_mapping) { switch (input[0]) { case 'b': binding.inputType = TYPE_BUTTON; - binding.input.button = input.substr(1).to_int(); + binding.input.button = (JoyButton)input.substr(1).to_int(); break; case 'a': binding.inputType = TYPE_AXIS; - binding.input.axis.axis = input.substr(1).to_int(); + binding.input.axis.axis = (JoyAxis)input.substr(1).to_int(); binding.input.axis.range = input_range; binding.input.axis.invert = invert_axis; break; @@ -1312,7 +1312,7 @@ void Input::parse_mapping(String p_mapping) { ERR_CONTINUE_MSG(input.length() != 4 || input[2] != '.', String(entry[idx] + "\nInvalid hat input: " + input)); binding.inputType = TYPE_HAT; - binding.input.hat.hat = input.substr(1, 1).to_int(); + binding.input.hat.hat = (HatDir)input.substr(1, 1).to_int(); binding.input.hat.hat_mask = static_cast<HatMask>(input.substr(3).to_int()); break; default: diff --git a/core/input/input.h b/core/input/input.h index ecb4981b13..fbcd5836ea 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -72,22 +72,6 @@ public: CURSOR_MAX }; - enum HatMask { - HAT_MASK_CENTER = 0, - HAT_MASK_UP = 1, - HAT_MASK_RIGHT = 2, - HAT_MASK_DOWN = 4, - HAT_MASK_LEFT = 8, - }; - - enum HatDir { - HAT_UP, - HAT_RIGHT, - HAT_DOWN, - HAT_LEFT, - HAT_MAX, - }; - enum { JOYPADS_MAX = 16, }; @@ -149,7 +133,7 @@ private: bool connected = false; bool last_buttons[JOY_BUTTON_MAX] = { false }; float last_axis[JOY_AXIS_MAX] = { 0.0f }; - int last_hat = HAT_MASK_CENTER; + int last_hat = HatMask::HAT_MASK_CENTER; int mapping = -1; int hat_current = 0; }; @@ -183,16 +167,16 @@ private: struct JoyBinding { JoyType inputType; union { - int button; + JoyButton button; struct { - int axis; + JoyAxis axis; JoyAxisRange range; bool invert; } axis; struct { - int hat; + HatDir hat; HatMask hat_mask; } hat; @@ -218,13 +202,13 @@ private: Vector<JoyDeviceMapping> map_db; - JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, int p_button); - JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, int p_axis, float p_value); - void _get_mapped_hat_events(const JoyDeviceMapping &mapping, int p_hat, JoyEvent r_events[HAT_MAX]); + JoyEvent _get_mapped_button_event(const JoyDeviceMapping &mapping, JoyButton p_button); + JoyEvent _get_mapped_axis_event(const JoyDeviceMapping &mapping, JoyAxis p_axis, float p_value); + void _get_mapped_hat_events(const JoyDeviceMapping &mapping, HatDir p_hat, JoyEvent r_events[HAT_MAX]); JoyButton _get_output_button(String output); JoyAxis _get_output_axis(String output); - void _button_event(int p_device, int p_index, bool p_pressed); - void _axis_event(int p_device, int p_axis, float p_value); + void _button_event(int p_device, JoyButton p_index, bool p_pressed); + void _axis_event(int p_device, JoyAxis p_axis, float p_value); void _parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated); @@ -261,8 +245,8 @@ public: static Input *get_singleton(); bool is_key_pressed(int p_keycode) const; - bool is_mouse_button_pressed(int p_button) const; - bool is_joy_button_pressed(int p_device, int p_button) const; + bool is_mouse_button_pressed(MouseButton p_button) const; + bool is_joy_button_pressed(int p_device, JoyButton p_button) const; bool is_action_pressed(const StringName &p_action, bool p_exact = false) const; bool is_action_just_pressed(const StringName &p_action, bool p_exact = false) const; bool is_action_just_released(const StringName &p_action, bool p_exact = false) const; @@ -272,7 +256,7 @@ public: float get_axis(const StringName &p_negative_action, const StringName &p_positive_action) const; Vector2 get_vector(const StringName &p_negative_x, const StringName &p_positive_x, const StringName &p_negative_y, const StringName &p_positive_y, float p_deadzone = -1.0f) const; - float get_joy_axis(int p_device, int p_axis) const; + float get_joy_axis(int p_device, JoyAxis p_axis) const; String get_joy_name(int p_idx); Array get_connected_joypads(); Vector2 get_joy_vibration_strength(int p_device); @@ -299,7 +283,7 @@ public: void set_accelerometer(const Vector3 &p_accel); void set_magnetometer(const Vector3 &p_magnetometer); void set_gyroscope(const Vector3 &p_gyroscope); - void set_joy_axis(int p_device, int p_axis, float p_value); + void set_joy_axis(int p_device, JoyAxis p_axis, float p_value); void start_joy_vibration(int p_device, float p_weak_magnitude, float p_strong_magnitude, float p_duration = 0); void stop_joy_vibration(int p_device); @@ -325,8 +309,8 @@ public: void set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape = Input::CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()); void parse_mapping(String p_mapping); - void joy_button(int p_device, int p_button, bool p_pressed); - void joy_axis(int p_device, int p_axis, const JoyAxisValue &p_value); + void joy_button(int p_device, JoyButton p_button, bool p_pressed); + void joy_axis(int p_device, JoyAxis p_axis, const JoyAxisValue &p_value); void joy_hat(int p_device, int p_val); void add_joy_mapping(String p_mapping, bool p_update_existing = false); diff --git a/core/input/input_enums.h b/core/input/input_enums.h new file mode 100644 index 0000000000..4479a85bfe --- /dev/null +++ b/core/input/input_enums.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* input_enums.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef INPUT_ENUMS_H +#define INPUT_ENUMS_H + +enum HatDir { + HAT_UP = 0, + HAT_RIGHT = 1, + HAT_DOWN = 2, + HAT_LEFT = 3, + HAT_MAX = 4, +}; + +enum HatMask { + HAT_MASK_CENTER = 0, + HAT_MASK_UP = 1, + HAT_MASK_RIGHT = 2, + HAT_MASK_DOWN = 4, + HAT_MASK_LEFT = 8, +}; + +enum JoyAxis { + JOY_AXIS_INVALID = -1, + JOY_AXIS_LEFT_X = 0, + JOY_AXIS_LEFT_Y = 1, + JOY_AXIS_RIGHT_X = 2, + JOY_AXIS_RIGHT_Y = 3, + JOY_AXIS_TRIGGER_LEFT = 4, + JOY_AXIS_TRIGGER_RIGHT = 5, + JOY_AXIS_SDL_MAX = 6, + JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes. +}; + +enum JoyButton { + JOY_BUTTON_INVALID = -1, + JOY_BUTTON_A = 0, + JOY_BUTTON_B = 1, + JOY_BUTTON_X = 2, + JOY_BUTTON_Y = 3, + JOY_BUTTON_BACK = 4, + JOY_BUTTON_GUIDE = 5, + JOY_BUTTON_START = 6, + JOY_BUTTON_LEFT_STICK = 7, + JOY_BUTTON_RIGHT_STICK = 8, + JOY_BUTTON_LEFT_SHOULDER = 9, + JOY_BUTTON_RIGHT_SHOULDER = 10, + JOY_BUTTON_DPAD_UP = 11, + JOY_BUTTON_DPAD_DOWN = 12, + JOY_BUTTON_DPAD_LEFT = 13, + JOY_BUTTON_DPAD_RIGHT = 14, + JOY_BUTTON_MISC1 = 15, + JOY_BUTTON_PADDLE1 = 16, + JOY_BUTTON_PADDLE2 = 17, + JOY_BUTTON_PADDLE3 = 18, + JOY_BUTTON_PADDLE4 = 19, + JOY_BUTTON_TOUCHPAD = 20, + JOY_BUTTON_SDL_MAX = 21, + JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons. +}; + +enum MIDIMessage { + MIDI_MESSAGE_NONE = 0, + MIDI_MESSAGE_NOTE_OFF = 0x8, + MIDI_MESSAGE_NOTE_ON = 0x9, + MIDI_MESSAGE_AFTERTOUCH = 0xA, + MIDI_MESSAGE_CONTROL_CHANGE = 0xB, + MIDI_MESSAGE_PROGRAM_CHANGE = 0xC, + MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD, + MIDI_MESSAGE_PITCH_BEND = 0xE, +}; + +enum MouseButton { + MOUSE_BUTTON_NONE = 0, + MOUSE_BUTTON_LEFT = 1, + MOUSE_BUTTON_RIGHT = 2, + MOUSE_BUTTON_MIDDLE = 3, + MOUSE_BUTTON_WHEEL_UP = 4, + MOUSE_BUTTON_WHEEL_DOWN = 5, + MOUSE_BUTTON_WHEEL_LEFT = 6, + MOUSE_BUTTON_WHEEL_RIGHT = 7, + MOUSE_BUTTON_XBUTTON1 = 8, + MOUSE_BUTTON_XBUTTON2 = 9, + MOUSE_BUTTON_MASK_LEFT = (1 << (MOUSE_BUTTON_LEFT - 1)), + MOUSE_BUTTON_MASK_RIGHT = (1 << (MOUSE_BUTTON_RIGHT - 1)), + MOUSE_BUTTON_MASK_MIDDLE = (1 << (MOUSE_BUTTON_MIDDLE - 1)), + MOUSE_BUTTON_MASK_XBUTTON1 = (1 << (MOUSE_BUTTON_XBUTTON1 - 1)), + MOUSE_BUTTON_MASK_XBUTTON2 = (1 << (MOUSE_BUTTON_XBUTTON2 - 1)), +}; + +inline MouseButton &operator|=(MouseButton &a, MouseButton b) { + return (MouseButton &)((int &)a |= (int)b); +} + +inline MouseButton &operator&=(MouseButton &a, MouseButton b) { + return (MouseButton &)((int &)a &= (int)b); +} + +#endif // INPUT_ENUMS_H diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index 6f063c217f..4a2abffae8 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -38,6 +38,7 @@ const int InputEvent::DEVICE_ID_INTERNAL = -2; void InputEvent::set_device(int p_device) { device = p_device; + emit_changed(); } int InputEvent::get_device() const { @@ -88,7 +89,7 @@ bool InputEvent::action_match(const Ref<InputEvent> &p_event, bool *p_pressed, f return false; } -bool InputEvent::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEvent::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { return false; } @@ -110,7 +111,7 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("as_text"), &InputEvent::as_text); - ClassDB::bind_method(D_METHOD("shortcut_match", "event"), &InputEvent::shortcut_match); + ClassDB::bind_method(D_METHOD("is_match", "event", "exact_match"), &InputEvent::is_match, DEFVAL(true)); ClassDB::bind_method(D_METHOD("is_action_type"), &InputEvent::is_action_type); @@ -131,6 +132,7 @@ void InputEventFromWindow::_bind_methods() { void InputEventFromWindow::set_window_id(int64_t p_id) { window_id = p_id; + emit_changed(); } int64_t InputEventFromWindow::get_window_id() const { @@ -141,6 +143,7 @@ int64_t InputEventFromWindow::get_window_id() const { void InputEventWithModifiers::set_store_command(bool p_enabled) { store_command = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_storing_command() const { @@ -149,6 +152,7 @@ bool InputEventWithModifiers::is_storing_command() const { void InputEventWithModifiers::set_shift_pressed(bool p_enabled) { shift_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_shift_pressed() const { @@ -157,6 +161,7 @@ bool InputEventWithModifiers::is_shift_pressed() const { void InputEventWithModifiers::set_alt_pressed(bool p_enabled) { alt_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_alt_pressed() const { @@ -165,6 +170,7 @@ bool InputEventWithModifiers::is_alt_pressed() const { void InputEventWithModifiers::set_ctrl_pressed(bool p_enabled) { ctrl_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_ctrl_pressed() const { @@ -173,6 +179,7 @@ bool InputEventWithModifiers::is_ctrl_pressed() const { void InputEventWithModifiers::set_meta_pressed(bool p_enabled) { meta_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_meta_pressed() const { @@ -181,6 +188,7 @@ bool InputEventWithModifiers::is_meta_pressed() const { void InputEventWithModifiers::set_command_pressed(bool p_enabled) { command_pressed = p_enabled; + emit_changed(); } bool InputEventWithModifiers::is_command_pressed() const { @@ -194,6 +202,23 @@ void InputEventWithModifiers::set_modifiers_from_event(const InputEventWithModif set_meta_pressed(event->is_meta_pressed()); } +uint32_t InputEventWithModifiers::get_modifiers_mask() const { + uint32_t mask = 0; + if (is_ctrl_pressed()) { + mask |= KEY_MASK_CTRL; + } + if (is_shift_pressed()) { + mask |= KEY_MASK_SHIFT; + } + if (is_alt_pressed()) { + mask |= KEY_MASK_ALT; + } + if (is_meta_pressed()) { + mask |= KEY_MASK_META; + } + return mask; +} + String InputEventWithModifiers::as_text() const { Vector<String> mod_names; @@ -274,6 +299,7 @@ void InputEventWithModifiers::_validate_property(PropertyInfo &property) const { void InputEventKey::set_pressed(bool p_pressed) { pressed = p_pressed; + emit_changed(); } bool InputEventKey::is_pressed() const { @@ -282,6 +308,7 @@ bool InputEventKey::is_pressed() const { void InputEventKey::set_keycode(uint32_t p_keycode) { keycode = p_keycode; + emit_changed(); } uint32_t InputEventKey::get_keycode() const { @@ -290,6 +317,7 @@ uint32_t InputEventKey::get_keycode() const { void InputEventKey::set_physical_keycode(uint32_t p_keycode) { physical_keycode = p_keycode; + emit_changed(); } uint32_t InputEventKey::get_physical_keycode() const { @@ -298,6 +326,7 @@ uint32_t InputEventKey::get_physical_keycode() const { void InputEventKey::set_unicode(uint32_t p_unicode) { unicode = p_unicode; + emit_changed(); } uint32_t InputEventKey::get_unicode() const { @@ -306,6 +335,7 @@ uint32_t InputEventKey::get_unicode() const { void InputEventKey::set_echo(bool p_enable) { echo = p_enable; + emit_changed(); } bool InputEventKey::is_echo() const { @@ -313,39 +343,11 @@ bool InputEventKey::is_echo() const { } uint32_t InputEventKey::get_keycode_with_modifiers() const { - uint32_t sc = keycode; - if (is_ctrl_pressed()) { - sc |= KEY_MASK_CTRL; - } - if (is_alt_pressed()) { - sc |= KEY_MASK_ALT; - } - if (is_shift_pressed()) { - sc |= KEY_MASK_SHIFT; - } - if (is_meta_pressed()) { - sc |= KEY_MASK_META; - } - - return sc; + return keycode | get_modifiers_mask(); } uint32_t InputEventKey::get_physical_keycode_with_modifiers() const { - uint32_t sc = physical_keycode; - if (is_ctrl_pressed()) { - sc |= KEY_MASK_CTRL; - } - if (is_alt_pressed()) { - sc |= KEY_MASK_ALT; - } - if (is_shift_pressed()) { - sc |= KEY_MASK_SHIFT; - } - if (is_meta_pressed()) { - sc |= KEY_MASK_META; - } - - return sc; + return physical_keycode | get_modifiers_mask(); } String InputEventKey::as_text() const { @@ -386,7 +388,7 @@ String InputEventKey::to_string() { Ref<InputEventKey> InputEventKey::create_reference(uint32_t p_keycode) { Ref<InputEventKey> ie; - ie.instance(); + ie.instantiate(); ie->set_keycode(p_keycode & KEY_CODE_MASK); ie->set_unicode(p_keycode & KEY_CODE_MASK); @@ -442,16 +444,14 @@ bool InputEventKey::action_match(const Ref<InputEvent> &p_event, bool *p_pressed return match; } -bool InputEventKey::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEventKey::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { Ref<InputEventKey> key = p_event; if (key.is_null()) { return false; } - uint32_t code = get_keycode_with_modifiers(); - uint32_t event_code = key->get_keycode_with_modifiers(); - - return code == event_code; + return keycode == key->keycode && + (!p_exact_match || get_modifiers_mask() == key->get_modifiers_mask()); } void InputEventKey::_bind_methods() { @@ -482,6 +482,7 @@ void InputEventKey::_bind_methods() { void InputEventMouse::set_button_mask(int p_mask) { button_mask = p_mask; + emit_changed(); } int InputEventMouse::get_button_mask() const { @@ -529,11 +530,12 @@ float InputEventMouseButton::get_factor() const { return factor; } -void InputEventMouseButton::set_button_index(int p_index) { +void InputEventMouseButton::set_button_index(MouseButton p_index) { button_index = p_index; + emit_changed(); } -int InputEventMouseButton::get_button_index() const { +MouseButton InputEventMouseButton::get_button_index() const { return button_index; } @@ -558,7 +560,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co Vector2 l = p_xform.xform(get_position() + p_local_ofs); Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_device(get_device()); mb->set_window_id(get_window_id()); @@ -599,6 +601,16 @@ bool InputEventMouseButton::action_match(const Ref<InputEvent> &p_event, bool *p return match; } +bool InputEventMouseButton::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_null()) { + return false; + } + + return button_index == mb->button_index && + (!p_exact_match || get_modifiers_mask() == mb->get_modifiers_mask()); +} + static const char *_mouse_button_descriptions[9] = { TTRC("Left Mouse Button"), TTRC("Right Mouse Button"), @@ -734,7 +746,7 @@ Ref<InputEvent> InputEventMouseMotion::xformed_by(const Transform2D &p_xform, co Vector2 s = p_xform.basis_xform(get_speed()); Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_device(get_device()); mm->set_window_id(get_window_id()); @@ -848,16 +860,18 @@ void InputEventMouseMotion::_bind_methods() { /////////////////////////////////// -void InputEventJoypadMotion::set_axis(int p_axis) { +void InputEventJoypadMotion::set_axis(JoyAxis p_axis) { axis = p_axis; + emit_changed(); } -int InputEventJoypadMotion::get_axis() const { +JoyAxis InputEventJoypadMotion::get_axis() const { return axis; } void InputEventJoypadMotion::set_axis_value(float p_value) { axis_value = p_value; + emit_changed(); } float InputEventJoypadMotion::get_axis_value() const { @@ -904,6 +918,16 @@ bool InputEventJoypadMotion::action_match(const Ref<InputEvent> &p_event, bool * return match; } +bool InputEventJoypadMotion::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { + Ref<InputEventJoypadMotion> jm = p_event; + if (jm.is_null()) { + return false; + } + + return axis == jm->axis && + (!p_exact_match || ((axis_value < 0) == (jm->axis_value < 0))); +} + static const char *_joy_axis_descriptions[JOY_AXIS_MAX] = { TTRC("Left Stick X-Axis, Joystick 0 X-Axis"), TTRC("Left Stick Y-Axis, Joystick 0 Y-Axis"), @@ -940,11 +964,12 @@ void InputEventJoypadMotion::_bind_methods() { /////////////////////////////////// -void InputEventJoypadButton::set_button_index(int p_index) { +void InputEventJoypadButton::set_button_index(JoyButton p_index) { button_index = p_index; + emit_changed(); } -int InputEventJoypadButton::get_button_index() const { +JoyButton InputEventJoypadButton::get_button_index() const { return button_index; } @@ -987,7 +1012,7 @@ bool InputEventJoypadButton::action_match(const Ref<InputEvent> &p_event, bool * return match; } -bool InputEventJoypadButton::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEventJoypadButton::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { Ref<InputEventJoypadButton> button = p_event; if (button.is_null()) { return false; @@ -1023,7 +1048,7 @@ static const char *_joy_button_descriptions[JOY_BUTTON_SDL_MAX] = { String InputEventJoypadButton::as_text() const { String text = "Joypad Button " + itos(button_index); - if (button_index < JOY_BUTTON_SDL_MAX) { + if (button_index >= 0 && button_index < JOY_BUTTON_SDL_MAX) { text += vformat(" (%s)", _joy_button_descriptions[button_index]); } @@ -1039,9 +1064,9 @@ String InputEventJoypadButton::to_string() { return vformat("InputEventJoypadButton: button_index=%d, pressed=%s, pressure=%.2f", button_index, p, pressure); } -Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(int p_btn_index) { +Ref<InputEventJoypadButton> InputEventJoypadButton::create_reference(JoyButton p_btn_index) { Ref<InputEventJoypadButton> ie; - ie.instance(); + ie.instantiate(); ie->set_button_index(p_btn_index); return ie; @@ -1090,7 +1115,7 @@ bool InputEventScreenTouch::is_pressed() const { Ref<InputEvent> InputEventScreenTouch::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventScreenTouch> st; - st.instance(); + st.instantiate(); st->set_device(get_device()); st->set_window_id(get_window_id()); st->set_index(index); @@ -1163,7 +1188,7 @@ Vector2 InputEventScreenDrag::get_speed() const { Ref<InputEvent> InputEventScreenDrag::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventScreenDrag> sd; - sd.instance(); + sd.instantiate(); sd->set_device(get_device()); sd->set_window_id(get_window_id()); @@ -1229,7 +1254,7 @@ float InputEventAction::get_strength() const { return strength; } -bool InputEventAction::shortcut_match(const Ref<InputEvent> &p_event) const { +bool InputEventAction::is_match(const Ref<InputEvent> &p_event, bool p_exact_match) const { if (p_event.is_null()) { return false; } @@ -1318,7 +1343,7 @@ real_t InputEventMagnifyGesture::get_factor() const { Ref<InputEvent> InputEventMagnifyGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventMagnifyGesture> ev; - ev.instance(); + ev.instantiate(); ev->set_device(get_device()); ev->set_window_id(get_window_id()); @@ -1358,7 +1383,7 @@ Vector2 InputEventPanGesture::get_delta() const { Ref<InputEvent> InputEventPanGesture::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const { Ref<InputEventPanGesture> ev; - ev.instance(); + ev.instantiate(); ev->set_device(get_device()); ev->set_window_id(get_window_id()); @@ -1396,11 +1421,11 @@ int InputEventMIDI::get_channel() const { return channel; } -void InputEventMIDI::set_message(const int p_message) { +void InputEventMIDI::set_message(const MIDIMessage p_message) { message = p_message; } -int InputEventMIDI::get_message() const { +MIDIMessage InputEventMIDI::get_message() const { return message; } diff --git a/core/input/input_event.h b/core/input/input_event.h index eed0d79326..76a45c04a4 100644 --- a/core/input/input_event.h +++ b/core/input/input_event.h @@ -31,6 +31,7 @@ #ifndef INPUT_EVENT_H #define INPUT_EVENT_H +#include "core/input/input_enums.h" #include "core/io/resource.h" #include "core/math/transform_2d.h" #include "core/string/ustring.h" @@ -41,72 +42,6 @@ * The events are pretty obvious. */ -enum MouseButton { - MOUSE_BUTTON_LEFT = 1, - MOUSE_BUTTON_RIGHT = 2, - MOUSE_BUTTON_MIDDLE = 3, - MOUSE_BUTTON_WHEEL_UP = 4, - MOUSE_BUTTON_WHEEL_DOWN = 5, - MOUSE_BUTTON_WHEEL_LEFT = 6, - MOUSE_BUTTON_WHEEL_RIGHT = 7, - MOUSE_BUTTON_XBUTTON1 = 8, - MOUSE_BUTTON_XBUTTON2 = 9, - MOUSE_BUTTON_MASK_LEFT = (1 << (MOUSE_BUTTON_LEFT - 1)), - MOUSE_BUTTON_MASK_RIGHT = (1 << (MOUSE_BUTTON_RIGHT - 1)), - MOUSE_BUTTON_MASK_MIDDLE = (1 << (MOUSE_BUTTON_MIDDLE - 1)), - MOUSE_BUTTON_MASK_XBUTTON1 = (1 << (MOUSE_BUTTON_XBUTTON1 - 1)), - MOUSE_BUTTON_MASK_XBUTTON2 = (1 << (MOUSE_BUTTON_XBUTTON2 - 1)) -}; - -enum JoyButton { - JOY_BUTTON_INVALID = -1, - JOY_BUTTON_A = 0, - JOY_BUTTON_B = 1, - JOY_BUTTON_X = 2, - JOY_BUTTON_Y = 3, - JOY_BUTTON_BACK = 4, - JOY_BUTTON_GUIDE = 5, - JOY_BUTTON_START = 6, - JOY_BUTTON_LEFT_STICK = 7, - JOY_BUTTON_RIGHT_STICK = 8, - JOY_BUTTON_LEFT_SHOULDER = 9, - JOY_BUTTON_RIGHT_SHOULDER = 10, - JOY_BUTTON_DPAD_UP = 11, - JOY_BUTTON_DPAD_DOWN = 12, - JOY_BUTTON_DPAD_LEFT = 13, - JOY_BUTTON_DPAD_RIGHT = 14, - JOY_BUTTON_MISC1 = 15, - JOY_BUTTON_PADDLE1 = 16, - JOY_BUTTON_PADDLE2 = 17, - JOY_BUTTON_PADDLE3 = 18, - JOY_BUTTON_PADDLE4 = 19, - JOY_BUTTON_TOUCHPAD = 20, - JOY_BUTTON_SDL_MAX = 21, - JOY_BUTTON_MAX = 36, // Android supports up to 36 buttons. -}; - -enum JoyAxis { - JOY_AXIS_INVALID = -1, - JOY_AXIS_LEFT_X = 0, - JOY_AXIS_LEFT_Y = 1, - JOY_AXIS_RIGHT_X = 2, - JOY_AXIS_RIGHT_Y = 3, - JOY_AXIS_TRIGGER_LEFT = 4, - JOY_AXIS_TRIGGER_RIGHT = 5, - JOY_AXIS_SDL_MAX = 6, - JOY_AXIS_MAX = 10, // OpenVR supports up to 5 Joysticks making a total of 10 axes. -}; - -enum MIDIMessage { - MIDI_MESSAGE_NOTE_OFF = 0x8, - MIDI_MESSAGE_NOTE_ON = 0x9, - MIDI_MESSAGE_AFTERTOUCH = 0xA, - MIDI_MESSAGE_CONTROL_CHANGE = 0xB, - MIDI_MESSAGE_PROGRAM_CHANGE = 0xC, - MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD, - MIDI_MESSAGE_PITCH_BEND = 0xE, -}; - /** * Input Modifier Status * for keyboard/mouse events. @@ -142,7 +77,8 @@ public: virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const; + virtual bool is_action_type() const; virtual bool accumulate(const Ref<InputEvent> &p_event) { return false; } @@ -212,6 +148,8 @@ public: void set_modifiers_from_event(const InputEventWithModifiers *event); + uint32_t get_modifiers_mask() const; + virtual String as_text() const override; virtual String to_string() override; @@ -252,7 +190,7 @@ public: uint32_t get_physical_keycode_with_modifiers() const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } @@ -292,7 +230,7 @@ class InputEventMouseButton : public InputEventMouse { GDCLASS(InputEventMouseButton, InputEventMouse); float factor = 1; - int button_index = 0; + MouseButton button_index = MOUSE_BUTTON_NONE; bool pressed = false; //otherwise released bool double_click = false; //last even less than double click time @@ -303,8 +241,8 @@ public: void set_factor(float p_factor); float get_factor() const; - void set_button_index(int p_index); - int get_button_index() const; + void set_button_index(MouseButton p_index); + MouseButton get_button_index() const; void set_pressed(bool p_pressed); virtual bool is_pressed() const override; @@ -313,7 +251,9 @@ public: bool is_double_click() const; virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override; + virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; @@ -357,15 +297,15 @@ public: class InputEventJoypadMotion : public InputEvent { GDCLASS(InputEventJoypadMotion, InputEvent); - int axis = 0; ///< Joypad axis + JoyAxis axis = (JoyAxis)0; ///< Joypad axis float axis_value = 0; ///< -1 to 1 protected: static void _bind_methods(); public: - void set_axis(int p_axis); - int get_axis() const; + void set_axis(JoyAxis p_axis); + JoyAxis get_axis() const; void set_axis_value(float p_value); float get_axis_value() const; @@ -373,6 +313,7 @@ public: virtual bool is_pressed() const override; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } virtual String as_text() const override; @@ -384,15 +325,15 @@ public: class InputEventJoypadButton : public InputEvent { GDCLASS(InputEventJoypadButton, InputEvent); - int button_index = 0; + JoyButton button_index = (JoyButton)0; bool pressed = false; float pressure = 0; //0 to 1 protected: static void _bind_methods(); public: - void set_button_index(int p_index); - int get_button_index() const; + void set_button_index(JoyButton p_index); + JoyButton get_button_index() const; void set_pressed(bool p_pressed); virtual bool is_pressed() const override; @@ -401,13 +342,14 @@ public: float get_pressure() const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; virtual String to_string() override; - static Ref<InputEventJoypadButton> create_reference(int p_btn_index); + static Ref<InputEventJoypadButton> create_reference(JoyButton p_btn_index); InputEventJoypadButton() {} }; @@ -491,9 +433,10 @@ public: virtual bool is_action(const StringName &p_action) const; virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override; + virtual bool is_match(const Ref<InputEvent> &p_event, bool p_exact_match = true) const override; - virtual bool shortcut_match(const Ref<InputEvent> &p_event) const override; virtual bool is_action_type() const override { return true; } + virtual String as_text() const override; virtual String to_string() override; @@ -553,7 +496,7 @@ class InputEventMIDI : public InputEvent { GDCLASS(InputEventMIDI, InputEvent); int channel = 0; - int message = 0; + MIDIMessage message = MIDI_MESSAGE_NONE; int pitch = 0; int velocity = 0; int instrument = 0; @@ -568,8 +511,8 @@ public: void set_channel(const int p_channel); int get_channel() const; - void set_message(const int p_message); - int get_message() const; + void set_message(const MIDIMessage p_message); + MIDIMessage get_message() const; void set_pitch(const int p_pitch); int get_pitch() const; diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 878ce820fb..b5f067d499 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -45,6 +45,7 @@ void InputMap::_bind_methods() { ClassDB::bind_method(D_METHOD("erase_action", "action"), &InputMap::erase_action); ClassDB::bind_method(D_METHOD("action_set_deadzone", "action", "deadzone"), &InputMap::action_set_deadzone); + ClassDB::bind_method(D_METHOD("action_get_deadzone", "action"), &InputMap::action_get_deadzone); ClassDB::bind_method(D_METHOD("action_add_event", "action", "event"), &InputMap::action_add_event); ClassDB::bind_method(D_METHOD("action_has_event", "action", "event"), &InputMap::action_has_event); ClassDB::bind_method(D_METHOD("action_erase_event", "action", "event"), &InputMap::action_erase_event); @@ -130,12 +131,9 @@ List<Ref<InputEvent>>::Element *InputMap::_find_event(Action &p_action, const Re for (List<Ref<InputEvent>>::Element *E = p_action.inputs.front(); E; E = E->next()) { const Ref<InputEvent> e = E->get(); - //if (e.type != Ref<InputEvent>::KEY && e.device != p_event.device) -- unsure about the KEY comparison, why is this here? - // continue; - int device = e->get_device(); if (device == ALL_DEVICES || device == p_event->get_device()) { - if (p_exact_match && e->shortcut_match(p_event)) { + if (p_exact_match && e->is_match(p_event, true)) { return E; } else if (!p_exact_match && e->action_match(p_event, p_pressed, p_strength, p_raw_strength, p_action.deadzone)) { return E; @@ -353,8 +351,9 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_text_scroll_down", TTRC("Scroll Down") }, { "ui_text_scroll_down.OSX", TTRC("Scroll Down") }, { "ui_text_select_all", TTRC("Select All") }, - { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") }, + { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") }, { "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") }, + { "ui_text_submit", TTRC("Text Submitted") }, { "ui_graph_duplicate", TTRC("Duplicate Nodes") }, { "ui_graph_delete", TTRC("Delete Nodes") }, { "ui_filedialog_up_one_level", TTRC("Go Up One Level") }, @@ -511,6 +510,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { // Text Backspace and Delete inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE)); + inputs.push_back(InputEventKey::create_reference(KEY_BACKSPACE | KEY_MASK_SHIFT)); default_builtin_cache.insert("ui_text_backspace", inputs); inputs = List<Ref<InputEvent>>(); @@ -667,6 +667,11 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { inputs.push_back(InputEventKey::create_reference(KEY_MENU)); default_builtin_cache.insert("ui_menu", inputs); + inputs = List<Ref<InputEvent>>(); + inputs.push_back(InputEventKey::create_reference(KEY_ENTER)); + inputs.push_back(InputEventKey::create_reference(KEY_KP_ENTER)); + default_builtin_cache.insert("ui_text_submit", inputs); + // ///// UI Graph Shortcuts ///// inputs = List<Ref<InputEvent>>(); diff --git a/core/io/compression.cpp b/core/io/compression.cpp index 6de626db99..ca56509253 100644 --- a/core/io/compression.cpp +++ b/core/io/compression.cpp @@ -238,7 +238,10 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s case Z_DATA_ERROR: case Z_MEM_ERROR: case Z_STREAM_ERROR: - WARN_PRINT(strm.msg); + case Z_BUF_ERROR: + if (strm.msg) { + WARN_PRINT(strm.msg); + } (void)inflateEnd(&strm); p_dst_vect->resize(0); return ret; diff --git a/core/io/config_file.h b/core/io/config_file.h index 1b28257c60..dbba43ace5 100644 --- a/core/io/config_file.h +++ b/core/io/config_file.h @@ -31,13 +31,13 @@ #ifndef CONFIG_FILE_H #define CONFIG_FILE_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "core/templates/ordered_hash_map.h" #include "core/variant/variant_parser.h" -class ConfigFile : public Reference { - GDCLASS(ConfigFile, Reference); +class ConfigFile : public RefCounted { + GDCLASS(ConfigFile, RefCounted); OrderedHashMap<String, OrderedHashMap<String, Variant>> values; diff --git a/core/os/dir_access.cpp b/core/io/dir_access.cpp index 39ae475c12..dfba00067f 100644 --- a/core/os/dir_access.cpp +++ b/core/io/dir_access.cpp @@ -31,7 +31,7 @@ #include "dir_access.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/memory.h" #include "core/os/os.h" diff --git a/core/os/dir_access.h b/core/io/dir_access.h index 16154a4850..16154a4850 100644 --- a/core/os/dir_access.h +++ b/core/io/dir_access.h diff --git a/core/io/dtls_server.cpp b/core/io/dtls_server.cpp index 288b2efe0e..655fb18535 100644 --- a/core/io/dtls_server.cpp +++ b/core/io/dtls_server.cpp @@ -31,7 +31,7 @@ #include "dtls_server.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" DTLSServer *(*DTLSServer::_create)() = nullptr; bool DTLSServer::available = false; diff --git a/core/io/dtls_server.h b/core/io/dtls_server.h index 92b6caf508..02a32533e1 100644 --- a/core/io/dtls_server.h +++ b/core/io/dtls_server.h @@ -34,8 +34,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer_dtls.h" -class DTLSServer : public Reference { - GDCLASS(DTLSServer, Reference); +class DTLSServer : public RefCounted { + GDCLASS(DTLSServer, RefCounted); protected: static DTLSServer *(*_create)(); diff --git a/core/os/file_access.cpp b/core/io/file_access.cpp index 3d04e4e619..d21c0bd9a2 100644 --- a/core/os/file_access.cpp +++ b/core/io/file_access.cpp @@ -551,6 +551,7 @@ void FileAccess::store_csv_line(const Vector<String> &p_values, const String &p_ } void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); for (uint64_t i = 0; i < p_length; i++) { store_8(p_src[i]); } diff --git a/core/os/file_access.h b/core/io/file_access.h index 5804aa2c47..5804aa2c47 100644 --- a/core/os/file_access.h +++ b/core/io/file_access.h diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index 19e4f241dd..3389e020e3 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -32,7 +32,7 @@ #define FILE_ACCESS_COMPRESSED_H #include "core/io/compression.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" class FileAccessCompressed : public FileAccess { Compression::Mode cmode = Compression::MODE_ZSTD; diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index b9514c8c8b..9e316291e8 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -257,6 +257,7 @@ Error FileAccessEncrypted::get_error() const { void FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); + ERR_FAIL_COND(!p_src && p_length > 0); if (pos < get_length()) { for (uint64_t i = 0; i < p_length; i++) { diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 00f14099f9..decffae696 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_ENCRYPTED_H #define FILE_ACCESS_ENCRYPTED_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #define ENCRYPTED_HEADER_MAGIC 0x43454447 diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 0114ab1765..627fd2bf9c 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -31,7 +31,7 @@ #include "file_access_memory.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/templates/map.h" static Map<String, Vector<uint8_t>> *files = nullptr; @@ -168,6 +168,7 @@ void FileAccessMemory::store_8(uint8_t p_byte) { } void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND(!p_src && p_length > 0); uint64_t left = length - pos; uint64_t write = MIN(p_length, left); if (write < p_length) { diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 4157531d01..14135bd68c 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_MEMORY_H #define FILE_ACCESS_MEMORY_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" class FileAccessMemory : public FileAccess { uint8_t *data = nullptr; diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 63a8f9c5b6..9ee3876c2f 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -210,7 +210,7 @@ FileAccessNetworkClient *FileAccessNetworkClient::singleton = nullptr; FileAccessNetworkClient::FileAccessNetworkClient() { singleton = this; - client.instance(); + client.instantiate(); } FileAccessNetworkClient::~FileAccessNetworkClient() { diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index 94b66c2480..1d9d761fbb 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_NETWORK_H #define FILE_ACCESS_NETWORK_H +#include "core/io/file_access.h" #include "core/io/stream_peer_tcp.h" -#include "core/os/file_access.h" #include "core/os/semaphore.h" #include "core/os/thread.h" diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 7a83fc938f..2f0ee62723 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -31,8 +31,8 @@ #ifndef FILE_ACCESS_PACK_H #define FILE_ACCESS_PACK_H -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/string/print_string.h" #include "core/templates/list.h" #include "core/templates/map.h" diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index b8383fd865..b5c882e9ce 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -32,7 +32,7 @@ #include "file_access_zip.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" ZipArchive *ZipArchive::instance = nullptr; diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp index 0cf870e7e7..8000dd4290 100644 --- a/core/io/http_client.cpp +++ b/core/io/http_client.cpp @@ -30,9 +30,6 @@ #include "http_client.h" -#include "core/io/stream_peer_ssl.h" -#include "core/version.h" - const char *HTTPClient::_methods[METHOD_MAX] = { "GET", "HEAD", @@ -45,698 +42,23 @@ const char *HTTPClient::_methods[METHOD_MAX] = { "PATCH" }; -#ifndef JAVASCRIPT_ENABLED -Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { - close(); - - conn_port = p_port; - conn_host = p_host; - - ssl = p_ssl; - ssl_verify_host = p_verify_host; - - String host_lower = conn_host.to_lower(); - if (host_lower.begins_with("http://")) { - conn_host = conn_host.substr(7, conn_host.length() - 7); - } else if (host_lower.begins_with("https://")) { - ssl = true; - conn_host = conn_host.substr(8, conn_host.length() - 8); - } - - ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER); - - if (conn_port < 0) { - if (ssl) { - conn_port = PORT_HTTPS; - } else { - conn_port = PORT_HTTP; - } - } - - connection = tcp_connection; - - if (conn_host.is_valid_ip_address()) { - // Host contains valid IP - Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port); - if (err) { - status = STATUS_CANT_CONNECT; - return err; - } - - status = STATUS_CONNECTING; - } else { - // Host contains hostname and needs to be resolved to IP - resolving = IP::get_singleton()->resolve_hostname_queue_item(conn_host); - status = STATUS_RESOLVING; +HTTPClient *HTTPClient::create() { + if (_create) { + return _create(); } - - return OK; + return nullptr; } -void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) { - ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object."); - - if (ssl) { - ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()), - "Connection is not a reference to a valid StreamPeerSSL object."); - } - - if (connection == p_connection) { - return; - } - - close(); - connection = p_connection; - status = STATUS_CONNECTED; +Error HTTPClient::_request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) { + int size = p_body.size(); + return request(p_method, p_url, p_headers, size > 0 ? p_body.ptr() : nullptr, size); } -Ref<StreamPeer> HTTPClient::get_connection() const { - return connection; +Error HTTPClient::_request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { + int size = p_body.length(); + return request(p_method, p_url, p_headers, size > 0 ? (const uint8_t *)p_body.utf8().get_data() : nullptr, size); } -static bool _check_request_url(HTTPClient::Method p_method, const String &p_url) { - switch (p_method) { - case HTTPClient::METHOD_CONNECT: { - // Authority in host:port format, as in RFC7231 - int pos = p_url.find_char(':'); - return 0 < pos && pos < p_url.length() - 1; - } - case HTTPClient::METHOD_OPTIONS: { - if (p_url == "*") { - return true; - } - [[fallthrough]]; - } - default: - // Absolute path or absolute URL - return p_url.begins_with("/") || p_url.begins_with("http://") || p_url.begins_with("https://"); - } -} - -Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) { - ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); - - String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - bool add_host = true; - bool add_clen = p_body.size() > 0; - bool add_uagent = true; - bool add_accept = true; - for (int i = 0; i < p_headers.size(); i++) { - request += p_headers[i] + "\r\n"; - if (add_host && p_headers[i].findn("Host:") == 0) { - add_host = false; - } - if (add_clen && p_headers[i].findn("Content-Length:") == 0) { - add_clen = false; - } - if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { - add_uagent = false; - } - if (add_accept && p_headers[i].findn("Accept:") == 0) { - add_accept = false; - } - } - if (add_host) { - if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { - // Don't append the standard ports - request += "Host: " + conn_host + "\r\n"; - } else { - request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; - } - } - if (add_clen) { - request += "Content-Length: " + itos(p_body.size()) + "\r\n"; - // Should it add utf8 encoding? - } - if (add_uagent) { - request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; - } - if (add_accept) { - request += "Accept: */*\r\n"; - } - request += "\r\n"; - CharString cs = request.utf8(); - - Vector<uint8_t> data; - data.resize(cs.length()); - { - uint8_t *data_write = data.ptrw(); - for (int i = 0; i < cs.length(); i++) { - data_write[i] = cs[i]; - } - } - - data.append_array(p_body); - - const uint8_t *r = data.ptr(); - Error err = connection->put_data(&r[0], data.size()); - - if (err) { - close(); - status = STATUS_CONNECTION_ERROR; - return err; - } - - status = STATUS_REQUESTING; - head_request = p_method == METHOD_HEAD; - - return OK; -} - -Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { - ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); - - String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; - bool add_host = true; - bool add_uagent = true; - bool add_accept = true; - bool add_clen = p_body.length() > 0; - for (int i = 0; i < p_headers.size(); i++) { - request += p_headers[i] + "\r\n"; - if (add_host && p_headers[i].findn("Host:") == 0) { - add_host = false; - } - if (add_clen && p_headers[i].findn("Content-Length:") == 0) { - add_clen = false; - } - if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { - add_uagent = false; - } - if (add_accept && p_headers[i].findn("Accept:") == 0) { - add_accept = false; - } - } - if (add_host) { - if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { - // Don't append the standard ports - request += "Host: " + conn_host + "\r\n"; - } else { - request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; - } - } - if (add_clen) { - request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n"; - // Should it add utf8 encoding? - } - if (add_uagent) { - request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; - } - if (add_accept) { - request += "Accept: */*\r\n"; - } - request += "\r\n"; - request += p_body; - - CharString cs = request.utf8(); - Error err = connection->put_data((const uint8_t *)cs.ptr(), cs.length()); - if (err) { - close(); - status = STATUS_CONNECTION_ERROR; - return err; - } - - status = STATUS_REQUESTING; - head_request = p_method == METHOD_HEAD; - - return OK; -} - -bool HTTPClient::has_response() const { - return response_headers.size() != 0; -} - -bool HTTPClient::is_response_chunked() const { - return chunked; -} - -int HTTPClient::get_response_code() const { - return response_num; -} - -Error HTTPClient::get_response_headers(List<String> *r_response) { - if (!response_headers.size()) { - return ERR_INVALID_PARAMETER; - } - - for (int i = 0; i < response_headers.size(); i++) { - r_response->push_back(response_headers[i]); - } - - response_headers.clear(); - - return OK; -} - -void HTTPClient::close() { - if (tcp_connection->get_status() != StreamPeerTCP::STATUS_NONE) { - tcp_connection->disconnect_from_host(); - } - - connection.unref(); - status = STATUS_DISCONNECTED; - head_request = false; - if (resolving != IP::RESOLVER_INVALID_ID) { - IP::get_singleton()->erase_resolve_item(resolving); - resolving = IP::RESOLVER_INVALID_ID; - } - - response_headers.clear(); - response_str.clear(); - body_size = -1; - body_left = 0; - chunk_left = 0; - chunk_trailer_part = false; - read_until_eof = false; - response_num = 0; - handshaking = false; -} - -Error HTTPClient::poll() { - switch (status) { - case STATUS_RESOLVING: { - ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG); - - IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving); - switch (rstatus) { - case IP::RESOLVER_STATUS_WAITING: - return OK; // Still resolving - - case IP::RESOLVER_STATUS_DONE: { - IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving); - Error err = tcp_connection->connect_to_host(host, conn_port); - IP::get_singleton()->erase_resolve_item(resolving); - resolving = IP::RESOLVER_INVALID_ID; - if (err) { - status = STATUS_CANT_CONNECT; - return err; - } - - status = STATUS_CONNECTING; - } break; - case IP::RESOLVER_STATUS_NONE: - case IP::RESOLVER_STATUS_ERROR: { - IP::get_singleton()->erase_resolve_item(resolving); - resolving = IP::RESOLVER_INVALID_ID; - close(); - status = STATUS_CANT_RESOLVE; - return ERR_CANT_RESOLVE; - } break; - } - } break; - case STATUS_CONNECTING: { - StreamPeerTCP::Status s = tcp_connection->get_status(); - switch (s) { - case StreamPeerTCP::STATUS_CONNECTING: { - return OK; - } break; - case StreamPeerTCP::STATUS_CONNECTED: { - if (ssl) { - Ref<StreamPeerSSL> ssl; - if (!handshaking) { - // Connect the StreamPeerSSL and start handshaking - ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); - ssl->set_blocking_handshake_enabled(false); - Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); - if (err != OK) { - close(); - status = STATUS_SSL_HANDSHAKE_ERROR; - return ERR_CANT_CONNECT; - } - connection = ssl; - handshaking = true; - } else { - // We are already handshaking, which means we can use your already active SSL connection - ssl = static_cast<Ref<StreamPeerSSL>>(connection); - if (ssl.is_null()) { - close(); - status = STATUS_SSL_HANDSHAKE_ERROR; - return ERR_CANT_CONNECT; - } - - ssl->poll(); // Try to finish the handshake - } - - if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { - // Handshake has been successful - handshaking = false; - status = STATUS_CONNECTED; - return OK; - } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { - // Handshake has failed - close(); - status = STATUS_SSL_HANDSHAKE_ERROR; - return ERR_CANT_CONNECT; - } - // ... we will need to poll more for handshake to finish - } else { - status = STATUS_CONNECTED; - } - return OK; - } break; - case StreamPeerTCP::STATUS_ERROR: - case StreamPeerTCP::STATUS_NONE: { - close(); - status = STATUS_CANT_CONNECT; - return ERR_CANT_CONNECT; - } break; - } - } break; - case STATUS_BODY: - case STATUS_CONNECTED: { - // Check if we are still connected - if (ssl) { - Ref<StreamPeerSSL> tmp = connection; - tmp->poll(); - if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) { - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } - } else if (tcp_connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } - // Connection established, requests can now be made - return OK; - } break; - case STATUS_REQUESTING: { - while (true) { - uint8_t byte; - int rec = 0; - Error err = _get_http_data(&byte, 1, rec); - if (err != OK) { - close(); - status = STATUS_CONNECTION_ERROR; - return ERR_CONNECTION_ERROR; - } - - if (rec == 0) { - return OK; // Still requesting, keep trying! - } - - response_str.push_back(byte); - int rs = response_str.size(); - if ( - (rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') || - (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { - // End of response, parse. - response_str.push_back(0); - String response; - response.parse_utf8((const char *)response_str.ptr()); - Vector<String> responses = response.split("\n"); - body_size = -1; - chunked = false; - body_left = 0; - chunk_left = 0; - chunk_trailer_part = false; - read_until_eof = false; - response_str.clear(); - response_headers.clear(); - response_num = RESPONSE_OK; - - // Per the HTTP 1.1 spec, keep-alive is the default. - // Not following that specification breaks standard implementations. - // Broken web servers should be fixed. - bool keep_alive = true; - - for (int i = 0; i < responses.size(); i++) { - String header = responses[i].strip_edges(); - String s = header.to_lower(); - if (s.length() == 0) { - continue; - } - if (s.begins_with("content-length:")) { - body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int(); - body_left = body_size; - - } else if (s.begins_with("transfer-encoding:")) { - String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges(); - if (encoding == "chunked") { - chunked = true; - } - } else if (s.begins_with("connection: close")) { - keep_alive = false; - } - - if (i == 0 && responses[i].begins_with("HTTP")) { - String num = responses[i].get_slicec(' ', 1); - response_num = num.to_int(); - } else { - response_headers.push_back(header); - } - } - - // This is a HEAD request, we won't receive anything. - if (head_request) { - body_size = 0; - body_left = 0; - } - - if (body_size != -1 || chunked) { - status = STATUS_BODY; - } else if (!keep_alive) { - read_until_eof = true; - status = STATUS_BODY; - } else { - status = STATUS_CONNECTED; - } - return OK; - } - } - } break; - case STATUS_DISCONNECTED: { - return ERR_UNCONFIGURED; - } break; - case STATUS_CONNECTION_ERROR: - case STATUS_SSL_HANDSHAKE_ERROR: { - return ERR_CONNECTION_ERROR; - } break; - case STATUS_CANT_CONNECT: { - return ERR_CANT_CONNECT; - } break; - case STATUS_CANT_RESOLVE: { - return ERR_CANT_RESOLVE; - } break; - } - - return OK; -} - -int HTTPClient::get_response_body_length() const { - return body_size; -} - -PackedByteArray HTTPClient::read_response_body_chunk() { - ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray()); - - PackedByteArray ret; - Error err = OK; - - if (chunked) { - while (true) { - if (chunk_trailer_part) { - // We need to consume the trailer part too or keep-alive will break - uint8_t b; - int rec = 0; - err = _get_http_data(&b, 1, rec); - - if (rec == 0) { - break; - } - - chunk.push_back(b); - int cs = chunk.size(); - if ((cs >= 2 && chunk[cs - 2] == '\r' && chunk[cs - 1] == '\n')) { - if (cs == 2) { - // Finally over - chunk_trailer_part = false; - status = STATUS_CONNECTED; - chunk.clear(); - break; - } else { - // We do not process nor return the trailer data - chunk.clear(); - } - } - } else if (chunk_left == 0) { - // Reading length - uint8_t b; - int rec = 0; - err = _get_http_data(&b, 1, rec); - - if (rec == 0) { - break; - } - - chunk.push_back(b); - - if (chunk.size() > 32) { - ERR_PRINT("HTTP Invalid chunk hex len"); - status = STATUS_CONNECTION_ERROR; - break; - } - - if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') { - int len = 0; - for (int i = 0; i < chunk.size() - 2; i++) { - char c = chunk[i]; - int v = 0; - if (c >= '0' && c <= '9') { - v = c - '0'; - } else if (c >= 'a' && c <= 'f') { - v = c - 'a' + 10; - } else if (c >= 'A' && c <= 'F') { - v = c - 'A' + 10; - } else { - ERR_PRINT("HTTP Chunk len not in hex!!"); - status = STATUS_CONNECTION_ERROR; - break; - } - len <<= 4; - len |= v; - if (len > (1 << 24)) { - ERR_PRINT("HTTP Chunk too big!! >16mb"); - status = STATUS_CONNECTION_ERROR; - break; - } - } - - if (len == 0) { - // End reached! - chunk_trailer_part = true; - chunk.clear(); - break; - } - - chunk_left = len + 2; - chunk.resize(chunk_left); - } - } else { - int rec = 0; - err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec); - if (rec == 0) { - break; - } - chunk_left -= rec; - - if (chunk_left == 0) { - if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') { - ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)"); - status = STATUS_CONNECTION_ERROR; - break; - } - - ret.resize(chunk.size() - 2); - uint8_t *w = ret.ptrw(); - memcpy(w, chunk.ptr(), chunk.size() - 2); - chunk.clear(); - } - - break; - } - } - - } else { - int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size; - ret.resize(to_read); - int _offset = 0; - while (to_read > 0) { - int rec = 0; - { - uint8_t *w = ret.ptrw(); - err = _get_http_data(w + _offset, to_read, rec); - } - if (rec <= 0) { // Ended up reading less - ret.resize(_offset); - break; - } else { - _offset += rec; - to_read -= rec; - if (!read_until_eof) { - body_left -= rec; - } - } - if (err != OK) { - break; - } - } - } - - if (err != OK) { - close(); - - if (err == ERR_FILE_EOF) { - status = STATUS_DISCONNECTED; // Server disconnected - } else { - status = STATUS_CONNECTION_ERROR; - } - } else if (body_left == 0 && !chunked && !read_until_eof) { - status = STATUS_CONNECTED; - } - - return ret; -} - -HTTPClient::Status HTTPClient::get_status() const { - return status; -} - -void HTTPClient::set_blocking_mode(bool p_enable) { - blocking = p_enable; -} - -bool HTTPClient::is_blocking_mode_enabled() const { - return blocking; -} - -Error HTTPClient::_get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - if (blocking) { - // We can't use StreamPeer.get_data, since when reaching EOF we will get an - // error without knowing how many bytes we received. - Error err = ERR_FILE_EOF; - int read = 0; - int left = p_bytes; - r_received = 0; - while (left > 0) { - err = connection->get_partial_data(p_buffer + r_received, left, read); - if (err == OK) { - r_received += read; - } else if (err == ERR_FILE_EOF) { - r_received += read; - return err; - } else { - return err; - } - left -= read; - } - return err; - } else { - return connection->get_partial_data(p_buffer, p_bytes, r_received); - } -} - -void HTTPClient::set_read_chunk_size(int p_size) { - ERR_FAIL_COND(p_size < 256 || p_size > (1 << 24)); - read_chunk_size = p_size; -} - -int HTTPClient::get_read_chunk_size() const { - return read_chunk_size; -} - -HTTPClient::HTTPClient() { - tcp_connection.instance(); -} - -HTTPClient::~HTTPClient() {} - -#endif // #ifndef JAVASCRIPT_ENABLED - String HTTPClient::query_string_from_dict(const Dictionary &p_dict) { String query = ""; Array keys = p_dict.keys(); @@ -802,8 +124,8 @@ void HTTPClient::_bind_methods() { ClassDB::bind_method(D_METHOD("connect_to_host", "host", "port", "use_ssl", "verify_host"), &HTTPClient::connect_to_host, DEFVAL(-1), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_connection", "connection"), &HTTPClient::set_connection); ClassDB::bind_method(D_METHOD("get_connection"), &HTTPClient::get_connection); - ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::request_raw); - ClassDB::bind_method(D_METHOD("request", "method", "url", "headers", "body"), &HTTPClient::request, DEFVAL(String())); + ClassDB::bind_method(D_METHOD("request_raw", "method", "url", "headers", "body"), &HTTPClient::_request_raw); + ClassDB::bind_method(D_METHOD("request", "method", "url", "headers", "body"), &HTTPClient::_request, DEFVAL(String())); ClassDB::bind_method(D_METHOD("close"), &HTTPClient::close); ClassDB::bind_method(D_METHOD("has_response"), &HTTPClient::has_response); @@ -825,7 +147,7 @@ void HTTPClient::_bind_methods() { ClassDB::bind_method(D_METHOD("query_string_from_dict", "fields"), &HTTPClient::query_string_from_dict); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "blocking_mode_enabled"), "set_blocking_mode", "is_blocking_mode_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_connection", "get_connection"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "connection", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", PROPERTY_USAGE_NONE), "set_connection", "get_connection"); ADD_PROPERTY(PropertyInfo(Variant::INT, "read_chunk_size", PROPERTY_HINT_RANGE, "256,16777216"), "set_read_chunk_size", "get_read_chunk_size"); BIND_ENUM_CONSTANT(METHOD_GET); diff --git a/core/io/http_client.h b/core/io/http_client.h index ec4b86b26f..718c3a905e 100644 --- a/core/io/http_client.h +++ b/core/io/http_client.h @@ -34,10 +34,10 @@ #include "core/io/ip.h" #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class HTTPClient : public Reference { - GDCLASS(HTTPClient, Reference); +class HTTPClient : public RefCounted { + GDCLASS(HTTPClient, RefCounted); public: enum ResponseCode { @@ -142,7 +142,7 @@ public: }; -private: +protected: static const char *_methods[METHOD_MAX]; static const int HOST_MIN_LEN = 4; @@ -152,79 +152,48 @@ private: }; -#ifndef JAVASCRIPT_ENABLED - Status status = STATUS_DISCONNECTED; - IP::ResolverID resolving = IP::RESOLVER_INVALID_ID; - int conn_port = -1; - String conn_host; - bool ssl = false; - bool ssl_verify_host = false; - bool blocking = false; - bool handshaking = false; - bool head_request = false; - - Vector<uint8_t> response_str; - - bool chunked = false; - Vector<uint8_t> chunk; - int chunk_left = 0; - bool chunk_trailer_part = false; - int body_size = -1; - int body_left = 0; - bool read_until_eof = false; - - Ref<StreamPeerTCP> tcp_connection; - Ref<StreamPeer> connection; - - int response_num = 0; - Vector<String> response_headers; - // 64 KiB by default (favors fast download speeds at the cost of memory usage). - int read_chunk_size = 65536; - - Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received); - -#else -#include "platform/javascript/http_client.h.inc" -#endif - PackedStringArray _get_response_headers(); Dictionary _get_response_headers_as_dictionary(); + Error _request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body); + Error _request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body = String()); + + static HTTPClient *(*_create)(); static void _bind_methods(); public: - Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true); + static HTTPClient *create(); - void set_connection(const Ref<StreamPeer> &p_connection); - Ref<StreamPeer> get_connection() const; + String query_string_from_dict(const Dictionary &p_dict); - Error request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body); - Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body = String()); + virtual Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) = 0; + virtual Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) = 0; - void close(); + virtual void set_connection(const Ref<StreamPeer> &p_connection) = 0; + virtual Ref<StreamPeer> get_connection() const = 0; - Status get_status() const; + virtual void close() = 0; - bool has_response() const; - bool is_response_chunked() const; - int get_response_code() const; - Error get_response_headers(List<String> *r_response); - int get_response_body_length() const; + virtual Status get_status() const = 0; - PackedByteArray read_response_body_chunk(); // Can't get body as partial text because of most encodings UTF8, gzip, etc. + virtual bool has_response() const = 0; + virtual bool is_response_chunked() const = 0; + virtual int get_response_code() const = 0; + virtual Error get_response_headers(List<String> *r_response) = 0; + virtual int get_response_body_length() const = 0; - void set_blocking_mode(bool p_enable); // Useful mostly if running in a thread - bool is_blocking_mode_enabled() const; + virtual PackedByteArray read_response_body_chunk() = 0; // Can't get body as partial text because of most encodings UTF8, gzip, etc. - void set_read_chunk_size(int p_size); - int get_read_chunk_size() const; + virtual void set_blocking_mode(bool p_enable) = 0; // Useful mostly if running in a thread + virtual bool is_blocking_mode_enabled() const = 0; - Error poll(); + virtual void set_read_chunk_size(int p_size) = 0; + virtual int get_read_chunk_size() const = 0; - String query_string_from_dict(const Dictionary &p_dict); + virtual Error poll() = 0; - HTTPClient(); - ~HTTPClient(); + HTTPClient() {} + virtual ~HTTPClient() {} }; VARIANT_ENUM_CAST(HTTPClient::ResponseCode) diff --git a/core/io/http_client_tcp.cpp b/core/io/http_client_tcp.cpp new file mode 100644 index 0000000000..f291086808 --- /dev/null +++ b/core/io/http_client_tcp.cpp @@ -0,0 +1,667 @@ +/*************************************************************************/ +/* http_client_tcp.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef JAVASCRIPT_ENABLED + +#include "http_client_tcp.h" + +#include "core/io/stream_peer_ssl.h" +#include "core/version.h" + +HTTPClient *HTTPClientTCP::_create_func() { + return memnew(HTTPClientTCP); +} + +Error HTTPClientTCP::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { + close(); + + conn_port = p_port; + conn_host = p_host; + + ssl = p_ssl; + ssl_verify_host = p_verify_host; + + String host_lower = conn_host.to_lower(); + if (host_lower.begins_with("http://")) { + conn_host = conn_host.substr(7, conn_host.length() - 7); + } else if (host_lower.begins_with("https://")) { + ssl = true; + conn_host = conn_host.substr(8, conn_host.length() - 8); + } + + ERR_FAIL_COND_V(conn_host.length() < HOST_MIN_LEN, ERR_INVALID_PARAMETER); + + if (conn_port < 0) { + if (ssl) { + conn_port = PORT_HTTPS; + } else { + conn_port = PORT_HTTP; + } + } + + connection = tcp_connection; + + if (conn_host.is_valid_ip_address()) { + // Host contains valid IP + Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port); + if (err) { + status = STATUS_CANT_CONNECT; + return err; + } + + status = STATUS_CONNECTING; + } else { + // Host contains hostname and needs to be resolved to IP + resolving = IP::get_singleton()->resolve_hostname_queue_item(conn_host); + status = STATUS_RESOLVING; + } + + return OK; +} + +void HTTPClientTCP::set_connection(const Ref<StreamPeer> &p_connection) { + ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object."); + + if (ssl) { + ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()), + "Connection is not a reference to a valid StreamPeerSSL object."); + } + + if (connection == p_connection) { + return; + } + + close(); + connection = p_connection; + status = STATUS_CONNECTED; +} + +Ref<StreamPeer> HTTPClientTCP::get_connection() const { + return connection; +} + +static bool _check_request_url(HTTPClientTCP::Method p_method, const String &p_url) { + switch (p_method) { + case HTTPClientTCP::METHOD_CONNECT: { + // Authority in host:port format, as in RFC7231 + int pos = p_url.find_char(':'); + return 0 < pos && pos < p_url.length() - 1; + } + case HTTPClientTCP::METHOD_OPTIONS: { + if (p_url == "*") { + return true; + } + [[fallthrough]]; + } + default: + // Absolute path or absolute URL + return p_url.begins_with("/") || p_url.begins_with("http://") || p_url.begins_with("https://"); + } +} + +Error HTTPClientTCP::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) { + ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA); + + String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n"; + bool add_host = true; + bool add_clen = p_body_size > 0; + bool add_uagent = true; + bool add_accept = true; + for (int i = 0; i < p_headers.size(); i++) { + request += p_headers[i] + "\r\n"; + if (add_host && p_headers[i].findn("Host:") == 0) { + add_host = false; + } + if (add_clen && p_headers[i].findn("Content-Length:") == 0) { + add_clen = false; + } + if (add_uagent && p_headers[i].findn("User-Agent:") == 0) { + add_uagent = false; + } + if (add_accept && p_headers[i].findn("Accept:") == 0) { + add_accept = false; + } + } + if (add_host) { + if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) { + // Don't append the standard ports + request += "Host: " + conn_host + "\r\n"; + } else { + request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n"; + } + } + if (add_clen) { + request += "Content-Length: " + itos(p_body_size) + "\r\n"; + // Should it add utf8 encoding? + } + if (add_uagent) { + request += "User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")\r\n"; + } + if (add_accept) { + request += "Accept: */*\r\n"; + } + request += "\r\n"; + CharString cs = request.utf8(); + + Vector<uint8_t> data; + data.resize(cs.length() + p_body_size); + memcpy(data.ptrw(), cs.get_data(), cs.length()); + if (p_body_size > 0) { + memcpy(data.ptrw() + cs.length(), p_body, p_body_size); + } + + // TODO Implement non-blocking requests. + Error err = connection->put_data(data.ptr(), data.size()); + + if (err) { + close(); + status = STATUS_CONNECTION_ERROR; + return err; + } + + status = STATUS_REQUESTING; + head_request = p_method == METHOD_HEAD; + + return OK; +} + +bool HTTPClientTCP::has_response() const { + return response_headers.size() != 0; +} + +bool HTTPClientTCP::is_response_chunked() const { + return chunked; +} + +int HTTPClientTCP::get_response_code() const { + return response_num; +} + +Error HTTPClientTCP::get_response_headers(List<String> *r_response) { + if (!response_headers.size()) { + return ERR_INVALID_PARAMETER; + } + + for (int i = 0; i < response_headers.size(); i++) { + r_response->push_back(response_headers[i]); + } + + response_headers.clear(); + + return OK; +} + +void HTTPClientTCP::close() { + if (tcp_connection->get_status() != StreamPeerTCP::STATUS_NONE) { + tcp_connection->disconnect_from_host(); + } + + connection.unref(); + status = STATUS_DISCONNECTED; + head_request = false; + if (resolving != IP::RESOLVER_INVALID_ID) { + IP::get_singleton()->erase_resolve_item(resolving); + resolving = IP::RESOLVER_INVALID_ID; + } + + response_headers.clear(); + response_str.clear(); + body_size = -1; + body_left = 0; + chunk_left = 0; + chunk_trailer_part = false; + read_until_eof = false; + response_num = 0; + handshaking = false; +} + +Error HTTPClientTCP::poll() { + switch (status) { + case STATUS_RESOLVING: { + ERR_FAIL_COND_V(resolving == IP::RESOLVER_INVALID_ID, ERR_BUG); + + IP::ResolverStatus rstatus = IP::get_singleton()->get_resolve_item_status(resolving); + switch (rstatus) { + case IP::RESOLVER_STATUS_WAITING: + return OK; // Still resolving + + case IP::RESOLVER_STATUS_DONE: { + IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving); + Error err = tcp_connection->connect_to_host(host, conn_port); + IP::get_singleton()->erase_resolve_item(resolving); + resolving = IP::RESOLVER_INVALID_ID; + if (err) { + status = STATUS_CANT_CONNECT; + return err; + } + + status = STATUS_CONNECTING; + } break; + case IP::RESOLVER_STATUS_NONE: + case IP::RESOLVER_STATUS_ERROR: { + IP::get_singleton()->erase_resolve_item(resolving); + resolving = IP::RESOLVER_INVALID_ID; + close(); + status = STATUS_CANT_RESOLVE; + return ERR_CANT_RESOLVE; + } break; + } + } break; + case STATUS_CONNECTING: { + StreamPeerTCP::Status s = tcp_connection->get_status(); + switch (s) { + case StreamPeerTCP::STATUS_CONNECTING: { + return OK; + } break; + case StreamPeerTCP::STATUS_CONNECTED: { + if (ssl) { + Ref<StreamPeerSSL> ssl; + if (!handshaking) { + // Connect the StreamPeerSSL and start handshaking + ssl = Ref<StreamPeerSSL>(StreamPeerSSL::create()); + ssl->set_blocking_handshake_enabled(false); + Error err = ssl->connect_to_stream(tcp_connection, ssl_verify_host, conn_host); + if (err != OK) { + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + connection = ssl; + handshaking = true; + } else { + // We are already handshaking, which means we can use your already active SSL connection + ssl = static_cast<Ref<StreamPeerSSL>>(connection); + if (ssl.is_null()) { + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + + ssl->poll(); // Try to finish the handshake + } + + if (ssl->get_status() == StreamPeerSSL::STATUS_CONNECTED) { + // Handshake has been successful + handshaking = false; + status = STATUS_CONNECTED; + return OK; + } else if (ssl->get_status() != StreamPeerSSL::STATUS_HANDSHAKING) { + // Handshake has failed + close(); + status = STATUS_SSL_HANDSHAKE_ERROR; + return ERR_CANT_CONNECT; + } + // ... we will need to poll more for handshake to finish + } else { + status = STATUS_CONNECTED; + } + return OK; + } break; + case StreamPeerTCP::STATUS_ERROR: + case StreamPeerTCP::STATUS_NONE: { + close(); + status = STATUS_CANT_CONNECT; + return ERR_CANT_CONNECT; + } break; + } + } break; + case STATUS_BODY: + case STATUS_CONNECTED: { + // Check if we are still connected + if (ssl) { + Ref<StreamPeerSSL> tmp = connection; + tmp->poll(); + if (tmp->get_status() != StreamPeerSSL::STATUS_CONNECTED) { + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + } else if (tcp_connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) { + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + // Connection established, requests can now be made + return OK; + } break; + case STATUS_REQUESTING: { + while (true) { + uint8_t byte; + int rec = 0; + Error err = _get_http_data(&byte, 1, rec); + if (err != OK) { + close(); + status = STATUS_CONNECTION_ERROR; + return ERR_CONNECTION_ERROR; + } + + if (rec == 0) { + return OK; // Still requesting, keep trying! + } + + response_str.push_back(byte); + int rs = response_str.size(); + if ( + (rs >= 2 && response_str[rs - 2] == '\n' && response_str[rs - 1] == '\n') || + (rs >= 4 && response_str[rs - 4] == '\r' && response_str[rs - 3] == '\n' && response_str[rs - 2] == '\r' && response_str[rs - 1] == '\n')) { + // End of response, parse. + response_str.push_back(0); + String response; + response.parse_utf8((const char *)response_str.ptr()); + Vector<String> responses = response.split("\n"); + body_size = -1; + chunked = false; + body_left = 0; + chunk_left = 0; + chunk_trailer_part = false; + read_until_eof = false; + response_str.clear(); + response_headers.clear(); + response_num = RESPONSE_OK; + + // Per the HTTP 1.1 spec, keep-alive is the default. + // Not following that specification breaks standard implementations. + // Broken web servers should be fixed. + bool keep_alive = true; + + for (int i = 0; i < responses.size(); i++) { + String header = responses[i].strip_edges(); + String s = header.to_lower(); + if (s.length() == 0) { + continue; + } + if (s.begins_with("content-length:")) { + body_size = s.substr(s.find(":") + 1, s.length()).strip_edges().to_int(); + body_left = body_size; + + } else if (s.begins_with("transfer-encoding:")) { + String encoding = header.substr(header.find(":") + 1, header.length()).strip_edges(); + if (encoding == "chunked") { + chunked = true; + } + } else if (s.begins_with("connection: close")) { + keep_alive = false; + } + + if (i == 0 && responses[i].begins_with("HTTP")) { + String num = responses[i].get_slicec(' ', 1); + response_num = num.to_int(); + } else { + response_headers.push_back(header); + } + } + + // This is a HEAD request, we won't receive anything. + if (head_request) { + body_size = 0; + body_left = 0; + } + + if (body_size != -1 || chunked) { + status = STATUS_BODY; + } else if (!keep_alive) { + read_until_eof = true; + status = STATUS_BODY; + } else { + status = STATUS_CONNECTED; + } + return OK; + } + } + } break; + case STATUS_DISCONNECTED: { + return ERR_UNCONFIGURED; + } break; + case STATUS_CONNECTION_ERROR: + case STATUS_SSL_HANDSHAKE_ERROR: { + return ERR_CONNECTION_ERROR; + } break; + case STATUS_CANT_CONNECT: { + return ERR_CANT_CONNECT; + } break; + case STATUS_CANT_RESOLVE: { + return ERR_CANT_RESOLVE; + } break; + } + + return OK; +} + +int HTTPClientTCP::get_response_body_length() const { + return body_size; +} + +PackedByteArray HTTPClientTCP::read_response_body_chunk() { + ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray()); + + PackedByteArray ret; + Error err = OK; + + if (chunked) { + while (true) { + if (chunk_trailer_part) { + // We need to consume the trailer part too or keep-alive will break + uint8_t b; + int rec = 0; + err = _get_http_data(&b, 1, rec); + + if (rec == 0) { + break; + } + + chunk.push_back(b); + int cs = chunk.size(); + if ((cs >= 2 && chunk[cs - 2] == '\r' && chunk[cs - 1] == '\n')) { + if (cs == 2) { + // Finally over + chunk_trailer_part = false; + status = STATUS_CONNECTED; + chunk.clear(); + break; + } else { + // We do not process nor return the trailer data + chunk.clear(); + } + } + } else if (chunk_left == 0) { + // Reading length + uint8_t b; + int rec = 0; + err = _get_http_data(&b, 1, rec); + + if (rec == 0) { + break; + } + + chunk.push_back(b); + + if (chunk.size() > 32) { + ERR_PRINT("HTTP Invalid chunk hex len"); + status = STATUS_CONNECTION_ERROR; + break; + } + + if (chunk.size() > 2 && chunk[chunk.size() - 2] == '\r' && chunk[chunk.size() - 1] == '\n') { + int len = 0; + for (int i = 0; i < chunk.size() - 2; i++) { + char c = chunk[i]; + int v = 0; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (c >= 'a' && c <= 'f') { + v = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + v = c - 'A' + 10; + } else { + ERR_PRINT("HTTP Chunk len not in hex!!"); + status = STATUS_CONNECTION_ERROR; + break; + } + len <<= 4; + len |= v; + if (len > (1 << 24)) { + ERR_PRINT("HTTP Chunk too big!! >16mb"); + status = STATUS_CONNECTION_ERROR; + break; + } + } + + if (len == 0) { + // End reached! + chunk_trailer_part = true; + chunk.clear(); + break; + } + + chunk_left = len + 2; + chunk.resize(chunk_left); + } + } else { + int rec = 0; + err = _get_http_data(&chunk.write[chunk.size() - chunk_left], chunk_left, rec); + if (rec == 0) { + break; + } + chunk_left -= rec; + + if (chunk_left == 0) { + if (chunk[chunk.size() - 2] != '\r' || chunk[chunk.size() - 1] != '\n') { + ERR_PRINT("HTTP Invalid chunk terminator (not \\r\\n)"); + status = STATUS_CONNECTION_ERROR; + break; + } + + ret.resize(chunk.size() - 2); + uint8_t *w = ret.ptrw(); + memcpy(w, chunk.ptr(), chunk.size() - 2); + chunk.clear(); + } + + break; + } + } + + } else { + int to_read = !read_until_eof ? MIN(body_left, read_chunk_size) : read_chunk_size; + ret.resize(to_read); + int _offset = 0; + while (to_read > 0) { + int rec = 0; + { + uint8_t *w = ret.ptrw(); + err = _get_http_data(w + _offset, to_read, rec); + } + if (rec <= 0) { // Ended up reading less + ret.resize(_offset); + break; + } else { + _offset += rec; + to_read -= rec; + if (!read_until_eof) { + body_left -= rec; + } + } + if (err != OK) { + ret.resize(_offset); + break; + } + } + } + + if (err != OK) { + close(); + + if (err == ERR_FILE_EOF) { + status = STATUS_DISCONNECTED; // Server disconnected + } else { + status = STATUS_CONNECTION_ERROR; + } + } else if (body_left == 0 && !chunked && !read_until_eof) { + status = STATUS_CONNECTED; + } + + return ret; +} + +HTTPClientTCP::Status HTTPClientTCP::get_status() const { + return status; +} + +void HTTPClientTCP::set_blocking_mode(bool p_enable) { + blocking = p_enable; +} + +bool HTTPClientTCP::is_blocking_mode_enabled() const { + return blocking; +} + +Error HTTPClientTCP::_get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received) { + if (blocking) { + // We can't use StreamPeer.get_data, since when reaching EOF we will get an + // error without knowing how many bytes we received. + Error err = ERR_FILE_EOF; + int read = 0; + int left = p_bytes; + r_received = 0; + while (left > 0) { + err = connection->get_partial_data(p_buffer + r_received, left, read); + if (err == OK) { + r_received += read; + } else if (err == ERR_FILE_EOF) { + r_received += read; + return err; + } else { + return err; + } + left -= read; + } + return err; + } else { + return connection->get_partial_data(p_buffer, p_bytes, r_received); + } +} + +void HTTPClientTCP::set_read_chunk_size(int p_size) { + ERR_FAIL_COND(p_size < 256 || p_size > (1 << 24)); + read_chunk_size = p_size; +} + +int HTTPClientTCP::get_read_chunk_size() const { + return read_chunk_size; +} + +HTTPClientTCP::HTTPClientTCP() { + tcp_connection.instantiate(); +} + +HTTPClient *(*HTTPClient::_create)() = HTTPClientTCP::_create_func; + +#endif // #ifndef JAVASCRIPT_ENABLED diff --git a/core/io/http_client_tcp.h b/core/io/http_client_tcp.h new file mode 100644 index 0000000000..e178399fbe --- /dev/null +++ b/core/io/http_client_tcp.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* http_client_tcp.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef HTTP_CLIENT_TCP_H +#define HTTP_CLIENT_TCP_H + +#include "http_client.h" + +class HTTPClientTCP : public HTTPClient { +private: + Status status = STATUS_DISCONNECTED; + IP::ResolverID resolving = IP::RESOLVER_INVALID_ID; + int conn_port = -1; + String conn_host; + bool ssl = false; + bool ssl_verify_host = false; + bool blocking = false; + bool handshaking = false; + bool head_request = false; + + Vector<uint8_t> response_str; + + bool chunked = false; + Vector<uint8_t> chunk; + int chunk_left = 0; + bool chunk_trailer_part = false; + int body_size = -1; + int body_left = 0; + bool read_until_eof = false; + + Ref<StreamPeerTCP> tcp_connection; + Ref<StreamPeer> connection; + + int response_num = 0; + Vector<String> response_headers; + // 64 KiB by default (favors fast download speeds at the cost of memory usage). + int read_chunk_size = 65536; + + Error _get_http_data(uint8_t *p_buffer, int p_bytes, int &r_received); + +public: + static HTTPClient *_create_func(); + + Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override; + + Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) override; + void set_connection(const Ref<StreamPeer> &p_connection) override; + Ref<StreamPeer> get_connection() const override; + void close() override; + Status get_status() const override; + bool has_response() const override; + bool is_response_chunked() const override; + int get_response_code() const override; + Error get_response_headers(List<String> *r_response) override; + int get_response_body_length() const override; + PackedByteArray read_response_body_chunk() override; + void set_blocking_mode(bool p_enable) override; + bool is_blocking_mode_enabled() const override; + void set_read_chunk_size(int p_size) override; + int get_read_chunk_size() const override; + Error poll() override; + HTTPClientTCP(); +}; + +#endif // HTTP_CLIENT_TCP_H diff --git a/core/io/image.cpp b/core/io/image.cpp index c36fa6e45f..3112dd217f 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -1428,16 +1428,23 @@ void Image::flip_x() { } } +/// Get mipmap size and offset. int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps, int *r_mm_width, int *r_mm_height) { + // Data offset in mipmaps (including the original texture). int size = 0; + int w = p_width; int h = p_height; + + // Current mipmap index in the loop below. p_mipmaps is the target mipmap index. + // In this function, mipmap 0 represents the first mipmap instead of the original texture. int mm = 0; int pixsize = get_format_pixel_size(p_format); int pixshift = get_format_pixel_rshift(p_format); int block = get_format_block_size(p_format); - //technically, you can still compress up to 1 px no matter the format, so commenting this + + // Technically, you can still compress up to 1 px no matter the format, so commenting this. //int minw, minh; //get_format_min_pixel_size(p_format, minw, minh); int minw = 1, minh = 1; @@ -1453,17 +1460,6 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & size += s; - if (r_mm_width) { - *r_mm_width = bw; - } - if (r_mm_height) { - *r_mm_height = bh; - } - - if (p_mipmaps >= 0 && mm == p_mipmaps) { - break; - } - if (p_mipmaps >= 0) { w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); @@ -1474,6 +1470,21 @@ int Image::_get_dst_image_size(int p_width, int p_height, Format p_format, int & w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); } + + // Set mipmap size. + // It might be necessary to put this after the minimum mipmap size check because of the possible occurrence of "1 >> 1". + if (r_mm_width) { + *r_mm_width = bw >> 1; + } + if (r_mm_height) { + *r_mm_height = bh >> 1; + } + + // Reach target mipmap. + if (p_mipmaps >= 0 && mm == p_mipmaps) { + break; + } + mm++; } @@ -1934,7 +1945,7 @@ Error Image::generate_mipmap_roughness(RoughnessChannel p_roughness_channel, con memcpy(wr.ptr(), ptr, size); wr = uint8_t*(); Ref<Image> im; - im.instance(); + im.instantiate(); im->create(w, h, false, format, imgdata); im->save_png("res://mipmap_" + itos(i) + ".png"); } @@ -1974,6 +1985,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); + ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "Image format out of range, please see Image's Format enum."); int mm = 0; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -1996,6 +2008,7 @@ void Image::create(int p_width, int p_height, bool p_use_mipmaps, Format p_forma ERR_FAIL_COND_MSG(p_width > MAX_WIDTH, "Image width cannot be greater than " + itos(MAX_WIDTH) + "."); ERR_FAIL_COND_MSG(p_height > MAX_HEIGHT, "Image height cannot be greater than " + itos(MAX_HEIGHT) + "."); ERR_FAIL_COND_MSG(p_width * p_height > MAX_PIXELS, "Too many pixels for image, maximum is " + itos(MAX_PIXELS)); + ERR_FAIL_INDEX_MSG(p_format, FORMAT_MAX, "Image format out of range, please see Image's Format enum."); int mm; int size = _get_dst_image_size(p_width, p_height, p_format, mm, p_use_mipmaps ? -1 : 0); @@ -2367,6 +2380,8 @@ Error Image::decompress() { } Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) { + ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode."); + ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source."); return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality); } @@ -2392,6 +2407,9 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE); _image_compress_bptc_func(this, p_lossy_quality, p_channels); } break; + case COMPRESS_MAX: { + ERR_FAIL_V(ERR_INVALID_PARAMETER); + } break; } return OK; @@ -2718,10 +2736,11 @@ void (*Image::_image_decompress_bptc)(Image *) = nullptr; void (*Image::_image_decompress_etc1)(Image *) = nullptr; void (*Image::_image_decompress_etc2)(Image *) = nullptr; -Vector<uint8_t> (*Image::lossy_packer)(const Ref<Image> &, float) = nullptr; -Ref<Image> (*Image::lossy_unpacker)(const Vector<uint8_t> &) = nullptr; -Vector<uint8_t> (*Image::lossless_packer)(const Ref<Image> &) = nullptr; -Ref<Image> (*Image::lossless_unpacker)(const Vector<uint8_t> &) = nullptr; +Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr; +Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr; +Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr; +Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr; +Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr; Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr; Ref<Image> (*Image::basis_universal_unpacker)(const Vector<uint8_t> &) = nullptr; @@ -2985,6 +3004,8 @@ void Image::set_pixel(int p_x, int p_y, const Color &p_color) { } void Image::adjust_bcs(float p_brightness, float p_contrast, float p_saturation) { + ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot adjust_bcs in compressed or custom image formats."); + uint8_t *w = data.ptrw(); uint32_t pixel_size = get_format_pixel_size(format); uint32_t pixel_count = data.size() / pixel_size; @@ -3268,7 +3289,7 @@ Ref<Image> Image::rgbe_to_srgb() { ERR_FAIL_COND_V(format != FORMAT_RGBE9995, Ref<Image>()); Ref<Image> new_image; - new_image.instance(); + new_image.instantiate(); new_image->create(width, height, false, Image::FORMAT_RGB8); for (int row = 0; row < height; row++) { @@ -3298,7 +3319,7 @@ Ref<Image> Image::get_image_from_mipmap(int p_mipamp) const { } Ref<Image> image; - image.instance(); + image.instantiate(); image->width = w; image->height = h; image->format = format; @@ -3615,7 +3636,7 @@ Image::Image(const uint8_t *p_mem_png_jpg, int p_len) { Ref<Resource> Image::duplicate(bool p_subresources) const { Ref<Image> copy; - copy.instance(); + copy.instantiate(); copy->_copy_internals_from(*this); return copy; } diff --git a/core/io/image.h b/core/io/image.h index df8f9b35a1..8f1b251ac3 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -148,10 +148,11 @@ public: static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc2)(Image *); - static Vector<uint8_t> (*lossy_packer)(const Ref<Image> &p_image, float p_quality); - static Ref<Image> (*lossy_unpacker)(const Vector<uint8_t> &p_buffer); - static Vector<uint8_t> (*lossless_packer)(const Ref<Image> &p_image); - static Ref<Image> (*lossless_unpacker)(const Vector<uint8_t> &p_buffer); + static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality); + static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image); + static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer); + static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image); + static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer); static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels); static Ref<Image> (*basis_universal_unpacker)(const Vector<uint8_t> &p_buffer); @@ -335,11 +336,13 @@ public: COMPRESS_ETC, COMPRESS_ETC2, COMPRESS_BPTC, + COMPRESS_MAX, }; enum CompressSource { COMPRESS_SOURCE_GENERIC, COMPRESS_SOURCE_SRGB, - COMPRESS_SOURCE_NORMAL + COMPRESS_SOURCE_NORMAL, + COMPRESS_SOURCE_MAX, }; Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7); diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp index 7de038e6fe..b45e9d26b1 100644 --- a/core/io/image_loader.cpp +++ b/core/io/image_loader.cpp @@ -163,7 +163,7 @@ RES ResourceFormatLoaderImage::load(const String &p_path, const String &p_origin } Ref<Image> image; - image.instance(); + image.instantiate(); Error err = ImageLoader::loader[idx]->load_image(image, f, false, 1.0); diff --git a/core/io/image_loader.h b/core/io/image_loader.h index a5d588e0b5..6d1b1e3646 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -31,9 +31,9 @@ #ifndef IMAGE_LOADER_H #define IMAGE_LOADER_H +#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/string/ustring.h" #include "core/templates/list.h" diff --git a/core/io/json.cpp b/core/io/json.cpp index 394cf216e8..b3a2498212 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -45,7 +45,7 @@ const char *JSON::tk_name[TK_MAX] = { "EOF", }; -static String _make_indent(const String &p_indent, int p_size) { +String JSON::_make_indent(const String &p_indent, int p_size) { String indent_text = ""; if (!p_indent.is_empty()) { for (int i = 0; i < p_size; i++) { @@ -55,7 +55,7 @@ static String _make_indent(const String &p_indent, int p_size) { return indent_text; } -String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys) { +String JSON::_stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision) { String colon = ":"; String end_statement = ""; @@ -71,8 +71,17 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ return p_var.operator bool() ? "true" : "false"; case Variant::INT: return itos(p_var); - case Variant::FLOAT: - return rtos(p_var); + case Variant::FLOAT: { + double num = p_var; + if (p_full_precision) { + // Store unreliable digits (17) instead of just reliable + // digits (14) so that the value can be decoded exactly. + return String::num(num, 17 - (int)floor(log10(num))); + } else { + // Store only reliable digits (14) by default. + return String::num(num, 14 - (int)floor(log10(num))); + } + } case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: case Variant::PACKED_FLOAT32_ARRAY: @@ -82,20 +91,29 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ String s = "["; s += end_statement; Array a = p_var; + + ERR_FAIL_COND_V_MSG(p_markers.has(a.id()), "\"[...]\"", "Converting circular structure to JSON."); + p_markers.insert(a.id()); + for (int i = 0; i < a.size(); i++) { if (i > 0) { s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(a[i], p_indent, p_cur_indent + 1, p_sort_keys); + s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(a[i], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "]"; + p_markers.erase(a.id()); return s; } case Variant::DICTIONARY: { String s = "{"; s += end_statement; Dictionary d = p_var; + + ERR_FAIL_COND_V_MSG(p_markers.has(d.id()), "\"{...}\"", "Converting circular structure to JSON."); + p_markers.insert(d.id()); + List<Variant> keys; d.get_key_list(&keys); @@ -108,12 +126,13 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ s += ","; s += end_statement; } - s += _make_indent(p_indent, p_cur_indent + 1) + _print_var(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys); + s += _make_indent(p_indent, p_cur_indent + 1) + _stringify(String(E->get()), p_indent, p_cur_indent + 1, p_sort_keys, p_markers); s += colon; - s += _print_var(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys); + s += _stringify(d[E->get()], p_indent, p_cur_indent + 1, p_sort_keys, p_markers); } s += end_statement + _make_indent(p_indent, p_cur_indent) + "}"; + p_markers.erase(d.id()); return s; } default: @@ -121,10 +140,6 @@ String JSON::_print_var(const Variant &p_var, const String &p_indent, int p_cur_ } } -String JSON::print(const Variant &p_var, const String &p_indent, bool p_sort_keys) { - return _print_var(p_var, p_indent, 0, p_sort_keys); -} - Error JSON::_get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str) { while (p_len > 0) { switch (p_str[index]) { @@ -479,7 +494,7 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, return ERR_PARSE_ERROR; } -Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { +Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { const char32_t *str = p_json.ptr(); int idx = 0; int len = p_json.length(); @@ -510,34 +525,24 @@ Error JSON::parse(const String &p_json, Variant &r_ret, String &r_err_str, int & return err; } -Error JSONParser::parse_string(const String &p_json_string) { - return JSON::parse(p_json_string, data, err_text, err_line); -} -String JSONParser::get_error_text() const { - return err_text; -} -int JSONParser::get_error_line() const { - return err_line; -} -Variant JSONParser::get_data() const { - return data; +String JSON::stringify(const Variant &p_var, const String &p_indent, bool p_sort_keys, bool p_full_precision) { + Set<const void *> markers; + return _stringify(p_var, p_indent, 0, p_sort_keys, markers, p_full_precision); } -Error JSONParser::decode_data(const Variant &p_data, const String &p_indent, bool p_sort_keys) { - string = JSON::print(p_data, p_indent, p_sort_keys); - data = p_data; - return OK; +Error JSON::parse(const String &p_json_string) { + Error err = _parse_string(p_json_string, data, err_str, err_line); + if (err == Error::OK) { + err_line = 0; + } + return err; } -String JSONParser::get_string() const { - return string; -} +void JSON::_bind_methods() { + ClassDB::bind_method(D_METHOD("stringify", "data", "indent", "sort_keys", "full_precision"), &JSON::stringify, DEFVAL(""), DEFVAL(true), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); -void JSONParser::_bind_methods() { - ClassDB::bind_method(D_METHOD("parse_string", "json_string"), &JSONParser::parse_string); - ClassDB::bind_method(D_METHOD("get_error_text"), &JSONParser::get_error_text); - ClassDB::bind_method(D_METHOD("get_error_line"), &JSONParser::get_error_line); - ClassDB::bind_method(D_METHOD("get_data"), &JSONParser::get_data); - ClassDB::bind_method(D_METHOD("decode_data", "data", "indent", "sort_keys"), &JSONParser::decode_data, DEFVAL(""), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_string"), &JSONParser::get_string); + ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data); + ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line); + ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message); } diff --git a/core/io/json.h b/core/io/json.h index 537477666e..f20c97f540 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -31,9 +31,12 @@ #ifndef JSON_H #define JSON_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/variant/variant.h" -class JSON { + +class JSON : public RefCounted { + GDCLASS(JSON, RefCounted); + enum TokenType { TK_CURLY_BRACKET_OPEN, TK_CURLY_BRACKET_CLOSE, @@ -60,39 +63,30 @@ class JSON { Variant value; }; - static const char *tk_name[TK_MAX]; + Variant data; + String err_str; + int err_line = 0; - static String _print_var(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys); + static const char *tk_name[]; + static String _make_indent(const String &p_indent, int p_size); + static String _stringify(const Variant &p_var, const String &p_indent, int p_cur_indent, bool p_sort_keys, Set<const void *> &p_markers, bool p_full_precision = false); static Error _get_token(const char32_t *p_str, int &index, int p_len, Token &r_token, int &line, String &r_err_str); static Error _parse_value(Variant &value, Token &token, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); static Error _parse_array(Array &array, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); static Error _parse_object(Dictionary &object, const char32_t *p_str, int &index, int p_len, int &line, String &r_err_str); - -public: - static String print(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true); - static Error parse(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); -}; - -class JSONParser : public Reference { - GDCLASS(JSONParser, Reference); - - Variant data; - String string; - String err_text; - int err_line = 0; + static Error _parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line); protected: static void _bind_methods(); public: - Error parse_string(const String &p_json_string); - String get_error_text() const; - int get_error_line() const; - Variant get_data() const; + String stringify(const Variant &p_var, const String &p_indent = "", bool p_sort_keys = true, bool p_full_precision = false); + Error parse(const String &p_json_string); - Error decode_data(const Variant &p_data, const String &p_indent = "", bool p_sort_keys = true); - String get_string() const; + inline Variant get_data() const { return data; } + inline int get_error_line() const { return err_line; } + inline String get_error_message() const { return err_str; } }; #endif // JSON_H diff --git a/core/io/logger.cpp b/core/io/logger.cpp index 8a07459a1d..09539f716c 100644 --- a/core/io/logger.cpp +++ b/core/io/logger.cpp @@ -31,8 +31,9 @@ #include "logger.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/string/print_string.h" #if defined(MINGW_ENABLED) || defined(_MSC_VER) @@ -156,11 +157,7 @@ void RotatedFileLogger::rotate_file() { if (FileAccess::exists(base_path)) { if (max_files > 1) { - char timestamp[21]; - OS::Date date = OS::get_singleton()->get_date(); - OS::Time time = OS::get_singleton()->get_time(); - sprintf(timestamp, "_%04d-%02d-%02d_%02d.%02d.%02d", date.year, date.month, date.day, time.hour, time.min, time.sec); - + String timestamp = Time::get_singleton()->get_datetime_string_from_system().replace(":", "."); String backup_name = base_path.get_basename() + timestamp; if (base_path.get_extension() != String()) { backup_name += "." + base_path.get_extension(); diff --git a/core/io/logger.h b/core/io/logger.h index a12945911c..ccf68562d6 100644 --- a/core/io/logger.h +++ b/core/io/logger.h @@ -31,7 +31,7 @@ #ifndef LOGGER_H #define LOGGER_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/ustring.h" #include "core/templates/vector.h" diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index 0282609270..f342db2dad 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -30,7 +30,7 @@ #include "marshalls.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" @@ -111,6 +111,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int *r_len = 4; } + // Note: We cannot use sizeof(real_t) for decoding, in case a different size is encoded. + // Decoding math types always checks for the encoded size, while encoding always uses compilation setting. + // This does lead to some code duplication for decoding, but compatibility is the priority. switch (type & ENCODE_MASK) { case Variant::NIL: { r_variant = Variant(); @@ -144,18 +147,18 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::FLOAT: { if (type & ENCODE_FLAG_64) { - ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); + ERR_FAIL_COND_V((size_t)len < sizeof(double), ERR_INVALID_DATA); double val = decode_double(buf); r_variant = val; if (r_len) { - (*r_len) += 8; + (*r_len) += sizeof(double); } } else { - ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); + ERR_FAIL_COND_V((size_t)len < sizeof(float), ERR_INVALID_DATA); float val = decode_float(buf); r_variant = val; if (r_len) { - (*r_len) += 4; + (*r_len) += sizeof(float); } } @@ -172,15 +175,25 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int // math types case Variant::VECTOR2: { - ERR_FAIL_COND_V(len < 4 * 2, ERR_INVALID_DATA); Vector2 val; - val.x = decode_float(&buf[0]); - val.y = decode_float(&buf[4]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 2, ERR_INVALID_DATA); + val.x = decode_double(&buf[0]); + val.y = decode_double(&buf[sizeof(double)]); - if (r_len) { - (*r_len) += 4 * 2; + if (r_len) { + (*r_len) += sizeof(double) * 2; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 2, ERR_INVALID_DATA); + val.x = decode_float(&buf[0]); + val.y = decode_float(&buf[sizeof(float)]); + + if (r_len) { + (*r_len) += sizeof(float) * 2; + } } + r_variant = val; } break; case Variant::VECTOR2I: { @@ -196,17 +209,29 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::RECT2: { - ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); Rect2 val; - val.position.x = decode_float(&buf[0]); - val.position.y = decode_float(&buf[4]); - val.size.x = decode_float(&buf[8]); - val.size.y = decode_float(&buf[12]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); + val.position.x = decode_double(&buf[0]); + val.position.y = decode_double(&buf[sizeof(double)]); + val.size.x = decode_double(&buf[sizeof(double) * 2]); + val.size.y = decode_double(&buf[sizeof(double) * 3]); - if (r_len) { - (*r_len) += 4 * 4; + if (r_len) { + (*r_len) += sizeof(double) * 4; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 4, ERR_INVALID_DATA); + val.position.x = decode_float(&buf[0]); + val.position.y = decode_float(&buf[sizeof(float)]); + val.size.x = decode_float(&buf[sizeof(float) * 2]); + val.size.y = decode_float(&buf[sizeof(float) * 3]); + + if (r_len) { + (*r_len) += sizeof(float) * 4; + } } + r_variant = val; } break; case Variant::RECT2I: { @@ -224,16 +249,27 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::VECTOR3: { - ERR_FAIL_COND_V(len < 4 * 3, ERR_INVALID_DATA); Vector3 val; - val.x = decode_float(&buf[0]); - val.y = decode_float(&buf[4]); - val.z = decode_float(&buf[8]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 3, ERR_INVALID_DATA); + val.x = decode_double(&buf[0]); + val.y = decode_double(&buf[sizeof(double)]); + val.z = decode_double(&buf[sizeof(double) * 2]); - if (r_len) { - (*r_len) += 4 * 3; + if (r_len) { + (*r_len) += sizeof(double) * 3; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 3, ERR_INVALID_DATA); + val.x = decode_float(&buf[0]); + val.y = decode_float(&buf[sizeof(float)]); + val.z = decode_float(&buf[sizeof(float) * 2]); + + if (r_len) { + (*r_len) += sizeof(float) * 3; + } } + r_variant = val; } break; case Variant::VECTOR3I: { @@ -250,101 +286,177 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::TRANSFORM2D: { - ERR_FAIL_COND_V(len < 4 * 6, ERR_INVALID_DATA); Transform2D val; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 2; j++) { - val.elements[i][j] = decode_float(&buf[(i * 2 + j) * 4]); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + val.elements[i][j] = decode_double(&buf[(i * 2 + j) * sizeof(double)]); + } } - } - r_variant = val; + if (r_len) { + (*r_len) += sizeof(double) * 6; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 6, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 2; j++) { + val.elements[i][j] = decode_float(&buf[(i * 2 + j) * sizeof(float)]); + } + } - if (r_len) { - (*r_len) += 4 * 6; + if (r_len) { + (*r_len) += sizeof(float) * 6; + } } + r_variant = val; } break; case Variant::PLANE: { - ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); Plane val; - val.normal.x = decode_float(&buf[0]); - val.normal.y = decode_float(&buf[4]); - val.normal.z = decode_float(&buf[8]); - val.d = decode_float(&buf[12]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); + val.normal.x = decode_double(&buf[0]); + val.normal.y = decode_double(&buf[sizeof(double)]); + val.normal.z = decode_double(&buf[sizeof(double) * 2]); + val.d = decode_double(&buf[sizeof(double) * 3]); - if (r_len) { - (*r_len) += 4 * 4; + if (r_len) { + (*r_len) += sizeof(double) * 4; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 4, ERR_INVALID_DATA); + val.normal.x = decode_float(&buf[0]); + val.normal.y = decode_float(&buf[sizeof(float)]); + val.normal.z = decode_float(&buf[sizeof(float) * 2]); + val.d = decode_float(&buf[sizeof(float) * 3]); + + if (r_len) { + (*r_len) += sizeof(float) * 4; + } } + r_variant = val; } break; - case Variant::QUAT: { - ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); - Quat val; - val.x = decode_float(&buf[0]); - val.y = decode_float(&buf[4]); - val.z = decode_float(&buf[8]); - val.w = decode_float(&buf[12]); - r_variant = val; + case Variant::QUATERNION: { + Quaternion val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); + val.x = decode_double(&buf[0]); + val.y = decode_double(&buf[sizeof(double)]); + val.z = decode_double(&buf[sizeof(double) * 2]); + val.w = decode_double(&buf[sizeof(double) * 3]); - if (r_len) { - (*r_len) += 4 * 4; + if (r_len) { + (*r_len) += sizeof(double) * 4; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 4, ERR_INVALID_DATA); + val.x = decode_float(&buf[0]); + val.y = decode_float(&buf[sizeof(float)]); + val.z = decode_float(&buf[sizeof(float) * 2]); + val.w = decode_float(&buf[sizeof(float) * 3]); + + if (r_len) { + (*r_len) += sizeof(float) * 4; + } } + r_variant = val; } break; case Variant::AABB: { - ERR_FAIL_COND_V(len < 4 * 6, ERR_INVALID_DATA); AABB val; - val.position.x = decode_float(&buf[0]); - val.position.y = decode_float(&buf[4]); - val.position.z = decode_float(&buf[8]); - val.size.x = decode_float(&buf[12]); - val.size.y = decode_float(&buf[16]); - val.size.z = decode_float(&buf[20]); - r_variant = val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); + val.position.x = decode_double(&buf[0]); + val.position.y = decode_double(&buf[sizeof(double)]); + val.position.z = decode_double(&buf[sizeof(double) * 2]); + val.size.x = decode_double(&buf[sizeof(double) * 3]); + val.size.y = decode_double(&buf[sizeof(double) * 4]); + val.size.z = decode_double(&buf[sizeof(double) * 5]); - if (r_len) { - (*r_len) += 4 * 6; + if (r_len) { + (*r_len) += sizeof(double) * 6; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 6, ERR_INVALID_DATA); + val.position.x = decode_float(&buf[0]); + val.position.y = decode_float(&buf[sizeof(float)]); + val.position.z = decode_float(&buf[sizeof(float) * 2]); + val.size.x = decode_float(&buf[sizeof(float) * 3]); + val.size.y = decode_float(&buf[sizeof(float) * 4]); + val.size.z = decode_float(&buf[sizeof(float) * 5]); + + if (r_len) { + (*r_len) += sizeof(float) * 6; + } } + r_variant = val; } break; case Variant::BASIS: { - ERR_FAIL_COND_V(len < 4 * 9, ERR_INVALID_DATA); Basis val; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - val.elements[i][j] = decode_float(&buf[(i * 3 + j) * 4]); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 9, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.elements[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]); + } } - } - r_variant = val; + if (r_len) { + (*r_len) += sizeof(double) * 9; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 9, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.elements[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]); + } + } - if (r_len) { - (*r_len) += 4 * 9; + if (r_len) { + (*r_len) += sizeof(float) * 9; + } } + r_variant = val; } break; - case Variant::TRANSFORM: { - ERR_FAIL_COND_V(len < 4 * 12, ERR_INVALID_DATA); - Transform val; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * 4]); + case Variant::TRANSFORM3D: { + Transform3D val; + if (type & ENCODE_FLAG_64) { + ERR_FAIL_COND_V((size_t)len < sizeof(double) * 12, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.basis.elements[i][j] = decode_double(&buf[(i * 3 + j) * sizeof(double)]); + } } - } - val.origin[0] = decode_float(&buf[36]); - val.origin[1] = decode_float(&buf[40]); - val.origin[2] = decode_float(&buf[44]); + val.origin[0] = decode_double(&buf[sizeof(double) * 9]); + val.origin[1] = decode_double(&buf[sizeof(double) * 10]); + val.origin[2] = decode_double(&buf[sizeof(double) * 11]); - r_variant = val; + if (r_len) { + (*r_len) += sizeof(double) * 12; + } + } else { + ERR_FAIL_COND_V((size_t)len < sizeof(float) * 12, ERR_INVALID_DATA); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + val.basis.elements[i][j] = decode_float(&buf[(i * 3 + j) * sizeof(float)]); + } + } + val.origin[0] = decode_float(&buf[sizeof(float) * 9]); + val.origin[1] = decode_float(&buf[sizeof(float) * 10]); + val.origin[2] = decode_float(&buf[sizeof(float) * 11]); - if (r_len) { - (*r_len) += 4 * 12; + if (r_len) { + (*r_len) += sizeof(float) * 12; + } } + r_variant = val; } break; - // misc types case Variant::COLOR: { ERR_FAIL_COND_V(len < 4 * 4, ERR_INVALID_DATA); @@ -356,9 +468,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = val; if (r_len) { - (*r_len) += 4 * 4; + (*r_len) += 4 * 4; // Colors should always be in single-precision. } - } break; case Variant::STRING_NAME: { String str; @@ -436,7 +547,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = (Object *)nullptr; } else { Ref<EncodedObjectAsID> obj_as_id; - obj_as_id.instance(); + obj_as_id.instantiate(); obj_as_id->set_object_id(val); r_variant = obj_as_id; @@ -454,7 +565,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int if (str == String()) { r_variant = (Object *)nullptr; } else { - Object *obj = ClassDB::instance(str); + Object *obj = ClassDB::instantiate(str); ERR_FAIL_COND_V(!obj, ERR_UNAVAILABLE); ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); @@ -463,7 +574,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int buf += 4; len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } for (int i = 0; i < count; i++) { @@ -489,8 +600,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int obj->set(str, value); } - if (Object::cast_to<Reference>(obj)) { - REF ref = REF(Object::cast_to<Reference>(obj)); + if (Object::cast_to<RefCounted>(obj)) { + REF ref = REF(Object::cast_to<RefCounted>(obj)); r_variant = ref; } else { r_variant = obj; @@ -516,7 +627,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } Dictionary d; @@ -559,7 +670,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } Array varr; @@ -716,9 +827,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int len -= 4; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } - //printf("string count: %i\n",count); for (int32_t i = 0; i < count; i++) { String str; @@ -739,30 +849,57 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int buf += 4; len -= 4; - ERR_FAIL_MUL_OF(count, 4 * 2, ERR_INVALID_DATA); - ERR_FAIL_COND_V(count < 0 || count * 4 * 2 > len, ERR_INVALID_DATA); Vector<Vector2> varray; - if (r_len) { - (*r_len) += 4; - } - - if (count) { - varray.resize(count); - Vector2 *w = varray.ptrw(); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_MUL_OF(count, sizeof(double) * 2, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 2 > (size_t)len, ERR_INVALID_DATA); - for (int32_t i = 0; i < count; i++) { - w[i].x = decode_float(buf + i * 4 * 2 + 4 * 0); - w[i].y = decode_float(buf + i * 4 * 2 + 4 * 1); + if (r_len) { + (*r_len) += 4; // Size of count number. } - int adv = 4 * 2 * count; + if (count) { + varray.resize(count); + Vector2 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_double(buf + i * sizeof(double) * 2 + sizeof(double) * 0); + w[i].y = decode_double(buf + i * sizeof(double) * 2 + sizeof(double) * 1); + } + + int adv = sizeof(double) * 2 * count; + + if (r_len) { + (*r_len) += adv; + } + len -= adv; + buf += adv; + } + } else { + ERR_FAIL_MUL_OF(count, sizeof(float) * 2, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(float) * 2 > (size_t)len, ERR_INVALID_DATA); if (r_len) { - (*r_len) += adv; + (*r_len) += 4; // Size of count number. } - } + if (count) { + varray.resize(count); + Vector2 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_float(buf + i * sizeof(float) * 2 + sizeof(float) * 0); + w[i].y = decode_float(buf + i * sizeof(float) * 2 + sizeof(float) * 1); + } + + int adv = sizeof(float) * 2 * count; + + if (r_len) { + (*r_len) += adv; + } + } + } r_variant = varray; } break; @@ -772,32 +909,61 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int buf += 4; len -= 4; - ERR_FAIL_MUL_OF(count, 4 * 3, ERR_INVALID_DATA); - ERR_FAIL_COND_V(count < 0 || count * 4 * 3 > len, ERR_INVALID_DATA); - Vector<Vector3> varray; - if (r_len) { - (*r_len) += 4; - } - - if (count) { - varray.resize(count); - Vector3 *w = varray.ptrw(); + if (type & ENCODE_FLAG_64) { + ERR_FAIL_MUL_OF(count, sizeof(double) * 3, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 3 > (size_t)len, ERR_INVALID_DATA); - for (int32_t i = 0; i < count; i++) { - w[i].x = decode_float(buf + i * 4 * 3 + 4 * 0); - w[i].y = decode_float(buf + i * 4 * 3 + 4 * 1); - w[i].z = decode_float(buf + i * 4 * 3 + 4 * 2); + if (r_len) { + (*r_len) += 4; // Size of count number. } - int adv = 4 * 3 * count; + if (count) { + varray.resize(count); + Vector3 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_double(buf + i * sizeof(double) * 3 + sizeof(double) * 0); + w[i].y = decode_double(buf + i * sizeof(double) * 3 + sizeof(double) * 1); + w[i].z = decode_double(buf + i * sizeof(double) * 3 + sizeof(double) * 2); + } + + int adv = sizeof(double) * 3 * count; + + if (r_len) { + (*r_len) += adv; + } + len -= adv; + buf += adv; + } + } else { + ERR_FAIL_MUL_OF(count, sizeof(float) * 3, ERR_INVALID_DATA); + ERR_FAIL_COND_V(count < 0 || count * sizeof(float) * 3 > (size_t)len, ERR_INVALID_DATA); if (r_len) { - (*r_len) += adv; + (*r_len) += 4; // Size of count number. } - } + if (count) { + varray.resize(count); + Vector3 *w = varray.ptrw(); + + for (int32_t i = 0; i < count; i++) { + w[i].x = decode_float(buf + i * sizeof(float) * 3 + sizeof(float) * 0); + w[i].y = decode_float(buf + i * sizeof(float) * 3 + sizeof(float) * 1); + w[i].z = decode_float(buf + i * sizeof(float) * 3 + sizeof(float) * 2); + } + + int adv = sizeof(float) * 3 * count; + + if (r_len) { + (*r_len) += adv; + } + len -= adv; + buf += adv; + } + } r_variant = varray; } break; @@ -813,7 +979,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Vector<Color> carray; if (r_len) { - (*r_len) += 4; + (*r_len) += 4; // Size of count number. } if (count) { @@ -821,6 +987,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Color *w = carray.ptrw(); for (int32_t i = 0; i < count; i++) { + // Colors should always be in single-precision. w[i].r = decode_float(buf + i * 4 * 4 + 4 * 0); w[i].g = decode_float(buf + i * 4 * 4 + 4 * 1); w[i].b = decode_float(buf + i * 4 * 4 + 4 * 2); @@ -882,14 +1049,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo double d = p_variant; float f = d; if (double(f) != d) { - flags |= ENCODE_FLAG_64; //always encode real as double + flags |= ENCODE_FLAG_64; } } break; case Variant::OBJECT: { // Test for potential wrong values sent by the debugger when it breaks. Object *obj = p_variant.get_validated_object(); if (!obj) { - // Object is invalid, send a nullptr instead. + // Object is invalid, send a nullptr instead. if (buf) { encode_uint32(Variant::NIL, buf); } @@ -1013,11 +1180,11 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::VECTOR2: { if (buf) { Vector2 v2 = p_variant; - encode_float(v2.x, &buf[0]); - encode_float(v2.y, &buf[4]); + encode_real(v2.x, &buf[0]); + encode_real(v2.y, &buf[sizeof(real_t)]); } - r_len += 2 * 4; + r_len += 2 * sizeof(real_t); } break; case Variant::VECTOR2I: { @@ -1033,12 +1200,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::RECT2: { if (buf) { Rect2 r2 = p_variant; - encode_float(r2.position.x, &buf[0]); - encode_float(r2.position.y, &buf[4]); - encode_float(r2.size.x, &buf[8]); - encode_float(r2.size.y, &buf[12]); + encode_real(r2.position.x, &buf[0]); + encode_real(r2.position.y, &buf[sizeof(real_t)]); + encode_real(r2.size.x, &buf[sizeof(real_t) * 2]); + encode_real(r2.size.y, &buf[sizeof(real_t) * 3]); } - r_len += 4 * 4; + r_len += 4 * sizeof(real_t); } break; case Variant::RECT2I: { @@ -1055,12 +1222,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::VECTOR3: { if (buf) { Vector3 v3 = p_variant; - encode_float(v3.x, &buf[0]); - encode_float(v3.y, &buf[4]); - encode_float(v3.z, &buf[8]); + encode_real(v3.x, &buf[0]); + encode_real(v3.y, &buf[sizeof(real_t)]); + encode_real(v3.z, &buf[sizeof(real_t) * 2]); } - r_len += 3 * 4; + r_len += 3 * sizeof(real_t); } break; case Variant::VECTOR3I: { @@ -1079,50 +1246,50 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo Transform2D val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { - memcpy(&buf[(i * 2 + j) * 4], &val.elements[i][j], sizeof(float)); + memcpy(&buf[(i * 2 + j) * sizeof(real_t)], &val.elements[i][j], sizeof(real_t)); } } } - r_len += 6 * 4; + r_len += 6 * sizeof(real_t); } break; case Variant::PLANE: { if (buf) { Plane p = p_variant; - encode_float(p.normal.x, &buf[0]); - encode_float(p.normal.y, &buf[4]); - encode_float(p.normal.z, &buf[8]); - encode_float(p.d, &buf[12]); + encode_real(p.normal.x, &buf[0]); + encode_real(p.normal.y, &buf[sizeof(real_t)]); + encode_real(p.normal.z, &buf[sizeof(real_t) * 2]); + encode_real(p.d, &buf[sizeof(real_t) * 3]); } - r_len += 4 * 4; + r_len += 4 * sizeof(real_t); } break; - case Variant::QUAT: { + case Variant::QUATERNION: { if (buf) { - Quat q = p_variant; - encode_float(q.x, &buf[0]); - encode_float(q.y, &buf[4]); - encode_float(q.z, &buf[8]); - encode_float(q.w, &buf[12]); + Quaternion q = p_variant; + encode_real(q.x, &buf[0]); + encode_real(q.y, &buf[sizeof(real_t)]); + encode_real(q.z, &buf[sizeof(real_t) * 2]); + encode_real(q.w, &buf[sizeof(real_t) * 3]); } - r_len += 4 * 4; + r_len += 4 * sizeof(real_t); } break; case Variant::AABB: { if (buf) { AABB aabb = p_variant; - encode_float(aabb.position.x, &buf[0]); - encode_float(aabb.position.y, &buf[4]); - encode_float(aabb.position.z, &buf[8]); - encode_float(aabb.size.x, &buf[12]); - encode_float(aabb.size.y, &buf[16]); - encode_float(aabb.size.z, &buf[20]); + encode_real(aabb.position.x, &buf[0]); + encode_real(aabb.position.y, &buf[sizeof(real_t)]); + encode_real(aabb.position.z, &buf[sizeof(real_t) * 2]); + encode_real(aabb.size.x, &buf[sizeof(real_t) * 3]); + encode_real(aabb.size.y, &buf[sizeof(real_t) * 4]); + encode_real(aabb.size.z, &buf[sizeof(real_t) * 5]); } - r_len += 6 * 4; + r_len += 6 * sizeof(real_t); } break; case Variant::BASIS: { @@ -1130,29 +1297,29 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo Basis val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - memcpy(&buf[(i * 3 + j) * 4], &val.elements[i][j], sizeof(float)); + memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.elements[i][j], sizeof(real_t)); } } } - r_len += 9 * 4; + r_len += 9 * sizeof(real_t); } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { if (buf) { - Transform val = p_variant; + Transform3D val = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - memcpy(&buf[(i * 3 + j) * 4], &val.basis.elements[i][j], sizeof(float)); + memcpy(&buf[(i * 3 + j) * sizeof(real_t)], &val.basis.elements[i][j], sizeof(real_t)); } } - encode_float(val.origin.x, &buf[36]); - encode_float(val.origin.y, &buf[40]); - encode_float(val.origin.z, &buf[44]); + encode_real(val.origin.x, &buf[sizeof(real_t) * 9]); + encode_real(val.origin.y, &buf[sizeof(real_t) * 10]); + encode_real(val.origin.z, &buf[sizeof(real_t) * 11]); } - r_len += 12 * 4; + r_len += 12 * sizeof(real_t); } break; @@ -1166,7 +1333,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo encode_float(c.a, &buf[12]); } - r_len += 4 * 4; + r_len += 4 * 4; // Colors should always be in single-precision. } break; case Variant::RID: { @@ -1441,13 +1608,13 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo for (int i = 0; i < len; i++) { Vector2 v = data.get(i); - encode_float(v.x, &buf[0]); - encode_float(v.y, &buf[4]); - buf += 4 * 2; + encode_real(v.x, &buf[0]); + encode_real(v.y, &buf[sizeof(real_t)]); + buf += sizeof(real_t) * 2; } } - r_len += 4 * 2 * len; + r_len += sizeof(real_t) * 2 * len; } break; case Variant::PACKED_VECTOR3_ARRAY: { @@ -1465,14 +1632,14 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo for (int i = 0; i < len; i++) { Vector3 v = data.get(i); - encode_float(v.x, &buf[0]); - encode_float(v.y, &buf[4]); - encode_float(v.z, &buf[8]); - buf += 4 * 3; + encode_real(v.x, &buf[0]); + encode_real(v.y, &buf[sizeof(real_t)]); + encode_real(v.z, &buf[sizeof(real_t) * 2]); + buf += sizeof(real_t) * 3; } } - r_len += 4 * 3 * len; + r_len += sizeof(real_t) * 3 * len; } break; case Variant::PACKED_COLOR_ARRAY: { @@ -1494,7 +1661,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo encode_float(c.g, &buf[4]); encode_float(c.b, &buf[8]); encode_float(c.a, &buf[12]); - buf += 4 * 4; + buf += 4 * 4; // Colors should always be in single-precision. } } diff --git a/core/io/marshalls.h b/core/io/marshalls.h index cc0e9ba301..3ebed914a3 100644 --- a/core/io/marshalls.h +++ b/core/io/marshalls.h @@ -31,10 +31,18 @@ #ifndef MARSHALLS_H #define MARSHALLS_H -#include "core/object/reference.h" +#include "core/math/math_defs.h" +#include "core/object/ref_counted.h" #include "core/typedefs.h" #include "core/variant/variant.h" +// uintr_t is only for pairing with real_t, and we only need it in here. +#ifdef REAL_T_IS_DOUBLE +typedef uint64_t uintr_t; +#else +typedef uint32_t uintr_t; +#endif + /** * Miscellaneous helpers for marshalling data types, and encoding * in an endian independent way @@ -50,6 +58,12 @@ union MarshallDouble { double d; ///< double }; +// Behaves like one of the above, depending on compilation setting. +union MarshallReal { + uintr_t i; + real_t r; +}; + static inline unsigned int encode_uint16(uint16_t p_uint, uint8_t *p_arr) { for (int i = 0; i < 2; i++) { *p_arr = p_uint & 0xFF; @@ -96,6 +110,24 @@ static inline unsigned int encode_double(double p_double, uint8_t *p_arr) { return sizeof(uint64_t); } +static inline unsigned int encode_uintr(uintr_t p_uint, uint8_t *p_arr) { + for (size_t i = 0; i < sizeof(uintr_t); i++) { + *p_arr = p_uint & 0xFF; + p_arr++; + p_uint >>= 8; + } + + return sizeof(uintr_t); +} + +static inline unsigned int encode_real(real_t p_real, uint8_t *p_arr) { + MarshallReal mr; + mr.r = p_real; + encode_uintr(mr.i, p_arr); + + return sizeof(uintr_t); +} + static inline int encode_cstring(const char *p_string, uint8_t *p_data) { int len = 0; @@ -165,8 +197,8 @@ static inline double decode_double(const uint8_t *p_arr) { return md.d; } -class EncodedObjectAsID : public Reference { - GDCLASS(EncodedObjectAsID, Reference); +class EncodedObjectAsID : public RefCounted { + GDCLASS(EncodedObjectAsID, RefCounted); ObjectID id; diff --git a/core/io/multiplayer_api.cpp b/core/io/multiplayer_api.cpp index fda4083804..564397c88c 100644 --- a/core/io/multiplayer_api.cpp +++ b/core/io/multiplayer_api.cpp @@ -44,6 +44,56 @@ #include "core/os/os.h" #endif +String _get_rpc_md5(const Node *p_node) { + String rpc_list; + const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + rpc_list += String(node_config[i].name); + } + if (p_node->get_script_instance()) { + const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + rpc_list += String(script_config[i].name); + } + } + return rpc_list.md5_text(); +} + +const MultiplayerAPI::RPCConfig _get_rpc_config(const Node *p_node, const StringName &p_method, uint16_t &r_id) { + const Vector<MultiplayerAPI::RPCConfig> node_config = p_node->get_node_rpc_methods(); + for (int i = 0; i < node_config.size(); i++) { + if (node_config[i].name == p_method) { + r_id = ((uint16_t)i) & (1 << 15); + return node_config[i]; + } + } + if (p_node->get_script_instance()) { + const Vector<MultiplayerAPI::RPCConfig> script_config = p_node->get_script_instance()->get_rpc_methods(); + for (int i = 0; i < script_config.size(); i++) { + if (script_config[i].name == p_method) { + r_id = (uint16_t)i; + return script_config[i]; + } + } + } + return MultiplayerAPI::RPCConfig(); +} + +const MultiplayerAPI::RPCConfig _get_rpc_config_by_id(Node *p_node, uint16_t p_id) { + Vector<MultiplayerAPI::RPCConfig> config; + uint16_t id = p_id; + if (id & (1 << 15)) { + id = id & ~(1 << 15); + config = p_node->get_node_rpc_methods(); + } else if (p_node->get_script_instance()) { + config = p_node->get_script_instance()->get_rpc_methods(); + } + if (id < config.size()) { + return config[p_id]; + } + return MultiplayerAPI::RPCConfig(); +} + _FORCE_INLINE_ bool _should_call_local(MultiplayerAPI::RPCMode mode, bool is_master, bool &r_skip_rpc) { switch (mode) { case MultiplayerAPI::RPC_MODE_DISABLED: { @@ -99,7 +149,7 @@ _FORCE_INLINE_ bool _can_call_mode(Node *p_node, MultiplayerAPI::RPCMode mode, i } void MultiplayerAPI::poll() { - if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) { + if (!network_peer.is_valid() || network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED) { return; } @@ -146,13 +196,13 @@ Node *MultiplayerAPI::get_root_node() { return root_node; } -void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer) { +void MultiplayerAPI::set_network_peer(const Ref<MultiplayerPeer> &p_peer) { if (p_peer == network_peer) { return; // Nothing to do } - ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, - "Supplied NetworkedMultiplayerPeer must be connecting or connected."); + ERR_FAIL_COND_MSG(p_peer.is_valid() && p_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, + "Supplied MultiplayerPeer must be connecting or connected."); if (network_peer.is_valid()) { network_peer->disconnect("peer_connected", callable_mp(this, &MultiplayerAPI::_add_peer)); @@ -174,7 +224,7 @@ void MultiplayerAPI::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_pee } } -Ref<NetworkedMultiplayerPeer> MultiplayerAPI::get_network_peer() const { +Ref<MultiplayerPeer> MultiplayerAPI::get_network_peer() const { return network_peer; } @@ -231,8 +281,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ _process_confirm_path(p_from, p_packet, p_packet_len); } break; - case NETWORK_COMMAND_REMOTE_CALL: - case NETWORK_COMMAND_REMOTE_SET: { + case NETWORK_COMMAND_REMOTE_CALL: { // Extract packet meta int packet_min_size = 1; int name_id_offset = 1; @@ -302,13 +351,7 @@ void MultiplayerAPI::_process_packet(int p_from, const uint8_t *p_packet, int p_ } const int packet_len = get_packet_len(node_target, p_packet_len); - if (packet_type == NETWORK_COMMAND_REMOTE_CALL) { - _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); - - } else { - _process_rset(node, name_id, p_from, p_packet, packet_len, packet_min_size); - } - + _process_rpc(node, name_id, p_from, p_packet, packet_len, packet_min_size); } break; case NETWORK_COMMAND_RAW: { @@ -362,16 +405,11 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, ERR_FAIL_COND_MSG(p_offset > p_packet_len, "Invalid packet received. Size too small."); // Check that remote can call the RPC on this node. - StringName name = p_node->get_node_rpc_method(p_rpc_method_id); - RPCMode rpc_mode = p_node->get_node_rpc_mode_by_id(p_rpc_method_id); - if (name == StringName() && p_node->get_script_instance()) { - name = p_node->get_script_instance()->get_rpc_method(p_rpc_method_id); - rpc_mode = p_node->get_script_instance()->get_rpc_mode_by_id(p_rpc_method_id); - } - ERR_FAIL_COND(name == StringName()); + const RPCConfig config = _get_rpc_config_by_id(p_node, p_rpc_method_id); + ERR_FAIL_COND(config.name == StringName()); - bool can_call = _can_call_mode(p_node, rpc_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); + bool can_call = _can_call_mode(p_node, config.rpc_mode, p_from); + ERR_FAIL_COND_MSG(!can_call, "RPC '" + String(config.name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)config.rpc_mode) + ", master is " + itos(p_node->get_network_master()) + "."); int argc = 0; bool byte_only = false; @@ -424,47 +462,14 @@ void MultiplayerAPI::_process_rpc(Node *p_node, const uint16_t p_rpc_method_id, Callable::CallError ce; - p_node->call(name, (const Variant **)argp.ptr(), argc, ce); + p_node->call(config.name, (const Variant **)argp.ptr(), argc, ce); if (ce.error != Callable::CallError::CALL_OK) { - String error = Variant::get_call_error_text(p_node, name, (const Variant **)argp.ptr(), argc, ce); + String error = Variant::get_call_error_text(p_node, config.name, (const Variant **)argp.ptr(), argc, ce); error = "RPC - " + error; ERR_PRINT(error); } } -void MultiplayerAPI::_process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset) { - ERR_FAIL_COND_MSG(p_offset >= p_packet_len, "Invalid packet received. Size too small."); - - // Check that remote can call the RSET on this node. - StringName name = p_node->get_node_rset_property(p_rpc_property_id); - RPCMode rset_mode = p_node->get_node_rset_mode_by_id(p_rpc_property_id); - if (name == StringName() && p_node->get_script_instance()) { - name = p_node->get_script_instance()->get_rset_property(p_rpc_property_id); - rset_mode = p_node->get_script_instance()->get_rset_mode_by_id(p_rpc_property_id); - } - ERR_FAIL_COND(name == StringName()); - - bool can_call = _can_call_mode(p_node, rset_mode, p_from); - ERR_FAIL_COND_MSG(!can_call, "RSET '" + String(name) + "' is not allowed on node " + p_node->get_path() + " from: " + itos(p_from) + ". Mode is " + itos((int)rset_mode) + ", master is " + itos(p_node->get_network_master()) + "."); - -#ifdef DEBUG_ENABLED - _profile_node_data("in_rset", p_node->get_instance_id()); -#endif - - Variant value; - Error err = _decode_and_decompress_variant(value, &p_packet[p_offset], p_packet_len - p_offset, nullptr); - - ERR_FAIL_COND_MSG(err != OK, "Invalid packet received. Unable to decode RSET value."); - - bool valid; - - p_node->set(name, value, &valid); - if (!valid) { - String error = "Error setting remote property '" + String(name) + "', not found in object of type " + p_node->get_class() + "."; - ERR_PRINT(error); - } -} - void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, int p_packet_len) { ERR_FAIL_COND_MSG(p_packet_len < 38, "Invalid packet received. Size too small."); int ofs = 1; @@ -487,7 +492,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, Node *node = root_node->get_node(path); ERR_FAIL_COND(node == nullptr); - const bool valid_rpc_checksum = node->get_rpc_md5() == methods_md5; + const bool valid_rpc_checksum = _get_rpc_md5(node) == methods_md5; if (valid_rpc_checksum == false) { ERR_PRINT("The rpc node checksum failed. Make sure to have the same methods on both nodes. Node path: " + path); } @@ -508,7 +513,7 @@ void MultiplayerAPI::_process_simplify_path(int p_from, const uint8_t *p_packet, packet.write[1] = valid_rpc_checksum; encode_cstring(pname.get_data(), &packet.write[2]); - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); network_peer->set_target_peer(p_from); network_peer->put_packet(packet.ptr(), packet.size()); } @@ -569,7 +574,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC const int path_len = encode_cstring(path.get_data(), nullptr); // Extract MD5 from rpc methods list. - const String methods_md5 = p_node->get_rpc_md5(); + const String methods_md5 = _get_rpc_md5(p_node); const int methods_md5_len = 33; // 32 + 1 for the `0` that is added by the encoder. Vector<uint8_t> packet; @@ -587,7 +592,7 @@ bool MultiplayerAPI::_send_confirm_path(Node *p_node, NodePath p_path, PathSentC for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) { network_peer->set_target_peer(E->get()); // To all of you. - network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(MultiplayerPeer::TRANSFER_MODE_RELIABLE); network_peer->put_packet(packet.ptr(), packet.size()); psc->confirmed_peers.insert(E->get(), false); // Insert into confirmed, but as false since it was not confirmed. @@ -752,12 +757,12 @@ Error MultiplayerAPI::_decode_and_decompress_variant(Variant &r_variant, const u return OK; } -void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) { +void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_MSG(network_peer.is_null(), "Attempt to remote call/set when networking is not active in SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_CONNECTING, "Attempt to remote call/set when networking is not connected yet in SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() == MultiplayerPeer::CONNECTION_DISCONNECTED, "Attempt to remote call/set when networking is disconnected."); ERR_FAIL_COND_MSG(p_argcount > 255, "Too many arguments >255."); @@ -797,7 +802,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p // - `NetworkNameIdCompression` in the next 1 bit. // - `byte_only_or_no_args` in the next 1 bit. // - So we still have the last bit free! - uint8_t command_type = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL; + uint8_t command_type = NETWORK_COMMAND_REMOTE_CALL; uint8_t node_id_compression = UINT8_MAX; uint8_t name_id_compression = UINT8_MAX; bool byte_only_or_no_args = false; @@ -837,81 +842,42 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p ofs += 4; } - if (p_set) { - // Take the rpc property ID - uint16_t property_id = p_from->get_node_rset_property_id(p_name); - if (property_id == UINT16_MAX && p_from->get_script_instance()) { - property_id = p_from->get_script_instance()->get_rset_property_id(p_name); - } - ERR_FAIL_COND_MSG(property_id == UINT16_MAX, "Unable to take the `property_id` for the property:" + p_name + ". This can only happen if this property is not marked as `remote`."); - - if (property_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(property_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(property_id, &(packet_cache.write[ofs])); - ofs += 2; - } - - // Set argument. - int len(0); - Error err = _encode_and_compress_variant(*p_arg[0], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RSET value. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - _encode_and_compress_variant(*p_arg[0], &(packet_cache.write[ofs]), len); - ofs += len; - + // Encode method ID + if (p_rpc_id <= UINT8_MAX) { + // The ID fits in 1 byte + name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = static_cast<uint8_t>(p_rpc_id); + ofs += 1; } else { - // Take the rpc method ID - uint16_t method_id = p_from->get_node_rpc_method_id(p_name); - if (method_id == UINT16_MAX && p_from->get_script_instance()) { - method_id = p_from->get_script_instance()->get_rpc_method_id(p_name); - } - ERR_FAIL_COND_MSG(method_id == UINT16_MAX, - vformat("Unable to take the `method_id` for the function \"%s\" at path: \"%s\". This happens when the method is not marked as `remote`.", p_name, p_from->get_path())); - - if (method_id <= UINT8_MAX) { - // The ID fits in 1 byte - name_id_compression = NETWORK_NAME_ID_COMPRESSION_8; - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = static_cast<uint8_t>(method_id); - ofs += 1; - } else { - // The ID is larger, let's use 2 bytes - name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; - MAKE_ROOM(ofs + 2); - encode_uint16(method_id, &(packet_cache.write[ofs])); - ofs += 2; - } + // The ID is larger, let's use 2 bytes + name_id_compression = NETWORK_NAME_ID_COMPRESSION_16; + MAKE_ROOM(ofs + 2); + encode_uint16(p_rpc_id, &(packet_cache.write[ofs])); + ofs += 2; + } - if (p_argcount == 0) { - byte_only_or_no_args = true; - } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { - byte_only_or_no_args = true; - // Special optimization when only the byte vector is sent. - const Vector<uint8_t> data = *p_arg[0]; - MAKE_ROOM(ofs + data.size()); - memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); - ofs += data.size(); - } else { - // Arguments - MAKE_ROOM(ofs + 1); - packet_cache.write[ofs] = p_argcount; - ofs += 1; - for (int i = 0; i < p_argcount; i++) { - int len(0); - Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len); - ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); - MAKE_ROOM(ofs + len); - _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); - ofs += len; - } + if (p_argcount == 0) { + byte_only_or_no_args = true; + } else if (p_argcount == 1 && p_arg[0]->get_type() == Variant::PACKED_BYTE_ARRAY) { + byte_only_or_no_args = true; + // Special optimization when only the byte vector is sent. + const Vector<uint8_t> data = *p_arg[0]; + MAKE_ROOM(ofs + data.size()); + memcpy(&(packet_cache.write[ofs]), data.ptr(), sizeof(uint8_t) * data.size()); + ofs += data.size(); + } else { + // Arguments + MAKE_ROOM(ofs + 1); + packet_cache.write[ofs] = p_argcount; + ofs += 1; + for (int i = 0; i < p_argcount; i++) { + int len(0); + Error err = _encode_and_compress_variant(*p_arg[i], nullptr, len); + ERR_FAIL_COND_MSG(err != OK, "Unable to encode RPC argument. THIS IS LIKELY A BUG IN THE ENGINE!"); + MAKE_ROOM(ofs + len); + _encode_and_compress_variant(*p_arg[i], &(packet_cache.write[ofs]), len); + ofs += len; } } @@ -927,7 +893,7 @@ void MultiplayerAPI::_send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p #endif // Take chance and set transfer mode, since all send methods will use it. - network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + network_peer->set_transfer_mode(p_config.transfer_mode); if (has_all_peers) { // They all have verified paths, so send fast. @@ -1008,26 +974,22 @@ void MultiplayerAPI::_server_disconnected() { void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to call an RPC while no network peer is active."); ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to call an RPC on a node which is not inside SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); + ERR_FAIL_COND_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, "Trying to call an RPC via a network peer which is not connected."); int node_id = network_peer->get_unique_id(); bool skip_rpc = node_id == p_peer_id; bool call_local_native = false; bool call_local_script = false; bool is_master = p_node->is_network_master(); - + uint16_t rpc_id = UINT16_MAX; + const RPCConfig config = _get_rpc_config(p_node, p_method, rpc_id); + ERR_FAIL_COND_MSG(config.name == StringName(), + vformat("Unable to get the RPC configuration for the function \"%s\" at path: \"%s\". This happens when the method is not marked for RPCs.", p_method, p_node->get_path())); if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - // Check that send mode can use local call. - - RPCMode rpc_mode = p_node->get_node_rpc_mode(p_method); - call_local_native = _should_call_local(rpc_mode, is_master, skip_rpc); - - if (call_local_native) { - // Done below. - } else if (p_node->get_script_instance()) { - // Attempt with script. - rpc_mode = p_node->get_script_instance()->get_rpc_mode(p_method); - call_local_script = _should_call_local(rpc_mode, is_master, skip_rpc); + if (rpc_id & (1 << 15)) { + call_local_native = _should_call_local(config.rpc_mode, is_master, skip_rpc); + } else { + call_local_script = _should_call_local(config.rpc_mode, is_master, skip_rpc); } } @@ -1036,7 +998,7 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const _profile_node_data("out_rpc", p_node->get_instance_id()); #endif - _send_rpc(p_node, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount); + _send_rpc(p_node, p_peer_id, rpc_id, config, p_method, p_arg, p_argcount); } if (call_local_native) { @@ -1071,74 +1033,10 @@ void MultiplayerAPI::rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const ERR_FAIL_COND_MSG(skip_rpc && !(call_local_native || call_local_script), "RPC '" + p_method + "' on yourself is not allowed by selected mode."); } -void MultiplayerAPI::rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { - ERR_FAIL_COND_MSG(!network_peer.is_valid(), "Trying to RSET while no network peer is active."); - ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "Trying to RSET on a node which is not inside SceneTree."); - ERR_FAIL_COND_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, "Trying to send an RSET via a network peer which is not connected."); - - int node_id = network_peer->get_unique_id(); - bool is_master = p_node->is_network_master(); - bool skip_rset = node_id == p_peer_id; - bool set_local = false; - - if (p_peer_id == 0 || p_peer_id == node_id || (p_peer_id < 0 && p_peer_id != -node_id)) { - // Check that send mode can use local call. - RPCMode rpc_mode = p_node->get_node_rset_mode(p_property); - set_local = _should_call_local(rpc_mode, is_master, skip_rset); - - if (set_local) { - bool valid; - int temp_id = rpc_sender_id; - - rpc_sender_id = get_network_unique_id(); - p_node->set(p_property, p_value, &valid); - rpc_sender_id = temp_id; - - if (!valid) { - String error = "rset() aborted in local set, property not found: - " + String(p_property) + "."; - ERR_PRINT(error); - return; - } - } else if (p_node->get_script_instance()) { - // Attempt with script. - rpc_mode = p_node->get_script_instance()->get_rset_mode(p_property); - - set_local = _should_call_local(rpc_mode, is_master, skip_rset); - - if (set_local) { - int temp_id = rpc_sender_id; - - rpc_sender_id = get_network_unique_id(); - bool valid = p_node->get_script_instance()->set(p_property, p_value); - rpc_sender_id = temp_id; - - if (!valid) { - String error = "rset() aborted in local script set, property not found: - " + String(p_property) + "."; - ERR_PRINT(error); - return; - } - } - } - } - - if (skip_rset) { - ERR_FAIL_COND_MSG(!set_local, "RSET for '" + p_property + "' on yourself is not allowed by selected mode."); - return; - } - -#ifdef DEBUG_ENABLED - _profile_node_data("out_rset", p_node->get_instance_id()); -#endif - - const Variant *vptr = &p_value; - - _send_rpc(p_node, p_peer_id, p_unreliable, true, p_property, &vptr, 1); -} - -Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, NetworkedMultiplayerPeer::TransferMode p_mode) { +Error MultiplayerAPI::send_bytes(Vector<uint8_t> p_data, int p_to, MultiplayerPeer::TransferMode p_mode) { ERR_FAIL_COND_V_MSG(p_data.size() < 1, ERR_INVALID_DATA, "Trying to send an empty raw packet."); ERR_FAIL_COND_V_MSG(!network_peer.is_valid(), ERR_UNCONFIGURED, "Trying to send a raw packet while no network peer is active."); - ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != NetworkedMultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected."); + ERR_FAIL_COND_V_MSG(network_peer->get_connection_status() != MultiplayerPeer::CONNECTION_CONNECTED, ERR_UNCONFIGURED, "Trying to send a raw packet via a network peer which is not connected."); MAKE_ROOM(p_data.size() + 1); const uint8_t *r = p_data.ptr(); @@ -1207,7 +1105,7 @@ bool MultiplayerAPI::is_object_decoding_allowed() const { void MultiplayerAPI::_bind_methods() { ClassDB::bind_method(D_METHOD("set_root_node", "node"), &MultiplayerAPI::set_root_node); ClassDB::bind_method(D_METHOD("get_root_node"), &MultiplayerAPI::get_root_node); - ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE)); + ClassDB::bind_method(D_METHOD("send_bytes", "bytes", "id", "mode"), &MultiplayerAPI::send_bytes, DEFVAL(MultiplayerPeer::TARGET_PEER_BROADCAST), DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE)); ClassDB::bind_method(D_METHOD("has_network_peer"), &MultiplayerAPI::has_network_peer); ClassDB::bind_method(D_METHOD("get_network_peer"), &MultiplayerAPI::get_network_peer); ClassDB::bind_method(D_METHOD("get_network_unique_id"), &MultiplayerAPI::get_network_unique_id); @@ -1225,8 +1123,8 @@ void MultiplayerAPI::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_object_decoding"), "set_allow_object_decoding", "is_object_decoding_allowed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_root_node", "get_root_node"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerPeer", PROPERTY_USAGE_NONE), "set_network_peer", "get_network_peer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root_node", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_root_node", "get_root_node"); ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); diff --git a/core/io/multiplayer_api.h b/core/io/multiplayer_api.h index 7f88b53a27..e9f96383c9 100644 --- a/core/io/multiplayer_api.h +++ b/core/io/multiplayer_api.h @@ -31,11 +31,40 @@ #ifndef MULTIPLAYER_API_H #define MULTIPLAYER_API_H -#include "core/io/networked_multiplayer_peer.h" -#include "core/object/reference.h" +#include "core/io/multiplayer_peer.h" +#include "core/object/ref_counted.h" -class MultiplayerAPI : public Reference { - GDCLASS(MultiplayerAPI, Reference); +class MultiplayerAPI : public RefCounted { + GDCLASS(MultiplayerAPI, RefCounted); + +public: + enum RPCMode { + RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) + RPC_MODE_REMOTE, // Using rpc() on it will call method in all remote peers + RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote + RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets + RPC_MODE_REMOTESYNC, // Using rpc() on it will call method in all remote peers and locally + RPC_MODE_MASTERSYNC, // Using rpc() on it will call method in the master peer and locally + RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method in all puppets peers and locally + }; + + struct RPCConfig { + StringName name; + RPCMode rpc_mode = RPC_MODE_DISABLED; + MultiplayerPeer::TransferMode transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + int channel = 0; + + bool operator==(RPCConfig const &p_other) const { + return name == p_other.name; + } + }; + + struct SortRPCConfig { + StringName::AlphCompare compare; + bool operator()(const RPCConfig &p_a, const RPCConfig &p_b) const { + return compare(p_a.name, p_b.name); + } + }; private: //path sent caches @@ -54,7 +83,7 @@ private: Map<int, NodeInfo> nodes; }; - Ref<NetworkedMultiplayerPeer> network_peer; + Ref<MultiplayerPeer> network_peer; int rpc_sender_id = 0; Set<int> connected_peers; HashMap<NodePath, PathSentCache> path_send_cache; @@ -72,10 +101,9 @@ protected: void _process_confirm_path(int p_from, const uint8_t *p_packet, int p_packet_len); Node *_process_get_node(int p_from, const uint8_t *p_packet, uint32_t p_node_target, int p_packet_len); void _process_rpc(Node *p_node, const uint16_t p_rpc_method_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); - void _process_rset(Node *p_node, const uint16_t p_rpc_property_id, int p_from, const uint8_t *p_packet, int p_packet_len, int p_offset); void _process_raw(int p_from, const uint8_t *p_packet, int p_packet_len); - void _send_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount); + void _send_rpc(Node *p_from, int p_to, uint16_t p_rpc_id, const RPCConfig &p_config, const StringName &p_name, const Variant **p_arg, int p_argcount); bool _send_confirm_path(Node *p_node, NodePath p_path, PathSentCache *psc, int p_target); Error _encode_and_compress_variant(const Variant &p_variant, uint8_t *p_buffer, int &r_len); @@ -84,7 +112,6 @@ protected: public: enum NetworkCommands { NETWORK_COMMAND_REMOTE_CALL = 0, - NETWORK_COMMAND_REMOTE_SET, NETWORK_COMMAND_SIMPLIFY_PATH, NETWORK_COMMAND_CONFIRM_PATH, NETWORK_COMMAND_RAW, @@ -101,28 +128,16 @@ public: NETWORK_NAME_ID_COMPRESSION_16, }; - enum RPCMode { - RPC_MODE_DISABLED, // No rpc for this method, calls to this will be blocked (default) - RPC_MODE_REMOTE, // Using rpc() on it will call method / set property in all remote peers - RPC_MODE_MASTER, // Using rpc() on it will call method on wherever the master is, be it local or remote - RPC_MODE_PUPPET, // Using rpc() on it will call method for all puppets - RPC_MODE_REMOTESYNC, // Using rpc() on it will call method / set property in all remote peers and locally - RPC_MODE_MASTERSYNC, // Using rpc() on it will call method / set property in the master peer and locally - RPC_MODE_PUPPETSYNC, // Using rpc() on it will call method / set property in all puppets peers and locally - }; - void poll(); void clear(); void set_root_node(Node *p_node); Node *get_root_node(); - void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_peer); - Ref<NetworkedMultiplayerPeer> get_network_peer() const; - Error send_bytes(Vector<uint8_t> p_data, int p_to = NetworkedMultiplayerPeer::TARGET_PEER_BROADCAST, NetworkedMultiplayerPeer::TransferMode p_mode = NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE); + void set_network_peer(const Ref<MultiplayerPeer> &p_peer); + Ref<MultiplayerPeer> get_network_peer() const; + Error send_bytes(Vector<uint8_t> p_data, int p_to = MultiplayerPeer::TARGET_PEER_BROADCAST, MultiplayerPeer::TransferMode p_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE); // Called by Node.rpc void rpcp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); - // Called by Node.rset - void rsetp(Node *p_node, int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); void _add_peer(int p_id); void _del_peer(int p_id); diff --git a/core/io/networked_multiplayer_peer.cpp b/core/io/multiplayer_peer.cpp index b6af046e77..8126b4cea3 100644 --- a/core/io/networked_multiplayer_peer.cpp +++ b/core/io/multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_peer.cpp */ +/* multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,22 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "networked_multiplayer_peer.h" +#include "multiplayer_peer.h" -void NetworkedMultiplayerPeer::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &NetworkedMultiplayerPeer::set_transfer_mode); - ClassDB::bind_method(D_METHOD("get_transfer_mode"), &NetworkedMultiplayerPeer::get_transfer_mode); - ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &NetworkedMultiplayerPeer::set_target_peer); +void MultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_transfer_mode", "mode"), &MultiplayerPeer::set_transfer_mode); + ClassDB::bind_method(D_METHOD("get_transfer_mode"), &MultiplayerPeer::get_transfer_mode); + ClassDB::bind_method(D_METHOD("set_target_peer", "id"), &MultiplayerPeer::set_target_peer); - ClassDB::bind_method(D_METHOD("get_packet_peer"), &NetworkedMultiplayerPeer::get_packet_peer); + ClassDB::bind_method(D_METHOD("get_packet_peer"), &MultiplayerPeer::get_packet_peer); - ClassDB::bind_method(D_METHOD("poll"), &NetworkedMultiplayerPeer::poll); + ClassDB::bind_method(D_METHOD("poll"), &MultiplayerPeer::poll); - ClassDB::bind_method(D_METHOD("get_connection_status"), &NetworkedMultiplayerPeer::get_connection_status); - ClassDB::bind_method(D_METHOD("get_unique_id"), &NetworkedMultiplayerPeer::get_unique_id); + ClassDB::bind_method(D_METHOD("get_connection_status"), &MultiplayerPeer::get_connection_status); + ClassDB::bind_method(D_METHOD("get_unique_id"), &MultiplayerPeer::get_unique_id); - ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &NetworkedMultiplayerPeer::set_refuse_new_connections); - ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &NetworkedMultiplayerPeer::is_refusing_new_connections); + ClassDB::bind_method(D_METHOD("set_refuse_new_connections", "enable"), &MultiplayerPeer::set_refuse_new_connections); + ClassDB::bind_method(D_METHOD("is_refusing_new_connections"), &MultiplayerPeer::is_refusing_new_connections); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_connections"), "set_refuse_new_connections", "is_refusing_new_connections"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_mode", PROPERTY_HINT_ENUM, "Unreliable,Unreliable Ordered,Reliable"), "set_transfer_mode", "get_transfer_mode"); diff --git a/core/io/networked_multiplayer_peer.h b/core/io/multiplayer_peer.h index 7c90f97d88..432f47280f 100644 --- a/core/io/networked_multiplayer_peer.h +++ b/core/io/multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_peer.h */ +/* multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,8 +33,8 @@ #include "core/io/packet_peer.h" -class NetworkedMultiplayerPeer : public PacketPeer { - GDCLASS(NetworkedMultiplayerPeer, PacketPeer); +class MultiplayerPeer : public PacketPeer { + GDCLASS(MultiplayerPeer, PacketPeer); protected: static void _bind_methods(); @@ -73,10 +73,10 @@ public: virtual ConnectionStatus get_connection_status() const = 0; - NetworkedMultiplayerPeer() {} + MultiplayerPeer() {} }; -VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::TransferMode) -VARIANT_ENUM_CAST(NetworkedMultiplayerPeer::ConnectionStatus) +VARIANT_ENUM_CAST(MultiplayerPeer::TransferMode) +VARIANT_ENUM_CAST(MultiplayerPeer::ConnectionStatus) #endif // NETWORKED_MULTIPLAYER_PEER_H diff --git a/core/io/net_socket.h b/core/io/net_socket.h index 98ff9562d9..fd7d50c704 100644 --- a/core/io/net_socket.h +++ b/core/io/net_socket.h @@ -32,9 +32,9 @@ #define NET_SOCKET_H #include "core/io/ip.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class NetSocket : public Reference { +class NetSocket : public RefCounted { protected: static NetSocket *(*_create)(); diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp index 52169987fd..cf6a0b6027 100644 --- a/core/io/packed_data_container.cpp +++ b/core/io/packed_data_container.cpp @@ -227,10 +227,10 @@ uint32_t PackedDataContainer::_pack(const Variant &p_data, Vector<uint8_t> &tmpd case Variant::VECTOR3: case Variant::TRANSFORM2D: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::BASIS: - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::PACKED_BYTE_ARRAY: case Variant::PACKED_INT32_ARRAY: case Variant::PACKED_INT64_ARRAY: diff --git a/core/io/packed_data_container.h b/core/io/packed_data_container.h index 7791e21bb3..40772bb2bf 100644 --- a/core/io/packed_data_container.h +++ b/core/io/packed_data_container.h @@ -80,8 +80,8 @@ public: PackedDataContainer() {} }; -class PackedDataContainerRef : public Reference { - GDCLASS(PackedDataContainerRef, Reference); +class PackedDataContainerRef : public RefCounted { + GDCLASS(PackedDataContainerRef, RefCounted); friend class PackedDataContainer; uint32_t offset = 0; diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp index 318fd10243..8da44fd290 100644 --- a/core/io/packet_peer.cpp +++ b/core/io/packet_peer.cpp @@ -161,7 +161,7 @@ void PacketPeerStream::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "input_buffer_max_size"), "set_input_buffer_max_size", "get_input_buffer_max_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "output_buffer_max_size"), "set_output_buffer_max_size", "get_output_buffer_max_size"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream_peer", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", 0), "set_stream_peer", "get_stream_peer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream_peer", PROPERTY_HINT_RESOURCE_TYPE, "StreamPeer", PROPERTY_USAGE_NONE), "set_stream_peer", "get_stream_peer"); } Error PacketPeerStream::_poll_buffer() const { diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h index 9e03c44750..9a345af3d0 100644 --- a/core/io/packet_peer.h +++ b/core/io/packet_peer.h @@ -35,8 +35,8 @@ #include "core/object/class_db.h" #include "core/templates/ring_buffer.h" -class PacketPeer : public Reference { - GDCLASS(PacketPeer, Reference); +class PacketPeer : public RefCounted { + GDCLASS(PacketPeer, RefCounted); Variant _bnd_get_var(bool p_allow_objects = false); diff --git a/core/io/packet_peer_dtls.cpp b/core/io/packet_peer_dtls.cpp index bac98e20e7..a6d220622b 100644 --- a/core/io/packet_peer_dtls.cpp +++ b/core/io/packet_peer_dtls.cpp @@ -30,7 +30,7 @@ #include "packet_peer_dtls.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" PacketPeerDTLS *(*PacketPeerDTLS::_create)() = nullptr; bool PacketPeerDTLS::available = false; diff --git a/core/io/pck_packer.cpp b/core/io/pck_packer.cpp index cadb02b5dd..806a95398f 100644 --- a/core/io/pck_packer.cpp +++ b/core/io/pck_packer.cpp @@ -31,9 +31,9 @@ #include "pck_packer.h" #include "core/crypto/crypto_core.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION -#include "core/os/file_access.h" #include "core/version.h" static int _get_pad(int p_alignment, int p_n) { diff --git a/core/io/pck_packer.h b/core/io/pck_packer.h index dec8f8748d..3d2ce8f240 100644 --- a/core/io/pck_packer.h +++ b/core/io/pck_packer.h @@ -31,12 +31,12 @@ #ifndef PCK_PACKER_H #define PCK_PACKER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class FileAccess; -class PCKPacker : public Reference { - GDCLASS(PCKPacker, Reference); +class PCKPacker : public RefCounted { + GDCLASS(PCKPacker, RefCounted); FileAccess *file = nullptr; int alignment = 0; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index d46e9edafa..efa622d976 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -31,9 +31,9 @@ #include "resource.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "scene/main/node.h" //only so casting works @@ -164,7 +164,7 @@ Ref<Resource> Resource::duplicate_for_local_scene(Node *p_for_scene, Map<Ref<Res List<PropertyInfo> plist; get_property_list(&plist); - Ref<Resource> r = Object::cast_to<Resource>(ClassDB::instance(get_class())); + Ref<Resource> r = Object::cast_to<Resource>(ClassDB::instantiate(get_class())); ERR_FAIL_COND_V(r.is_null(), Ref<Resource>()); r->local_scene = p_for_scene; @@ -224,7 +224,7 @@ Ref<Resource> Resource::duplicate(bool p_subresources) const { List<PropertyInfo> plist; get_property_list(&plist); - Ref<Resource> r = (Resource *)ClassDB::instance(get_class()); + Ref<Resource> r = (Resource *)ClassDB::instantiate(get_class()); ERR_FAIL_COND_V(r.is_null(), Ref<Resource>()); for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { diff --git a/core/io/resource.h b/core/io/resource.h index 75a9f928f8..028fed1c6e 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -32,7 +32,7 @@ #define RESOURCE_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/safe_refcount.h" #include "core/templates/self_list.h" @@ -43,8 +43,8 @@ public: \ private: -class Resource : public Reference { - GDCLASS(Resource, Reference); +class Resource : public RefCounted { + GDCLASS(Resource, RefCounted); OBJ_CATEGORY("Resources"); public: diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index d6601513bc..0e9815245f 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -31,10 +31,10 @@ #include "resource_format_binary.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/file_access_compressed.h" #include "core/io/image.h" #include "core/io/marshalls.h" -#include "core/os/dir_access.h" #include "core/version.h" //#define print_bl(m_what) print_line(m_what) @@ -51,7 +51,7 @@ enum { VARIANT_RECT2 = 11, VARIANT_VECTOR3 = 12, VARIANT_PLANE = 13, - VARIANT_QUAT = 14, + VARIANT_QUATERNION = 14, VARIANT_AABB = 15, VARIANT_MATRIX3 = 16, VARIANT_TRANSFORM = 17, @@ -199,8 +199,8 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { v.d = f->get_real(); r_v = v; } break; - case VARIANT_QUAT: { - Quat v; + case VARIANT_QUATERNION: { + Quaternion v; v.x = f->get_real(); v.y = f->get_real(); v.z = f->get_real(); @@ -245,7 +245,7 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) { } break; case VARIANT_TRANSFORM: { - Transform v; + Transform3D v; v.basis.elements[0].x = f->get_real(); v.basis.elements[0].y = f->get_real(); v.basis.elements[0].z = f->get_real(); @@ -704,7 +704,7 @@ Error ResourceLoaderBinary::load() { if (res.is_null()) { //did not replace - Object *obj = ClassDB::instance(t); + Object *obj = ClassDB::instantiate(t); if (!obj) { error = ERR_FILE_CORRUPT; ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, local_path + ":Resource of unrecognized type in file: " + t + "."); @@ -1371,9 +1371,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.d); } break; - case Variant::QUAT: { - f->store_32(VARIANT_QUAT); - Quat val = p_property; + case Variant::QUATERNION: { + f->store_32(VARIANT_QUATERNION); + Quaternion val = p_property; f->store_real(val.x); f->store_real(val.y); f->store_real(val.z); @@ -1416,9 +1416,9 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia f->store_real(val.elements[2].z); } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { f->store_32(VARIANT_TRANSFORM); - Transform val = p_property; + Transform3D val = p_property; f->store_real(val.basis.elements[0].x); f->store_real(val.basis.elements[0].y); f->store_real(val.basis.elements[0].z); diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index 3592bbdbc4..abc7403935 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -31,9 +31,9 @@ #ifndef RESOURCE_FORMAT_BINARY_H #define RESOURCE_FORMAT_BINARY_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" class ResourceLoaderBinary { bool translation_remapped = false; diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index a14d6ba52c..2ceeb176e5 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -93,8 +93,8 @@ public: ResourceFormatImporter(); }; -class ResourceImporter : public Reference { - GDCLASS(ResourceImporter, Reference); +class ResourceImporter : public RefCounted { + GDCLASS(ResourceImporter, RefCounted); public: virtual String get_importer_name() const = 0; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index b942c30086..c5dfe1f2b0 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -31,8 +31,8 @@ #include "resource_loader.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_importer.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/string/print_string.h" #include "core/string/translation.h" @@ -68,17 +68,17 @@ bool ResourceFormatLoader::recognize_path(const String &p_path, const String &p_ } bool ResourceFormatLoader::handles_type(const String &p_type) const { - if (get_script_instance() && get_script_instance()->has_method("handles_type")) { + if (get_script_instance() && get_script_instance()->has_method("_handles_type")) { // I guess custom loaders for custom resources should use "Resource" - return get_script_instance()->call("handles_type", p_type); + return get_script_instance()->call("_handles_type", p_type); } return false; } String ResourceFormatLoader::get_resource_type(const String &p_path) const { - if (get_script_instance() && get_script_instance()->has_method("get_resource_type")) { - return get_script_instance()->call("get_resource_type", p_path); + if (get_script_instance() && get_script_instance()->has_method("_get_resource_type")) { + return get_script_instance()->call("_get_resource_type", p_path); } return ""; @@ -101,8 +101,8 @@ bool ResourceFormatLoader::exists(const String &p_path) const { } void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) const { - if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { - PackedStringArray exts = get_script_instance()->call("get_recognized_extensions"); + if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) { + PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions"); { const String *r = exts.ptr(); @@ -115,8 +115,8 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions) RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { // Check user-defined loader if there's any. Hard fail if it returns an error. - if (get_script_instance() && get_script_instance()->has_method("load")) { - Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode); + if (get_script_instance() && get_script_instance()->has_method("_load")) { + Variant res = get_script_instance()->call("_load", p_path, p_original_path, p_use_sub_threads, p_cache_mode); if (res.get_type() == Variant::INT) { // Error code, abort. if (r_error) { @@ -135,8 +135,8 @@ RES ResourceFormatLoader::load(const String &p_path, const String &p_original_pa } void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) { - if (get_script_instance() && get_script_instance()->has_method("get_dependencies")) { - PackedStringArray deps = get_script_instance()->call("get_dependencies", p_path, p_add_types); + if (get_script_instance() && get_script_instance()->has_method("_get_dependencies")) { + PackedStringArray deps = get_script_instance()->call("_get_dependencies", p_path, p_add_types); { const String *r = deps.ptr(); @@ -148,13 +148,13 @@ void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> * } Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map<String, String> &p_map) { - if (get_script_instance() && get_script_instance()->has_method("rename_dependencies")) { + if (get_script_instance() && get_script_instance()->has_method("_rename_dependencies")) { Dictionary deps_dict; for (Map<String, String>::Element *E = p_map.front(); E; E = E->next()) { deps_dict[E->key()] = E->value(); } - int64_t res = get_script_instance()->call("rename_dependencies", deps_dict); + int64_t res = get_script_instance()->call("_rename_dependencies", deps_dict); return (Error)res; } @@ -163,16 +163,16 @@ Error ResourceFormatLoader::rename_dependencies(const String &p_path, const Map< void ResourceFormatLoader::_bind_methods() { { - MethodInfo info = MethodInfo(Variant::NIL, "load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode")); + MethodInfo info = MethodInfo(Variant::NIL, "_load", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "original_path"), PropertyInfo(Variant::BOOL, "use_sub_threads"), PropertyInfo(Variant::INT, "cache_mode")); info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - ClassDB::add_virtual_method(get_class_static(), info); + BIND_VMETHOD(info); } - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type", PropertyInfo(Variant::STRING, "path"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles_type", PropertyInfo(Variant::STRING_NAME, "typename"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_resource_type", PropertyInfo(Variant::STRING, "path"))); + BIND_VMETHOD(MethodInfo("_get_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "add_types"))); + BIND_VMETHOD(MethodInfo(Variant::INT, "_rename_dependencies", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::STRING, "renames"))); BIND_ENUM_CONSTANT(CACHE_MODE_IGNORE); BIND_ENUM_CONSTANT(CACHE_MODE_REUSE); @@ -354,7 +354,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String & ThreadLoadTask &load_task = thread_load_tasks[local_path]; - if (load_task.resource.is_null()) { //needs to be loaded in thread + if (load_task.resource.is_null()) { //needs to be loaded in thread load_task.semaphore = memnew(Semaphore); if (thread_loading_count < thread_load_max) { @@ -1045,7 +1045,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatLoader"); ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceLoader: " + script_path + "."); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + "."); diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index 914d988caa..c656b9a69c 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -35,8 +35,8 @@ #include "core/os/semaphore.h" #include "core/os/thread.h" -class ResourceFormatLoader : public Reference { - GDCLASS(ResourceFormatLoader, Reference); +class ResourceFormatLoader : public RefCounted { + GDCLASS(ResourceFormatLoader, RefCounted); public: enum CacheMode { diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index 7ebc7f34b3..80cb85fba3 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -30,9 +30,9 @@ #include "resource_saver.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" Ref<ResourceFormatSaver> ResourceSaver::saver[MAX_SAVERS]; @@ -41,24 +41,24 @@ bool ResourceSaver::timestamp_on_save = false; ResourceSavedCallback ResourceSaver::save_callback = nullptr; Error ResourceFormatSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { - if (get_script_instance() && get_script_instance()->has_method("save")) { - return (Error)get_script_instance()->call("save", p_path, p_resource, p_flags).operator int64_t(); + if (get_script_instance() && get_script_instance()->has_method("_save")) { + return (Error)get_script_instance()->call("_save", p_path, p_resource, p_flags).operator int64_t(); } return ERR_METHOD_NOT_FOUND; } bool ResourceFormatSaver::recognize(const RES &p_resource) const { - if (get_script_instance() && get_script_instance()->has_method("recognize")) { - return get_script_instance()->call("recognize", p_resource); + if (get_script_instance() && get_script_instance()->has_method("_recognize")) { + return get_script_instance()->call("_recognize", p_resource); } return false; } void ResourceFormatSaver::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (get_script_instance() && get_script_instance()->has_method("get_recognized_extensions")) { - PackedStringArray exts = get_script_instance()->call("get_recognized_extensions", p_resource); + if (get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions")) { + PackedStringArray exts = get_script_instance()->call("_get_recognized_extensions", p_resource); { const String *r = exts.ptr(); @@ -74,11 +74,11 @@ void ResourceFormatSaver::_bind_methods() { PropertyInfo arg0 = PropertyInfo(Variant::STRING, "path"); PropertyInfo arg1 = PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"); PropertyInfo arg2 = PropertyInfo(Variant::INT, "flags"); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "save", arg0, arg1, arg2)); + BIND_VMETHOD(MethodInfo(Variant::INT, "_save", arg0, arg1, arg2)); } - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_recognized_extensions", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_recognize", PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); } Error ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { @@ -210,7 +210,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { bool valid_type = ClassDB::is_parent_class(ibt, "ResourceFormatSaver"); ERR_FAIL_COND_V_MSG(!valid_type, false, "Script does not inherit a CustomResourceSaver: " + script_path + "."); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + "."); diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 2c9e8f1aa3..07154aac4d 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -33,8 +33,8 @@ #include "core/io/resource.h" -class ResourceFormatSaver : public Reference { - GDCLASS(ResourceFormatSaver, Reference); +class ResourceFormatSaver : public RefCounted { + GDCLASS(ResourceFormatSaver, RefCounted); protected: static void _bind_methods(); diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp index ee5e9eca0c..27f8d4e88f 100644 --- a/core/io/stream_peer.cpp +++ b/core/io/stream_peer.cpp @@ -512,7 +512,7 @@ void StreamPeerBuffer::clear() { Ref<StreamPeerBuffer> StreamPeerBuffer::duplicate() const { Ref<StreamPeerBuffer> spb; - spb.instance(); + spb.instantiate(); spb->data = data; return spb; } diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h index 1e1a3e890c..effc3850af 100644 --- a/core/io/stream_peer.h +++ b/core/io/stream_peer.h @@ -31,10 +31,10 @@ #ifndef STREAM_PEER_H #define STREAM_PEER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class StreamPeer : public Reference { - GDCLASS(StreamPeer, Reference); +class StreamPeer : public RefCounted { + GDCLASS(StreamPeer, RefCounted); OBJ_CATEGORY("Networking"); protected: diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp index b760a9ef80..5e0c0390f9 100644 --- a/core/io/tcp_server.cpp +++ b/core/io/tcp_server.cpp @@ -43,7 +43,6 @@ Error TCPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) { ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); Error err; IP::Type ip_type = IP::TYPE_ANY; diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h index abefa53c6f..10985a04d5 100644 --- a/core/io/tcp_server.h +++ b/core/io/tcp_server.h @@ -36,8 +36,8 @@ #include "core/io/stream_peer.h" #include "core/io/stream_peer_tcp.h" -class TCPServer : public Reference { - GDCLASS(TCPServer, Reference); +class TCPServer : public RefCounted { + GDCLASS(TCPServer, RefCounted); protected: enum { diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index 9adf912224..83d575cee8 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -30,7 +30,7 @@ #include "translation_loader_po.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/translation.h" #include "core/string/translation_po.h" diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 36d33fcac3..c52820e60d 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -31,8 +31,8 @@ #ifndef TRANSLATION_LOADER_PO_H #define TRANSLATION_LOADER_PO_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/string/translation.h" class TranslationLoaderPO : public ResourceFormatLoader { diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp index 6a1af0c2a9..27a1cab721 100644 --- a/core/io/udp_server.cpp +++ b/core/io/udp_server.cpp @@ -91,7 +91,6 @@ Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) { ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE); ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE); ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); Error err; IP::Type ip_type = IP::TYPE_ANY; diff --git a/core/io/udp_server.h b/core/io/udp_server.h index 60d03f37f0..e49a559c51 100644 --- a/core/io/udp_server.h +++ b/core/io/udp_server.h @@ -34,8 +34,8 @@ #include "core/io/net_socket.h" #include "core/io/packet_peer_udp.h" -class UDPServer : public Reference { - GDCLASS(UDPServer, Reference); +class UDPServer : public RefCounted { + GDCLASS(UDPServer, RefCounted); protected: enum { diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h index 847edf958d..1113cce715 100644 --- a/core/io/xml_parser.h +++ b/core/io/xml_parser.h @@ -31,8 +31,8 @@ #ifndef XML_PARSER_H #define XML_PARSER_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/templates/vector.h" @@ -40,8 +40,8 @@ Based on irrXML (see their zlib license). Added mainly for compatibility with their Collada loader. */ -class XMLParser : public Reference { - GDCLASS(XMLParser, Reference); +class XMLParser : public RefCounted { + GDCLASS(XMLParser, RefCounted); public: //! Enumeration of all supported source text file formats @@ -80,7 +80,6 @@ private: Vector<Attribute> attributes; - String _replace_special_characters(const String &origstr); bool _set_text(char *start, char *end); void _parse_closing_xml_element(); void _ignore_definition(); diff --git a/core/io/zip_io.h b/core/io/zip_io.h index 52691c65e9..776473bfa1 100644 --- a/core/io/zip_io.h +++ b/core/io/zip_io.h @@ -31,7 +31,7 @@ #ifndef ZIP_IO_H #define ZIP_IO_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" // Not directly used in this header, but assumed available in downstream users // like platform/*/export/export.cpp. Could be fixed, but probably better to have diff --git a/core/math/a_star.h b/core/math/a_star.h index 4c61abd91c..44758cb046 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -31,7 +31,7 @@ #ifndef A_STAR_H #define A_STAR_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/oa_hash_map.h" /** @@ -40,8 +40,8 @@ @author Juan Linietsky <reduzio@gmail.com> */ -class AStar : public Reference { - GDCLASS(AStar, Reference); +class AStar : public RefCounted { + GDCLASS(AStar, RefCounted); friend class AStar2D; struct Point { @@ -157,8 +157,8 @@ public: ~AStar(); }; -class AStar2D : public Reference { - GDCLASS(AStar2D, Reference); +class AStar2D : public RefCounted { + GDCLASS(AStar2D, RefCounted); AStar astar; bool _solve(AStar::Point *begin_point, AStar::Point *end_point); diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp index 2c721997d8..33aa65f15d 100644 --- a/core/math/aabb.cpp +++ b/core/math/aabb.cpp @@ -392,5 +392,5 @@ Variant AABB::intersects_ray_bind(const Vector3 &p_from, const Vector3 &p_dir) c } AABB::operator String() const { - return String() + position + " - " + size; + return "[P: " + position.operator String() + ", S: " + size + "]"; } diff --git a/core/math/basis.cpp b/core/math/basis.cpp index 037378b9d7..aa3831d4cf 100644 --- a/core/math/basis.cpp +++ b/core/math/basis.cpp @@ -345,12 +345,12 @@ void Basis::rotate(const Vector3 &p_euler) { *this = rotated(p_euler); } -Basis Basis::rotated(const Quat &p_quat) const { - return Basis(p_quat) * (*this); +Basis Basis::rotated(const Quaternion &p_quaternion) const { + return Basis(p_quaternion) * (*this); } -void Basis::rotate(const Quat &p_quat) { - *this = rotated(p_quat); +void Basis::rotate(const Quaternion &p_quaternion) { + *this = rotated(p_quaternion); } Vector3 Basis::get_rotation_euler() const { @@ -367,7 +367,7 @@ Vector3 Basis::get_rotation_euler() const { return m.get_euler(); } -Quat Basis::get_rotation_quat() const { +Quaternion Basis::get_rotation_quaternion() const { // Assumes that the matrix can be decomposed into a proper rotation and scaling matrix as M = R.S, // and returns the Euler angles corresponding to the rotation part, complementing get_scale(). // See the comment in get_scale() for further information. @@ -378,7 +378,7 @@ Quat Basis::get_rotation_quat() const { m.scale(Vector3(-1, -1, -1)); } - return m.get_quat(); + return m.get_quaternion(); } void Basis::get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const { @@ -756,23 +756,14 @@ bool Basis::operator!=(const Basis &p_matrix) const { } Basis::operator String() const { - String mtx; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - if (i != 0 || j != 0) { - mtx += ", "; - } - - mtx += rtos(elements[j][i]); //matrix is stored transposed for performance, so print it transposed - } - } - - return mtx; + return "[X: " + get_axis(0).operator String() + + ", Y: " + get_axis(1).operator String() + + ", Z: " + get_axis(2).operator String() + "]"; } -Quat Basis::get_quat() const { +Quaternion Basis::get_quaternion() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_rotation(), Quat(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quat() or call orthonormalized() instead."); + ERR_FAIL_COND_V_MSG(!is_rotation(), Quaternion(), "Basis must be normalized in order to be casted to a Quaternion. Use get_rotation_quaternion() or call orthonormalized() instead."); #endif /* Allow getting a quaternion from an unnormalized transform */ Basis m = *this; @@ -803,7 +794,7 @@ Quat Basis::get_quat() const { temp[k] = (m.elements[k][i] + m.elements[i][k]) * s; } - return Quat(temp[0], temp[1], temp[2], temp[3]); + return Quaternion(temp[0], temp[1], temp[2], temp[3]); } static const Basis _ortho_bases[24] = { @@ -945,13 +936,13 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = angle; } -void Basis::set_quat(const Quat &p_quat) { - real_t d = p_quat.length_squared(); +void Basis::set_quaternion(const Quaternion &p_quaternion) { + real_t d = p_quaternion.length_squared(); real_t s = 2.0 / d; - real_t xs = p_quat.x * s, ys = p_quat.y * s, zs = p_quat.z * s; - real_t wx = p_quat.w * xs, wy = p_quat.w * ys, wz = p_quat.w * zs; - real_t xx = p_quat.x * xs, xy = p_quat.x * ys, xz = p_quat.x * zs; - real_t yy = p_quat.y * ys, yz = p_quat.y * zs, zz = p_quat.z * zs; + real_t xs = p_quaternion.x * s, ys = p_quaternion.y * s, zs = p_quaternion.z * s; + real_t wx = p_quaternion.w * xs, wy = p_quaternion.w * ys, wz = p_quaternion.w * zs; + real_t xx = p_quaternion.x * xs, xy = p_quaternion.x * ys, xz = p_quaternion.x * zs; + real_t yy = p_quaternion.y * ys, yz = p_quaternion.y * zs, zz = p_quaternion.z * zs; set(1.0 - (yy + zz), xy - wz, xz + wy, xy + wz, 1.0 - (xx + zz), yz - wx, xz - wy, yz + wx, 1.0 - (xx + yy)); @@ -997,9 +988,9 @@ void Basis::set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale) { rotate(p_euler); } -void Basis::set_quat_scale(const Quat &p_quat, const Vector3 &p_scale) { +void Basis::set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_diagonal(p_scale); - rotate(p_quat); + rotate(p_quaternion); } void Basis::set_diagonal(const Vector3 &p_diag) { @@ -1018,8 +1009,8 @@ void Basis::set_diagonal(const Vector3 &p_diag) { Basis Basis::slerp(const Basis &p_to, const real_t &p_weight) const { //consider scale - Quat from(*this); - Quat to(p_to); + Quaternion from(*this); + Quaternion to(p_to); Basis b(from.slerp(to, p_weight)); b.elements[0] *= Math::lerp(elements[0].length(), p_to.elements[0].length(), p_weight); diff --git a/core/math/basis.h b/core/math/basis.h index 56f6227313..2889a4aa5e 100644 --- a/core/math/basis.h +++ b/core/math/basis.h @@ -31,7 +31,7 @@ #ifndef BASIS_H #define BASIS_H -#include "core/math/quat.h" +#include "core/math/quaternion.h" #include "core/math/vector3.h" class Basis { @@ -79,13 +79,13 @@ public: void rotate(const Vector3 &p_euler); Basis rotated(const Vector3 &p_euler) const; - void rotate(const Quat &p_quat); - Basis rotated(const Quat &p_quat) const; + void rotate(const Quaternion &p_quaternion); + Basis rotated(const Quaternion &p_quaternion) const; Vector3 get_rotation_euler() const; void get_rotation_axis_angle(Vector3 &p_axis, real_t &p_angle) const; void get_rotation_axis_angle_local(Vector3 &p_axis, real_t &p_angle) const; - Quat get_rotation_quat() const; + Quaternion get_rotation_quaternion() const; Vector3 get_rotation() const { return get_rotation_euler(); }; Vector3 rotref_posscale_decomposition(Basis &rotref) const; @@ -108,8 +108,8 @@ public: Vector3 get_euler_zyx() const; void set_euler_zyx(const Vector3 &p_euler); - Quat get_quat() const; - void set_quat(const Quat &p_quat); + Quaternion get_quaternion() const; + void set_quaternion(const Quaternion &p_quaternion); Vector3 get_euler() const { return get_euler_yxz(); } void set_euler(const Vector3 &p_euler) { set_euler_yxz(p_euler); } @@ -132,7 +132,7 @@ public: void set_axis_angle_scale(const Vector3 &p_axis, real_t p_phi, const Vector3 &p_scale); void set_euler_scale(const Vector3 &p_euler, const Vector3 &p_scale); - void set_quat_scale(const Quat &p_quat, const Vector3 &p_scale); + void set_quaternion_scale(const Quaternion &p_quaternion, const Vector3 &p_scale); // transposed dot products _FORCE_INLINE_ real_t tdotx(const Vector3 &v) const { @@ -158,8 +158,8 @@ public: _FORCE_INLINE_ Basis operator+(const Basis &p_matrix) const; _FORCE_INLINE_ void operator-=(const Basis &p_matrix); _FORCE_INLINE_ Basis operator-(const Basis &p_matrix) const; - _FORCE_INLINE_ void operator*=(real_t p_val); - _FORCE_INLINE_ Basis operator*(real_t p_val) const; + _FORCE_INLINE_ void operator*=(const real_t p_val); + _FORCE_INLINE_ Basis operator*(const real_t p_val) const; int get_orthogonal_index() const; void set_orthogonal_index(int p_index); @@ -240,10 +240,10 @@ public: #endif Basis diagonalize(); - operator Quat() const { return get_quat(); } + operator Quaternion() const { return get_quaternion(); } - Basis(const Quat &p_quat) { set_quat(p_quat); }; - Basis(const Quat &p_quat, const Vector3 &p_scale) { set_quat_scale(p_quat, p_scale); } + Basis(const Quaternion &p_quaternion) { set_quaternion(p_quaternion); }; + Basis(const Quaternion &p_quaternion, const Vector3 &p_scale) { set_quaternion_scale(p_quaternion, p_scale); } Basis(const Vector3 &p_euler) { set_euler(p_euler); } Basis(const Vector3 &p_euler, const Vector3 &p_scale) { set_euler_scale(p_euler, p_scale); } @@ -298,13 +298,13 @@ _FORCE_INLINE_ Basis Basis::operator-(const Basis &p_matrix) const { return ret; } -_FORCE_INLINE_ void Basis::operator*=(real_t p_val) { +_FORCE_INLINE_ void Basis::operator*=(const real_t p_val) { elements[0] *= p_val; elements[1] *= p_val; elements[2] *= p_val; } -_FORCE_INLINE_ Basis Basis::operator*(real_t p_val) const { +_FORCE_INLINE_ Basis Basis::operator*(const real_t p_val) const { Basis ret(*this); ret *= p_val; return ret; diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index 1066cf5e30..66c18f7b3c 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -315,8 +315,8 @@ Vector2 CameraMatrix::get_far_plane_half_extents() const { return Vector2(res.x, res.y); } -bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const { - Vector<Plane> planes = get_projection_planes(Transform()); +bool CameraMatrix::get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const { + Vector<Plane> planes = get_projection_planes(Transform3D()); const Planes intersections[8][3] = { { PLANE_FAR, PLANE_LEFT, PLANE_TOP }, { PLANE_FAR, PLANE_LEFT, PLANE_BOTTOM }, @@ -338,7 +338,7 @@ bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8point return true; } -Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const { +Vector<Plane> CameraMatrix::get_projection_planes(const Transform3D &p_transform) const { /** Fast Plane Extraction from combined modelview/projection matrices. * References: * https://web.archive.org/web/20011221205252/http://www.markmorley.com/opengl/frustumculling.html @@ -707,8 +707,8 @@ void CameraMatrix::scale_translate_to_fit(const AABB &p_aabb) { matrix[3][3] = 1; } -CameraMatrix::operator Transform() const { - Transform tr; +CameraMatrix::operator Transform3D() const { + Transform3D tr; const real_t *m = &matrix[0][0]; tr.basis.elements[0][0] = m[0]; @@ -730,8 +730,8 @@ CameraMatrix::operator Transform() const { return tr; } -CameraMatrix::CameraMatrix(const Transform &p_transform) { - const Transform &tr = p_transform; +CameraMatrix::CameraMatrix(const Transform3D &p_transform) { + const Transform3D &tr = p_transform; real_t *m = &matrix[0][0]; m[0] = tr.basis.elements[0][0]; diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h index 3f327d3bc4..786d46055a 100644 --- a/core/math/camera_matrix.h +++ b/core/math/camera_matrix.h @@ -32,7 +32,7 @@ #define CAMERA_MATRIX_H #include "core/math/rect2.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" struct CameraMatrix { enum Planes { @@ -71,9 +71,9 @@ struct CameraMatrix { real_t get_fov() const; bool is_orthogonal() const; - Vector<Plane> get_projection_planes(const Transform &p_transform) const; + Vector<Plane> get_projection_planes(const Transform3D &p_transform) const; - bool get_endpoints(const Transform &p_transform, Vector3 *p_8points) const; + bool get_endpoints(const Transform3D &p_transform, Vector3 *p_8points) const; Vector2 get_viewport_half_extents() const; Vector2 get_far_plane_half_extents() const; @@ -90,7 +90,7 @@ struct CameraMatrix { void scale_translate_to_fit(const AABB &p_aabb); void make_scale(const Vector3 &p_scale); int get_pixels_per_meter(int p_for_pixel_width) const; - operator Transform() const; + operator Transform3D() const; void flip_y(); @@ -112,7 +112,7 @@ struct CameraMatrix { float get_lod_multiplier() const; CameraMatrix(); - CameraMatrix(const Transform &p_transform); + CameraMatrix(const Transform3D &p_transform); ~CameraMatrix(); }; diff --git a/core/math/color.cpp b/core/math/color.cpp index 52f029ef4b..dc86cacf8f 100644 --- a/core/math/color.cpp +++ b/core/math/color.cpp @@ -368,7 +368,7 @@ Color Color::named(const String &p_name) { ERR_FAIL_V_MSG(Color(), "Invalid color name: " + p_name + "."); return Color(); } - return get_named_color(idx); + return named_colors[idx].color; } Color Color::named(const String &p_name, const Color &p_default) { @@ -376,7 +376,7 @@ Color Color::named(const String &p_name, const Color &p_default) { if (idx == -1) { return p_default; } - return get_named_color(idx); + return named_colors[idx].color; } int Color::find_named_color(const String &p_name) { @@ -409,10 +409,12 @@ int Color::get_named_color_count() { } String Color::get_named_color_name(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), ""); return named_colors[p_idx].name; } Color Color::get_named_color(int p_idx) { + ERR_FAIL_INDEX_V(p_idx, get_named_color_count(), Color()); return named_colors[p_idx].color; } @@ -466,7 +468,7 @@ Color Color::from_hsv(float p_h, float p_s, float p_v, float p_a) const { } Color::operator String() const { - return rtos(r) + ", " + rtos(g) + ", " + rtos(b) + ", " + rtos(a); + return "(" + String::num(r, 4) + ", " + String::num(g, 4) + ", " + String::num(b, 4) + ", " + String::num(a, 4) + ")"; } Color Color::operator+(const Color &p_color) const { diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 25cc1125db..6f7209556e 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -31,10 +31,10 @@ #ifndef DELAUNAY_3D_H #define DELAUNAY_3D_H +#include "core/io/file_access.h" #include "core/math/aabb.h" #include "core/math/camera_matrix.h" #include "core/math/vector3.h" -#include "core/os/file_access.h" #include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/oa_hash_map.h" diff --git a/core/math/expression.cpp b/core/math/expression.cpp index f7ac44d321..0146c345f0 100644 --- a/core/math/expression.cpp +++ b/core/math/expression.cpp @@ -33,7 +33,7 @@ #include "core/io/marshalls.h" #include "core/math/math_funcs.h" #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" diff --git a/core/math/expression.h b/core/math/expression.h index a6b288ed6e..aecf662d0a 100644 --- a/core/math/expression.h +++ b/core/math/expression.h @@ -31,10 +31,10 @@ #ifndef EXPRESSION_H #define EXPRESSION_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class Expression : public Reference { - GDCLASS(Expression, Reference); +class Expression : public RefCounted { + GDCLASS(Expression, RefCounted); private: struct Input { diff --git a/core/math/face3.cpp b/core/math/face3.cpp index 20c316c322..9af3f868d2 100644 --- a/core/math/face3.cpp +++ b/core/math/face3.cpp @@ -230,7 +230,7 @@ bool Face3::intersects_aabb(const AABB &p_aabb) const { real_t minA, maxA, minB, maxB; p_aabb.project_range_in_plane(Plane(axis, 0), minA, maxA); - project_range(axis, Transform(), minB, maxB); + project_range(axis, Transform3D(), minB, maxB); if (maxA < minB || maxB < minA) { return false; @@ -244,7 +244,7 @@ Face3::operator String() const { return String() + vertex[0] + ", " + vertex[1] + ", " + vertex[2]; } -void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void Face3::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { for (int i = 0; i < 3; i++) { Vector3 v = p_transform.xform(vertex[i]); real_t d = p_normal.dot(v); @@ -259,7 +259,7 @@ void Face3::project_range(const Vector3 &p_normal, const Transform &p_transform, } } -void Face3::get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { +void Face3::get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const { #define _FACE_IS_VALID_SUPPORT_THRESHOLD 0.98 #define _EDGE_IS_VALID_SUPPORT_THRESHOLD 0.05 diff --git a/core/math/face3.h b/core/math/face3.h index 2e86b0a904..5091b338ef 100644 --- a/core/math/face3.h +++ b/core/math/face3.h @@ -33,7 +33,7 @@ #include "core/math/aabb.h" #include "core/math/plane.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" class Face3 { @@ -74,8 +74,8 @@ public: ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity - void get_support(const Vector3 &p_normal, const Transform &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; - void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const; + void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; AABB get_aabb() const { AABB aabb(vertex[0], Vector3()); diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index 4958b5ac6a..a2894bc1d3 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -362,6 +362,19 @@ public: return (intersections & 1); } + static bool is_segment_intersecting_polygon(const Vector2 &p_from, const Vector2 &p_to, const Vector<Vector2> &p_polygon) { + int c = p_polygon.size(); + const Vector2 *p = p_polygon.ptr(); + for (int i = 0; i < c; i++) { + const Vector2 &v1 = p[i]; + const Vector2 &v2 = p[(i + 1) % c]; + if (segment_intersects_segment(p_from, p_to, v1, v2, nullptr)) { + return true; + } + } + return false; + } + static real_t vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B) { return (real_t)(A.x - O.x) * (B.y - O.y) - (real_t)(A.y - O.y) * (B.x - O.x); } diff --git a/core/math/math_fieldwise.cpp b/core/math/math_fieldwise.cpp index 0985a727f2..570c57e254 100644 --- a/core/math/math_fieldwise.cpp +++ b/core/math/math_fieldwise.cpp @@ -88,8 +88,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } - case Variant::QUAT: { - SETUP_TYPE(Quat) + case Variant::QUATERNION: { + SETUP_TYPE(Quaternion) /**/ TRY_TRANSFER_FIELD("x", x) else TRY_TRANSFER_FIELD("y", y) @@ -141,8 +141,8 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const return target; } - case Variant::TRANSFORM: { - SETUP_TYPE(Transform) + case Variant::TRANSFORM3D: { + SETUP_TYPE(Transform3D) /**/ TRY_TRANSFER_FIELD("xx", basis.elements[0][0]) else TRY_TRANSFER_FIELD("xy", basis.elements[0][1]) diff --git a/core/math/plane.cpp b/core/math/plane.cpp index f1d3bbbd54..3c78b55b90 100644 --- a/core/math/plane.cpp +++ b/core/math/plane.cpp @@ -175,5 +175,5 @@ bool Plane::is_equal_approx(const Plane &p_plane) const { } Plane::operator String() const { - return normal.operator String() + ", " + rtos(d); + return "[N: " + normal.operator String() + ", D: " + String::num_real(d, false) + "]"; } diff --git a/core/math/quat.cpp b/core/math/quaternion.cpp index 3982a0b993..3f1d2c58e5 100644 --- a/core/math/quat.cpp +++ b/core/math/quaternion.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.cpp */ +/* quaternion.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "quat.h" +#include "quaternion.h" #include "core/math/basis.h" #include "core/string/print_string.h" +real_t Quaternion::angle_to(const Quaternion &p_to) const { + real_t d = dot(p_to); + return Math::acos(CLAMP(d * d * 2 - 1, -1, 1)); +} + // get_euler_xyz returns a vector containing the Euler angles in the format // (ax,ay,az), where ax is the angle of rotation around x axis, // and similar for other axes. // This implementation uses XYZ convention (Z is the first rotation). -Vector3 Quat::get_euler_xyz() const { +Vector3 Quaternion::get_euler_xyz() const { Basis m(*this); return m.get_euler_xyz(); } @@ -46,7 +51,7 @@ Vector3 Quat::get_euler_xyz() const { // (ax,ay,az), where ax is the angle of rotation around x axis, // and similar for other axes. // This implementation uses YXZ convention (Z is the first rotation). -Vector3 Quat::get_euler_yxz() const { +Vector3 Quaternion::get_euler_yxz() const { #ifdef MATH_CHECKS ERR_FAIL_COND_V_MSG(!is_normalized(), Vector3(0, 0, 0), "The quaternion must be normalized."); #endif @@ -54,7 +59,7 @@ Vector3 Quat::get_euler_yxz() const { return m.get_euler_yxz(); } -void Quat::operator*=(const Quat &p_q) { +void Quaternion::operator*=(const Quaternion &p_q) { real_t xx = w * p_q.x + x * p_q.w + y * p_q.z - z * p_q.y; real_t yy = w * p_q.y + y * p_q.w + z * p_q.x - x * p_q.z; real_t zz = w * p_q.z + z * p_q.w + x * p_q.y - y * p_q.x; @@ -64,45 +69,45 @@ void Quat::operator*=(const Quat &p_q) { z = zz; } -Quat Quat::operator*(const Quat &p_q) const { - Quat r = *this; +Quaternion Quaternion::operator*(const Quaternion &p_q) const { + Quaternion r = *this; r *= p_q; return r; } -bool Quat::is_equal_approx(const Quat &p_quat) const { - return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w); +bool Quaternion::is_equal_approx(const Quaternion &p_quaternion) const { + return Math::is_equal_approx(x, p_quaternion.x) && Math::is_equal_approx(y, p_quaternion.y) && Math::is_equal_approx(z, p_quaternion.z) && Math::is_equal_approx(w, p_quaternion.w); } -real_t Quat::length() const { +real_t Quaternion::length() const { return Math::sqrt(length_squared()); } -void Quat::normalize() { +void Quaternion::normalize() { *this /= length(); } -Quat Quat::normalized() const { +Quaternion Quaternion::normalized() const { return *this / length(); } -bool Quat::is_normalized() const { +bool Quaternion::is_normalized() const { return Math::is_equal_approx(length_squared(), 1, (real_t)UNIT_EPSILON); //use less epsilon } -Quat Quat::inverse() const { +Quaternion Quaternion::inverse() const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The quaternion must be normalized."); #endif - return Quat(-x, -y, -z, w); + return Quaternion(-x, -y, -z, w); } -Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { +Quaternion Quaternion::slerp(const Quaternion &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - Quat to1; + Quaternion to1; real_t omega, cosom, sinom, scale0, scale1; // calc cosine @@ -137,19 +142,19 @@ Quat Quat::slerp(const Quat &p_to, const real_t &p_weight) const { scale1 = p_weight; } // calculate final values - return Quat( + return Quaternion( scale0 * x + scale1 * to1.x, scale0 * y + scale1 * to1.y, scale0 * z + scale1 * to1.z, scale0 * w + scale1 * to1.w); } -Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { +Quaternion Quaternion::slerpni(const Quaternion &p_to, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_to.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif - const Quat &from = *this; + const Quaternion &from = *this; real_t dot = from.dot(p_to); @@ -162,29 +167,29 @@ Quat Quat::slerpni(const Quat &p_to, const real_t &p_weight) const { newFactor = Math::sin(p_weight * theta) * sinT, invFactor = Math::sin((1.0 - p_weight) * theta) * sinT; - return Quat(invFactor * from.x + newFactor * p_to.x, + return Quaternion(invFactor * from.x + newFactor * p_to.x, invFactor * from.y + newFactor * p_to.y, invFactor * from.z + newFactor * p_to.z, invFactor * from.w + newFactor * p_to.w); } -Quat Quat::cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const { +Quaternion Quaternion::cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const { #ifdef MATH_CHECKS - ERR_FAIL_COND_V_MSG(!is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quat(), "The end quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!p_b.is_normalized(), Quaternion(), "The end quaternion must be normalized."); #endif //the only way to do slerp :| real_t t2 = (1.0 - p_weight) * p_weight * 2; - Quat sp = this->slerp(p_b, p_weight); - Quat sq = p_pre_a.slerpni(p_post_b, p_weight); + Quaternion sp = this->slerp(p_b, p_weight); + Quaternion sq = p_pre_a.slerpni(p_post_b, p_weight); return sp.slerpni(sq, t2); } -Quat::operator String() const { - return String::num(x) + ", " + String::num(y) + ", " + String::num(z) + ", " + String::num(w); +Quaternion::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ", " + String::num_real(w, false) + ")"; } -Quat::Quat(const Vector3 &p_axis, real_t p_angle) { +Quaternion::Quaternion(const Vector3 &p_axis, real_t p_angle) { #ifdef MATH_CHECKS ERR_FAIL_COND_MSG(!p_axis.is_normalized(), "The axis Vector3 must be normalized."); #endif @@ -209,7 +214,7 @@ Quat::Quat(const Vector3 &p_axis, real_t p_angle) { // (ax, ay, az), where ax is the angle of rotation around x axis, // and similar for other axes. // This implementation uses YXZ convention (Z is the first rotation). -Quat::Quat(const Vector3 &p_euler) { +Quaternion::Quaternion(const Vector3 &p_euler) { real_t half_a1 = p_euler.y * 0.5; real_t half_a2 = p_euler.x * 0.5; real_t half_a3 = p_euler.z * 0.5; diff --git a/core/math/quat.h b/core/math/quaternion.h index d9b130c050..35324323b3 100644 --- a/core/math/quat.h +++ b/core/math/quaternion.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.h */ +/* quaternion.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,15 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef QUAT_H -#define QUAT_H +#ifndef QUATERNION_H +#define QUATERNION_H #include "core/math/math_defs.h" #include "core/math/math_funcs.h" #include "core/math/vector3.h" #include "core/string/ustring.h" -class Quat { +class Quaternion { public: union { struct { @@ -55,21 +55,22 @@ public: return components[idx]; } _FORCE_INLINE_ real_t length_squared() const; - bool is_equal_approx(const Quat &p_quat) const; + bool is_equal_approx(const Quaternion &p_quaternion) const; real_t length() const; void normalize(); - Quat normalized() const; + Quaternion normalized() const; bool is_normalized() const; - Quat inverse() const; - _FORCE_INLINE_ real_t dot(const Quat &p_q) const; + Quaternion inverse() const; + _FORCE_INLINE_ real_t dot(const Quaternion &p_q) const; + real_t angle_to(const Quaternion &p_to) const; Vector3 get_euler_xyz() const; Vector3 get_euler_yxz() const; Vector3 get_euler() const { return get_euler_yxz(); }; - Quat slerp(const Quat &p_to, const real_t &p_weight) const; - Quat slerpni(const Quat &p_to, const real_t &p_weight) const; - Quat cubic_slerp(const Quat &p_b, const Quat &p_pre_a, const Quat &p_post_b, const real_t &p_weight) const; + Quaternion slerp(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion slerpni(const Quaternion &p_to, const real_t &p_weight) const; + Quaternion cubic_slerp(const Quaternion &p_b, const Quaternion &p_pre_a, const Quaternion &p_post_b, const real_t &p_weight) const; _FORCE_INLINE_ void get_axis_angle(Vector3 &r_axis, real_t &r_angle) const { r_angle = 2 * Math::acos(w); @@ -79,11 +80,11 @@ public: r_axis.z = z * r; } - void operator*=(const Quat &p_q); - Quat operator*(const Quat &p_q) const; + void operator*=(const Quaternion &p_q); + Quaternion operator*(const Quaternion &p_q) const; - Quat operator*(const Vector3 &v) const { - return Quat(w * v.x + y * v.z - z * v.y, + Quaternion operator*(const Vector3 &v) const { + return Quaternion(w * v.x + y * v.z - z * v.y, w * v.y + z * v.x - x * v.z, w * v.z + x * v.y - y * v.x, -x * v.x - y * v.y - z * v.z); @@ -102,42 +103,42 @@ public: return inverse().xform(v); } - _FORCE_INLINE_ void operator+=(const Quat &p_q); - _FORCE_INLINE_ void operator-=(const Quat &p_q); + _FORCE_INLINE_ void operator+=(const Quaternion &p_q); + _FORCE_INLINE_ void operator-=(const Quaternion &p_q); _FORCE_INLINE_ void operator*=(const real_t &s); _FORCE_INLINE_ void operator/=(const real_t &s); - _FORCE_INLINE_ Quat operator+(const Quat &q2) const; - _FORCE_INLINE_ Quat operator-(const Quat &q2) const; - _FORCE_INLINE_ Quat operator-() const; - _FORCE_INLINE_ Quat operator*(const real_t &s) const; - _FORCE_INLINE_ Quat operator/(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator+(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-(const Quaternion &q2) const; + _FORCE_INLINE_ Quaternion operator-() const; + _FORCE_INLINE_ Quaternion operator*(const real_t &s) const; + _FORCE_INLINE_ Quaternion operator/(const real_t &s) const; - _FORCE_INLINE_ bool operator==(const Quat &p_quat) const; - _FORCE_INLINE_ bool operator!=(const Quat &p_quat) const; + _FORCE_INLINE_ bool operator==(const Quaternion &p_quaternion) const; + _FORCE_INLINE_ bool operator!=(const Quaternion &p_quaternion) const; operator String() const; - _FORCE_INLINE_ Quat() {} + _FORCE_INLINE_ Quaternion() {} - _FORCE_INLINE_ Quat(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : + _FORCE_INLINE_ Quaternion(real_t p_x, real_t p_y, real_t p_z, real_t p_w) : x(p_x), y(p_y), z(p_z), w(p_w) { } - Quat(const Vector3 &p_axis, real_t p_angle); + Quaternion(const Vector3 &p_axis, real_t p_angle); - Quat(const Vector3 &p_euler); + Quaternion(const Vector3 &p_euler); - Quat(const Quat &p_q) : + Quaternion(const Quaternion &p_q) : x(p_q.x), y(p_q.y), z(p_q.z), w(p_q.w) { } - Quat &operator=(const Quat &p_q) { + Quaternion &operator=(const Quaternion &p_q) { x = p_q.x; y = p_q.y; z = p_q.z; @@ -145,7 +146,7 @@ public: return *this; } - Quat(const Vector3 &v0, const Vector3 &v1) // shortest arc + Quaternion(const Vector3 &v0, const Vector3 &v1) // shortest arc { Vector3 c = v0.cross(v1); real_t d = v0.dot(v1); @@ -167,72 +168,72 @@ public: } }; -real_t Quat::dot(const Quat &p_q) const { +real_t Quaternion::dot(const Quaternion &p_q) const { return x * p_q.x + y * p_q.y + z * p_q.z + w * p_q.w; } -real_t Quat::length_squared() const { +real_t Quaternion::length_squared() const { return dot(*this); } -void Quat::operator+=(const Quat &p_q) { +void Quaternion::operator+=(const Quaternion &p_q) { x += p_q.x; y += p_q.y; z += p_q.z; w += p_q.w; } -void Quat::operator-=(const Quat &p_q) { +void Quaternion::operator-=(const Quaternion &p_q) { x -= p_q.x; y -= p_q.y; z -= p_q.z; w -= p_q.w; } -void Quat::operator*=(const real_t &s) { +void Quaternion::operator*=(const real_t &s) { x *= s; y *= s; z *= s; w *= s; } -void Quat::operator/=(const real_t &s) { +void Quaternion::operator/=(const real_t &s) { *this *= 1.0 / s; } -Quat Quat::operator+(const Quat &q2) const { - const Quat &q1 = *this; - return Quat(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); +Quaternion Quaternion::operator+(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x + q2.x, q1.y + q2.y, q1.z + q2.z, q1.w + q2.w); } -Quat Quat::operator-(const Quat &q2) const { - const Quat &q1 = *this; - return Quat(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); +Quaternion Quaternion::operator-(const Quaternion &q2) const { + const Quaternion &q1 = *this; + return Quaternion(q1.x - q2.x, q1.y - q2.y, q1.z - q2.z, q1.w - q2.w); } -Quat Quat::operator-() const { - const Quat &q2 = *this; - return Quat(-q2.x, -q2.y, -q2.z, -q2.w); +Quaternion Quaternion::operator-() const { + const Quaternion &q2 = *this; + return Quaternion(-q2.x, -q2.y, -q2.z, -q2.w); } -Quat Quat::operator*(const real_t &s) const { - return Quat(x * s, y * s, z * s, w * s); +Quaternion Quaternion::operator*(const real_t &s) const { + return Quaternion(x * s, y * s, z * s, w * s); } -Quat Quat::operator/(const real_t &s) const { +Quaternion Quaternion::operator/(const real_t &s) const { return *this * (1.0 / s); } -bool Quat::operator==(const Quat &p_quat) const { - return x == p_quat.x && y == p_quat.y && z == p_quat.z && w == p_quat.w; +bool Quaternion::operator==(const Quaternion &p_quaternion) const { + return x == p_quaternion.x && y == p_quaternion.y && z == p_quaternion.z && w == p_quaternion.w; } -bool Quat::operator!=(const Quat &p_quat) const { - return x != p_quat.x || y != p_quat.y || z != p_quat.z || w != p_quat.w; +bool Quaternion::operator!=(const Quaternion &p_quaternion) const { + return x != p_quaternion.x || y != p_quaternion.y || z != p_quaternion.z || w != p_quaternion.w; } -_FORCE_INLINE_ Quat operator*(const real_t &p_real, const Quat &p_quat) { - return p_quat * p_real; +_FORCE_INLINE_ Quaternion operator*(const real_t &p_real, const Quaternion &p_quaternion) { + return p_quaternion * p_real; } -#endif // QUAT_H +#endif // QUATERNION_H diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp index fe18cc3d41..0d77bfe933 100644 --- a/core/math/quick_hull.cpp +++ b/core/math/quick_hull.cpp @@ -112,7 +112,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry3D::MeshData &r_ } } - //fourth vertex is the one most further away from the plane + //fourth vertex is the one most further away from the plane { real_t maxd = 0; diff --git a/core/math/random_number_generator.h b/core/math/random_number_generator.h index a396c2b7d7..06cd3999f3 100644 --- a/core/math/random_number_generator.h +++ b/core/math/random_number_generator.h @@ -32,10 +32,10 @@ #define RANDOM_NUMBER_GENERATOR_H #include "core/math/random_pcg.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class RandomNumberGenerator : public Reference { - GDCLASS(RandomNumberGenerator, Reference); +class RandomNumberGenerator : public RefCounted { + GDCLASS(RandomNumberGenerator, RefCounted); protected: RandomPCG randbase; diff --git a/core/math/rect2.cpp b/core/math/rect2.cpp index 60c44999f7..f64bf560c8 100644 --- a/core/math/rect2.cpp +++ b/core/math/rect2.cpp @@ -263,3 +263,11 @@ next4: return true; } + +Rect2::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} + +Rect2i::operator String() const { + return "[P: " + position.operator String() + ", S: " + size + "]"; +} diff --git a/core/math/rect2.h b/core/math/rect2.h index 1dc027cf72..ab0b489b4a 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -320,7 +320,7 @@ struct Rect2 { return position + size; } - operator String() const { return String(position) + ", " + String(size); } + operator String() const; Rect2() {} Rect2(real_t p_x, real_t p_y, real_t p_width, real_t p_height) : @@ -498,7 +498,7 @@ struct Rect2i { return position + size; } - operator String() const { return String(position) + ", " + String(size); } + operator String() const; operator Rect2() const { return Rect2(position, size); } diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp index 4a521b96ae..16934d67df 100644 --- a/core/math/transform_2d.cpp +++ b/core/math/transform_2d.cpp @@ -158,6 +158,13 @@ bool Transform2D::is_equal_approx(const Transform2D &p_transform) const { return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]); } +Transform2D Transform2D::looking_at(const Vector2 &p_target) const { + Transform2D return_trans = Transform2D(get_rotation(), get_origin()); + Vector2 target_position = affine_inverse().xform(p_target); + return_trans.set_rotation(return_trans.get_rotation() + (target_position * get_scale()).angle()); + return return_trans; +} + bool Transform2D::operator==(const Transform2D &p_transform) const { for (int i = 0; i < 3; i++) { if (elements[i] != p_transform.elements[i]) { @@ -269,6 +276,20 @@ Transform2D Transform2D::interpolate_with(const Transform2D &p_transform, real_t return res; } +void Transform2D::operator*=(const real_t p_val) { + elements[0] *= p_val; + elements[1] *= p_val; + elements[2] *= p_val; +} + +Transform2D Transform2D::operator*(const real_t p_val) const { + Transform2D ret(*this); + ret *= p_val; + return ret; +} + Transform2D::operator String() const { - return String(String() + elements[0] + ", " + elements[1] + ", " + elements[2]); + return "[X: " + elements[0].operator String() + + ", Y: " + elements[1].operator String() + + ", O: " + elements[2].operator String() + "]"; } diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h index 327d0f244f..34cfd0c1a9 100644 --- a/core/math/transform_2d.h +++ b/core/math/transform_2d.h @@ -100,11 +100,15 @@ struct Transform2D { Transform2D orthonormalized() const; bool is_equal_approx(const Transform2D &p_transform) const; + Transform2D looking_at(const Vector2 &p_target) const; + bool operator==(const Transform2D &p_transform) const; bool operator!=(const Transform2D &p_transform) const; void operator*=(const Transform2D &p_transform); Transform2D operator*(const Transform2D &p_transform) const; + void operator*=(const real_t p_val); + Transform2D operator*(const real_t p_val) const; Transform2D interpolate_with(const Transform2D &p_transform, real_t p_c) const; diff --git a/core/math/transform.cpp b/core/math/transform_3d.cpp index d4d7ff6d28..51766b39f4 100644 --- a/core/math/transform.cpp +++ b/core/math/transform_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.cpp */ +/* transform_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,54 +28,54 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "transform.h" +#include "transform_3d.h" #include "core/math/math_funcs.h" #include "core/string/print_string.h" -void Transform::affine_invert() { +void Transform3D::affine_invert() { basis.invert(); origin = basis.xform(-origin); } -Transform Transform::affine_inverse() const { - Transform ret = *this; +Transform3D Transform3D::affine_inverse() const { + Transform3D ret = *this; ret.affine_invert(); return ret; } -void Transform::invert() { +void Transform3D::invert() { basis.transpose(); origin = basis.xform(-origin); } -Transform Transform::inverse() const { +Transform3D Transform3D::inverse() const { // FIXME: this function assumes the basis is a rotation matrix, with no scaling. - // Transform::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. - Transform ret = *this; + // Transform3D::affine_inverse can handle matrices with scaling, so GDScript should eventually use that. + Transform3D ret = *this; ret.invert(); return ret; } -void Transform::rotate(const Vector3 &p_axis, real_t p_phi) { +void Transform3D::rotate(const Vector3 &p_axis, real_t p_phi) { *this = rotated(p_axis, p_phi); } -Transform Transform::rotated(const Vector3 &p_axis, real_t p_phi) const { - return Transform(Basis(p_axis, p_phi), Vector3()) * (*this); +Transform3D Transform3D::rotated(const Vector3 &p_axis, real_t p_phi) const { + return Transform3D(Basis(p_axis, p_phi), Vector3()) * (*this); } -void Transform::rotate_basis(const Vector3 &p_axis, real_t p_phi) { +void Transform3D::rotate_basis(const Vector3 &p_axis, real_t p_phi) { basis.rotate(p_axis, p_phi); } -Transform Transform::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { - Transform t = *this; +Transform3D Transform3D::looking_at(const Vector3 &p_target, const Vector3 &p_up) const { + Transform3D t = *this; t.set_look_at(origin, p_target, p_up); return t; } -void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { +void Transform3D::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up) { #ifdef MATH_CHECKS ERR_FAIL_COND(p_eye == p_target); ERR_FAIL_COND(p_up.length() == 0); @@ -108,105 +108,119 @@ void Transform::set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const origin = p_eye; } -Transform Transform::interpolate_with(const Transform &p_transform, real_t p_c) const { +Transform3D Transform3D::interpolate_with(const Transform3D &p_transform, real_t p_c) const { /* not sure if very "efficient" but good enough? */ Vector3 src_scale = basis.get_scale(); - Quat src_rot = basis.get_rotation_quat(); + Quaternion src_rot = basis.get_rotation_quaternion(); Vector3 src_loc = origin; Vector3 dst_scale = p_transform.basis.get_scale(); - Quat dst_rot = p_transform.basis.get_rotation_quat(); + Quaternion dst_rot = p_transform.basis.get_rotation_quaternion(); Vector3 dst_loc = p_transform.origin; - Transform interp; - interp.basis.set_quat_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); + Transform3D interp; + interp.basis.set_quaternion_scale(src_rot.slerp(dst_rot, p_c).normalized(), src_scale.lerp(dst_scale, p_c)); interp.origin = src_loc.lerp(dst_loc, p_c); return interp; } -void Transform::scale(const Vector3 &p_scale) { +void Transform3D::scale(const Vector3 &p_scale) { basis.scale(p_scale); origin *= p_scale; } -Transform Transform::scaled(const Vector3 &p_scale) const { - Transform t = *this; +Transform3D Transform3D::scaled(const Vector3 &p_scale) const { + Transform3D t = *this; t.scale(p_scale); return t; } -void Transform::scale_basis(const Vector3 &p_scale) { +void Transform3D::scale_basis(const Vector3 &p_scale) { basis.scale(p_scale); } -void Transform::translate(real_t p_tx, real_t p_ty, real_t p_tz) { +void Transform3D::translate(real_t p_tx, real_t p_ty, real_t p_tz) { translate(Vector3(p_tx, p_ty, p_tz)); } -void Transform::translate(const Vector3 &p_translation) { +void Transform3D::translate(const Vector3 &p_translation) { for (int i = 0; i < 3; i++) { origin[i] += basis[i].dot(p_translation); } } -Transform Transform::translated(const Vector3 &p_translation) const { - Transform t = *this; +Transform3D Transform3D::translated(const Vector3 &p_translation) const { + Transform3D t = *this; t.translate(p_translation); return t; } -void Transform::orthonormalize() { +void Transform3D::orthonormalize() { basis.orthonormalize(); } -Transform Transform::orthonormalized() const { - Transform _copy = *this; +Transform3D Transform3D::orthonormalized() const { + Transform3D _copy = *this; _copy.orthonormalize(); return _copy; } -bool Transform::is_equal_approx(const Transform &p_transform) const { +bool Transform3D::is_equal_approx(const Transform3D &p_transform) const { return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin); } -bool Transform::operator==(const Transform &p_transform) const { +bool Transform3D::operator==(const Transform3D &p_transform) const { return (basis == p_transform.basis && origin == p_transform.origin); } -bool Transform::operator!=(const Transform &p_transform) const { +bool Transform3D::operator!=(const Transform3D &p_transform) const { return (basis != p_transform.basis || origin != p_transform.origin); } -void Transform::operator*=(const Transform &p_transform) { +void Transform3D::operator*=(const Transform3D &p_transform) { origin = xform(p_transform.origin); basis *= p_transform.basis; } -Transform Transform::operator*(const Transform &p_transform) const { - Transform t = *this; +Transform3D Transform3D::operator*(const Transform3D &p_transform) const { + Transform3D t = *this; t *= p_transform; return t; } -Transform::operator String() const { - return basis.operator String() + " - " + origin.operator String(); +void Transform3D::operator*=(const real_t p_val) { + origin *= p_val; + basis *= p_val; } -Transform::Transform(const Basis &p_basis, const Vector3 &p_origin) : +Transform3D Transform3D::operator*(const real_t p_val) const { + Transform3D ret(*this); + ret *= p_val; + return ret; +} + +Transform3D::operator String() const { + return "[X: " + basis.get_axis(0).operator String() + + ", Y: " + basis.get_axis(1).operator String() + + ", Z: " + basis.get_axis(2).operator String() + + ", O: " + origin.operator String() + "]"; +} + +Transform3D::Transform3D(const Basis &p_basis, const Vector3 &p_origin) : basis(p_basis), origin(p_origin) { } -Transform::Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : +Transform3D::Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin) : origin(p_origin) { basis.set_axis(0, p_x); basis.set_axis(1, p_y); basis.set_axis(2, p_z); } -Transform::Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { +Transform3D::Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz) { basis = Basis(xx, xy, xz, yx, yy, yz, zx, zy, zz); origin = Vector3(ox, oy, oz); } diff --git a/core/math/transform.h b/core/math/transform_3d.h index 1c05dbe554..3d8e70cec7 100644 --- a/core/math/transform.h +++ b/core/math/transform_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.h */ +/* transform_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -35,31 +35,31 @@ #include "core/math/basis.h" #include "core/math/plane.h" -class Transform { +class Transform3D { public: Basis basis; Vector3 origin; void invert(); - Transform inverse() const; + Transform3D inverse() const; void affine_invert(); - Transform affine_inverse() const; + Transform3D affine_inverse() const; - Transform rotated(const Vector3 &p_axis, real_t p_phi) const; + Transform3D rotated(const Vector3 &p_axis, real_t p_phi) const; void rotate(const Vector3 &p_axis, real_t p_phi); void rotate_basis(const Vector3 &p_axis, real_t p_phi); void set_look_at(const Vector3 &p_eye, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); - Transform looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; + Transform3D looking_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)) const; void scale(const Vector3 &p_scale); - Transform scaled(const Vector3 &p_scale) const; + Transform3D scaled(const Vector3 &p_scale) const; void scale_basis(const Vector3 &p_scale); void translate(real_t p_tx, real_t p_ty, real_t p_tz); void translate(const Vector3 &p_translation); - Transform translated(const Vector3 &p_translation) const; + Transform3D translated(const Vector3 &p_translation) const; const Basis &get_basis() const { return basis; } void set_basis(const Basis &p_basis) { basis = p_basis; } @@ -68,11 +68,11 @@ public: void set_origin(const Vector3 &p_origin) { origin = p_origin; } void orthonormalize(); - Transform orthonormalized() const; - bool is_equal_approx(const Transform &p_transform) const; + Transform3D orthonormalized() const; + bool is_equal_approx(const Transform3D &p_transform) const; - bool operator==(const Transform &p_transform) const; - bool operator!=(const Transform &p_transform) const; + bool operator==(const Transform3D &p_transform) const; + bool operator!=(const Transform3D &p_transform) const; _FORCE_INLINE_ Vector3 xform(const Vector3 &p_vector) const; _FORCE_INLINE_ Vector3 xform_inv(const Vector3 &p_vector) const; @@ -86,14 +86,16 @@ public: _FORCE_INLINE_ Vector<Vector3> xform(const Vector<Vector3> &p_array) const; _FORCE_INLINE_ Vector<Vector3> xform_inv(const Vector<Vector3> &p_array) const; - void operator*=(const Transform &p_transform); - Transform operator*(const Transform &p_transform) const; + void operator*=(const Transform3D &p_transform); + Transform3D operator*(const Transform3D &p_transform) const; + void operator*=(const real_t p_val); + Transform3D operator*(const real_t p_val) const; - Transform interpolate_with(const Transform &p_transform, real_t p_c) const; + Transform3D interpolate_with(const Transform3D &p_transform, real_t p_c) const; - _FORCE_INLINE_ Transform inverse_xform(const Transform &t) const { + _FORCE_INLINE_ Transform3D inverse_xform(const Transform3D &t) const { Vector3 v = t.origin - origin; - return Transform(basis.transpose_xform(t.basis), + return Transform3D(basis.transpose_xform(t.basis), basis.xform(v)); } @@ -106,20 +108,20 @@ public: operator String() const; - Transform() {} - Transform(const Basis &p_basis, const Vector3 &p_origin = Vector3()); - Transform(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); - Transform(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); + Transform3D() {} + Transform3D(const Basis &p_basis, const Vector3 &p_origin = Vector3()); + Transform3D(const Vector3 &p_x, const Vector3 &p_y, const Vector3 &p_z, const Vector3 &p_origin); + Transform3D(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz, real_t ox, real_t oy, real_t oz); }; -_FORCE_INLINE_ Vector3 Transform::xform(const Vector3 &p_vector) const { +_FORCE_INLINE_ Vector3 Transform3D::xform(const Vector3 &p_vector) const { return Vector3( basis[0].dot(p_vector) + origin.x, basis[1].dot(p_vector) + origin.y, basis[2].dot(p_vector) + origin.z); } -_FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { +_FORCE_INLINE_ Vector3 Transform3D::xform_inv(const Vector3 &p_vector) const { Vector3 v = p_vector - origin; return Vector3( @@ -128,7 +130,7 @@ _FORCE_INLINE_ Vector3 Transform::xform_inv(const Vector3 &p_vector) const { (basis.elements[0][2] * v.x) + (basis.elements[1][2] * v.y) + (basis.elements[2][2] * v.z)); } -_FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { +_FORCE_INLINE_ Plane Transform3D::xform(const Plane &p_plane) const { Vector3 point = p_plane.normal * p_plane.d; Vector3 point_dir = point + p_plane.normal; point = xform(point); @@ -141,7 +143,7 @@ _FORCE_INLINE_ Plane Transform::xform(const Plane &p_plane) const { return Plane(normal, d); } -_FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { +_FORCE_INLINE_ Plane Transform3D::xform_inv(const Plane &p_plane) const { Vector3 point = p_plane.normal * p_plane.d; Vector3 point_dir = point + p_plane.normal; point = xform_inv(point); @@ -154,7 +156,7 @@ _FORCE_INLINE_ Plane Transform::xform_inv(const Plane &p_plane) const { return Plane(normal, d); } -_FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { +_FORCE_INLINE_ AABB Transform3D::xform(const AABB &p_aabb) const { /* http://dev.theomader.com/transform-bounding-boxes/ */ Vector3 min = p_aabb.position; Vector3 max = p_aabb.position + p_aabb.size; @@ -179,7 +181,7 @@ _FORCE_INLINE_ AABB Transform::xform(const AABB &p_aabb) const { return r_aabb; } -_FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { +_FORCE_INLINE_ AABB Transform3D::xform_inv(const AABB &p_aabb) const { /* define vertices */ Vector3 vertices[8] = { Vector3(p_aabb.position.x + p_aabb.size.x, p_aabb.position.y + p_aabb.size.y, p_aabb.position.z + p_aabb.size.z), @@ -203,7 +205,7 @@ _FORCE_INLINE_ AABB Transform::xform_inv(const AABB &p_aabb) const { return ret; } -Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const { +Vector<Vector3> Transform3D::xform(const Vector<Vector3> &p_array) const { Vector<Vector3> array; array.resize(p_array.size()); @@ -216,7 +218,7 @@ Vector<Vector3> Transform::xform(const Vector<Vector3> &p_array) const { return array; } -Vector<Vector3> Transform::xform_inv(const Vector<Vector3> &p_array) const { +Vector<Vector3> Transform3D::xform_inv(const Vector<Vector3> &p_array) const { Vector<Vector3> array; array.resize(p_array.size()); diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp index 23c0c686a2..903d5951a8 100644 --- a/core/math/triangle_mesh.cpp +++ b/core/math/triangle_mesh.cpp @@ -600,7 +600,7 @@ bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *vertexptr = vertices.ptr(); const BVH *bvhptr = bvh.ptr(); - Transform scale(Basis().scaled(p_scale)); + Transform3D scale(Basis().scaled(p_scale)); int pos = bvh.size() - 1; diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h index 1d1dbc114b..463b0dd5c8 100644 --- a/core/math/triangle_mesh.h +++ b/core/math/triangle_mesh.h @@ -32,10 +32,10 @@ #define TRIANGLE_MESH_H #include "core/math/face3.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class TriangleMesh : public Reference { - GDCLASS(TriangleMesh, Reference); +class TriangleMesh : public RefCounted { + GDCLASS(TriangleMesh, RefCounted); struct Triangle { Vector3 normal; diff --git a/core/math/vector2.cpp b/core/math/vector2.cpp index ea430b15c4..eb3301f5d0 100644 --- a/core/math/vector2.cpp +++ b/core/math/vector2.cpp @@ -193,6 +193,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const { return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y); } +Vector2::operator String() const { + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")"; +} + /* Vector2i */ Vector2i Vector2i::clamp(const Vector2i &p_min, const Vector2i &p_max) const { @@ -269,3 +273,7 @@ bool Vector2i::operator==(const Vector2i &p_vec2) const { bool Vector2i::operator!=(const Vector2i &p_vec2) const { return x != p_vec2.x || y != p_vec2.y; } + +Vector2i::operator String() const { + return "(" + itos(x) + ", " + itos(y) + ")"; +} diff --git a/core/math/vector2.h b/core/math/vector2.h index b0d2049f55..78deb473b4 100644 --- a/core/math/vector2.h +++ b/core/math/vector2.h @@ -165,7 +165,7 @@ struct Vector2 { Vector2 clamp(const Vector2 &p_min, const Vector2 &p_max) const; real_t aspect() const { return width / height; } - operator String() const { return String::num(x) + ", " + String::num(y); } + operator String() const; _FORCE_INLINE_ Vector2() {} _FORCE_INLINE_ Vector2(real_t p_x, real_t p_y) { @@ -340,7 +340,7 @@ struct Vector2i { Vector2i abs() const { return Vector2i(ABS(x), ABS(y)); } Vector2i clamp(const Vector2i &p_min, const Vector2i &p_max) const; - operator String() const { return String::num(x) + ", " + String::num(y); } + operator String() const; operator Vector2() const { return Vector2(x, y); } diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp index d5ca985244..3d59064af6 100644 --- a/core/math/vector3.cpp +++ b/core/math/vector3.cpp @@ -126,5 +126,5 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const { } Vector3::operator String() const { - return (rtos(x) + ", " + rtos(y) + ", " + rtos(z)); + return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")"; } diff --git a/core/math/vector3i.cpp b/core/math/vector3i.cpp index a82db7f7fc..2de1e4e331 100644 --- a/core/math/vector3i.cpp +++ b/core/math/vector3i.cpp @@ -56,5 +56,5 @@ Vector3i Vector3i::clamp(const Vector3i &p_min, const Vector3i &p_max) const { } Vector3i::operator String() const { - return (itos(x) + ", " + itos(y) + ", " + itos(z)); + return "(" + itos(x) + ", " + itos(y) + ", " + itos(z) + ")"; } diff --git a/core/object/SCsub b/core/object/SCsub index 5d429960e5..dc116aeb19 100644 --- a/core/object/SCsub +++ b/core/object/SCsub @@ -2,6 +2,11 @@ Import("env") +import make_virtuals +from platform_methods import run_in_subprocess + +env.CommandNoCache(["gdvirtual.gen.inc"], "make_virtuals.py", run_in_subprocess(make_virtuals.run)) + env_object = env.Clone() env_object.add_source_files(env.core_sources, "*.cpp") diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp index fb7eb42738..a10405dfae 100644 --- a/core/object/class_db.cpp +++ b/core/object/class_db.cpp @@ -501,12 +501,27 @@ void ClassDB::add_compatibility_class(const StringName &p_class, const StringNam compat_classes[p_class] = p_fallback; } -Object *ClassDB::instance(const StringName &p_class) { +thread_local bool initializing_with_extension = false; +thread_local ObjectNativeExtension *initializing_extension = nullptr; +thread_local GDExtensionClassInstancePtr initializing_extension_instance = nullptr; + +void ClassDB::instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance) { + if (initializing_with_extension) { + *r_extension = initializing_extension; + *r_extension_instance = initializing_extension_instance; + initializing_with_extension = false; + } else { + *r_extension = nullptr; + *r_extension_instance = nullptr; + } +} + +Object *ClassDB::instantiate(const StringName &p_class) { ClassInfo *ti; { OBJTYPE_RLOCK; ti = classes.getptr(p_class); - if (!ti || ti->disabled || !ti->creation_func) { + if (!ti || ti->disabled || !ti->creation_func || (ti->native_extension && !ti->native_extension->create_instance)) { if (compat_classes.has(p_class)) { ti = classes.getptr(compat_classes[p_class]); } @@ -521,10 +536,15 @@ Object *ClassDB::instance(const StringName &p_class) { return nullptr; } #endif + if (ti->native_extension) { + initializing_with_extension = true; + initializing_extension = ti->native_extension; + initializing_extension_instance = ti->native_extension->create_instance(ti->native_extension->class_userdata); + } return ti->creation_func(); } -bool ClassDB::can_instance(const StringName &p_class) { +bool ClassDB::can_instantiate(const StringName &p_class) { OBJTYPE_RLOCK; ClassInfo *ti = classes.getptr(p_class); @@ -534,7 +554,7 @@ bool ClassDB::can_instance(const StringName &p_class) { return false; } #endif - return (!ti->disabled && ti->creation_func != nullptr); + return (!ti->disabled && ti->creation_func != nullptr && !(ti->native_extension && !ti->native_extension->create_instance)); } void ClassDB::_add_class2(const StringName &p_class, const StringName &p_inherits) { @@ -1310,6 +1330,24 @@ bool ClassDB::has_method(StringName p_class, StringName p_method, bool p_no_inhe return false; } +void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) { + ClassInfo *type = classes.getptr(p_class); + if (!type) { + ERR_FAIL_MSG("Couldn't bind custom method '" + p_method->get_name() + "' for instance '" + p_class + "'."); + } + + if (type->method_map.has(p_method->get_name())) { + // overloading not supported + ERR_FAIL_MSG("Method already bound '" + p_class + "::" + p_method->get_name() + "'."); + } + +#ifdef DEBUG_METHODS_ENABLED + type->method_order.push_back(p_method->get_name()); +#endif + + type->method_map[p_method->get_name()] = p_method; +} + #ifdef DEBUG_METHODS_ENABLED MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) { StringName mdname = method_name.name; @@ -1484,8 +1522,8 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con if (Engine::get_singleton()->has_singleton(p_class)) { c = Engine::get_singleton()->get_singleton_object(p_class); cleanup_c = false; - } else if (ClassDB::can_instance(p_class)) { - c = ClassDB::instance(p_class); + } else if (ClassDB::can_instantiate(p_class)) { + c = ClassDB::instantiate(p_class); cleanup_c = true; } @@ -1545,6 +1583,31 @@ Variant ClassDB::class_get_default_property_value(const StringName &p_class, con return var; } +void ClassDB::register_extension_class(ObjectNativeExtension *p_extension) { + GLOBAL_LOCK_FUNCTION; + + ERR_FAIL_COND_MSG(classes.has(p_extension->class_name), "Class already registered: " + String(p_extension->class_name)); + ERR_FAIL_COND_MSG(classes.has(p_extension->parent_class_name), "Parent class name for extension class not found: " + String(p_extension->parent_class_name)); + + ClassInfo *parent = classes.getptr(p_extension->parent_class_name); + + ClassInfo c; + c.api = p_extension->editor_class ? API_EDITOR_EXTENSION : API_EXTENSION; + c.native_extension = p_extension; + c.name = p_extension->class_name; + c.creation_func = parent->creation_func; + c.inherits = parent->name; + c.class_ptr = parent->class_ptr; + c.inherits_ptr = parent; + + classes[p_extension->class_name] = c; +} + +void ClassDB::unregister_extension_class(const StringName &p_class) { + ERR_FAIL_COND(!classes.has(p_class)); + classes.erase(p_class); +} + RWLock ClassDB::lock; void ClassDB::cleanup_defaults() { diff --git a/core/object/class_db.h b/core/object/class_db.h index 6fd5748dbb..af528bfde7 100644 --- a/core/object/class_db.h +++ b/core/object/class_db.h @@ -97,6 +97,8 @@ public: enum APIType { API_CORE, API_EDITOR, + API_EXTENSION, + API_EDITOR_EXTENSION, API_NONE }; @@ -115,6 +117,8 @@ public: ClassInfo *inherits_ptr = nullptr; void *class_ptr = nullptr; + ObjectNativeExtension *native_extension = nullptr; + HashMap<StringName, MethodBind *> method_map; HashMap<StringName, int> constant_map; HashMap<StringName, List<StringName>> enum_map; @@ -199,6 +203,9 @@ public: //nothing } + static void register_extension_class(ObjectNativeExtension *p_extension); + static void unregister_extension_class(const StringName &p_class); + template <class T> static Object *_create_ptr_func() { return T::create(); @@ -224,8 +231,10 @@ public: static StringName get_compatibility_remapped_class(const StringName &p_class); static bool class_exists(const StringName &p_class); static bool is_parent_class(const StringName &p_class, const StringName &p_inherits); - static bool can_instance(const StringName &p_class); - static Object *instance(const StringName &p_class); + static bool can_instantiate(const StringName &p_class); + static Object *instantiate(const StringName &p_class); + static void instance_get_native_extension_data(ObjectNativeExtension **r_extension, GDExtensionClassInstancePtr *r_extension_instance); + static APIType get_api_type(const StringName &p_class); static uint64_t get_api_hash(APIType p_api); @@ -334,6 +343,8 @@ public: return bind; } + static void bind_method_custom(const StringName &p_class, MethodBind *p_method); + static void add_signal(StringName p_class, const MethodInfo &p_signal); static bool has_signal(StringName p_class, StringName p_signal, bool p_no_inheritance = false); static bool get_signal(StringName p_class, StringName p_signal, MethodInfo *r_signal); diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py new file mode 100644 index 0000000000..2c6b8cddc9 --- /dev/null +++ b/core/object/make_virtuals.py @@ -0,0 +1,152 @@ +proto = """ +#define GDVIRTUAL$VER($RET m_name $ARG) \\ +GDNativeExtensionClassCallVirtual _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, #m_name) : (GDNativeExtensionClassCallVirtual) nullptr;\\ +StringName _gdvirtual_##m_name##_sn = #m_name;\\ +bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\ + ScriptInstance *script_instance = ((Object*)(this))->get_script_instance();\\ + if (script_instance) {\\ + Callable::CallError ce; \\ + $CALLSIARGS\\ + $CALLSIBEGINscript_instance->call(_gdvirtual_##m_name##_sn, $CALLSIARGPASS, ce);\\ + if (ce.error == Callable::CallError::CALL_OK) {\\ + $CALLSIRET\\ + return true;\\ + } \\ + }\\ + if (_gdvirtual_##m_name) {\\ + $CALLPTRARGS\\ + $CALLPTRRETDEF\\ + _gdvirtual_##m_name(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\ + $CALLPTRRET\\ + return true;\\ + }\\ +\\ + return false;\\ +}\\ +\\ +_FORCE_INLINE_ static MethodInfo _gdvirtual_##m_name##_get_method_info() { \\ + MethodInfo method_info;\\ + method_info.name = #m_name;\\ + method_info.flags = METHOD_FLAG_VIRTUAL;\\ + $FILL_METHOD_INFO\\ + return method_info;\\ +} + + +""" + + +def generate_version(argcount, const=False, returns=False): + s = proto + sproto = str(argcount) + method_info = "" + if returns: + sproto += "R" + s = s.replace("$RET", "m_ret, ") + s = s.replace("$CALLPTRRETDEF", "PtrToArg<m_ret>::EncodeT ret;") + method_info += "\tmethod_info.return_val = GetTypeInfo<m_ret>::get_class_info();\\\n" + else: + s = s.replace("$RET", "") + s = s.replace("$CALLPTRRETDEF", "") + + if const: + sproto += "C" + s = s.replace("$CONST", "const") + method_info += "\tmethod_info.flags|=METHOD_FLAG_CONST;\\\n" + else: + s = s.replace("$CONST", "") + + s = s.replace("$VER", sproto) + argtext = "" + callargtext = "" + callsiargs = "" + callsiargptrs = "" + callptrargsptr = "" + if argcount > 0: + argtext += ", " + callsiargs = "Variant vargs[" + str(argcount) + "]={" + callsiargptrs = "\t\tconst Variant *vargptrs[" + str(argcount) + "]={" + callptrargsptr = "\t\tconst GDNativeTypePtr argptrs[" + str(argcount) + "]={" + callptrargs = "" + for i in range(argcount): + if i > 0: + argtext += ", " + callargtext += ", " + callsiargs += ", " + callsiargptrs += ", " + callptrargs += "\t\t" + callptrargsptr += ", " + argtext += "m_type" + str(i + 1) + callargtext += "const m_type" + str(i + 1) + "& arg" + str(i + 1) + callsiargs += "Variant(arg" + str(i + 1) + ")" + callsiargptrs += "&vargs[" + str(i) + "]" + callptrargs += ( + "PtrToArg<m_type" + str(i + 1) + ">::EncodeT argval" + str(i + 1) + " = arg" + str(i + 1) + ";\\\n" + ) + callptrargsptr += "&argval" + str(i + 1) + method_info += "\tmethod_info.arguments.push_back(GetTypeInfo<m_type" + str(i + 1) + ">::get_class_info());\\\n" + + if argcount: + callsiargs += "};\\\n" + callsiargptrs += "};\\\n" + s = s.replace("$CALLSIARGS", callsiargs + callsiargptrs) + s = s.replace("$CALLSIARGPASS", "(const Variant **)vargptrs," + str(argcount)) + callptrargsptr += "};\\\n" + s = s.replace("$CALLPTRARGS", callptrargs + callptrargsptr) + s = s.replace("$CALLPTRARGPASS", "(const GDNativeTypePtr*)argptrs") + else: + s = s.replace("$CALLSIARGS", "") + s = s.replace("$CALLSIARGPASS", "nullptr, 0") + s = s.replace("$CALLPTRARGS", "") + s = s.replace("$CALLPTRARGPASS", "nullptr") + + if returns: + if argcount > 0: + callargtext += "," + callargtext += " m_ret& r_ret" + s = s.replace("$CALLSIBEGIN", "Variant ret = ") + s = s.replace("$CALLSIRET", "r_ret = ret;") + s = s.replace("$CALLPTRRETPASS", "&ret") + s = s.replace("$CALLPTRRET", "r_ret = ret;") + else: + s = s.replace("$CALLSIBEGIN", "") + s = s.replace("$CALLSIRET", "") + s = s.replace("$CALLPTRRETPASS", "nullptr") + s = s.replace("$CALLPTRRET", "") + + s = s.replace("$ARG", argtext) + s = s.replace("$CALLARGS", callargtext) + s = s.replace("$FILL_METHOD_INFO", method_info) + + return s + + +def run(target, source, env): + + max_versions = 12 + + txt = """ +#ifndef GDVIRTUAL_GEN_H +#define GDVIRTUAL_GEN_H + + +""" + + for i in range(max_versions + 1): + + txt += "/* " + str(i) + " Arguments */\n\n" + txt += generate_version(i, False, False) + txt += generate_version(i, False, True) + txt += generate_version(i, True, False) + txt += generate_version(i, True, True) + + txt += "#endif" + + with open(target[0], "w") as f: + f.write(txt) + + +if __name__ == "__main__": + from platform_methods import subprocess_main + + subprocess_main(globals()) diff --git a/core/object/method_bind.cpp b/core/object/method_bind.cpp index 9c5ed60708..c53104fe3f 100644 --- a/core/object/method_bind.cpp +++ b/core/object/method_bind.cpp @@ -34,6 +34,35 @@ #include "method_bind.h" +uint32_t MethodBind::get_hash() const { + uint32_t hash = hash_djb2_one_32(has_return() ? 1 : 0); + hash = hash_djb2_one_32(get_argument_count(), hash); + +#ifndef _MSC_VER +#warning This needs proper class name and argument type for hashing +#endif +#if 0 + + for (int i = (has_return() ? -1 : 0); i < get_argument_count(); i++) { + PropertyInfo pi = i == -1 ? get_return_info() : get_argument_info(i); + hash = hash_djb2_one_32(get_argument_type(i), hash); + if (pi.class_name != StringName()) { + hash = hash_djb2_one_32(pi.class_name.operator String().hash(), hash); + } + } +#endif + hash = hash_djb2_one_32(get_default_argument_count(), hash); + for (int i = 0; i < get_default_argument_count(); i++) { + Variant v = get_default_argument(i); + hash = hash_djb2_one_32(v.hash(), hash); + } + + hash = hash_djb2_one_32(is_const(), hash); + hash = hash_djb2_one_32(is_vararg(), hash); + + return hash; +} + #ifdef DEBUG_METHODS_ENABLED PropertyInfo MethodBind::get_argument_info(int p_argument) const { ERR_FAIL_INDEX_V(p_argument, get_argument_count(), PropertyInfo()); diff --git a/core/object/method_bind.h b/core/object/method_bind.h index 7030ae201b..92b964772a 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -135,6 +135,8 @@ public: void set_default_arguments(const Vector<Variant> &p_defargs); + uint32_t get_hash() const; + MethodBind(); virtual ~MethodBind(); }; diff --git a/core/object/object.cpp b/core/object/object.cpp index a8b2c4a939..296d876701 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -385,6 +385,23 @@ void Object::set(const StringName &p_name, const Variant &p_value, bool *r_valid } } + if (_extension && _extension->set) { +// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + if (_extension->set(_extension_instance, (const GDNativeStringNamePtr)&p_name, (const GDNativeVariantPtr)&p_value)) { + if (r_valid) { + *r_valid = true; + } + return; + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + } + //try built-in setgetter { if (ClassDB::set_property(this, p_name, p_value, r_valid)) { @@ -450,6 +467,23 @@ Variant Object::get(const StringName &p_name, bool *r_valid) const { return ret; } } + if (_extension && _extension->get) { +// C style pointer casts should never trigger a compiler warning because the risk is assumed by the user, so GCC should keep quiet about it. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-qualifiers" +#endif + + if (_extension->get(_extension_instance, (const GDNativeStringNamePtr)&p_name, (GDNativeVariantPtr)&ret)) { + if (r_valid) { + *r_valid = true; + } + return ret; + } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + } //try built-in setgetter { @@ -596,6 +630,17 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons _get_property_listv(p_list, p_reversed); + if (_extension && _extension->get_property_list) { + uint32_t pcount; + const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount); + for (uint32_t i = 0; i < pcount; i++) { + p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name)); + } + if (_extension->free_property_list) { + _extension->free_property_list(_extension_instance, pinfo); + } + } + if (!is_class("Script")) { // can still be set, but this is for user-friendliness p_list->push_back(PropertyInfo(Variant::OBJECT, "script", PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_DEFAULT)); } @@ -740,7 +785,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; return Variant(); } - if (Object::cast_to<Reference>(this)) { + if (Object::cast_to<RefCounted>(this)) { r_error.argument = 0; r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; ERR_FAIL_V_MSG(Variant(), "Can't 'free' a reference."); @@ -761,6 +806,7 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a Variant ret; OBJ_DEBUG_LOCK + if (script_instance) { ret = script_instance->call(p_method, p_args, p_argcount, r_error); //force jumptable @@ -778,6 +824,8 @@ Variant Object::call(const StringName &p_method, const Variant **p_args, int p_a } } + //extension does not need this, because all methods are registered in MethodBind + MethodBind *method = ClassDB::get_method(get_class_name(), p_method); if (method) { @@ -795,6 +843,10 @@ void Object::notification(int p_notification, bool p_reversed) { if (script_instance) { script_instance->notification(p_notification); } + + if (_extension && _extension->notification) { + _extension->notification(_extension_instance, p_notification); + } } String Object::to_string() { @@ -805,6 +857,9 @@ String Object::to_string() { return ret; } } + if (_extension && _extension->to_string) { + return _extension->to_string(_extension_instance); + } return "[" + get_class() + ":" + itos(get_instance_id()) + "]"; } @@ -832,7 +887,7 @@ void Object::set_script(const Variant &p_script) { Ref<Script> s = script; if (!s.is_null()) { - if (s->can_instance()) { + if (s->can_instantiate()) { OBJ_DEBUG_LOCK script_instance = s->instance_create(this); } else if (Engine::get_singleton()->is_editor_hint()) { @@ -881,7 +936,7 @@ void Object::set_meta(const String &p_name, const Variant &p_value) { } Variant Object::get_meta(const String &p_name) const { - ERR_FAIL_COND_V(!metadata.has(p_name), Variant()); + ERR_FAIL_COND_V_MSG(!metadata.has(p_name), Variant(), "The object does not have any 'meta' values with the key '" + p_name + "'."); return metadata[p_name]; } @@ -1248,10 +1303,10 @@ void Object::get_signals_connected_to_this(List<Connection> *p_connections) cons } Error Object::connect(const StringName &p_signal, const Callable &p_callable, const Vector<Variant> &p_binds, uint32_t p_flags) { - ERR_FAIL_COND_V(p_callable.is_null(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null."); Object *target_object = p_callable.get_object(); - ERR_FAIL_COND_V(!target_object, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(!target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null."); SignalData *s = signal_map.getptr(p_signal); if (!s) { @@ -1309,7 +1364,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, co } bool Object::is_connected(const StringName &p_signal, const Callable &p_callable) const { - ERR_FAIL_COND_V(p_callable.is_null(), false); + ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot determine if connected to '" + p_signal + "': the provided callable is null."); const SignalData *s = signal_map.getptr(p_signal); if (!s) { bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal); @@ -1336,10 +1391,10 @@ void Object::disconnect(const StringName &p_signal, const Callable &p_callable) } void Object::_disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force) { - ERR_FAIL_COND(p_callable.is_null()); + ERR_FAIL_COND_MSG(p_callable.is_null(), "Cannot disconnect from '" + p_signal + "': the provided callable is null."); Object *target_object = p_callable.get_object(); - ERR_FAIL_COND(!target_object); + ERR_FAIL_COND_MSG(!target_object, "Cannot disconnect '" + p_signal + "' from callable '" + p_callable + "': the callable object is null."); SignalData *s = signal_map.getptr(p_signal); if (!s) { @@ -1714,42 +1769,43 @@ uint32_t Object::get_edited_version() const { } #endif -void *Object::get_script_instance_binding(int p_script_language_index) { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr); -#endif - - //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync - //just return the same pointer. - //if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it - //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards - - if (!_script_instance_bindings[p_script_language_index]) { - void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this); - if (script_data) { - instance_binding_count.increment(); - _script_instance_bindings[p_script_language_index] = script_data; +void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) { + void *binding = nullptr; + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].token == p_token) { + binding = _instance_bindings[i].binding; + break; } } + if (unlikely(!binding)) { + uint32_t current_size = next_power_of_2(_instance_binding_count); + uint32_t new_size = next_power_of_2(_instance_binding_count + 1); - return _script_instance_bindings[p_script_language_index]; -} + if (current_size == 0 || new_size > current_size) { + _instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding)); + } -bool Object::has_script_instance_binding(int p_script_language_index) { - return _script_instance_bindings[p_script_language_index] != nullptr; -} + _instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback; + _instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback; + _instance_bindings[_instance_binding_count].token = p_token; -void Object::set_script_instance_binding(int p_script_language_index, void *p_data) { -#ifdef DEBUG_ENABLED - CRASH_COND(_script_instance_bindings[p_script_language_index] != nullptr); -#endif - _script_instance_bindings[p_script_language_index] = p_data; + binding = p_callbacks->create_callback(p_token, this); + _instance_bindings[_instance_binding_count].binding = binding; + + _instance_binding_count++; + } + + _instance_binding_mutex.unlock(); + + return binding; } void Object::_construct_object(bool p_reference) { type_is_reference = p_reference; _instance_id = ObjectDB::add_instance(this); - memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); + + ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance); #ifdef DEBUG_ENABLED _lock_index.init(1); @@ -1770,6 +1826,12 @@ Object::~Object() { } script_instance = nullptr; + if (_extension && _extension->free_instance) { + _extension->free_instance(_extension->class_userdata, _extension_instance); + _extension = nullptr; + _extension_instance = nullptr; + } + const StringName *S = nullptr; if (_emitting) { @@ -1801,12 +1863,13 @@ Object::~Object() { _instance_id = ObjectID(); _predelete_ok = 2; - if (!ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]); + if (_instance_bindings != nullptr) { + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].free_callback) { + _instance_bindings[i].free_callback(_instance_bindings[i].token, _instance_bindings[i].binding, this); } } + memfree(_instance_bindings); } } @@ -1824,7 +1887,6 @@ void ObjectDB::debug_objects(DebugFunc p_func) { for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) { if (object_slots[i].validator) { p_func(object_slots[i].object); - count--; } } @@ -1853,7 +1915,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max); for (uint32_t i = slot_max; i < new_slot_max; i++) { object_slots[i].object = nullptr; - object_slots[i].is_reference = false; + object_slots[i].is_ref_counted = false; object_slots[i].next_free = i; object_slots[i].validator = 0; } @@ -1866,7 +1928,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID()); } object_slots[slot].object = p_object; - object_slots[slot].is_reference = p_object->is_reference(); + object_slots[slot].is_ref_counted = p_object->is_ref_counted(); validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK; if (unlikely(validator_counter == 0)) { validator_counter = 1; @@ -1877,7 +1939,7 @@ ObjectID ObjectDB::add_instance(Object *p_object) { id <<= OBJECTDB_SLOT_MAX_COUNT_BITS; id |= uint64_t(slot); - if (p_object->is_reference()) { + if (p_object->is_ref_counted()) { id |= OBJECTDB_REFERENCE_BIT; } @@ -1915,7 +1977,7 @@ void ObjectDB::remove_instance(Object *p_object) { object_slots[slot_count].next_free = slot; //invalidate, so checks against it fail object_slots[slot].validator = 0; - object_slots[slot].is_reference = false; + object_slots[slot].is_ref_counted = false; object_slots[slot].object = nullptr; spin_lock.unlock(); @@ -1950,7 +2012,7 @@ void ObjectDB::cleanup() { extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error)); } - uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_reference ? OBJECTDB_REFERENCE_BIT : 0); + uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0); print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + extra_info); count--; diff --git a/core/object/object.h b/core/object/object.h index 448a33d3bc..8389d80afc 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -31,6 +31,7 @@ #ifndef OBJECT_H #define OBJECT_H +#include "core/extension/gdnative_interface.h" #include "core/object/object_id.h" #include "core/os/rw_lock.h" #include "core/os/spin_lock.h" @@ -57,8 +58,7 @@ enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. - PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional" - PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit + PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range. PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") PROPERTY_HINT_LENGTH, ///< hint_text= "length" (as integer) @@ -101,6 +101,7 @@ enum PropertyHint { }; enum PropertyUsageFlags { + PROPERTY_USAGE_NONE = 0, PROPERTY_USAGE_STORAGE = 1, PROPERTY_USAGE_EDITOR = 2, PROPERTY_USAGE_NETWORK = 4, @@ -150,7 +151,7 @@ struct PropertyInfo { String hint_string; uint32_t usage = PROPERTY_USAGE_DEFAULT; - _FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const { + _FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const { PropertyInfo pi = *this; pi.usage |= p_fl; return pi; @@ -162,7 +163,7 @@ struct PropertyInfo { PropertyInfo() {} - PropertyInfo(Variant::Type p_type, const String p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) : + PropertyInfo(const Variant::Type p_type, const String p_name, const PropertyHint p_hint = PROPERTY_HINT_NONE, const String &p_hint_string = "", const uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const StringName &p_class_name = StringName()) : type(p_type), name(p_name), hint(p_hint), @@ -238,6 +239,44 @@ struct MethodInfo { ////else //return nullptr; +// API used to extend in GDNative and other C compatible compiled languages +class MethodBind; + +struct ObjectNativeExtension { + ObjectNativeExtension *parent = nullptr; + List<ObjectNativeExtension *> children; + StringName parent_class_name; + StringName class_name; + bool editor_class = false; + GDNativeExtensionClassSet set; + GDNativeExtensionClassGet get; + GDNativeExtensionClassGetPropertyList get_property_list; + GDNativeExtensionClassFreePropertyList free_property_list; + GDNativeExtensionClassNotification notification; + GDNativeExtensionClassToString to_string; + GDNativeExtensionClassReference reference; + GDNativeExtensionClassReference unreference; + + _FORCE_INLINE_ bool is_class(const String &p_class) const { + const ObjectNativeExtension *e = this; + while (e) { + if (p_class == e->class_name.operator String()) { + return true; + } + e = e->parent; + } + return false; + } + void *class_userdata = nullptr; + + GDNativeExtensionClassCreateInstance create_instance; + GDNativeExtensionClassFreeInstance free_instance; + GDNativeExtensionClassGetVirtual get_virtual; +}; + +#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call(__VA_ARGS__) +#define GDVIRTUAL_BIND(m_name) ClassDB::add_virtual_method(get_class_static(), _gdvirtual_##m_name##_get_method_info()); + /* the following is an incomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model. */ @@ -262,9 +301,15 @@ private: \ public: \ virtual String get_class() const override { \ + if (_get_extension()) { \ + return _get_extension()->class_name.operator String(); \ + } \ return String(#m_class); \ } \ virtual const StringName *_get_class_namev() const override { \ + if (_get_extension()) { \ + return &_get_extension()->class_name; \ + } \ if (!_class_name) { \ _class_name = get_class_static(); \ } \ @@ -297,7 +342,12 @@ public: static String inherits_static() { \ return String(#m_inherits); \ } \ - virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \ + virtual bool is_class(const String &p_class) const override { \ + if (_get_extension() && _get_extension()->is_class(p_class)) { \ + return true; \ + } \ + return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \ + } \ virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \ \ static void get_valid_parents_static(List<String> *p_parents) { \ @@ -430,16 +480,15 @@ public: }; private: - enum { - MAX_SCRIPT_INSTANCE_BINDINGS = 8 - }; - #ifdef DEBUG_ENABLED friend struct _ObjectDebugLock; #endif friend bool predelete_handler(Object *); friend void postinitialize_handler(Object *); + ObjectNativeExtension *_extension = nullptr; + GDExtensionClassInstancePtr _extension_instance = nullptr; + struct SignalData { struct Slot { int reference_count = 0; @@ -487,14 +536,40 @@ private: _FORCE_INLINE_ void _construct_object(bool p_reference); - friend class Reference; + friend class RefCounted; bool type_is_reference = false; - SafeNumeric<uint32_t> instance_binding_count; - void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; + + std::mutex _instance_binding_mutex; + struct InstanceBinding { + void *binding; + void *token; + GDNativeInstanceBindingFreeCallback free_callback = nullptr; + GDNativeInstanceBindingReferenceCallback reference_callback = nullptr; + }; + InstanceBinding *_instance_bindings = nullptr; + uint32_t _instance_binding_count = 0; Object(bool p_reference); protected: + _FORCE_INLINE_ bool _instance_binding_reference(bool p_reference) { + bool can_die = true; + if (_instance_bindings) { + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].reference_callback) { + if (!_instance_bindings[i].reference_callback(_instance_bindings[i].token, _instance_bindings[i].binding, p_reference)) { + can_die = false; + } + } + } + _instance_binding_mutex.unlock(); + } + return can_die; + } + friend class NativeExtensionMethodBind; + _ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; } + _ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; } virtual void _initialize_classv() { initialize_class(); } virtual bool _setv(const StringName &p_name, const Variant &p_property) { return false; }; virtual bool _getv(const StringName &p_name, Variant &r_property) const { return false; }; @@ -610,13 +685,25 @@ public: static String get_parent_class_static() { return String(); } static String get_category_static() { return String(); } - virtual String get_class() const { return "Object"; } + virtual String get_class() const { + if (_extension) + return _extension->class_name.operator String(); + return "Object"; + } virtual String get_save_class() const { return get_class(); } //class stored when saving - virtual bool is_class(const String &p_class) const { return (p_class == "Object"); } + virtual bool is_class(const String &p_class) const { + if (_extension && _extension->is_class(p_class)) { + return true; + } + return (p_class == "Object"); + } virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; } _FORCE_INLINE_ const StringName &get_class_name() const { + if (_extension) { + return _extension->class_name; + } if (!_class_ptr) { return *_get_class_namev(); } else { @@ -717,13 +804,11 @@ public: #endif //used by script languages to store binding data - void *get_script_instance_binding(int p_script_language_index); - bool has_script_instance_binding(int p_script_language_index); - void set_script_instance_binding(int p_script_language_index, void *p_data); + void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks); void clear_internal_resource_paths(); - _ALWAYS_INLINE_ bool is_reference() const { return type_is_reference; } + _ALWAYS_INLINE_ bool is_ref_counted() const { return type_is_reference; } Object(); virtual ~Object(); @@ -743,7 +828,7 @@ class ObjectDB { struct ObjectSlot { //128 bits per slot uint64_t validator : OBJECTDB_VALIDATOR_BITS; uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS; - uint64_t is_reference : 1; + uint64_t is_ref_counted : 1; Object *object; }; diff --git a/core/object/object_id.h b/core/object/object_id.h index 7f2496ad48..0666ec0855 100644 --- a/core/object/object_id.h +++ b/core/object/object_id.h @@ -42,7 +42,7 @@ class ObjectID { uint64_t id = 0; public: - _ALWAYS_INLINE_ bool is_reference() const { return (id & (uint64_t(1) << 63)) != 0; } + _ALWAYS_INLINE_ bool is_ref_counted() const { return (id & (uint64_t(1) << 63)) != 0; } _ALWAYS_INLINE_ bool is_valid() const { return id != 0; } _ALWAYS_INLINE_ bool is_null() const { return id == 0; } _ALWAYS_INLINE_ operator uint64_t() const { return id; } diff --git a/core/object/reference.cpp b/core/object/ref_counted.cpp index 22e4e8a336..2833f774dc 100644 --- a/core/object/reference.cpp +++ b/core/object/ref_counted.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* reference.cpp */ +/* ref_counted.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "reference.h" +#include "ref_counted.h" #include "core/object/script_language.h" -bool Reference::init_ref() { +bool RefCounted::init_ref() { if (reference()) { if (!is_referenced() && refcount_init.unref()) { unreference(); // first referencing is already 1, so compensate for the ref above @@ -44,17 +44,17 @@ bool Reference::init_ref() { } } -void Reference::_bind_methods() { - ClassDB::bind_method(D_METHOD("init_ref"), &Reference::init_ref); - ClassDB::bind_method(D_METHOD("reference"), &Reference::reference); - ClassDB::bind_method(D_METHOD("unreference"), &Reference::unreference); +void RefCounted::_bind_methods() { + ClassDB::bind_method(D_METHOD("init_ref"), &RefCounted::init_ref); + ClassDB::bind_method(D_METHOD("reference"), &RefCounted::reference); + ClassDB::bind_method(D_METHOD("unreference"), &RefCounted::unreference); } -int Reference::reference_get_count() const { +int RefCounted::reference_get_count() const { return refcount.get(); } -bool Reference::reference() { +bool RefCounted::reference() { uint32_t rc_val = refcount.refval(); bool success = rc_val != 0; @@ -62,19 +62,17 @@ bool Reference::reference() { if (get_script_instance()) { get_script_instance()->refcount_incremented(); } - if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->refcount_incremented_instance_binding(this); - } - } + if (_get_extension() && _get_extension()->reference) { + _get_extension()->reference(_get_extension_instance()); } + + _instance_binding_reference(true); } return success; } -bool Reference::unreference() { +bool RefCounted::unreference() { uint32_t rc_val = refcount.unrefval(); bool die = rc_val == 0; @@ -83,20 +81,17 @@ bool Reference::unreference() { bool script_ret = get_script_instance()->refcount_decremented(); die = die && script_ret; } - if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this); - die = die && script_ret; - } - } + if (_get_extension() && _get_extension()->unreference) { + _get_extension()->unreference(_get_extension_instance()); } + + die = die && _instance_binding_reference(false); } return die; } -Reference::Reference() : +RefCounted::RefCounted() : Object(true) { refcount.init(); refcount_init.init(); @@ -111,7 +106,7 @@ Variant WeakRef::get_ref() const { if (!obj) { return Variant(); } - Reference *r = cast_to<Reference>(obj); + RefCounted *r = cast_to<RefCounted>(obj); if (r) { return REF(r); } diff --git a/core/object/reference.h b/core/object/ref_counted.h index d02cb12069..e0af2c18bb 100644 --- a/core/object/reference.h +++ b/core/object/ref_counted.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* reference.h */ +/* ref_counted.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef REFERENCE_H -#define REFERENCE_H +#ifndef REF_COUNTED_H +#define REF_COUNTED_H #include "core/object/class_db.h" #include "core/templates/safe_refcount.h" -class Reference : public Object { - GDCLASS(Reference, Object); +class RefCounted : public Object { + GDCLASS(RefCounted, Object); SafeRefCount refcount; SafeRefCount refcount_init; @@ -49,8 +49,8 @@ public: bool unreference(); int reference_get_count() const; - Reference(); - ~Reference() {} + RefCounted(); + ~RefCounted() {} }; template <class T> @@ -78,7 +78,7 @@ class Ref { } } - //virtual Reference * get_reference() const { return reference; } + //virtual RefCounted * get_reference() const { return reference; } public: _FORCE_INLINE_ bool operator==(const T *p_ptr) const { return reference == p_ptr; @@ -130,7 +130,7 @@ public: template <class T_Other> void operator=(const Ref<T_Other> &p_from) { - Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr())); + RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); if (!refb) { unref(); return; @@ -179,7 +179,7 @@ public: template <class T_Other> Ref(const Ref<T_Other> &p_from) { - Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr())); + RefCounted *refb = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_from.ptr())); if (!refb) { unref(); return; @@ -213,7 +213,7 @@ public: inline bool is_null() const { return reference == nullptr; } void unref() { - //TODO this should be moved to mutexes, since this engine does not really + // TODO: this should be moved to mutexes, since this engine does not really // do a lot of referencing on references and stuff // mutexes will avoid more crashes? @@ -223,7 +223,7 @@ public: reference = nullptr; } - void instance() { + void instantiate() { ref(memnew(T)); } @@ -234,10 +234,10 @@ public: } }; -typedef Ref<Reference> REF; +typedef Ref<RefCounted> REF; -class WeakRef : public Reference { - GDCLASS(WeakRef, Reference); +class WeakRef : public RefCounted { + GDCLASS(WeakRef, RefCounted); ObjectID ref; @@ -258,13 +258,17 @@ struct PtrToArg<Ref<T>> { return Ref<T>(const_cast<T *>(reinterpret_cast<const T *>(p_ptr))); } + typedef Ref<T> EncodeT; + _FORCE_INLINE_ static void encode(Ref<T> p_val, const void *p_ptr) { - *(Ref<Reference> *)p_ptr = p_val; + *(Ref<RefCounted> *)p_ptr = p_val; } }; template <class T> struct PtrToArg<const Ref<T> &> { + typedef Ref<T> EncodeT; + _FORCE_INLINE_ static Ref<T> convert(const void *p_ptr) { return Ref<T>((T *)p_ptr); } @@ -294,4 +298,4 @@ struct GetTypeInfo<const Ref<T> &> { #endif // DEBUG_METHODS_ENABLED -#endif // REFERENCE_H +#endif // REF_COUNTED_H diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 42fb0a0caf..626a7413e7 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -100,7 +100,7 @@ Dictionary Script::_get_script_constant_map() { } void Script::_bind_methods() { - ClassDB::bind_method(D_METHOD("can_instance"), &Script::can_instance); + ClassDB::bind_method(D_METHOD("can_instantiate"), &Script::can_instantiate); //ClassDB::bind_method(D_METHOD("instance_create","base_object"),&Script::instance_create); ClassDB::bind_method(D_METHOD("instance_has", "base_object"), &Script::instance_has); ClassDB::bind_method(D_METHOD("has_source_code"), &Script::has_source_code); @@ -120,7 +120,7 @@ void Script::_bind_methods() { ClassDB::bind_method(D_METHOD("is_tool"), &Script::is_tool); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", 0), "set_source_code", "get_source_code"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code"); } void ScriptServer::set_scripting_enabled(bool p_enabled) { @@ -353,10 +353,10 @@ void ScriptLanguage::get_core_type_words(List<String> *p_core_type_words) const p_core_type_words->push_back("Vector3i"); p_core_type_words->push_back("Transform2D"); p_core_type_words->push_back("Plane"); - p_core_type_words->push_back("Quat"); + p_core_type_words->push_back("Quaternion"); p_core_type_words->push_back("AABB"); p_core_type_words->push_back("Basis"); - p_core_type_words->push_back("Transform"); + p_core_type_words->push_back("Transform3D"); p_core_type_words->push_back("Color"); p_core_type_words->push_back("StringName"); p_core_type_words->push_back("NodePath"); @@ -585,14 +585,6 @@ Variant PlaceHolderScriptInstance::property_get_fallback(const StringName &p_nam return Variant(); } -uint16_t PlaceHolderScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return UINT16_MAX; -} - -uint16_t PlaceHolderScriptInstance::get_rset_property_id(const StringName &p_method) const { - return UINT16_MAX; -} - PlaceHolderScriptInstance::PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner) : owner(p_owner), language(p_language), diff --git a/core/object/script_language.h b/core/object/script_language.h index 9ed3c7e80f..2cbaa0f52e 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -41,21 +41,6 @@ class ScriptLanguage; typedef void (*ScriptEditRequestFunction)(const String &p_path); -struct ScriptNetData { - StringName name; - MultiplayerAPI::RPCMode mode; - bool operator==(ScriptNetData const &p_other) const { - return name == p_other.name; - } -}; - -struct SortNetData { - StringName::AlphCompare compare; - bool operator()(const ScriptNetData &p_a, const ScriptNetData &p_b) const { - return compare(p_a.name, p_b.name); - } -}; - class ScriptServer { enum { MAX_LANGUAGES = 16 @@ -130,7 +115,7 @@ protected: Dictionary _get_script_constant_map(); public: - virtual bool can_instance() const = 0; + virtual bool can_instantiate() const = 0; virtual Ref<Script> get_base_script() const = 0; //for script inheritance @@ -174,17 +159,7 @@ public: virtual bool is_placeholder_fallback_enabled() const { return false; } - virtual Vector<ScriptNetData> get_rpc_methods() const = 0; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; - - virtual Vector<ScriptNetData> get_rset_properties() const = 0; - virtual uint16_t get_rset_property_id(const StringName &p_property) const = 0; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; Script() {} }; @@ -225,17 +200,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid); - virtual Vector<ScriptNetData> get_rpc_methods() const = 0; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const = 0; - virtual StringName get_rpc_method(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const = 0; - - virtual Vector<ScriptNetData> get_rset_properties() const = 0; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const = 0; - virtual StringName get_rset_property(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const = 0; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const = 0; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const = 0; virtual ScriptLanguage *get_language() = 0; virtual ~ScriptInstance(); @@ -303,6 +268,12 @@ public: String message; }; + struct ScriptError { + int line = -1; + int column = -1; + String message; + }; + void get_core_type_words(List<String> *p_core_type_words) const; virtual void get_reserved_words(List<String> *p_words) const = 0; virtual bool is_control_flow_keyword(String p_string) const = 0; @@ -311,7 +282,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const = 0; virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {} virtual bool is_using_templates() { return false; } - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptError> *r_errors = nullptr, List<Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const = 0; virtual String validate_path(const String &p_path) const { return ""; } virtual Script *create_script() const = 0; virtual bool has_named_classes() const = 0; @@ -447,17 +418,7 @@ public: virtual void property_set_fallback(const StringName &p_name, const Variant &p_value, bool *r_valid = nullptr); virtual Variant property_get_fallback(const StringName &p_name, bool *r_valid = nullptr); - virtual Vector<ScriptNetData> get_rpc_methods() const { return Vector<ScriptNetData>(); } - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const { return StringName(); } - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - - virtual Vector<ScriptNetData> get_rset_properties() const { return Vector<ScriptNetData>(); } - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const { return StringName(); } - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const { return MultiplayerAPI::RPC_MODE_DISABLED; } - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const { return MultiplayerAPI::RPC_MODE_DISABLED; } + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const { return Vector<MultiplayerAPI::RPCConfig>(); } PlaceHolderScriptInstance(ScriptLanguage *p_language, Ref<Script> p_script, Object *p_owner); ~PlaceHolderScriptInstance(); diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index e8735e335c..96c96c1efb 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -122,8 +122,8 @@ void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIA ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_METHOD; @@ -148,8 +148,8 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_METHOD; @@ -167,8 +167,8 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_PROPERTY; @@ -189,8 +189,8 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_PROPERTY; @@ -205,8 +205,8 @@ void UndoRedo::add_do_reference(Object *p_object) { ERR_FAIL_COND((current_action + 1) >= actions.size()); Operation do_op; do_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - do_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + do_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } do_op.type = Operation::TYPE_REFERENCE; @@ -225,8 +225,8 @@ void UndoRedo::add_undo_reference(Object *p_object) { Operation undo_op; undo_op.object = p_object->get_instance_id(); - if (Object::cast_to<Reference>(p_object)) { - undo_op.ref = Ref<Reference>(Object::cast_to<Reference>(p_object)); + if (Object::cast_to<RefCounted>(p_object)) { + undo_op.ref = Ref<RefCounted>(Object::cast_to<RefCounted>(p_object)); } undo_op.type = Operation::TYPE_REFERENCE; diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index a08ca7792f..8f009830e3 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -32,7 +32,7 @@ #define UNDO_REDO_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class UndoRedo : public Object { GDCLASS(UndoRedo, Object); @@ -61,7 +61,7 @@ private: }; Type type; - Ref<Reference> ref; + Ref<RefCounted> ref; ObjectID object; StringName name; Variant args[VARIANT_ARG_MAX]; diff --git a/core/os/main_loop.h b/core/os/main_loop.h index 25a09fe98f..34e944709b 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -32,7 +32,7 @@ #define MAIN_LOOP_H #include "core/input/input_event.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" class MainLoop : public Object { diff --git a/core/os/memory.h b/core/os/memory.h index 10e678103d..9d09626b8c 100644 --- a/core/os/memory.h +++ b/core/os/memory.h @@ -80,7 +80,7 @@ void operator delete(void *p_mem, void *p_pointer, size_t check, const char *p_d #define memalloc(m_size) Memory::alloc_static(m_size) #define memrealloc(m_mem, m_size) Memory::realloc_static(m_mem, m_size) -#define memfree(m_size) Memory::free_static(m_size) +#define memfree(m_mem) Memory::free_static(m_mem) _ALWAYS_INLINE_ void postinitialize_handler(void *) {} diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp index a8be84c56c..ee87346dfc 100644 --- a/core/os/midi_driver.cpp +++ b/core/os/midi_driver.cpp @@ -45,23 +45,23 @@ void MIDIDriver::set_singleton() { void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) { Ref<InputEventMIDI> event; - event.instance(); + event.instantiate(); uint32_t param_position = 1; if (length >= 1) { if (data[0] >= 0xF0) { // channel does not apply to system common messages event->set_channel(0); - event->set_message(data[0]); + event->set_message(MIDIMessage(data[0])); last_received_message = data[0]; } else if ((data[0] & 0x80) == 0x00) { // running status event->set_channel(last_received_message & 0xF); - event->set_message(last_received_message >> 4); + event->set_message(MIDIMessage(last_received_message >> 4)); param_position = 0; } else { event->set_channel(data[0] & 0xF); - event->set_message(data[0] >> 4); + event->set_message(MIDIMessage(data[0] >> 4)); param_position = 1; last_received_message = data[0]; } @@ -112,6 +112,8 @@ void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_ event->set_pressure(data[param_position]); } break; + default: + break; } Input *id = Input::get_singleton(); diff --git a/core/os/os.cpp b/core/os/os.cpp index ca1b798e11..535eee4797 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -32,8 +32,8 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/midi_driver.h" #include "core/version_generated.gen.h" #include "servers/audio_server.h" @@ -47,37 +47,8 @@ OS *OS::get_singleton() { return singleton; } -uint32_t OS::get_ticks_msec() const { - return get_ticks_usec() / 1000; -} - -String OS::get_iso_date_time(bool local) const { - OS::Date date = get_date(local); - OS::Time time = get_time(local); - - String timezone; - if (!local) { - TimeZoneInfo zone = get_time_zone_info(); - if (zone.bias >= 0) { - timezone = "+"; - } - timezone = timezone + itos(zone.bias / 60).pad_zeros(2) + itos(zone.bias % 60).pad_zeros(2); - } else { - timezone = "Z"; - } - - return itos(date.year).pad_zeros(2) + - "-" + - itos(date.month).pad_zeros(2) + - "-" + - itos(date.day).pad_zeros(2) + - "T" + - itos(time.hour).pad_zeros(2) + - ":" + - itos(time.min).pad_zeros(2) + - ":" + - itos(time.sec).pad_zeros(2) + - timezone; +uint64_t OS::get_ticks_msec() const { + return get_ticks_usec() / 1000ULL; } double OS::get_unix_time() const { @@ -310,6 +281,11 @@ String OS::get_user_data_dir() const { return "."; } +// Android OS path to app's external data storage +String OS::get_external_data_dir() const { + return get_user_data_dir(); +}; + // Absolute path to res:// String OS::get_resource_dir() const { return ProjectSettings::get_singleton()->get_resource_path(); diff --git a/core/os/os.h b/core/os/os.h index 7198607237..301718a8b3 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -58,8 +58,6 @@ class OS { int _orientation; bool _allow_hidpi = false; bool _allow_layered = false; - bool _use_vsync; - bool _vsync_via_compositor; bool _stdout_enabled = true; bool _stderr_enabled = true; @@ -158,17 +156,17 @@ public: virtual void yield(); - enum Weekday { - DAY_SUNDAY, - DAY_MONDAY, - DAY_TUESDAY, - DAY_WEDNESDAY, - DAY_THURSDAY, - DAY_FRIDAY, - DAY_SATURDAY + enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, }; - enum Month { + enum Month : uint8_t { /// Start at 1 to follow Windows SYSTEMTIME structure /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx MONTH_JANUARY = 1, @@ -182,21 +180,21 @@ public: MONTH_SEPTEMBER, MONTH_OCTOBER, MONTH_NOVEMBER, - MONTH_DECEMBER + MONTH_DECEMBER, }; struct Date { - int year; + int64_t year; Month month; - int day; + uint8_t day; Weekday weekday; bool dst; }; struct Time { - int hour; - int min; - int sec; + uint8_t hour; + uint8_t minute; + uint8_t second; }; struct TimeZoneInfo { @@ -207,14 +205,13 @@ public: virtual Date get_date(bool local = false) const = 0; virtual Time get_time(bool local = false) const = 0; virtual TimeZoneInfo get_time_zone_info() const = 0; - virtual String get_iso_date_time(bool local = false) const; virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; virtual void add_frame_delay(bool p_can_draw); virtual uint64_t get_ticks_usec() const = 0; - uint32_t get_ticks_msec() const; + uint64_t get_ticks_msec() const; virtual bool is_userfs_persistent() const { return true; } @@ -252,6 +249,7 @@ public: virtual String get_bundle_resource_dir() const; virtual String get_user_data_dir() const; + virtual String get_external_data_dir() const; virtual String get_resource_dir() const; enum SystemDir { diff --git a/core/os/time.cpp b/core/os/time.cpp new file mode 100644 index 0000000000..a185029969 --- /dev/null +++ b/core/os/time.cpp @@ -0,0 +1,433 @@ +/*************************************************************************/ +/* time.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "time.h" + +#include "core/os/os.h" + +#define UNIX_EPOCH_YEAR_AD 1970 // 1970 +#define SECONDS_PER_DAY (24 * 60 * 60) // 86400 +#define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400))) +#define YEAR_SIZE(year) (IS_LEAP_YEAR(year) ? 366 : 365) + +#define YEAR_KEY "year" +#define MONTH_KEY "month" +#define DAY_KEY "day" +#define WEEKDAY_KEY "weekday" +#define HOUR_KEY "hour" +#define MINUTE_KEY "minute" +#define SECOND_KEY "second" +#define DST_KEY "dst" + +// Table of number of days in each month (for regular year and leap year). +static const uint8_t MONTH_DAYS_TABLE[2][12] = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +VARIANT_ENUM_CAST(Time::Month); +VARIANT_ENUM_CAST(Time::Weekday); + +#define UNIX_TIME_TO_HMS \ + uint8_t hour, minute, second; \ + { \ + /* The time of the day (in seconds since start of day). */ \ + uint32_t day_clock = Math::posmod(p_unix_time_val, SECONDS_PER_DAY); \ + /* On x86 these 4 lines can be optimized to only 2 divisions. */ \ + second = day_clock % 60; \ + day_clock /= 60; \ + minute = day_clock % 60; \ + hour = day_clock / 60; \ + } + +#define UNIX_TIME_TO_YMD \ + int64_t year; \ + Month month; \ + uint8_t day; \ + /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \ + int64_t day_number = Math::floor(p_unix_time_val / (double)SECONDS_PER_DAY); \ + { \ + int64_t day_number_copy = day_number; \ + year = UNIX_EPOCH_YEAR_AD; \ + uint8_t month_zero_index = 0; \ + while (day_number_copy >= YEAR_SIZE(year)) { \ + day_number_copy -= YEAR_SIZE(year); \ + year++; \ + } \ + while (day_number_copy < 0) { \ + year--; \ + day_number_copy += YEAR_SIZE(year); \ + } \ + /* After the above, day_number now represents the day of the year (0-index). */ \ + while (day_number_copy >= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]) { \ + day_number_copy -= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]; \ + month_zero_index++; \ + } \ + /* After the above, day_number now represents the day of the month (0-index). */ \ + month = (Month)(month_zero_index + 1); \ + day = day_number_copy + 1; \ + } + +#define VALIDATE_YMDHMS \ + ERR_FAIL_COND_V_MSG(month == 0, 0, "Invalid month value of: " + itos(month) + ", months are 1-indexed and cannot be 0. See the Time.Month enum for valid values."); \ + ERR_FAIL_COND_V_MSG(month > 12, 0, "Invalid month value of: " + itos(month) + ". See the Time.Month enum for valid values."); \ + ERR_FAIL_COND_V_MSG(hour > 23, 0, "Invalid hour value of: " + itos(hour) + "."); \ + ERR_FAIL_COND_V_MSG(minute > 59, 0, "Invalid minute value of: " + itos(minute) + "."); \ + ERR_FAIL_COND_V_MSG(second > 59, 0, "Invalid second value of: " + itos(second) + " (leap seconds are not supported)."); \ + /* Do this check after month is tested as valid. */ \ + ERR_FAIL_COND_V_MSG(day == 0, 0, "Invalid day value of: " + itos(month) + ", days are 1-indexed and cannot be 0."); \ + uint8_t days_in_this_month = MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month - 1]; \ + ERR_FAIL_COND_V_MSG(day > days_in_this_month, 0, "Invalid day value of: " + itos(day) + " which is larger than the maximum for this month, " + itos(days_in_this_month) + "."); + +#define YMD_TO_DAY_NUMBER \ + /* The day number since Unix epoch (0-index). Days before 1970 are negative. */ \ + int64_t day_number = day - 1; \ + /* Add the days in the months to day_number. */ \ + for (int i = 0; i < month - 1; i++) { \ + day_number += MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][i]; \ + } \ + /* Add the days in the years to day_number. */ \ + if (year >= UNIX_EPOCH_YEAR_AD) { \ + for (int64_t iyear = UNIX_EPOCH_YEAR_AD; iyear < year; iyear++) { \ + day_number += YEAR_SIZE(iyear); \ + } \ + } else { \ + for (int64_t iyear = UNIX_EPOCH_YEAR_AD - 1; iyear >= year; iyear--) { \ + day_number -= YEAR_SIZE(iyear); \ + } \ + } + +#define PARSE_ISO8601_STRING \ + int64_t year = UNIX_EPOCH_YEAR_AD; \ + Month month = MONTH_JANUARY; \ + uint8_t day = 1; \ + uint8_t hour = 0; \ + uint8_t minute = 0; \ + uint8_t second = 0; \ + { \ + bool has_date = false, has_time = false; \ + String date, time; \ + if (p_datetime.find_char('T') > 0) { \ + has_date = has_time = true; \ + PackedStringArray array = p_datetime.split("T"); \ + date = array[0]; \ + time = array[1]; \ + } else if (p_datetime.find_char(' ') > 0) { \ + has_date = has_time = true; \ + PackedStringArray array = p_datetime.split(" "); \ + date = array[0]; \ + time = array[1]; \ + } else if (p_datetime.find_char('-', 1) > 0) { \ + has_date = true; \ + date = p_datetime; \ + } else if (p_datetime.find_char(':') > 0) { \ + has_time = true; \ + time = p_datetime; \ + } \ + /* Set the variables from the contents of the string. */ \ + if (has_date) { \ + PackedInt32Array array = date.split_ints("-", false); \ + year = array[0]; \ + month = (Month)array[1]; \ + day = array[2]; \ + /* Handle negative years. */ \ + if (p_datetime.find_char('-') == 0) { \ + year *= -1; \ + } \ + } \ + if (has_time) { \ + PackedInt32Array array = time.split_ints(":", false); \ + hour = array[0]; \ + minute = array[1]; \ + second = array[2]; \ + } \ + } + +#define EXTRACT_FROM_DICTIONARY \ + /* Get all time values from the dictionary. If it doesn't exist, set the */ \ + /* values to the default values for Unix epoch (1970-01-01 00:00:00). */ \ + int64_t year = p_datetime.has(YEAR_KEY) ? int64_t(p_datetime[YEAR_KEY]) : UNIX_EPOCH_YEAR_AD; \ + Month month = Month((p_datetime.has(MONTH_KEY)) ? uint8_t(p_datetime[MONTH_KEY]) : 1); \ + uint8_t day = p_datetime.has(DAY_KEY) ? uint8_t(p_datetime[DAY_KEY]) : 1; \ + uint8_t hour = p_datetime.has(HOUR_KEY) ? uint8_t(p_datetime[HOUR_KEY]) : 0; \ + uint8_t minute = p_datetime.has(MINUTE_KEY) ? uint8_t(p_datetime[MINUTE_KEY]) : 0; \ + uint8_t second = p_datetime.has(SECOND_KEY) ? uint8_t(p_datetime[SECOND_KEY]) : 0; + +Time *Time::singleton = nullptr; + +Time *Time::get_singleton() { + if (!singleton) { + memnew(Time); + } + return singleton; +} + +Dictionary Time::get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + UNIX_TIME_TO_YMD + Dictionary datetime; + datetime[YEAR_KEY] = year; + datetime[MONTH_KEY] = (uint8_t)month; + datetime[DAY_KEY] = day; + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + datetime[HOUR_KEY] = hour; + datetime[MINUTE_KEY] = minute; + datetime[SECOND_KEY] = second; + + return datetime; +} + +Dictionary Time::get_date_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_YMD + Dictionary datetime; + datetime[YEAR_KEY] = year; + datetime[MONTH_KEY] = (uint8_t)month; + datetime[DAY_KEY] = day; + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + datetime[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + + return datetime; +} + +Dictionary Time::get_time_dict_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + Dictionary datetime; + datetime[HOUR_KEY] = hour; + datetime[MINUTE_KEY] = minute; + datetime[SECOND_KEY] = second; + + return datetime; +} + +String Time::get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space) const { + UNIX_TIME_TO_HMS + UNIX_TIME_TO_YMD + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second); + } + + return timestamp; +} + +String Time::get_date_string_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_YMD + // Android is picky about the types passed to make Variant, so we need a cast. + return vformat("%04d-%02d-%02d", year, (uint8_t)month, day); +} + +String Time::get_time_string_from_unix_time(int64_t p_unix_time_val) const { + UNIX_TIME_TO_HMS + return vformat("%02d:%02d:%02d", hour, minute, second); +} + +Dictionary Time::get_datetime_dict_from_string(String p_datetime, bool p_weekday) const { + PARSE_ISO8601_STRING + Dictionary dict; + dict[YEAR_KEY] = year; + dict[MONTH_KEY] = (uint8_t)month; + dict[DAY_KEY] = day; + if (p_weekday) { + YMD_TO_DAY_NUMBER + // Unix epoch was a Thursday (day 0 aka 1970-01-01). + dict[WEEKDAY_KEY] = Math::posmod(day_number + WEEKDAY_THURSDAY, 7); + } + dict[HOUR_KEY] = hour; + dict[MINUTE_KEY] = minute; + dict[SECOND_KEY] = second; + + return dict; +} + +String Time::get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space) const { + ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), "", "Invalid datetime Dictionary: Dictionary is empty."); + EXTRACT_FROM_DICTIONARY + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", year, (uint8_t)month, day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, hour, minute, second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, hour, minute, second); + } + return timestamp; +} + +int64_t Time::get_unix_time_from_datetime_dict(Dictionary p_datetime) const { + ERR_FAIL_COND_V_MSG(p_datetime.is_empty(), 0, "Invalid datetime Dictionary: Dictionary is empty"); + EXTRACT_FROM_DICTIONARY + VALIDATE_YMDHMS + YMD_TO_DAY_NUMBER + return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second; +} + +int64_t Time::get_unix_time_from_datetime_string(String p_datetime) const { + PARSE_ISO8601_STRING + VALIDATE_YMDHMS + YMD_TO_DAY_NUMBER + return day_number * SECONDS_PER_DAY + hour * 3600 + minute * 60 + second; +} + +Dictionary Time::get_datetime_dict_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + OS::Time time = OS::get_singleton()->get_time(p_utc); + Dictionary datetime; + datetime[YEAR_KEY] = date.year; + datetime[MONTH_KEY] = (uint8_t)date.month; + datetime[DAY_KEY] = date.day; + datetime[WEEKDAY_KEY] = (uint8_t)date.weekday; + datetime[DST_KEY] = date.dst; + datetime[HOUR_KEY] = time.hour; + datetime[MINUTE_KEY] = time.minute; + datetime[SECOND_KEY] = time.second; + return datetime; +} + +Dictionary Time::get_date_dict_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + Dictionary date_dictionary; + date_dictionary[YEAR_KEY] = date.year; + date_dictionary[MONTH_KEY] = (uint8_t)date.month; + date_dictionary[DAY_KEY] = date.day; + date_dictionary[WEEKDAY_KEY] = (uint8_t)date.weekday; + date_dictionary[DST_KEY] = date.dst; + return date_dictionary; +} + +Dictionary Time::get_time_dict_from_system(bool p_utc) const { + OS::Time time = OS::get_singleton()->get_time(p_utc); + Dictionary time_dictionary; + time_dictionary[HOUR_KEY] = time.hour; + time_dictionary[MINUTE_KEY] = time.minute; + time_dictionary[SECOND_KEY] = time.second; + return time_dictionary; +} + +String Time::get_datetime_string_from_system(bool p_utc, bool p_use_space) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + OS::Time time = OS::get_singleton()->get_time(p_utc); + // vformat only supports up to 6 arguments, so we need to split this up into 2 parts. + String timestamp = vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day); + if (p_use_space) { + timestamp = vformat("%s %02d:%02d:%02d", timestamp, time.hour, time.minute, time.second); + } else { + timestamp = vformat("%sT%02d:%02d:%02d", timestamp, time.hour, time.minute, time.second); + } + + return timestamp; +} + +String Time::get_date_string_from_system(bool p_utc) const { + OS::Date date = OS::get_singleton()->get_date(p_utc); + // Android is picky about the types passed to make Variant, so we need a cast. + return vformat("%04d-%02d-%02d", date.year, (uint8_t)date.month, date.day); +} + +String Time::get_time_string_from_system(bool p_utc) const { + OS::Time time = OS::get_singleton()->get_time(p_utc); + return vformat("%02d:%02d:%02d", time.hour, time.minute, time.second); +} + +Dictionary Time::get_time_zone_from_system() const { + OS::TimeZoneInfo info = OS::get_singleton()->get_time_zone_info(); + Dictionary timezone; + timezone["bias"] = info.bias; + timezone["name"] = info.name; + return timezone; +} + +double Time::get_unix_time_from_system() const { + return OS::get_singleton()->get_unix_time(); +} + +uint64_t Time::get_ticks_msec() const { + return OS::get_singleton()->get_ticks_msec(); +} + +uint64_t Time::get_ticks_usec() const { + return OS::get_singleton()->get_ticks_usec(); +} + +void Time::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_unix_time", "unix_time_val"), &Time::get_datetime_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_date_dict_from_unix_time", "unix_time_val"), &Time::get_date_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_time_dict_from_unix_time", "unix_time_val"), &Time::get_time_dict_from_unix_time); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_unix_time", "unix_time_val", "use_space"), &Time::get_datetime_string_from_unix_time, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_string_from_unix_time", "unix_time_val"), &Time::get_date_string_from_unix_time); + ClassDB::bind_method(D_METHOD("get_time_string_from_unix_time", "unix_time_val"), &Time::get_time_string_from_unix_time); + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_string", "datetime", "weekday"), &Time::get_datetime_dict_from_string); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_dict", "datetime", "use_space"), &Time::get_datetime_string_from_dict); + ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_dict", "datetime"), &Time::get_unix_time_from_datetime_dict); + ClassDB::bind_method(D_METHOD("get_unix_time_from_datetime_string", "datetime"), &Time::get_unix_time_from_datetime_string); + + ClassDB::bind_method(D_METHOD("get_datetime_dict_from_system", "utc"), &Time::get_datetime_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_dict_from_system", "utc"), &Time::get_date_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_dict_from_system", "utc"), &Time::get_time_dict_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_datetime_string_from_system", "utc", "use_space"), &Time::get_datetime_string_from_system, DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_date_string_from_system", "utc"), &Time::get_date_string_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_string_from_system", "utc"), &Time::get_time_string_from_system, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_time_zone_from_system"), &Time::get_time_zone_from_system); + ClassDB::bind_method(D_METHOD("get_unix_time_from_system"), &Time::get_unix_time_from_system); + ClassDB::bind_method(D_METHOD("get_ticks_msec"), &Time::get_ticks_msec); + ClassDB::bind_method(D_METHOD("get_ticks_usec"), &Time::get_ticks_usec); + + BIND_ENUM_CONSTANT(MONTH_JANUARY); + BIND_ENUM_CONSTANT(MONTH_FEBRUARY); + BIND_ENUM_CONSTANT(MONTH_MARCH); + BIND_ENUM_CONSTANT(MONTH_APRIL); + BIND_ENUM_CONSTANT(MONTH_MAY); + BIND_ENUM_CONSTANT(MONTH_JUNE); + BIND_ENUM_CONSTANT(MONTH_JULY); + BIND_ENUM_CONSTANT(MONTH_AUGUST); + BIND_ENUM_CONSTANT(MONTH_SEPTEMBER); + BIND_ENUM_CONSTANT(MONTH_OCTOBER); + BIND_ENUM_CONSTANT(MONTH_NOVEMBER); + BIND_ENUM_CONSTANT(MONTH_DECEMBER); + + BIND_ENUM_CONSTANT(WEEKDAY_SUNDAY); + BIND_ENUM_CONSTANT(WEEKDAY_MONDAY); + BIND_ENUM_CONSTANT(WEEKDAY_TUESDAY); + BIND_ENUM_CONSTANT(WEEKDAY_WEDNESDAY); + BIND_ENUM_CONSTANT(WEEKDAY_THURSDAY); + BIND_ENUM_CONSTANT(WEEKDAY_FRIDAY); + BIND_ENUM_CONSTANT(WEEKDAY_SATURDAY); +} + +Time::Time() { + ERR_FAIL_COND_MSG(singleton, "Singleton for Time already exists."); + singleton = this; +} + +Time::~Time() { + singleton = nullptr; +} diff --git a/core/os/time.h b/core/os/time.h new file mode 100644 index 0000000000..4325f93d56 --- /dev/null +++ b/core/os/time.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* time.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef TIME_H +#define TIME_H + +#include "core/object/class_db.h" + +// This Time class conforms with as many of the ISO 8601 standards as possible. +// * As per ISO 8601:2004 4.3.2.1, all dates follow the Proleptic Gregorian +// calendar. As such, the day before 1582-10-15 is 1582-10-14, not 1582-10-04. +// See: https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar +// * As per ISO 8601:2004 3.4.2 and 4.1.2.4, the year before 1 AD (aka 1 BC) +// is number "0", with the year before that (2 BC) being "-1", etc. +// Conversion methods assume "the same timezone", and do not handle DST. +// Leap seconds are not handled, they must be done manually if desired. +// Suffixes such as "Z" are not handled, you need to strip them away manually. + +class Time : public Object { + GDCLASS(Time, Object); + static void _bind_methods(); + static Time *singleton; + +public: + static Time *get_singleton(); + + enum Month : uint8_t { + /// Start at 1 to follow Windows SYSTEMTIME structure + /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx + MONTH_JANUARY = 1, + MONTH_FEBRUARY, + MONTH_MARCH, + MONTH_APRIL, + MONTH_MAY, + MONTH_JUNE, + MONTH_JULY, + MONTH_AUGUST, + MONTH_SEPTEMBER, + MONTH_OCTOBER, + MONTH_NOVEMBER, + MONTH_DECEMBER, + }; + + enum Weekday : uint8_t { + WEEKDAY_SUNDAY, + WEEKDAY_MONDAY, + WEEKDAY_TUESDAY, + WEEKDAY_WEDNESDAY, + WEEKDAY_THURSDAY, + WEEKDAY_FRIDAY, + WEEKDAY_SATURDAY, + }; + + // Methods that convert times. + Dictionary get_datetime_dict_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_date_dict_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_time_dict_from_unix_time(int64_t p_unix_time_val) const; + String get_datetime_string_from_unix_time(int64_t p_unix_time_val, bool p_use_space = false) const; + String get_date_string_from_unix_time(int64_t p_unix_time_val) const; + String get_time_string_from_unix_time(int64_t p_unix_time_val) const; + Dictionary get_datetime_dict_from_string(String p_datetime, bool p_weekday = true) const; + String get_datetime_string_from_dict(Dictionary p_datetime, bool p_use_space = false) const; + int64_t get_unix_time_from_datetime_dict(Dictionary p_datetime) const; + int64_t get_unix_time_from_datetime_string(String p_datetime) const; + + // Methods that get information from OS. + Dictionary get_datetime_dict_from_system(bool p_utc = false) const; + Dictionary get_date_dict_from_system(bool p_utc = false) const; + Dictionary get_time_dict_from_system(bool p_utc = false) const; + String get_datetime_string_from_system(bool p_utc = false, bool p_use_space = false) const; + String get_date_string_from_system(bool p_utc = false) const; + String get_time_string_from_system(bool p_utc = false) const; + Dictionary get_time_zone_from_system() const; + double get_unix_time_from_system() const; + uint64_t get_ticks_msec() const; + uint64_t get_ticks_usec() const; + + Time(); + virtual ~Time(); +}; + +#endif // TIME_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index f1b1b98bea..0739a0336d 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -37,6 +37,8 @@ #include "core/crypto/aes_context.h" #include "core/crypto/crypto.h" #include "core/crypto/hashing_context.h" +#include "core/extension/native_extension.h" +#include "core/extension/native_extension_manager.h" #include "core/input/input.h" #include "core/input/input_map.h" #include "core/io/config_file.h" @@ -46,7 +48,7 @@ #include "core/io/json.h" #include "core/io/marshalls.h" #include "core/io/multiplayer_api.h" -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "core/io/packed_data_container.h" #include "core/io/packet_peer.h" #include "core/io/packet_peer_dtls.h" @@ -68,6 +70,7 @@ #include "core/object/class_db.h" #include "core/object/undo_redo.h" #include "core/os/main_loop.h" +#include "core/os/time.h" #include "core/string/optimized_translation.h" #include "core/string/translation.h" @@ -85,7 +88,6 @@ static _OS *_os = nullptr; static _Engine *_engine = nullptr; static _ClassDB *_classdb = nullptr; static _Marshalls *_marshalls = nullptr; -static _JSON *_json = nullptr; static _EngineDebugger *_engine_debugger = nullptr; static IP *ip = nullptr; @@ -95,6 +97,8 @@ static _Geometry3D *_geometry_3d = nullptr; extern Mutex _global_mutex; +static NativeExtensionManager *native_extension_manager = nullptr; + extern void register_global_constants(); extern void unregister_global_constants(); @@ -113,25 +117,25 @@ void register_core_types() { CoreStringNames::create(); - resource_format_po.instance(); + resource_format_po.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_po); - resource_saver_binary.instance(); + resource_saver_binary.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_binary); - resource_loader_binary.instance(); + resource_loader_binary.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_binary); - resource_format_importer.instance(); + resource_format_importer.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_importer); - resource_format_image.instance(); + resource_format_image.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_image); ClassDB::register_class<Object>(); ClassDB::register_virtual_class<Script>(); - ClassDB::register_class<Reference>(); + ClassDB::register_class<RefCounted>(); ClassDB::register_class<WeakRef>(); ClassDB::register_class<Resource>(); ClassDB::register_class<Image>(); @@ -153,14 +157,20 @@ void register_core_types() { ClassDB::register_class<InputEventPanGesture>(); ClassDB::register_class<InputEventMIDI>(); + // Network + ClassDB::register_virtual_class<IP>(); + ClassDB::register_virtual_class<StreamPeer>(); ClassDB::register_class<StreamPeerBuffer>(); ClassDB::register_class<StreamPeerTCP>(); ClassDB::register_class<TCPServer>(); + + ClassDB::register_virtual_class<PacketPeer>(); + ClassDB::register_class<PacketPeerStream>(); ClassDB::register_class<PacketPeerUDP>(); ClassDB::register_class<UDPServer>(); - ClassDB::register_custom_instance_class<PacketPeerDTLS>(); - ClassDB::register_custom_instance_class<DTLSServer>(); + + ClassDB::register_custom_instance_class<HTTPClient>(); // Crypto ClassDB::register_class<HashingContext>(); @@ -170,22 +180,20 @@ void register_core_types() { ClassDB::register_custom_instance_class<HMACContext>(); ClassDB::register_custom_instance_class<Crypto>(); ClassDB::register_custom_instance_class<StreamPeerSSL>(); + ClassDB::register_custom_instance_class<PacketPeerDTLS>(); + ClassDB::register_custom_instance_class<DTLSServer>(); - resource_format_saver_crypto.instance(); + resource_format_saver_crypto.instantiate(); ResourceSaver::add_resource_format_saver(resource_format_saver_crypto); - resource_format_loader_crypto.instance(); + resource_format_loader_crypto.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_loader_crypto); - ClassDB::register_virtual_class<IP>(); - ClassDB::register_virtual_class<PacketPeer>(); - ClassDB::register_class<PacketPeerStream>(); - ClassDB::register_virtual_class<NetworkedMultiplayerPeer>(); + ClassDB::register_virtual_class<MultiplayerPeer>(); ClassDB::register_class<MultiplayerAPI>(); ClassDB::register_class<MainLoop>(); ClassDB::register_class<Translation>(); ClassDB::register_class<OptimizedTranslation>(); ClassDB::register_class<UndoRedo>(); - ClassDB::register_class<HTTPClient>(); ClassDB::register_class<TriangleMesh>(); ClassDB::register_class<ResourceFormatLoader>(); @@ -198,7 +206,7 @@ void register_core_types() { ClassDB::register_class<_Semaphore>(); ClassDB::register_class<XMLParser>(); - ClassDB::register_class<JSONParser>(); + ClassDB::register_class<JSON>(); ClassDB::register_class<ConfigFile>(); @@ -211,10 +219,14 @@ void register_core_types() { ClassDB::register_class<EncodedObjectAsID>(); ClassDB::register_class<RandomNumberGenerator>(); - ClassDB::register_class<JSONParseResult>(); - ClassDB::register_virtual_class<ResourceImporter>(); + ClassDB::register_class<NativeExtension>(); + + ClassDB::register_virtual_class<NativeExtensionManager>(); + + native_extension_manager = memnew(NativeExtensionManager); + ip = IP::create(); _geometry_2d = memnew(_Geometry2D); @@ -226,7 +238,6 @@ void register_core_types() { _engine = memnew(_Engine); _classdb = memnew(_ClassDB); _marshalls = memnew(_Marshalls); - _json = memnew(_JSON); _engine_debugger = memnew(_EngineDebugger); } @@ -255,12 +266,12 @@ void register_core_singletons() { ClassDB::register_class<TranslationServer>(); ClassDB::register_virtual_class<Input>(); ClassDB::register_class<InputMap>(); - ClassDB::register_class<_JSON>(); ClassDB::register_class<Expression>(); ClassDB::register_class<_EngineDebugger>(); + ClassDB::register_class<Time>(); Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton(), "IP")); Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry2D", _Geometry2D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("Geometry3D", _Geometry3D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("ResourceLoader", _ResourceLoader::get_singleton())); @@ -272,18 +283,33 @@ void register_core_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("TranslationServer", TranslationServer::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("Input", Input::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("EngineDebugger", _EngineDebugger::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("NativeExtensionManager", NativeExtensionManager::get_singleton())); +} + +void register_core_extensions() { + //harcoded for now + if (ProjectSettings::get_singleton()->has_setting("native_extensions/paths")) { + Vector<String> paths = ProjectSettings::get_singleton()->get("native_extensions/paths"); + for (int i = 0; i < paths.size(); i++) { + NativeExtensionManager::LoadStatus status = native_extension_manager->load_extension(paths[i]); + ERR_CONTINUE_MSG(status != NativeExtensionManager::LOAD_STATUS_OK, "Error loading extension: " + paths[i]); + } + } + native_extension_manager->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); } void unregister_core_types() { + native_extension_manager->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_CORE); + + memdelete(native_extension_manager); memdelete(_resource_loader); memdelete(_resource_saver); memdelete(_os); memdelete(_engine); memdelete(_classdb); memdelete(_marshalls); - memdelete(_json); memdelete(_engine_debugger); memdelete(_geometry_2d); diff --git a/core/register_core_types.h b/core/register_core_types.h index baf7ddbe65..830f05607d 100644 --- a/core/register_core_types.h +++ b/core/register_core_types.h @@ -33,6 +33,7 @@ void register_core_types(); void register_core_settings(); +void register_core_extensions(); void register_core_singletons(); void unregister_core_types(); diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index ad768f7140..f9b4e661e4 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -30,7 +30,7 @@ #include "translation_po.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #ifdef DEBUG_TRANSLATION_PO void TranslationPO::print_translation_map() { @@ -188,7 +188,7 @@ void TranslationPO::set_plural_rule(const String &p_plural_rule) { plural_rule = plural_rule.replacen("(", ""); plural_rule = plural_rule.replacen(")", ""); _cache_plural_tests(plural_rule); - expr.instance(); + expr.instantiate(); input_name.push_back("n"); } diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index 7fec96944a..4cd2915ffa 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -54,7 +54,7 @@ #define snprintf _snprintf_s #endif -#define MAX_DIGITS 6 +#define MAX_DECIMALS 32 #define UPPERCASE(m_c) (((m_c) >= 'a' && (m_c) <= 'z') ? ((m_c) - ('a' - 'A')) : (m_c)) #define LOWERCASE(m_c) (((m_c) >= 'A' && (m_c) <= 'Z') ? ((m_c) + ('a' - 'A')) : (m_c)) #define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9') @@ -275,7 +275,7 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r base = base.substr(pos + 1, base.length() - pos - 1); } else { // Anything else - if (base.get_slice_count(":") > 1) { + if (base.get_slice_count(":") > 2) { return ERR_INVALID_PARAMETER; } pos = base.rfind(":"); @@ -294,7 +294,7 @@ Error String::parse_url(String &r_scheme, String &r_host, int &r_port, String &r // Port if (base.begins_with(":")) { base = base.substr(1, base.length() - 1); - if (!base.is_valid_integer()) { + if (!base.is_valid_int()) { return ERR_INVALID_PARAMETER; } r_port = base.to_int(); @@ -1379,8 +1379,11 @@ String String::num(double p_num, int p_decimals) { } #ifndef NO_USE_STDLIB - if (p_decimals > 16) { - p_decimals = 16; + if (p_decimals < 0) { + p_decimals = 14 - (int)floor(log10(p_num)); + } + if (p_decimals > MAX_DECIMALS) { + p_decimals = MAX_DECIMALS; } char fmt[7]; @@ -1391,7 +1394,6 @@ String String::num(double p_num, int p_decimals) { fmt[1] = 'l'; fmt[2] = 'f'; fmt[3] = 0; - } else if (p_decimals < 10) { fmt[2] = '0' + p_decimals; fmt[3] = 'l'; @@ -1458,8 +1460,9 @@ String String::num(double p_num, int p_decimals) { double dec = p_num - (double)((int)p_num); int digit = 0; - if (p_decimals > MAX_DIGITS) - p_decimals = MAX_DIGITS; + if (p_decimals > MAX_DECIMALS) { + p_decimals = MAX_DECIMALS; + } int dec_int = 0; int dec_max = 0; @@ -1471,16 +1474,18 @@ String String::num(double p_num, int p_decimals) { digit++; if (p_decimals == -1) { - if (digit == MAX_DIGITS) //no point in going to infinite + if (digit == MAX_DECIMALS) { //no point in going to infinite break; + } if (dec - (double)((int)dec) < 1e-6) { break; } } - if (digit == p_decimals) + if (digit == p_decimals) { break; + } } dec *= 10; int last = (int)dec % 10; @@ -1589,7 +1594,7 @@ String String::num_uint64(uint64_t p_num, int base, bool capitalize_hex) { return s; } -String String::num_real(double p_num) { +String String::num_real(double p_num, bool p_trailing) { if (Math::is_nan(p_num)) { return "nan"; } @@ -1616,7 +1621,15 @@ String String::num_real(double p_num) { double dec = p_num - (double)((int)p_num); int digit = 0; - int decimals = MAX_DIGITS; + +#if REAL_T_IS_DOUBLE + int decimals = 14 - (int)floor(log10(p_num)); +#else + int decimals = 6 - (int)floor(log10(p_num)); +#endif + if (decimals > MAX_DECIMALS) { + decimals = MAX_DECIMALS; + } int dec_int = 0; int dec_max = 0; @@ -1656,8 +1669,10 @@ String String::num_real(double p_num) { dec_int /= 10; } sd = '.' + decimal; - } else { + } else if (p_trailing) { sd = ".0"; + } else { + sd = ""; } if (intn == 0) { @@ -3767,7 +3782,7 @@ String String::humanize_size(uint64_t p_size) { return String::num(p_size / divisor).pad_decimals(digits) + " " + prefixes[prefix_idx]; } -bool String::is_abs_path() const { +bool String::is_absolute_path() const { if (length() > 1) { return (operator[](0) == '/' || operator[](0) == '\\' || find(":/") != -1 || find(":\\") != -1); } else if ((length()) == 1) { @@ -4134,7 +4149,7 @@ String String::trim_suffix(const String &p_suffix) const { return s; } -bool String::is_valid_integer() const { +bool String::is_valid_int() const { int len = length(); if (len == 0) { @@ -4359,7 +4374,7 @@ bool String::is_valid_ip_address() const { } for (int i = 0; i < ip.size(); i++) { String n = ip[i]; - if (!n.is_valid_integer()) { + if (!n.is_valid_int()) { return false; } int val = n.to_int(); @@ -4377,7 +4392,7 @@ bool String::is_resource_file() const { } bool String::is_rel_path() const { - return !is_abs_path(); + return !is_absolute_path(); } String String::get_base_dir() const { diff --git a/core/string/ustring.h b/core/string/ustring.h index a56845deff..ffb354d6e1 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -309,7 +309,7 @@ public: String unquote() const; static String num(double p_num, int p_decimals = -1); static String num_scientific(double p_num); - static String num_real(double p_num); + static String num_real(double p_num, bool p_trailing = true); static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false); static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false); static String chr(char32_t p_char); @@ -397,7 +397,7 @@ public: _FORCE_INLINE_ bool is_empty() const { return length() == 0; } // path functions - bool is_abs_path() const; + bool is_absolute_path() const; bool is_rel_path() const; bool is_resource_file() const; String path_to(const String &p_path) const; @@ -425,7 +425,7 @@ public: String validate_node_name() const; bool is_valid_identifier() const; - bool is_valid_integer() const; + bool is_valid_int() const; bool is_valid_float() const; bool is_valid_hex_number(bool p_with_prefix) const; bool is_valid_html_color() const; diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h new file mode 100644 index 0000000000..be9d0b5475 --- /dev/null +++ b/core/templates/bin_sorted_array.h @@ -0,0 +1,181 @@ +/*************************************************************************/ +/* bin_sorted_array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef BIN_SORTED_ARRAY_H +#define BIN_SORTED_ARRAY_H + +#include "core/templates/local_vector.h" +#include "core/templates/paged_array.h" + +template <class T> +class BinSortedArray { + PagedArray<T> array; + LocalVector<uint64_t> bin_limits; + + // Implement if elements need to keep track of their own index in the array. + _FORCE_INLINE_ virtual void _update_idx(T &r_element, uint64_t p_idx) {} + + _FORCE_INLINE_ void _swap(uint64_t p_a, uint64_t p_b) { + SWAP(array[p_a], array[p_b]); + _update_idx(array[p_a], p_a); + _update_idx(array[p_b], p_b); + } + +public: + uint64_t insert(T &p_element, uint64_t p_bin) { + array.push_back(p_element); + uint64_t new_idx = array.size() - 1; + _update_idx(p_element, new_idx); + bin_limits[0] = new_idx; + if (p_bin != 0) { + new_idx = move(new_idx, p_bin); + } + return new_idx; + } + + uint64_t move(uint64_t p_idx, uint64_t p_bin) { + ERR_FAIL_COND_V(p_idx >= array.size(), -1); + + uint64_t current_bin = bin_limits.size() - 1; + while (p_idx > bin_limits[current_bin]) { + current_bin--; + } + + if (p_bin == current_bin) { + return p_idx; + } + + uint64_t current_idx = p_idx; + if (p_bin > current_bin) { + while (p_bin > current_bin) { + uint64_t swap_idx = 0; + + if (current_bin == bin_limits.size() - 1) { + bin_limits.push_back(0); + } else { + bin_limits[current_bin + 1]++; + swap_idx = bin_limits[current_bin + 1]; + } + + if (current_idx != swap_idx) { + _swap(current_idx, swap_idx); + current_idx = swap_idx; + } + + current_bin++; + } + } else { + while (p_bin < current_bin) { + uint64_t swap_idx = bin_limits[current_bin]; + + if (current_idx != swap_idx) { + _swap(current_idx, swap_idx); + } + + if (current_bin == bin_limits.size() - 1 && bin_limits[current_bin] == 0) { + bin_limits.resize(bin_limits.size() - 1); + } else { + bin_limits[current_bin]--; + } + current_idx = swap_idx; + current_bin--; + } + } + + return current_idx; + } + + void remove(uint64_t p_idx) { + ERR_FAIL_COND(p_idx >= array.size()); + uint64_t new_idx = move(p_idx, 0); + uint64_t swap_idx = array.size() - 1; + + if (new_idx != swap_idx) { + _swap(new_idx, swap_idx); + } + + if (bin_limits[0] > 0) { + bin_limits[0]--; + } + + array.pop_back(); + } + + void set_page_pool(PagedArrayPool<T> *p_page_pool) { + array.set_page_pool(p_page_pool); + } + + _FORCE_INLINE_ const T &operator[](uint64_t p_index) const { + return array[p_index]; + } + + _FORCE_INLINE_ T &operator[](uint64_t p_index) { + return array[p_index]; + } + + int get_bin_count() { + if (array.size() == 0) { + return 0; + } + return bin_limits.size(); + } + + int get_bin_start(int p_bin) { + ERR_FAIL_COND_V(p_bin >= get_bin_count(), ~0U); + if ((unsigned int)p_bin == bin_limits.size() - 1) { + return 0; + } + return bin_limits[p_bin + 1] + 1; + } + + int get_bin_size(int p_bin) { + ERR_FAIL_COND_V(p_bin >= get_bin_count(), 0); + if ((unsigned int)p_bin == bin_limits.size() - 1) { + return bin_limits[p_bin] + 1; + } + return bin_limits[p_bin] - bin_limits[p_bin + 1]; + } + + void reset() { + array.reset(); + bin_limits.clear(); + bin_limits.push_back(0); + } + + BinSortedArray() { + bin_limits.push_back(0); + } + + virtual ~BinSortedArray() { + reset(); + } +}; + +#endif //BIN_SORTED_ARRAY_H diff --git a/core/templates/command_queue_mt.cpp b/core/templates/command_queue_mt.cpp index 238bf3975c..04a8095f0b 100644 --- a/core/templates/command_queue_mt.cpp +++ b/core/templates/command_queue_mt.cpp @@ -70,35 +70,7 @@ CommandQueueMT::SyncSemaphore *CommandQueueMT::_alloc_sync_sem() { return &sync_sems[idx]; } -bool CommandQueueMT::dealloc_one() { -tryagain: - if (dealloc_ptr == (write_ptr_and_epoch >> 1)) { - // The queue is empty - return false; - } - - uint32_t size = *(uint32_t *)&command_mem[dealloc_ptr]; - - if (size == 0) { - // End of command buffer wrap down - dealloc_ptr = 0; - goto tryagain; - } - - if (size & 1) { - // Still used, nothing can be deallocated - return false; - } - - dealloc_ptr += (size >> 1) + 8; - return true; -} - CommandQueueMT::CommandQueueMT(bool p_sync) { - command_mem_size = GLOBAL_DEF_RST("memory/limits/command_queue/multithreading_queue_size_kb", DEFAULT_COMMAND_MEM_SIZE_KB); - ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/command_queue/multithreading_queue_size_kb", PropertyInfo(Variant::INT, "memory/limits/command_queue/multithreading_queue_size_kb", PROPERTY_HINT_RANGE, "1,4096,1,or_greater")); - command_mem_size *= 1024; - command_mem = (uint8_t *)memalloc(command_mem_size); if (p_sync) { sync = memnew(Semaphore); } @@ -108,5 +80,4 @@ CommandQueueMT::~CommandQueueMT() { if (sync) { memdelete(sync); } - memfree(command_mem); } diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h index 0012cea72d..acc46da0d5 100644 --- a/core/templates/command_queue_mt.h +++ b/core/templates/command_queue_mt.h @@ -34,6 +34,8 @@ #include "core/os/memory.h" #include "core/os/mutex.h" #include "core/os/semaphore.h" +#include "core/string/print_string.h" +#include "core/templates/local_vector.h" #include "core/templates/simple_type.h" #include "core/typedefs.h" @@ -334,11 +336,7 @@ class CommandQueueMT { SYNC_SEMAPHORES = 8 }; - uint8_t *command_mem = nullptr; - uint32_t read_ptr_and_epoch = 0; - uint32_t write_ptr_and_epoch = 0; - uint32_t dealloc_ptr = 0; - uint32_t command_mem_size = 0; + LocalVector<uint8_t> command_mem; SyncSemaphore sync_sems[SYNC_SEMAPHORES]; Mutex mutex; Semaphore *sync = nullptr; @@ -346,138 +344,47 @@ class CommandQueueMT { template <class T> T *allocate() { // alloc size is size+T+safeguard - uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)) + 8; - - // Assert that the buffer is big enough to hold at least two messages. - ERR_FAIL_COND_V(alloc_size * 2 + sizeof(uint32_t) > command_mem_size, nullptr); - - tryagain: - uint32_t write_ptr = write_ptr_and_epoch >> 1; - - if (write_ptr < dealloc_ptr) { - // behind dealloc_ptr, check that there is room - if ((dealloc_ptr - write_ptr) <= alloc_size) { - // There is no more room, try to deallocate something - if (dealloc_one()) { - goto tryagain; - } - return nullptr; - } - } else { - // ahead of dealloc_ptr, check that there is room - - if ((command_mem_size - write_ptr) < alloc_size + sizeof(uint32_t)) { - // no room at the end, wrap down; - - if (dealloc_ptr == 0) { // don't want write_ptr to become dealloc_ptr - - // There is no more room, try to deallocate something - if (dealloc_one()) { - goto tryagain; - } - return nullptr; - } - - // if this happens, it's a bug - ERR_FAIL_COND_V((command_mem_size - write_ptr) < 8, nullptr); - // zero means, wrap to beginning - - uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = 1; - write_ptr_and_epoch = 0 | (1 & ~write_ptr_and_epoch); // Invert epoch. - // See if we can get the thread to run and clear up some more space while we wait. - // This is required if alloc_size * 2 + 4 > COMMAND_MEM_SIZE - if (sync) { - sync->post(); - } - goto tryagain; - } - } - // Allocate the size and the 'in use' bit. - // First bit used to mark if command is still in use (1) - // or if it has been destroyed and can be deallocated (0). - uint32_t size = (sizeof(T) + 8 - 1) & ~(8 - 1); - uint32_t *p = (uint32_t *)&command_mem[write_ptr]; - *p = (size << 1) | 1; - write_ptr += 8; - // allocate the command - T *cmd = memnew_placement(&command_mem[write_ptr], T); - write_ptr += size; - write_ptr_and_epoch = (write_ptr << 1) | (write_ptr_and_epoch & 1); + uint32_t alloc_size = ((sizeof(T) + 8 - 1) & ~(8 - 1)); + uint64_t size = command_mem.size(); + command_mem.resize(size + alloc_size + 8); + *(uint64_t *)&command_mem[size] = alloc_size; + T *cmd = memnew_placement(&command_mem[size + 8], T); return cmd; } template <class T> T *allocate_and_lock() { lock(); - T *ret; - - while ((ret = allocate<T>()) == nullptr) { - unlock(); - // sleep a little until fetch happened and some room is made - wait_for_flush(); - lock(); - } - + T *ret = allocate<T>(); return ret; } - bool flush_one(bool p_lock = true) { - if (p_lock) { - lock(); - } - tryagain: - - // tried to read an empty queue - if (read_ptr_and_epoch == write_ptr_and_epoch) { - if (p_lock) { - unlock(); - } - return false; - } - - uint32_t read_ptr = read_ptr_and_epoch >> 1; - uint32_t size_ptr = read_ptr; - uint32_t size = *(uint32_t *)&command_mem[read_ptr] >> 1; - - if (size == 0) { - *(uint32_t *)&command_mem[read_ptr] = 0; // clear in-use bit. - //end of ringbuffer, wrap - read_ptr_and_epoch = 0 | (1 & ~read_ptr_and_epoch); // Invert epoch. - goto tryagain; - } - - read_ptr += 8; + void _flush() { + lock(); - CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); + uint64_t read_ptr = 0; + uint64_t limit = command_mem.size(); - read_ptr += size; + while (read_ptr < limit) { + uint64_t size = *(uint64_t *)&command_mem[read_ptr]; + read_ptr += 8; + CommandBase *cmd = reinterpret_cast<CommandBase *>(&command_mem[read_ptr]); - read_ptr_and_epoch = (read_ptr << 1) | (read_ptr_and_epoch & 1); + cmd->call(); //execute the function + cmd->post(); //release in case it needs sync/ret + cmd->~CommandBase(); //should be done, so erase the command - if (p_lock) { - unlock(); - } - cmd->call(); - if (p_lock) { - lock(); + read_ptr += size; } - cmd->post(); - cmd->~CommandBase(); - *(uint32_t *)&command_mem[size_ptr] &= ~1; - - if (p_lock) { - unlock(); - } - return true; + command_mem.clear(); + unlock(); } void lock(); void unlock(); void wait_for_flush(); SyncSemaphore *_alloc_sync_sem(); - bool dealloc_one(); public: /* NORMAL PUSH COMMANDS */ @@ -492,23 +399,19 @@ public: DECL_PUSH_AND_SYNC(0) SPACE_SEP_LIST(DECL_PUSH_AND_SYNC, 15) - void wait_and_flush_one() { - ERR_FAIL_COND(!sync); - sync->wait(); - flush_one(); - } - _FORCE_INLINE_ void flush_if_pending() { - if (unlikely(read_ptr_and_epoch != write_ptr_and_epoch)) { - flush_all(); + if (unlikely(command_mem.size() > 0)) { + _flush(); } } void flush_all() { - //ERR_FAIL_COND(sync); - lock(); - while (flush_one(false)) { - } - unlock(); + _flush(); + } + + void wait_and_flush() { + ERR_FAIL_COND(!sync); + sync->wait(); + _flush(); } CommandQueueMT(bool p_sync); diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index dc378aed69..1257b54449 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -291,7 +291,7 @@ public: } /** - * Same as get, except it can return nullptr when item was not found. + * Same as get, except it can return nullptr when item was not found. * This is mainly used for speed purposes. */ @@ -324,7 +324,7 @@ public: } /** - * Same as get, except it can return nullptr when item was not found. + * Same as get, except it can return nullptr when item was not found. * This version is custom, will take a hash and a custom key (that should support operator==() */ @@ -443,7 +443,7 @@ public: /** * Get the next key to p_key, and the first key if p_key is null. - * Returns a pointer to the next key if found, nullptr otherwise. + * Returns a pointer to the next key if found, nullptr otherwise. * Adding/Removing elements while iterating will, of course, have unexpected results, don't do it. * * Example: diff --git a/core/templates/list.h b/core/templates/list.h index 010e35eed8..6047b89670 100644 --- a/core/templates/list.h +++ b/core/templates/list.h @@ -135,6 +135,83 @@ public: _FORCE_INLINE_ Element() {} }; + typedef T ValueType; + + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ T *operator->() const { return &E->get(); } + _FORCE_INLINE_ Iterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + Iterator(Element *p_E) { E = p_E; } + Iterator() {} + Iterator(const Iterator &p_it) { E = p_it.E; } + + private: + Element *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ const T *operator->() const { return &E->get(); } + _FORCE_INLINE_ ConstIterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + _FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; } + _FORCE_INLINE_ ConstIterator() {} + _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + + private: + const Element *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(front()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ Iterator find(const K &p_key) { + return Iterator(find(p_key)); + } +#endif + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(front()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } +#if 0 + //to use when replacing find() + _FORCE_INLINE_ ConstIterator find(const K &p_key) const { + return ConstIterator(find(p_key)); + } +#endif private: struct _Data { Element *first = nullptr; diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h index 5f22e08eb8..668ec513d6 100644 --- a/core/templates/local_vector.h +++ b/core/templates/local_vector.h @@ -178,7 +178,7 @@ public: } int64_t find(const T &p_val, U p_from = 0) const { - for (U i = 0; i < count; i++) { + for (U i = p_from; i < count; i++) { if (data[i] == p_val) { return int64_t(i); } diff --git a/core/templates/map.h b/core/templates/map.h index 7dfee13d2c..a47547d355 100644 --- a/core/templates/map.h +++ b/core/templates/map.h @@ -33,6 +33,7 @@ #include "core/error/error_macros.h" #include "core/os/memory.h" +#include "core/templates/pair.h" // based on the very nice implementation of rb-trees by: // https://web.archive.org/web/20120507164830/http://web.mit.edu/~emin/www/source_code/red_black_tree/index.html @@ -55,11 +56,12 @@ public: Element *parent = nullptr; Element *_next = nullptr; Element *_prev = nullptr; - K _key; - V _value; - //_Data *data; + KeyValue<K, V> _data; public: + KeyValue<K, V> &key_value() { return _data; } + const KeyValue<K, V> &key_value() const { return _data; } + const Element *next() const { return _next; } @@ -73,23 +75,106 @@ public: return _prev; } const K &key() const { - return _key; + return _data.key; } V &value() { - return _value; + return _data.value; } const V &value() const { - return _value; + return _data.value; } V &get() { - return _value; + return _data.value; } const V &get() const { - return _value; + return _data.value; } - Element() {} + Element(const KeyValue<K, V> &p_data) : + _data(p_data) {} }; + typedef KeyValue<K, V> ValueType; + + struct Iterator { + _FORCE_INLINE_ KeyValue<K, V> &operator*() const { + return E->key_value(); + } + _FORCE_INLINE_ KeyValue<K, V> *operator->() const { return &E->key_value(); } + _FORCE_INLINE_ Iterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + Iterator(Element *p_E) { E = p_E; } + Iterator() {} + Iterator(const Iterator &p_it) { E = p_it.E; } + + private: + Element *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const KeyValue<K, V> &operator*() const { + return E->key_value(); + } + _FORCE_INLINE_ const KeyValue<K, V> *operator->() const { return &E->key_value(); } + _FORCE_INLINE_ ConstIterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return E != b.E; } + + ConstIterator(const Element *p_E) { E = p_E; } + ConstIterator() {} + ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + + private: + const Element *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(front()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ Iterator find(const K &p_key) { + return Iterator(find(p_key)); + } +#endif + _FORCE_INLINE_ void remove(const Iterator &p_iter) { + return erase(p_iter.E); + } + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(front()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ ConstIterator find(const K &p_key) const { + return ConstIterator(find(p_key)); + } +#endif private: struct _Data { Element *_root = nullptr; @@ -107,7 +192,7 @@ private: } void _create_root() { - _root = memnew_allocator(Element, A); + _root = memnew_allocator(Element(KeyValue<K, V>(K(), V())), A); _root->parent = _root->left = _root->right = _nil; _root->color = BLACK; } @@ -216,9 +301,9 @@ private: C less; while (node != _data._nil) { - if (less(p_key, node->_key)) { + if (less(p_key, node->_data.key)) { node = node->left; - } else if (less(node->_key, p_key)) { + } else if (less(node->_data.key, p_key)) { node = node->right; } else { return node; // found @@ -236,9 +321,9 @@ private: while (node != _data._nil) { prev = node; - if (less(p_key, node->_key)) { + if (less(p_key, node->_data.key)) { node = node->left; - } else if (less(node->_key, p_key)) { + } else if (less(node->_data.key, p_key)) { node = node->right; } else { return node; // found @@ -249,7 +334,7 @@ private: return nullptr; // tree empty } - if (less(p_key, prev->_key)) { + if (less(p_key, prev->_data.key)) { prev = prev->_prev; } @@ -312,25 +397,25 @@ private: while (node != _data._nil) { new_parent = node; - if (less(p_key, node->_key)) { + if (less(p_key, node->_data.key)) { node = node->left; - } else if (less(node->_key, p_key)) { + } else if (less(node->_data.key, p_key)) { node = node->right; } else { - node->_value = p_value; + node->_data.value = p_value; return node; // Return existing node with new value } } - Element *new_node = memnew_allocator(Element, A); + typedef KeyValue<K, V> KV; + Element *new_node = memnew_allocator(Element(KV(p_key, p_value)), A); new_node->parent = new_parent; new_node->right = _data._nil; new_node->left = _data._nil; - new_node->_key = p_key; - new_node->_value = p_value; + //new_node->data=_data; - if (new_parent == _data._root || less(p_key, new_parent->_key)) { + if (new_parent == _data._root || less(p_key, new_parent->_data.key)) { new_parent->left = new_node; } else { new_parent->right = new_node; @@ -575,7 +660,7 @@ public: CRASH_COND(!_data._root); const Element *e = find(p_key); CRASH_COND(!e); - return e->_value; + return e->_data.value; } V &operator[](const K &p_key) { @@ -588,7 +673,7 @@ public: e = insert(p_key, V()); } - return e->_value; + return e->_data.value; } Element *front() const { diff --git a/core/templates/oa_hash_map.h b/core/templates/oa_hash_map.h index 2c7c64cd78..025cc30db4 100644 --- a/core/templates/oa_hash_map.h +++ b/core/templates/oa_hash_map.h @@ -231,7 +231,7 @@ public: /** * returns true if the value was found, false otherwise. * - * if r_data is not nullptr then the value will be written to the object + * if r_data is not nullptr then the value will be written to the object * it points to. */ bool lookup(const TKey &p_key, TValue &r_data) const { @@ -249,7 +249,7 @@ public: /** * returns true if the value was found, false otherwise. * - * if r_data is not nullptr then the value will be written to the object + * if r_data is not nullptr then the value will be written to the object * it points to. */ TValue *lookup_ptr(const TKey &p_key) const { diff --git a/core/templates/pair.h b/core/templates/pair.h index bc1a764694..31706b6ecb 100644 --- a/core/templates/pair.h +++ b/core/templates/pair.h @@ -31,6 +31,8 @@ #ifndef PAIR_H #define PAIR_H +#include "core/typedefs.h" + template <class F, class S> struct Pair { F first; @@ -64,4 +66,37 @@ struct PairSort { } }; +template <class K, class V> +struct KeyValue { + const K key; + V value; + + void operator=(const KeyValue &p_kv) = delete; + _FORCE_INLINE_ KeyValue(const KeyValue &p_kv) : + key(p_kv.key), + value(p_kv.value) { + } + _FORCE_INLINE_ KeyValue(const K &p_key, const V &p_value) : + key(p_key), + value(p_value) { + } +}; + +template <class K, class V> +bool operator==(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) { + return (pair.key == other.key) && (pair.value == other.value); +} + +template <class K, class V> +bool operator!=(const KeyValue<K, V> &pair, const KeyValue<K, V> &other) { + return (pair.key != other.key) || (pair.value != other.value); +} + +template <class K, class V> +struct KeyValueSort { + bool operator()(const KeyValue<K, V> &A, const KeyValue<K, V> &B) const { + return A.key < B.key; + } +}; + #endif // PAIR_H diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h index c4aa93c394..4f5c74ca46 100644 --- a/core/templates/rid_owner.h +++ b/core/templates/rid_owner.h @@ -79,7 +79,7 @@ class RID_Alloc : public RID_AllocBase { SpinLock spin_lock; - _FORCE_INLINE_ RID _allocate_rid(const T *p_initializer) { + _FORCE_INLINE_ RID _allocate_rid() { if (THREAD_SAFE) { spin_lock.lock(); } @@ -114,11 +114,6 @@ class RID_Alloc : public RID_AllocBase { uint32_t free_chunk = free_index / elements_in_chunk; uint32_t free_element = free_index % elements_in_chunk; - if (p_initializer) { - T *ptr = &chunks[free_chunk][free_element]; - memnew_placement(ptr, T(*p_initializer)); - } - uint32_t validator = (uint32_t)(_gen_id() & 0x7FFFFFFF); uint64_t id = validator; id <<= 32; @@ -126,9 +121,7 @@ class RID_Alloc : public RID_AllocBase { validator_chunks[free_chunk][free_element] = validator; - if (!p_initializer) { - validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit - } + validator_chunks[free_chunk][free_element] |= 0x80000000; //mark uninitialized bit alloc_count++; @@ -140,13 +133,20 @@ class RID_Alloc : public RID_AllocBase { } public: + RID make_rid() { + RID rid = _allocate_rid(); + initialize_rid(rid); + return rid; + } RID make_rid(const T &p_value) { - return _allocate_rid(&p_value); + RID rid = _allocate_rid(); + initialize_rid(rid, p_value); + return rid; } //allocate but don't initialize, use initialize_rid afterwards RID allocate_rid() { - return _allocate_rid(nullptr); + return _allocate_rid(); } _FORCE_INLINE_ T *getornull(const RID &p_rid, bool p_initialize = false) { @@ -193,7 +193,7 @@ public: if (THREAD_SAFE) { spin_lock.unlock(); } - if (validator_chunks[idx_chunk][idx_element] & 0x80000000) { + if ((validator_chunks[idx_chunk][idx_element] & 0x80000000) && validator_chunks[idx_chunk][idx_element] != 0xFFFFFFFF) { ERR_FAIL_V_MSG(nullptr, "Attempting to use an uninitialized RID"); } return nullptr; @@ -207,6 +207,11 @@ public: return ptr; } + void initialize_rid(RID p_rid) { + T *mem = getornull(p_rid, true); + ERR_FAIL_COND(!mem); + memnew_placement(mem, T); + } void initialize_rid(RID p_rid, const T &p_value) { T *mem = getornull(p_rid, true); ERR_FAIL_COND(!mem); @@ -333,7 +338,7 @@ public: description = p_descrption; } - RID_Alloc(uint32_t p_target_chunk_byte_size = 4096) { + RID_Alloc(uint32_t p_target_chunk_byte_size = 65536) { elements_in_chunk = sizeof(T) > p_target_chunk_byte_size ? 1 : (p_target_chunk_byte_size / sizeof(T)); } @@ -351,6 +356,9 @@ public: for (size_t i = 0; i < max_alloc; i++) { uint64_t validator = validator_chunks[i / elements_in_chunk][i % elements_in_chunk]; + if (validator & 0x80000000) { + continue; //uninitialized + } if (validator != 0xFFFFFFFF) { chunks[i / elements_in_chunk][i % elements_in_chunk].~T(); } @@ -431,7 +439,7 @@ public: alloc.set_description(p_descrption); } - RID_PtrOwner(uint32_t p_target_chunk_byte_size = 4096) : + RID_PtrOwner(uint32_t p_target_chunk_byte_size = 65536) : alloc(p_target_chunk_byte_size) {} }; @@ -440,6 +448,9 @@ class RID_Owner { RID_Alloc<T, THREAD_SAFE> alloc; public: + _FORCE_INLINE_ RID make_rid() { + return alloc.make_rid(); + } _FORCE_INLINE_ RID make_rid(const T &p_ptr) { return alloc.make_rid(p_ptr); } @@ -448,6 +459,10 @@ public: return alloc.allocate_rid(); } + _FORCE_INLINE_ void initialize_rid(RID p_rid) { + alloc.initialize_rid(p_rid); + } + _FORCE_INLINE_ void initialize_rid(RID p_rid, const T &p_ptr) { alloc.initialize_rid(p_rid, p_ptr); } @@ -483,7 +498,7 @@ public: void set_description(const char *p_descrption) { alloc.set_description(p_descrption); } - RID_Owner(uint32_t p_target_chunk_byte_size = 4096) : + RID_Owner(uint32_t p_target_chunk_byte_size = 65536) : alloc(p_target_chunk_byte_size) {} }; diff --git a/core/templates/set.h b/core/templates/set.h index 3036ecf27d..245c174862 100644 --- a/core/templates/set.h +++ b/core/templates/set.h @@ -77,6 +77,85 @@ public: Element() {} }; + typedef T ValueType; + + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ T *operator->() const { return &E->get(); } + _FORCE_INLINE_ Iterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + Iterator(Element *p_E) { E = p_E; } + Iterator() {} + Iterator(const Iterator &p_it) { E = p_it.E; } + + private: + Element *E = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return E->get(); + } + _FORCE_INLINE_ const T *operator->() const { return &E->get(); } + _FORCE_INLINE_ ConstIterator &operator++() { + E = E->next(); + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + E = E->prev(); + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return E == b.E; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return E != b.E; } + + _FORCE_INLINE_ ConstIterator(const Element *p_E) { E = p_E; } + _FORCE_INLINE_ ConstIterator() {} + _FORCE_INLINE_ ConstIterator(const ConstIterator &p_it) { E = p_it.E; } + + private: + const Element *E = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(front()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ Iterator find(const K &p_key) { + return Iterator(find(p_key)); + } +#endif + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(front()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(nullptr); + } + +#if 0 + //to use when replacing find() + _FORCE_INLINE_ ConstIterator find(const K &p_key) const { + return ConstIterator(find(p_key)); + } +#endif private: struct _Data { Element *_root = nullptr; diff --git a/core/templates/thread_work_pool.h b/core/templates/thread_work_pool.h index 9f7a692cc5..b242648bc8 100644 --- a/core/templates/thread_work_pool.h +++ b/core/templates/thread_work_pool.h @@ -105,7 +105,7 @@ public: } bool is_done_dispatching() const { - ERR_FAIL_COND_V(current_work == nullptr, false); + ERR_FAIL_COND_V(current_work == nullptr, true); return index.load(std::memory_order_acquire) >= current_work->max_elements; } diff --git a/core/templates/vector.h b/core/templates/vector.h index dae8874a87..08cbef6ba4 100644 --- a/core/templates/vector.h +++ b/core/templates/vector.h @@ -187,6 +187,70 @@ public: return false; } + struct Iterator { + _FORCE_INLINE_ T &operator*() const { + return *elem_ptr; + } + _FORCE_INLINE_ T *operator->() const { return elem_ptr; } + _FORCE_INLINE_ Iterator &operator++() { + elem_ptr++; + return *this; + } + _FORCE_INLINE_ Iterator &operator--() { + elem_ptr--; + return *this; + } + + _FORCE_INLINE_ bool operator==(const Iterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const Iterator &b) const { return elem_ptr != b.elem_ptr; } + + Iterator(T *p_ptr) { elem_ptr = p_ptr; } + Iterator() {} + Iterator(const Iterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + T *elem_ptr = nullptr; + }; + + struct ConstIterator { + _FORCE_INLINE_ const T &operator*() const { + return *elem_ptr; + } + _FORCE_INLINE_ const T *operator->() const { return elem_ptr; } + _FORCE_INLINE_ ConstIterator &operator++() { + elem_ptr++; + return *this; + } + _FORCE_INLINE_ ConstIterator &operator--() { + elem_ptr--; + return *this; + } + + _FORCE_INLINE_ bool operator==(const ConstIterator &b) const { return elem_ptr == b.elem_ptr; } + _FORCE_INLINE_ bool operator!=(const ConstIterator &b) const { return elem_ptr != b.elem_ptr; } + + ConstIterator(T *p_ptr) { elem_ptr = p_ptr; } + ConstIterator() {} + ConstIterator(const ConstIterator &p_it) { elem_ptr = p_it.elem_ptr; } + + private: + const T *elem_ptr = nullptr; + }; + + _FORCE_INLINE_ Iterator begin() { + return Iterator(ptrw()); + } + _FORCE_INLINE_ Iterator end() { + return Iterator(ptrw() + size()); + } + + _FORCE_INLINE_ ConstIterator begin() const { + return ConstIterator(ptr()); + } + _FORCE_INLINE_ ConstIterator end() const { + return ConstIterator(ptr() + size()); + } + _FORCE_INLINE_ Vector() {} _FORCE_INLINE_ Vector(const Vector &p_from) { _cowdata._ref(p_from._cowdata); } diff --git a/core/variant/binder_common.h b/core/variant/binder_common.h index 830e0a5cbd..ef5867c685 100644 --- a/core/variant/binder_common.h +++ b/core/variant/binder_common.h @@ -31,6 +31,7 @@ #ifndef BINDER_COMMON_H #define BINDER_COMMON_H +#include "core/input/input_enums.h" #include "core/object/object.h" #include "core/templates/list.h" #include "core/templates/simple_type.h" @@ -76,6 +77,7 @@ struct VariantCaster<const T &> { _FORCE_INLINE_ static m_enum convert(const void *p_ptr) { \ return m_enum(*reinterpret_cast<const int *>(p_ptr)); \ } \ + typedef int64_t EncodeT; \ _FORCE_INLINE_ static void encode(m_enum p_val, const void *p_ptr) { \ *(int *)p_ptr = p_val; \ } \ @@ -90,6 +92,12 @@ VARIANT_ENUM_CAST(Error); VARIANT_ENUM_CAST(Side); VARIANT_ENUM_CAST(ClockDirection); VARIANT_ENUM_CAST(Corner); +VARIANT_ENUM_CAST(HatDir); +VARIANT_ENUM_CAST(HatMask); +VARIANT_ENUM_CAST(JoyAxis); +VARIANT_ENUM_CAST(JoyButton); +VARIANT_ENUM_CAST(MIDIMessage); +VARIANT_ENUM_CAST(MouseButton); VARIANT_ENUM_CAST(Orientation); VARIANT_ENUM_CAST(HAlign); VARIANT_ENUM_CAST(VAlign); @@ -110,6 +118,7 @@ struct PtrToArg<char32_t> { _FORCE_INLINE_ static char32_t convert(const void *p_ptr) { return char32_t(*reinterpret_cast<const int *>(p_ptr)); } + typedef int64_t EncodeT; _FORCE_INLINE_ static void encode(char32_t p_val, const void *p_ptr) { *(int *)p_ptr = p_val; } diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp index 5c87042f6b..ca6f3d615e 100644 --- a/core/variant/callable.cpp +++ b/core/variant/callable.cpp @@ -33,7 +33,7 @@ #include "callable_bind.h" #include "core/object/message_queue.h" #include "core/object/object.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" void Callable::call_deferred(const Variant **p_arguments, int p_argcount) const { @@ -89,6 +89,10 @@ Callable Callable::unbind(int p_argcount) const { return Callable(memnew(CallableCustomUnbind(*this, p_argcount))); } +bool Callable::is_valid() const { + return get_object() && (is_custom() || get_object()->has_method(get_method())); +} + Object *Callable::get_object() const { if (is_null()) { return nullptr; diff --git a/core/variant/callable.h b/core/variant/callable.h index 20d0804292..52094af3aa 100644 --- a/core/variant/callable.h +++ b/core/variant/callable.h @@ -81,6 +81,7 @@ public: _FORCE_INLINE_ bool is_standard() const { return method != StringName(); } + bool is_valid() const; Callable bind(const Variant **p_arguments, int p_argcount) const; Callable unbind(int p_argcount) const; diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index b2f7c6aa0a..07b3a9a675 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -33,6 +33,11 @@ #include "core/templates/ordered_hash_map.h" #include "core/templates/safe_refcount.h" #include "core/variant/variant.h" +// required in this order by VariantInternal, do not remove this comment. +#include "core/object/class_db.h" +#include "core/object/object.h" +#include "core/variant/type_info.h" +#include "core/variant/variant_internal.h" struct DictionaryPrivate { SafeRefCount refcount; @@ -74,15 +79,32 @@ Variant Dictionary::get_value_at_index(int p_index) const { } Variant &Dictionary::operator[](const Variant &p_key) { - return _p->variant_map[p_key]; + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + return _p->variant_map[sn->operator String()]; + } else { + return _p->variant_map[p_key]; + } } const Variant &Dictionary::operator[](const Variant &p_key) const { - return _p->variant_map[p_key]; + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + return _p->variant_map[sn->operator String()]; + } else { + return _p->variant_map[p_key]; + } } const Variant *Dictionary::getptr(const Variant &p_key) const { - OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E; + + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); + } else { + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + } if (!E) { return nullptr; @@ -91,8 +113,14 @@ const Variant *Dictionary::getptr(const Variant &p_key) const { } Variant *Dictionary::getptr(const Variant &p_key) { - OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E; + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + E = ((OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); + } else { + E = ((OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + } if (!E) { return nullptr; } @@ -100,7 +128,14 @@ Variant *Dictionary::getptr(const Variant &p_key) { } Variant Dictionary::get_valid(const Variant &p_key) const { - OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::ConstElement E; + + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(sn->operator String()); + } else { + E = ((const OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator> *)&_p->variant_map)->find(p_key); + } if (!E) { return Variant(); @@ -126,7 +161,12 @@ bool Dictionary::is_empty() const { } bool Dictionary::has(const Variant &p_key) const { - return _p->variant_map.has(p_key); + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + return _p->variant_map.has(sn->operator String()); + } else { + return _p->variant_map.has(p_key); + } } bool Dictionary::has_all(const Array &p_keys) const { @@ -139,7 +179,12 @@ bool Dictionary::has_all(const Array &p_keys) const { } bool Dictionary::erase(const Variant &p_key) { - return _p->variant_map.erase(p_key); + if (p_key.get_type() == Variant::STRING_NAME) { + const StringName *sn = VariantInternal::get_string_name(&p_key); + return _p->variant_map.erase(sn->operator String()); + } else { + return _p->variant_map.erase(p_key); + } } bool Dictionary::operator==(const Dictionary &p_dictionary) const { diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h index e91029f330..7852187b77 100644 --- a/core/variant/method_ptrcall.h +++ b/core/variant/method_ptrcall.h @@ -45,6 +45,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ @@ -54,6 +55,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ @@ -65,6 +67,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \ } \ + typedef m_conv EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \ } \ @@ -74,6 +77,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return static_cast<m_type>(*reinterpret_cast<const m_conv *>(p_ptr)); \ } \ + typedef m_conv EncodeT; \ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \ *((m_conv *)p_ptr) = static_cast<m_conv>(p_val); \ } \ @@ -85,6 +89,7 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ @@ -94,12 +99,13 @@ struct PtrToArg {}; _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \ return *reinterpret_cast<const m_type *>(p_ptr); \ } \ + typedef m_type EncodeT; \ _FORCE_INLINE_ static void encode(const m_type &p_val, void *p_ptr) { \ *((m_type *)p_ptr) = p_val; \ } \ } -MAKE_PTRARG(bool); +MAKE_PTRARGCONV(bool, uint32_t); // Integer types. MAKE_PTRARGCONV(uint8_t, int64_t); MAKE_PTRARGCONV(int8_t, int64_t); @@ -122,10 +128,10 @@ MAKE_PTRARG_BY_REFERENCE(Vector3); MAKE_PTRARG_BY_REFERENCE(Vector3i); MAKE_PTRARG(Transform2D); MAKE_PTRARG_BY_REFERENCE(Plane); -MAKE_PTRARG(Quat); +MAKE_PTRARG(Quaternion); MAKE_PTRARG_BY_REFERENCE(AABB); MAKE_PTRARG_BY_REFERENCE(Basis); -MAKE_PTRARG_BY_REFERENCE(Transform); +MAKE_PTRARG_BY_REFERENCE(Transform3D); MAKE_PTRARG_BY_REFERENCE(Color); MAKE_PTRARG(StringName); MAKE_PTRARG(NodePath); @@ -153,7 +159,7 @@ struct PtrToArg<T *> { _FORCE_INLINE_ static T *convert(const void *p_ptr) { return const_cast<T *>(reinterpret_cast<const T *>(p_ptr)); } - + typedef Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { *((T **)p_ptr) = p_var; } @@ -164,7 +170,7 @@ struct PtrToArg<const T *> { _FORCE_INLINE_ static const T *convert(const void *p_ptr) { return reinterpret_cast<const T *>(p_ptr); } - + typedef const Object *EncodeT; _FORCE_INLINE_ static void encode(T *p_var, void *p_ptr) { *((T **)p_ptr) = p_var; } @@ -177,7 +183,7 @@ struct PtrToArg<ObjectID> { _FORCE_INLINE_ static const ObjectID convert(const void *p_ptr) { return ObjectID(*reinterpret_cast<const uint64_t *>(p_ptr)); } - + typedef uint64_t EncodeT; _FORCE_INLINE_ static void encode(const ObjectID &p_val, void *p_ptr) { *((uint64_t *)p_ptr) = p_val; } diff --git a/core/variant/type_info.h b/core/variant/type_info.h index d5b6d85dfb..76cb065d10 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -146,10 +146,10 @@ MAKE_TYPE_INFO(Rect2i, Variant::RECT2I) MAKE_TYPE_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPE_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPE_INFO(Plane, Variant::PLANE) -MAKE_TYPE_INFO(Quat, Variant::QUAT) +MAKE_TYPE_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPE_INFO(AABB, Variant::AABB) MAKE_TYPE_INFO(Basis, Variant::BASIS) -MAKE_TYPE_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPE_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPE_INFO(Color, Variant::COLOR) MAKE_TYPE_INFO(StringName, Variant::STRING_NAME) MAKE_TYPE_INFO(NodePath, Variant::NODE_PATH) diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h index e0309aa3fe..900dcf7689 100644 --- a/core/variant/typed_array.h +++ b/core/variant/typed_array.h @@ -98,10 +98,10 @@ MAKE_TYPED_ARRAY(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY(Plane, Variant::PLANE) -MAKE_TYPED_ARRAY(Quat, Variant::QUAT) +MAKE_TYPED_ARRAY(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY(AABB, Variant::AABB) MAKE_TYPED_ARRAY(Basis, Variant::BASIS) -MAKE_TYPED_ARRAY(Transform, Variant::TRANSFORM) +MAKE_TYPED_ARRAY(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY(Color, Variant::COLOR) MAKE_TYPED_ARRAY(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY(NodePath, Variant::NODE_PATH) @@ -196,10 +196,10 @@ MAKE_TYPED_ARRAY_INFO(Vector3, Variant::VECTOR3) MAKE_TYPED_ARRAY_INFO(Vector3i, Variant::VECTOR3I) MAKE_TYPED_ARRAY_INFO(Transform2D, Variant::TRANSFORM2D) MAKE_TYPED_ARRAY_INFO(Plane, Variant::PLANE) -MAKE_TYPED_ARRAY_INFO(Quat, Variant::QUAT) +MAKE_TYPED_ARRAY_INFO(Quaternion, Variant::QUATERNION) MAKE_TYPED_ARRAY_INFO(AABB, Variant::AABB) MAKE_TYPED_ARRAY_INFO(Basis, Variant::BASIS) -MAKE_TYPED_ARRAY_INFO(Transform, Variant::TRANSFORM) +MAKE_TYPED_ARRAY_INFO(Transform3D, Variant::TRANSFORM3D) MAKE_TYPED_ARRAY_INFO(Color, Variant::COLOR) MAKE_TYPED_ARRAY_INFO(StringName, Variant::STRING_NAME) MAKE_TYPED_ARRAY_INFO(NodePath, Variant::NODE_PATH) diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 333dd8e8d1..badb5ba103 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -32,6 +32,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" +#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/io/resource.h" #include "core/math/math_funcs.h" @@ -91,16 +92,16 @@ String Variant::get_type_name(Variant::Type p_type) { case AABB: { return "AABB"; } break; - case QUAT: { - return "Quat"; + case QUATERNION: { + return "Quaternion"; } break; case BASIS: { return "Basis"; } break; - case TRANSFORM: { - return "Transform"; + case TRANSFORM3D: { + return "Transform3D"; } break; @@ -275,7 +276,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case TRANSFORM2D: { static const Type valid[] = { - TRANSFORM, + TRANSFORM3D, NIL }; @@ -300,7 +301,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; - case QUAT: { + case QUATERNION: { static const Type valid[] = { BASIS, NIL @@ -311,7 +312,7 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { } break; case BASIS: { static const Type valid[] = { - QUAT, + QUATERNION, VECTOR3, NIL }; @@ -319,10 +320,10 @@ bool Variant::can_convert(Variant::Type p_type_from, Variant::Type p_type_to) { valid_types = valid; } break; - case TRANSFORM: { + case TRANSFORM3D: { static const Type valid[] = { TRANSFORM2D, - QUAT, + QUATERNION, BASIS, NIL }; @@ -582,7 +583,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case TRANSFORM2D: { static const Type valid[] = { - TRANSFORM, + TRANSFORM3D, NIL }; @@ -607,7 +608,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; - case QUAT: { + case QUATERNION: { static const Type valid[] = { BASIS, NIL @@ -618,7 +619,7 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type } break; case BASIS: { static const Type valid[] = { - QUAT, + QUATERNION, VECTOR3, NIL }; @@ -626,10 +627,10 @@ bool Variant::can_convert_strict(Variant::Type p_type_from, Variant::Type p_type valid_types = valid; } break; - case TRANSFORM: { + case TRANSFORM3D: { static const Type valid[] = { TRANSFORM2D, - QUAT, + QUATERNION, BASIS, NIL }; @@ -873,16 +874,16 @@ bool Variant::is_zero() const { case AABB: { return *_data._aabb == ::AABB(); } break; - case QUAT: { - return *reinterpret_cast<const Quat *>(_data._mem) == Quat(); + case QUATERNION: { + return *reinterpret_cast<const Quaternion *>(_data._mem) == Quaternion(); } break; case BASIS: { return *_data._basis == Basis(); } break; - case TRANSFORM: { - return *_data._transform == Transform(); + case TRANSFORM3D: { + return *_data._transform3d == Transform3D(); } break; @@ -1092,16 +1093,16 @@ void Variant::reference(const Variant &p_variant) { case AABB: { _data._aabb = memnew(::AABB(*p_variant._data._aabb)); } break; - case QUAT: { - memnew_placement(_data._mem, Quat(*reinterpret_cast<const Quat *>(p_variant._data._mem))); + case QUATERNION: { + memnew_placement(_data._mem, Quaternion(*reinterpret_cast<const Quaternion *>(p_variant._data._mem))); } break; case BASIS: { _data._basis = memnew(Basis(*p_variant._data._basis)); } break; - case TRANSFORM: { - _data._transform = memnew(Transform(*p_variant._data._transform)); + case TRANSFORM3D: { + _data._transform3d = memnew(Transform3D(*p_variant._data._transform3d)); } break; // misc types @@ -1115,9 +1116,9 @@ void Variant::reference(const Variant &p_variant) { case OBJECT: { memnew_placement(_data._mem, ObjData); - if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); - if (!reference->reference()) { + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) { + RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj); + if (!ref_counted->reference()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); break; @@ -1254,8 +1255,8 @@ void Variant::zero() { case PLANE: *reinterpret_cast<Plane *>(this->_data._mem) = Plane(); break; - case QUAT: - *reinterpret_cast<Quat *>(this->_data._mem) = Quat(); + case QUATERNION: + *reinterpret_cast<Quaternion *>(this->_data._mem) = Quaternion(); break; case COLOR: *reinterpret_cast<Color *>(this->_data._mem) = Color(); @@ -1275,7 +1276,7 @@ void Variant::_clear_internal() { // no point, they don't allocate memory VECTOR3, PLANE, - QUAT, + QUATERNION, COLOR, VECTOR2, RECT2 @@ -1289,8 +1290,8 @@ void Variant::_clear_internal() { case BASIS: { memdelete(_data._basis); } break; - case TRANSFORM: { - memdelete(_data._transform); + case TRANSFORM3D: { + memdelete(_data._transform3d); } break; // misc types @@ -1301,11 +1302,11 @@ void Variant::_clear_internal() { reinterpret_cast<NodePath *>(_data._mem)->~NodePath(); } break; case OBJECT: { - if (_get_obj().id.is_reference()) { + if (_get_obj().id.is_ref_counted()) { //we are safe that there is a reference here - Reference *reference = static_cast<Reference *>(_get_obj().obj); - if (reference->unreference()) { - memdelete(reference); + RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj); + if (ref_counted->unreference()) { + memdelete(ref_counted); } } _get_obj().obj = nullptr; @@ -1636,60 +1637,35 @@ String Variant::stringify(List<const void *> &stack) const { case STRING: return *reinterpret_cast<const String *>(_data._mem); case VECTOR2: - return "(" + operator Vector2() + ")"; + return operator Vector2(); case VECTOR2I: - return "(" + operator Vector2i() + ")"; + return operator Vector2i(); case RECT2: - return "(" + operator Rect2() + ")"; + return operator Rect2(); case RECT2I: - return "(" + operator Rect2i() + ")"; - case TRANSFORM2D: { - Transform2D mat32 = operator Transform2D(); - return "(" + Variant(mat32.elements[0]).operator String() + ", " + Variant(mat32.elements[1]).operator String() + ", " + Variant(mat32.elements[2]).operator String() + ")"; - } break; + return operator Rect2i(); + case TRANSFORM2D: + return operator Transform2D(); case VECTOR3: - return "(" + operator Vector3() + ")"; + return operator Vector3(); case VECTOR3I: - return "(" + operator Vector3i() + ")"; + return operator Vector3i(); case PLANE: return operator Plane(); - //case QUAT: case AABB: return operator ::AABB(); - case QUAT: - return "(" + operator Quat() + ")"; - case BASIS: { - Basis mat3 = operator Basis(); - - String mtx("("); - for (int i = 0; i < 3; i++) { - if (i != 0) { - mtx += ", "; - } - - mtx += "("; - - for (int j = 0; j < 3; j++) { - if (j != 0) { - mtx += ", "; - } - - mtx += Variant(mat3.elements[i][j]).operator String(); - } - - mtx += ")"; - } - - return mtx + ")"; - } break; - case TRANSFORM: - return operator Transform(); + case QUATERNION: + return operator Quaternion(); + case BASIS: + return operator Basis(); + case TRANSFORM3D: + return operator Transform3D(); case STRING_NAME: return operator StringName(); case NODE_PATH: return operator NodePath(); case COLOR: - return String::num(operator Color().r) + "," + String::num(operator Color().g) + "," + String::num(operator Color().b) + "," + String::num(operator Color().a); + return operator Color(); case DICTIONARY: { const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); if (stack.find(d.id())) { @@ -1723,6 +1699,7 @@ String Variant::stringify(List<const void *> &stack) const { } str += "}"; + stack.erase(d.id()); return str; } break; case PACKED_VECTOR2_ARRAY: { @@ -1826,12 +1803,13 @@ String Variant::stringify(List<const void *> &stack) const { } str += "]"; + stack.erase(arr.id()); return str; } break; case OBJECT: { if (_get_obj().obj) { - if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (!_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { return "[Freed Object]"; } @@ -1861,6 +1839,11 @@ String Variant::stringify(List<const void *> &stack) const { return ""; } +String Variant::to_json_string() const { + JSON json; + return json.stringify(*this); +} + Variant::operator Vector2() const { if (type == VECTOR2) { return *reinterpret_cast<const Vector2 *>(_data._mem); @@ -1956,39 +1939,39 @@ Variant::operator ::AABB() const { Variant::operator Basis() const { if (type == BASIS) { return *_data._basis; - } else if (type == QUAT) { - return *reinterpret_cast<const Quat *>(_data._mem); + } else if (type == QUATERNION) { + return *reinterpret_cast<const Quaternion *>(_data._mem); } else if (type == VECTOR3) { return Basis(*reinterpret_cast<const Vector3 *>(_data._mem)); - } else if (type == TRANSFORM) { // unexposed in Variant::can_convert? - return _data._transform->basis; + } else if (type == TRANSFORM3D) { // unexposed in Variant::can_convert? + return _data._transform3d->basis; } else { return Basis(); } } -Variant::operator Quat() const { - if (type == QUAT) { - return *reinterpret_cast<const Quat *>(_data._mem); +Variant::operator Quaternion() const { + if (type == QUATERNION) { + return *reinterpret_cast<const Quaternion *>(_data._mem); } else if (type == BASIS) { return *_data._basis; - } else if (type == TRANSFORM) { - return _data._transform->basis; + } else if (type == TRANSFORM3D) { + return _data._transform3d->basis; } else { - return Quat(); + return Quaternion(); } } -Variant::operator Transform() const { - if (type == TRANSFORM) { - return *_data._transform; +Variant::operator Transform3D() const { + if (type == TRANSFORM3D) { + return *_data._transform3d; } else if (type == BASIS) { - return Transform(*_data._basis, Vector3()); - } else if (type == QUAT) { - return Transform(Basis(*reinterpret_cast<const Quat *>(_data._mem)), Vector3()); + return Transform3D(*_data._basis, Vector3()); + } else if (type == QUATERNION) { + return Transform3D(Basis(*reinterpret_cast<const Quaternion *>(_data._mem)), Vector3()); } else if (type == TRANSFORM2D) { const Transform2D &t = *_data._transform2d; - Transform m; + Transform3D m; m.basis.elements[0][0] = t.elements[0][0]; m.basis.elements[1][0] = t.elements[0][1]; m.basis.elements[0][1] = t.elements[1][0]; @@ -1997,15 +1980,15 @@ Variant::operator Transform() const { m.origin[1] = t.elements[2][1]; return m; } else { - return Transform(); + return Transform3D(); } } Variant::operator Transform2D() const { if (type == TRANSFORM2D) { return *_data._transform2d; - } else if (type == TRANSFORM) { - const Transform &t = *_data._transform; + } else if (type == TRANSFORM3D) { + const Transform3D &t = *_data._transform3d; Transform2D m; m.elements[0][0] = t.basis.elements[0][0]; m.elements[0][1] = t.basis.elements[1][0]; @@ -2495,14 +2478,14 @@ Variant::Variant(const Basis &p_matrix) { _data._basis = memnew(Basis(p_matrix)); } -Variant::Variant(const Quat &p_quat) { - type = QUAT; - memnew_placement(_data._mem, Quat(p_quat)); +Variant::Variant(const Quaternion &p_quaternion) { + type = QUATERNION; + memnew_placement(_data._mem, Quaternion(p_quaternion)); } -Variant::Variant(const Transform &p_transform) { - type = TRANSFORM; - _data._transform = memnew(Transform(p_transform)); +Variant::Variant(const Transform3D &p_transform) { + type = TRANSFORM3D; + _data._transform3d = memnew(Transform3D(p_transform)); } Variant::Variant(const Transform2D &p_transform) { @@ -2531,9 +2514,9 @@ Variant::Variant(const Object *p_object) { memnew_placement(_data._mem, ObjData); if (p_object) { - if (p_object->is_reference()) { - Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(p_object)); - if (!reference->init_ref()) { + if (p_object->is_ref_counted()) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(p_object)); + if (!ref_counted->init_ref()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); return; @@ -2739,14 +2722,14 @@ void Variant::operator=(const Variant &p_variant) { case AABB: { *_data._aabb = *(p_variant._data._aabb); } break; - case QUAT: { - *reinterpret_cast<Quat *>(_data._mem) = *reinterpret_cast<const Quat *>(p_variant._data._mem); + case QUATERNION: { + *reinterpret_cast<Quaternion *>(_data._mem) = *reinterpret_cast<const Quaternion *>(p_variant._data._mem); } break; case BASIS: { *_data._basis = *(p_variant._data._basis); } break; - case TRANSFORM: { - *_data._transform = *(p_variant._data._transform); + case TRANSFORM3D: { + *_data._transform3d = *(p_variant._data._transform3d); } break; // misc types @@ -2757,17 +2740,17 @@ void Variant::operator=(const Variant &p_variant) { *reinterpret_cast<::RID *>(_data._mem) = *reinterpret_cast<const ::RID *>(p_variant._data._mem); } break; case OBJECT: { - if (_get_obj().id.is_reference()) { + if (_get_obj().id.is_ref_counted()) { //we are safe that there is a reference here - Reference *reference = static_cast<Reference *>(_get_obj().obj); - if (reference->unreference()) { - memdelete(reference); + RefCounted *ref_counted = static_cast<RefCounted *>(_get_obj().obj); + if (ref_counted->unreference()) { + memdelete(ref_counted); } } - if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { - Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); - if (!reference->reference()) { + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_ref_counted()) { + RefCounted *ref_counted = static_cast<RefCounted *>(p_variant._get_obj().obj); + if (!ref_counted->reference()) { _get_obj().obj = nullptr; _get_obj().id = ObjectID(); break; @@ -2916,11 +2899,11 @@ uint32_t Variant::hash() const { return hash; } break; - case QUAT: { - uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->x); - hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->y, hash); - hash = hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->z, hash); - return hash_djb2_one_float(reinterpret_cast<const Quat *>(_data._mem)->w, hash); + case QUATERNION: { + uint32_t hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->x); + hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->y, hash); + hash = hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->z, hash); + return hash_djb2_one_float(reinterpret_cast<const Quaternion *>(_data._mem)->w, hash); } break; case BASIS: { @@ -2934,13 +2917,13 @@ uint32_t Variant::hash() const { return hash; } break; - case TRANSFORM: { + case TRANSFORM3D: { uint32_t hash = 5831; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { - hash = hash_djb2_one_float(_data._transform->basis.elements[i][j], hash); + hash = hash_djb2_one_float(_data._transform3d->basis.elements[i][j], hash); } - hash = hash_djb2_one_float(_data._transform->origin[i], hash); + hash = hash_djb2_one_float(_data._transform3d->origin[i], hash); } return hash; @@ -3127,7 +3110,7 @@ uint32_t Variant::hash() const { (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) -#define hash_compare_quat(p_lhs, p_rhs) \ +#define hash_compare_quaternion(p_lhs, p_rhs) \ (hash_compare_scalar((p_lhs).x, (p_rhs).x)) && \ (hash_compare_scalar((p_lhs).y, (p_rhs).y)) && \ (hash_compare_scalar((p_lhs).z, (p_rhs).z)) && \ @@ -3235,11 +3218,11 @@ bool Variant::hash_compare(const Variant &p_variant) const { } break; - case QUAT: { - const Quat *l = reinterpret_cast<const Quat *>(_data._mem); - const Quat *r = reinterpret_cast<const Quat *>(p_variant._data._mem); + case QUATERNION: { + const Quaternion *l = reinterpret_cast<const Quaternion *>(_data._mem); + const Quaternion *r = reinterpret_cast<const Quaternion *>(p_variant._data._mem); - return hash_compare_quat(*l, *r); + return hash_compare_quaternion(*l, *r); } break; case BASIS: { @@ -3255,9 +3238,9 @@ bool Variant::hash_compare(const Variant &p_variant) const { return true; } break; - case TRANSFORM: { - const Transform *l = _data._transform; - const Transform *r = p_variant._data._transform; + case TRANSFORM3D: { + const Transform3D *l = _data._transform3d; + const Transform3D *r = p_variant._data._transform3d; for (int i = 0; i < 3; i++) { if (!(hash_compare_vector3(l->basis.elements[i], r->basis.elements[i]))) { @@ -3324,7 +3307,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { } bool Variant::is_ref() const { - return type == OBJECT && _get_obj().id.is_reference(); + return type == OBJECT && _get_obj().id.is_ref_counted(); } Vector<Variant> varray() { diff --git a/core/variant/variant.h b/core/variant/variant.h index 7f3c3477fc..373fe32921 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -37,9 +37,9 @@ #include "core/math/color.h" #include "core/math/face3.h" #include "core/math/plane.h" -#include "core/math/quat.h" -#include "core/math/transform.h" +#include "core/math/quaternion.h" #include "core/math/transform_2d.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/math/vector3i.h" #include "core/object/object_id.h" @@ -88,10 +88,10 @@ public: VECTOR3I, TRANSFORM2D, PLANE, - QUAT, + QUATERNION, AABB, BASIS, - TRANSFORM, + TRANSFORM3D, // misc types COLOR, @@ -200,7 +200,7 @@ private: Transform2D *_transform2d; ::AABB *_aabb; Basis *_basis; - Transform *_transform; + Transform3D *_transform3d; PackedArrayRefBase *packed_array; void *_ptr; //generic pointer uint8_t _mem[sizeof(ObjData) > (sizeof(real_t) * 4) ? sizeof(ObjData) : (sizeof(real_t) * 4)]; @@ -225,7 +225,7 @@ private: false, //VECTOR3I, true, //TRANSFORM2D, false, //PLANE, - false, //QUAT, + false, //QUATERNION, true, //AABB, true, //BASIS, true, //TRANSFORM, @@ -320,10 +320,10 @@ public: operator Vector3i() const; operator Plane() const; operator ::AABB() const; - operator Quat() const; + operator Quaternion() const; operator Basis() const; - operator Transform() const; operator Transform2D() const; + operator Transform3D() const; operator Color() const; operator NodePath() const; @@ -392,10 +392,10 @@ public: Variant(const Vector3i &p_vector3i); Variant(const Plane &p_plane); Variant(const ::AABB &p_aabb); - Variant(const Quat &p_quat); + Variant(const Quaternion &p_quat); Variant(const Basis &p_matrix); Variant(const Transform2D &p_transform); - Variant(const Transform &p_transform); + Variant(const Transform3D &p_transform); Variant(const Color &p_color); Variant(const NodePath &p_node_path); Variant(const ::RID &p_rid); @@ -499,6 +499,7 @@ public: static bool is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method); static void get_builtin_method_list(Variant::Type p_type, List<StringName> *p_list); static int get_builtin_method_count(Variant::Type p_type); + static uint32_t get_builtin_method_hash(Variant::Type p_type, const StringName &p_method); void call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error); Variant call(const StringName &p_method, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant()); @@ -586,7 +587,7 @@ public: typedef void (*PTRKeyedSetter)(void *base, const void *key, const void *value); typedef void (*PTRKeyedGetter)(const void *base, const void *key, void *value); - typedef bool (*PTRKeyedChecker)(const void *base, const void *key); + typedef uint32_t (*PTRKeyedChecker)(const void *base, const void *key); static PTRKeyedSetter get_member_ptr_keyed_setter(Variant::Type p_type); static PTRKeyedGetter get_member_ptr_keyed_getter(Variant::Type p_type); @@ -631,6 +632,7 @@ public: static bool has_utility_function_return_value(const StringName &p_name); static Variant::Type get_utility_function_return_type(const StringName &p_name); static bool is_utility_function_vararg(const StringName &p_name); + static uint32_t get_utility_function_hash(const StringName &p_name); static void get_utility_function_list(List<StringName> *r_functions); static int get_utility_function_count(); @@ -645,6 +647,7 @@ public: bool hash_compare(const Variant &p_variant) const; bool booleanize() const; String stringify(List<const void *> &stack) const; + String to_json_string() const; void static_assign(const Variant &p_variant); static void get_constants_for_type(Variant::Type p_type, List<StringName> *p_constants); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index d9cc97154d..733361fe58 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -972,7 +972,7 @@ void Variant::call(const StringName &p_method, const Variant **p_args, int p_arg return; } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL; return; } @@ -1126,6 +1126,25 @@ bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p return method->is_vararg; } +uint32_t Variant::get_builtin_method_hash(Variant::Type p_type, const StringName &p_method) { + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0); + const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method); + ERR_FAIL_COND_V(!method, 0); + uint32_t hash = hash_djb2_one_32(method->is_const); + hash = hash_djb2_one_32(method->is_static, hash); + hash = hash_djb2_one_32(method->is_vararg, hash); + hash = hash_djb2_one_32(method->has_return_type, hash); + if (method->has_return_type) { + hash = hash_djb2_one_32(method->return_type, hash); + } + hash = hash_djb2_one_32(method->argument_count, hash); + for (int i = 0; i < method->argument_count; i++) { + hash = method->get_argument_type(i); + } + + return hash; +} + void Variant::get_method_list(List<MethodInfo> *p_list) const { if (type == OBJECT) { Object *obj = get_validated_object(); @@ -1365,7 +1384,7 @@ static void _register_variant_builtin_methods() { // FIXME: Static function, not sure how to bind //bind_method(String, humanize_size, sarray("size"), varray()); - bind_method(String, is_abs_path, sarray(), varray()); + bind_method(String, is_absolute_path, sarray(), varray()); bind_method(String, is_rel_path, sarray(), varray()); bind_method(String, get_base_dir, sarray(), varray()); bind_method(String, get_file, sarray(), varray()); @@ -1380,7 +1399,7 @@ static void _register_variant_builtin_methods() { bind_method(String, validate_node_name, sarray(), varray()); bind_method(String, is_valid_identifier, sarray(), varray()); - bind_method(String, is_valid_integer, sarray(), varray()); + bind_method(String, is_valid_int, sarray(), varray()); bind_method(String, is_valid_float, sarray(), varray()); bind_method(String, is_valid_hex_number, sarray("with_prefix"), varray(false)); bind_method(String, is_valid_html_color, sarray(), varray()); @@ -1544,19 +1563,20 @@ static void _register_variant_builtin_methods() { bind_methodv(Plane, intersects_ray, &Plane::intersects_ray_bind, sarray("from", "dir"), varray()); bind_methodv(Plane, intersects_segment, &Plane::intersects_segment_bind, sarray("from", "to"), varray()); - /* Quat */ - - bind_method(Quat, length, sarray(), varray()); - bind_method(Quat, length_squared, sarray(), varray()); - bind_method(Quat, normalized, sarray(), varray()); - bind_method(Quat, is_normalized, sarray(), varray()); - bind_method(Quat, is_equal_approx, sarray("to"), varray()); - bind_method(Quat, inverse, sarray(), varray()); - bind_method(Quat, dot, sarray("with"), varray()); - bind_method(Quat, slerp, sarray("to", "weight"), varray()); - bind_method(Quat, slerpni, sarray("to", "weight"), varray()); - bind_method(Quat, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); - bind_method(Quat, get_euler, sarray(), varray()); + /* Quaternion */ + + bind_method(Quaternion, length, sarray(), varray()); + bind_method(Quaternion, length_squared, sarray(), varray()); + bind_method(Quaternion, normalized, sarray(), varray()); + bind_method(Quaternion, is_normalized, sarray(), varray()); + bind_method(Quaternion, is_equal_approx, sarray("to"), varray()); + bind_method(Quaternion, inverse, sarray(), varray()); + bind_method(Quaternion, angle_to, sarray("to"), varray()); + bind_method(Quaternion, dot, sarray("with"), varray()); + bind_method(Quaternion, slerp, sarray("to", "weight"), varray()); + bind_method(Quaternion, slerpni, sarray("to", "weight"), varray()); + bind_method(Quaternion, cubic_slerp, sarray("b", "pre_a", "post_b", "weight"), varray()); + bind_method(Quaternion, get_euler, sarray(), varray()); /* Color */ @@ -1610,6 +1630,7 @@ static void _register_variant_builtin_methods() { bind_method(Callable, is_null, sarray(), varray()); bind_method(Callable, is_custom, sarray(), varray()); bind_method(Callable, is_standard, sarray(), varray()); + bind_method(Callable, is_valid, sarray(), varray()); bind_method(Callable, get_object, sarray(), varray()); bind_method(Callable, get_object_id, sarray(), varray()); bind_method(Callable, get_method, sarray(), varray()); @@ -1651,6 +1672,8 @@ static void _register_variant_builtin_methods() { bind_method(Transform2D, basis_xform_inv, sarray("v"), varray()); bind_method(Transform2D, interpolate_with, sarray("xform", "weight"), varray()); bind_method(Transform2D, is_equal_approx, sarray("xform"), varray()); + bind_method(Transform2D, set_rotation, sarray("rotation"), varray()); + bind_method(Transform2D, looking_at, sarray("target"), varray(Transform2D())); /* Basis */ @@ -1668,7 +1691,7 @@ static void _register_variant_builtin_methods() { bind_method(Basis, get_orthogonal_index, sarray(), varray()); bind_method(Basis, slerp, sarray("to", "weight"), varray()); bind_method(Basis, is_equal_approx, sarray("b"), varray()); - bind_method(Basis, get_rotation_quat, sarray(), varray()); + bind_method(Basis, get_rotation_quaternion, sarray(), varray()); /* AABB */ @@ -1696,17 +1719,17 @@ static void _register_variant_builtin_methods() { bind_methodv(AABB, intersects_segment, &AABB::intersects_segment_bind, sarray("from", "to"), varray()); bind_methodv(AABB, intersects_ray, &AABB::intersects_ray_bind, sarray("from", "dir"), varray()); - /* Transform */ + /* Transform3D */ - bind_method(Transform, inverse, sarray(), varray()); - bind_method(Transform, affine_inverse, sarray(), varray()); - bind_method(Transform, orthonormalized, sarray(), varray()); - bind_method(Transform, rotated, sarray("axis", "phi"), varray()); - bind_method(Transform, scaled, sarray("scale"), varray()); - bind_method(Transform, translated, sarray("offset"), varray()); - bind_method(Transform, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); - bind_method(Transform, interpolate_with, sarray("xform", "weight"), varray()); - bind_method(Transform, is_equal_approx, sarray("xform"), varray()); + bind_method(Transform3D, inverse, sarray(), varray()); + bind_method(Transform3D, affine_inverse, sarray(), varray()); + bind_method(Transform3D, orthonormalized, sarray(), varray()); + bind_method(Transform3D, rotated, sarray("axis", "phi"), varray()); + bind_method(Transform3D, scaled, sarray("scale"), varray()); + bind_method(Transform3D, translated, sarray("offset"), varray()); + bind_method(Transform3D, looking_at, sarray("target", "up"), varray(Vector3(0, 1, 0))); + bind_method(Transform3D, interpolate_with, sarray("xform", "weight"), varray()); + bind_method(Transform3D, is_equal_approx, sarray("xform"), varray()); /* Dictionary */ @@ -2025,14 +2048,14 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); - Transform identity_transform = Transform(); - Transform flip_x_transform = Transform(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); - Transform flip_y_transform = Transform(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0); - Transform flip_z_transform = Transform(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "IDENTITY", identity_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_X", flip_x_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Y", flip_y_transform); - _VariantCall::add_variant_constant(Variant::TRANSFORM, "FLIP_Z", flip_z_transform); + Transform3D identity_transform = Transform3D(); + Transform3D flip_x_transform = Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0); + Transform3D flip_y_transform = Transform3D(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0); + Transform3D flip_z_transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "IDENTITY", identity_transform); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_X", flip_x_transform); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Y", flip_y_transform); + _VariantCall::add_variant_constant(Variant::TRANSFORM3D, "FLIP_Z", flip_z_transform); Basis identity_basis = Basis(); Basis flip_x_basis = Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1); @@ -2047,7 +2070,7 @@ static void _register_variant_builtin_methods() { _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XZ", Plane(Vector3(0, 1, 0), 0)); _VariantCall::add_variant_constant(Variant::PLANE, "PLANE_XY", Plane(Vector3(0, 0, 1), 0)); - _VariantCall::add_variant_constant(Variant::QUAT, "IDENTITY", Quat(0, 0, 0, 1)); + _VariantCall::add_variant_constant(Variant::QUATERNION, "IDENTITY", Quaternion(0, 0, 0, 1)); } void Variant::_register_variant_methods() { diff --git a/core/variant/variant_construct.cpp b/core/variant/variant_construct.cpp index f0c9e52b46..a1a2bec369 100644 --- a/core/variant/variant_construct.cpp +++ b/core/variant/variant_construct.cpp @@ -28,543 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "variant.h" - -#include "core/core_string_names.h" -#include "core/crypto/crypto_core.h" -#include "core/debugger/engine_debugger.h" -#include "core/io/compression.h" -#include "core/object/class_db.h" -#include "core/os/os.h" -#include "core/templates/local_vector.h" -#include "core/templates/oa_hash_map.h" - -template <class T> -struct PtrConstruct {}; - -#define MAKE_PTRCONSTRUCT(m_type) \ - template <> \ - struct PtrConstruct<m_type> { \ - _FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \ - memnew_placement(p_ptr, m_type(p_value)); \ - } \ - }; - -MAKE_PTRCONSTRUCT(bool); -MAKE_PTRCONSTRUCT(int64_t); -MAKE_PTRCONSTRUCT(double); -MAKE_PTRCONSTRUCT(String); -MAKE_PTRCONSTRUCT(Vector2); -MAKE_PTRCONSTRUCT(Vector2i); -MAKE_PTRCONSTRUCT(Rect2); -MAKE_PTRCONSTRUCT(Rect2i); -MAKE_PTRCONSTRUCT(Vector3); -MAKE_PTRCONSTRUCT(Vector3i); -MAKE_PTRCONSTRUCT(Transform2D); -MAKE_PTRCONSTRUCT(Plane); -MAKE_PTRCONSTRUCT(Quat); -MAKE_PTRCONSTRUCT(AABB); -MAKE_PTRCONSTRUCT(Basis); -MAKE_PTRCONSTRUCT(Transform); -MAKE_PTRCONSTRUCT(Color); -MAKE_PTRCONSTRUCT(StringName); -MAKE_PTRCONSTRUCT(NodePath); -MAKE_PTRCONSTRUCT(RID); - -template <> -struct PtrConstruct<Object *> { - _FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) { - *((Object **)p_ptr) = p_value; - } -}; - -MAKE_PTRCONSTRUCT(Callable); -MAKE_PTRCONSTRUCT(Signal); -MAKE_PTRCONSTRUCT(Dictionary); -MAKE_PTRCONSTRUCT(Array); -MAKE_PTRCONSTRUCT(PackedByteArray); -MAKE_PTRCONSTRUCT(PackedInt32Array); -MAKE_PTRCONSTRUCT(PackedInt64Array); -MAKE_PTRCONSTRUCT(PackedFloat32Array); -MAKE_PTRCONSTRUCT(PackedFloat64Array); -MAKE_PTRCONSTRUCT(PackedStringArray); -MAKE_PTRCONSTRUCT(PackedVector2Array); -MAKE_PTRCONSTRUCT(PackedVector3Array); -MAKE_PTRCONSTRUCT(PackedColorArray); -MAKE_PTRCONSTRUCT(Variant); - -template <class T, class... P> -class VariantConstructor { - template <size_t... Is> - static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) { - r_error.error = Callable::CallError::CALL_OK; - -#ifdef DEBUG_METHODS_ENABLED - base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); -#else - base = T(VariantCaster<P>::cast(*p_args[Is])...); -#endif - } - - template <size_t... Is> - static _FORCE_INLINE_ void validated_construct_helper(T &base, const Variant **p_args, IndexSequence<Is...>) { - base = T((*VariantGetInternalPtr<P>::get_ptr(p_args[Is]))...); - } - - template <size_t... Is> - static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) { - PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base); - } - -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - r_error.error = Callable::CallError::CALL_OK; - VariantTypeChanger<T>::change(&r_ret); - construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<T>::change(r_ret); - validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{}); - } - static void ptr_construct(void *base, const void **p_args) { - ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{}); - } - - static int get_argument_count() { - return sizeof...(P); - } - - static Variant::Type get_argument_type(int p_arg) { - return call_get_argument_type<P...>(p_arg); - } - - static Variant::Type get_base_type() { - return GetTypeInfo<T>::VARIANT_TYPE; - } -}; - -class VariantConstructorObject { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - if (p_args[0]->get_type() == Variant::NIL) { - VariantInternal::object_assign_null(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } else if (p_args[0]->get_type() == Variant::OBJECT) { - VariantInternal::object_assign(&r_ret, p_args[0]); - r_error.error = Callable::CallError::CALL_OK; - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - } - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign(r_ret, p_args[0]); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::OBJECT; - } - - static Variant::Type get_base_type() { - return Variant::OBJECT; - } -}; - -class VariantConstructorNilObject { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != Variant::NIL) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::NIL; - } - - VariantInternal::clear(&r_ret); - VariantInternal::object_assign_null(&r_ret); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign_null(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Object *>::construct(nullptr, base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::OBJECT; - } -}; - -class VariantConstructorCallableArgs { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - ObjectID object_id; - StringName method; - - if (p_args[0]->get_type() == Variant::NIL) { - // leave as is - } else if (p_args[0]->get_type() == Variant::OBJECT) { - object_id = VariantInternal::get_object_id(p_args[0]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return; - } - - if (p_args[1]->get_type() == Variant::STRING_NAME) { - method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); - } else if (p_args[1]->get_type() == Variant::STRING) { - method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return; - } - - VariantTypeChanger<Callable>::change(&r_ret); - *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<Callable>::change(r_ret); - *VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); - } - - static int get_argument_count() { - return 2; - } - - static Variant::Type get_argument_type(int p_arg) { - if (p_arg == 0) { - return Variant::OBJECT; - } else { - return Variant::STRING_NAME; - } - } - - static Variant::Type get_base_type() { - return Variant::CALLABLE; - } -}; - -class VariantConstructorSignalArgs { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - ObjectID object_id; - StringName method; - - if (p_args[0]->get_type() == Variant::NIL) { - // leave as is - } else if (p_args[0]->get_type() == Variant::OBJECT) { - object_id = VariantInternal::get_object_id(p_args[0]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - return; - } - - if (p_args[1]->get_type() == Variant::STRING_NAME) { - method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); - } else if (p_args[1]->get_type() == Variant::STRING) { - method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); - } else { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return; - } - - VariantTypeChanger<Signal>::change(&r_ret); - *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<Signal>::change(r_ret); - *VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); - } - - static int get_argument_count() { - return 2; - } - - static Variant::Type get_argument_type(int p_arg) { - if (p_arg == 0) { - return Variant::OBJECT; - } else { - return Variant::STRING_NAME; - } - } - - static Variant::Type get_base_type() { - return Variant::SIGNAL; - } -}; - -template <class T> -class VariantConstructorToArray { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != GetTypeInfo<T>::VARIANT_TYPE) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = GetTypeInfo<T>::VARIANT_TYPE; - return; - } - - VariantTypeChanger<Array>::change(&r_ret); - Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret); - const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr[i] = src_arr[i]; - } - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<Array>::change(r_ret); - Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret); - const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr[i] = src_arr[i]; - } - } - static void ptr_construct(void *base, const void **p_args) { - Array dst_arr; - T src_arr = PtrToArg<T>::convert(p_args[0]); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr[i] = src_arr[i]; - } - - PtrConstruct<Array>::construct(dst_arr, base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return GetTypeInfo<T>::VARIANT_TYPE; - } - - static Variant::Type get_base_type() { - return Variant::ARRAY; - } -}; - -template <class T> -class VariantConstructorFromArray { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != Variant::ARRAY) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::ARRAY; - return; - } - - VariantTypeChanger<T>::change(&r_ret); - const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); - T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr.write[i] = src_arr[i]; - } - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<T>::change(r_ret); - const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); - T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret); - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr.write[i] = src_arr[i]; - } - } - static void ptr_construct(void *base, const void **p_args) { - Array src_arr = PtrToArg<Array>::convert(p_args[0]); - T dst_arr; - - int size = src_arr.size(); - dst_arr.resize(size); - for (int i = 0; i < size; i++) { - dst_arr.write[i] = src_arr[i]; - } - - PtrConstruct<T>::construct(dst_arr, base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::ARRAY; - } - - static Variant::Type get_base_type() { - return GetTypeInfo<T>::VARIANT_TYPE; - } -}; - -class VariantConstructorNil { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - if (p_args[0]->get_type() != Variant::NIL) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::NIL; - return; - } - - r_error.error = Callable::CallError::CALL_OK; - VariantInternal::clear(&r_ret); - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Variant>::construct(Variant(), base); - } - - static int get_argument_count() { - return 1; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::NIL; - } -}; - -template <class T> -class VariantConstructNoArgs { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantTypeChanger<T>::change_and_reset(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantTypeChanger<T>::change_and_reset(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<T>::construct(T(), base); - } - - static int get_argument_count() { - return 0; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return GetTypeInfo<T>::VARIANT_TYPE; - } -}; - -class VariantConstructNoArgsNil { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - ERR_FAIL_MSG("can't ptrcall nil constructor"); - } - - static int get_argument_count() { - return 0; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::NIL; - } -}; - -class VariantConstructNoArgsObject { -public: - static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { - VariantInternal::clear(&r_ret); - VariantInternal::object_assign_null(&r_ret); - r_error.error = Callable::CallError::CALL_OK; - } - - static void validated_construct(Variant *r_ret, const Variant **p_args) { - VariantInternal::clear(r_ret); - VariantInternal::object_assign_null(r_ret); - } - static void ptr_construct(void *base, const void **p_args) { - PtrConstruct<Object *>::construct(nullptr, base); - } - - static int get_argument_count() { - return 0; - } - - static Variant::Type get_argument_type(int p_arg) { - return Variant::NIL; - } - - static Variant::Type get_base_type() { - return Variant::OBJECT; - } -}; +#include "variant_construct.h" struct VariantConstructData { void (*construct)(Variant &r_base, const Variant **p_args, Callable::CallError &r_error); @@ -659,13 +123,13 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructor<Plane, Vector3, Vector3, Vector3>>(sarray("point1", "point2", "point3")); add_constructor<VariantConstructor<Plane, double, double, double, double>>(sarray("a", "b", "c", "d")); - add_constructor<VariantConstructNoArgs<Quat>>(sarray()); - add_constructor<VariantConstructor<Quat, Quat>>(sarray("from")); - add_constructor<VariantConstructor<Quat, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Quat, Vector3>>(sarray("euler")); - add_constructor<VariantConstructor<Quat, Vector3, double>>(sarray("axis", "angle")); - add_constructor<VariantConstructor<Quat, Vector3, Vector3>>(sarray("arc_from", "arc_to")); - add_constructor<VariantConstructor<Quat, double, double, double, double>>(sarray("x", "y", "z", "w")); + add_constructor<VariantConstructNoArgs<Quaternion>>(sarray()); + add_constructor<VariantConstructor<Quaternion, Quaternion>>(sarray("from")); + add_constructor<VariantConstructor<Quaternion, Basis>>(sarray("from")); + add_constructor<VariantConstructor<Quaternion, Vector3>>(sarray("euler")); + add_constructor<VariantConstructor<Quaternion, Vector3, double>>(sarray("axis", "angle")); + add_constructor<VariantConstructor<Quaternion, Vector3, Vector3>>(sarray("arc_from", "arc_to")); + add_constructor<VariantConstructor<Quaternion, double, double, double, double>>(sarray("x", "y", "z", "w")); add_constructor<VariantConstructNoArgs<::AABB>>(sarray()); add_constructor<VariantConstructor<::AABB, ::AABB>>(sarray("from")); @@ -673,15 +137,15 @@ void Variant::_register_variant_constructors() { add_constructor<VariantConstructNoArgs<Basis>>(sarray()); add_constructor<VariantConstructor<Basis, Basis>>(sarray("from")); - add_constructor<VariantConstructor<Basis, Quat>>(sarray("from")); + add_constructor<VariantConstructor<Basis, Quaternion>>(sarray("from")); add_constructor<VariantConstructor<Basis, Vector3>>(sarray("euler")); add_constructor<VariantConstructor<Basis, Vector3, double>>(sarray("axis", "phi")); add_constructor<VariantConstructor<Basis, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis")); - add_constructor<VariantConstructNoArgs<Transform>>(sarray()); - add_constructor<VariantConstructor<Transform, Transform>>(sarray("from")); - add_constructor<VariantConstructor<Transform, Basis, Vector3>>(sarray("basis", "origin")); - add_constructor<VariantConstructor<Transform, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin")); + add_constructor<VariantConstructNoArgs<Transform3D>>(sarray()); + add_constructor<VariantConstructor<Transform3D, Transform3D>>(sarray("from")); + add_constructor<VariantConstructor<Transform3D, Basis, Vector3>>(sarray("basis", "origin")); + add_constructor<VariantConstructor<Transform3D, Vector3, Vector3, Vector3, Vector3>>(sarray("x_axis", "y_axis", "z_axis", "origin")); add_constructor<VariantConstructNoArgs<Color>>(sarray()); add_constructor<VariantConstructor<Color, Color>>(sarray("from")); @@ -836,9 +300,9 @@ String Variant::get_constructor_argument_name(Variant::Type p_type, int p_constr void VariantInternal::object_assign(Variant *v, const Object *o) { if (o) { - if (o->is_reference()) { - Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(o)); - if (!reference->init_ref()) { + if (o->is_ref_counted()) { + RefCounted *ref_counted = const_cast<RefCounted *>(static_cast<const RefCounted *>(o)); + if (!ref_counted->init_ref()) { v->_get_obj().obj = nullptr; v->_get_obj().id = ObjectID(); return; diff --git a/core/variant/variant_construct.h b/core/variant/variant_construct.h new file mode 100644 index 0000000000..b03f4a8d3b --- /dev/null +++ b/core/variant/variant_construct.h @@ -0,0 +1,572 @@ +/*************************************************************************/ +/* variant_construct.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef VARIANT_CONSTRUCT_H +#define VARIANT_CONSTRUCT_H + +#include "variant.h" + +#include "core/core_string_names.h" +#include "core/crypto/crypto_core.h" +#include "core/debugger/engine_debugger.h" +#include "core/io/compression.h" +#include "core/object/class_db.h" +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "core/templates/oa_hash_map.h" + +template <class T> +struct PtrConstruct {}; + +#define MAKE_PTRCONSTRUCT(m_type) \ + template <> \ + struct PtrConstruct<m_type> { \ + _FORCE_INLINE_ static void construct(const m_type &p_value, void *p_ptr) { \ + memnew_placement(p_ptr, m_type(p_value)); \ + } \ + }; + +MAKE_PTRCONSTRUCT(bool); +MAKE_PTRCONSTRUCT(int64_t); +MAKE_PTRCONSTRUCT(double); +MAKE_PTRCONSTRUCT(String); +MAKE_PTRCONSTRUCT(Vector2); +MAKE_PTRCONSTRUCT(Vector2i); +MAKE_PTRCONSTRUCT(Rect2); +MAKE_PTRCONSTRUCT(Rect2i); +MAKE_PTRCONSTRUCT(Vector3); +MAKE_PTRCONSTRUCT(Vector3i); +MAKE_PTRCONSTRUCT(Transform2D); +MAKE_PTRCONSTRUCT(Plane); +MAKE_PTRCONSTRUCT(Quaternion); +MAKE_PTRCONSTRUCT(AABB); +MAKE_PTRCONSTRUCT(Basis); +MAKE_PTRCONSTRUCT(Transform3D); +MAKE_PTRCONSTRUCT(Color); +MAKE_PTRCONSTRUCT(StringName); +MAKE_PTRCONSTRUCT(NodePath); +MAKE_PTRCONSTRUCT(RID); + +template <> +struct PtrConstruct<Object *> { + _FORCE_INLINE_ static void construct(Object *p_value, void *p_ptr) { + *((Object **)p_ptr) = p_value; + } +}; + +MAKE_PTRCONSTRUCT(Callable); +MAKE_PTRCONSTRUCT(Signal); +MAKE_PTRCONSTRUCT(Dictionary); +MAKE_PTRCONSTRUCT(Array); +MAKE_PTRCONSTRUCT(PackedByteArray); +MAKE_PTRCONSTRUCT(PackedInt32Array); +MAKE_PTRCONSTRUCT(PackedInt64Array); +MAKE_PTRCONSTRUCT(PackedFloat32Array); +MAKE_PTRCONSTRUCT(PackedFloat64Array); +MAKE_PTRCONSTRUCT(PackedStringArray); +MAKE_PTRCONSTRUCT(PackedVector2Array); +MAKE_PTRCONSTRUCT(PackedVector3Array); +MAKE_PTRCONSTRUCT(PackedColorArray); +MAKE_PTRCONSTRUCT(Variant); + +template <class T, class... P> +class VariantConstructor { + template <size_t... Is> + static _FORCE_INLINE_ void construct_helper(T &base, const Variant **p_args, Callable::CallError &r_error, IndexSequence<Is...>) { + r_error.error = Callable::CallError::CALL_OK; + +#ifdef DEBUG_METHODS_ENABLED + base = T(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...); +#else + base = T(VariantCaster<P>::cast(*p_args[Is])...); +#endif + } + + template <size_t... Is> + static _FORCE_INLINE_ void validated_construct_helper(T &base, const Variant **p_args, IndexSequence<Is...>) { + base = T((*VariantGetInternalPtr<P>::get_ptr(p_args[Is]))...); + } + + template <size_t... Is> + static _FORCE_INLINE_ void ptr_construct_helper(void *base, const void **p_args, IndexSequence<Is...>) { + PtrConstruct<T>::construct(T(PtrToArg<P>::convert(p_args[Is])...), base); + } + +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + r_error.error = Callable::CallError::CALL_OK; + VariantTypeChanger<T>::change(&r_ret); + construct_helper(*VariantGetInternalPtr<T>::get_ptr(&r_ret), p_args, r_error, BuildIndexSequence<sizeof...(P)>{}); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change(r_ret); + validated_construct_helper(*VariantGetInternalPtr<T>::get_ptr(r_ret), p_args, BuildIndexSequence<sizeof...(P)>{}); + } + static void ptr_construct(void *base, const void **p_args) { + ptr_construct_helper(base, p_args, BuildIndexSequence<sizeof...(P)>{}); + } + + static int get_argument_count() { + return sizeof...(P); + } + + static Variant::Type get_argument_type(int p_arg) { + return call_get_argument_type<P...>(p_arg); + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + +class VariantConstructorObject { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); + if (p_args[0]->get_type() == Variant::NIL) { + VariantInternal::object_assign_null(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } else if (p_args[0]->get_type() == Variant::OBJECT) { + VariantInternal::object_assign(&r_ret, p_args[0]); + r_error.error = Callable::CallError::CALL_OK; + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + VariantInternal::object_assign(r_ret, p_args[0]); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Object *>::construct(PtrToArg<Object *>::convert(p_args[0]), base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::OBJECT; + } + + static Variant::Type get_base_type() { + return Variant::OBJECT; + } +}; + +class VariantConstructorNilObject { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::NIL) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::NIL; + } + + VariantInternal::clear(&r_ret); + VariantInternal::object_assign_null(&r_ret); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + VariantInternal::object_assign_null(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Object *>::construct(nullptr, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::OBJECT; + } +}; + +class VariantConstructorCallableArgs { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + ObjectID object_id; + StringName method; + + if (p_args[0]->get_type() == Variant::NIL) { + // leave as is + } else if (p_args[0]->get_type() == Variant::OBJECT) { + object_id = VariantInternal::get_object_id(p_args[0]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() == Variant::STRING_NAME) { + method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); + } else if (p_args[1]->get_type() == Variant::STRING) { + method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + VariantTypeChanger<Callable>::change(&r_ret); + *VariantGetInternalPtr<Callable>::get_ptr(&r_ret) = Callable(object_id, method); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<Callable>::change(r_ret); + *VariantGetInternalPtr<Callable>::get_ptr(r_ret) = Callable(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Callable>::construct(Callable(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); + } + + static int get_argument_count() { + return 2; + } + + static Variant::Type get_argument_type(int p_arg) { + if (p_arg == 0) { + return Variant::OBJECT; + } else { + return Variant::STRING_NAME; + } + } + + static Variant::Type get_base_type() { + return Variant::CALLABLE; + } +}; + +class VariantConstructorSignalArgs { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + ObjectID object_id; + StringName method; + + if (p_args[0]->get_type() == Variant::NIL) { + // leave as is + } else if (p_args[0]->get_type() == Variant::OBJECT) { + object_id = VariantInternal::get_object_id(p_args[0]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::OBJECT; + return; + } + + if (p_args[1]->get_type() == Variant::STRING_NAME) { + method = *VariantGetInternalPtr<StringName>::get_ptr(p_args[1]); + } else if (p_args[1]->get_type() == Variant::STRING) { + method = *VariantGetInternalPtr<String>::get_ptr(p_args[1]); + } else { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 1; + r_error.expected = Variant::STRING_NAME; + return; + } + + VariantTypeChanger<Signal>::change(&r_ret); + *VariantGetInternalPtr<Signal>::get_ptr(&r_ret) = Signal(object_id, method); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<Signal>::change(r_ret); + *VariantGetInternalPtr<Signal>::get_ptr(r_ret) = Signal(VariantInternal::get_object_id(p_args[0]), *VariantGetInternalPtr<StringName>::get_ptr(p_args[1])); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Signal>::construct(Signal(PtrToArg<Object *>::convert(p_args[0]), PtrToArg<StringName>::convert(p_args[1])), base); + } + + static int get_argument_count() { + return 2; + } + + static Variant::Type get_argument_type(int p_arg) { + if (p_arg == 0) { + return Variant::OBJECT; + } else { + return Variant::STRING_NAME; + } + } + + static Variant::Type get_base_type() { + return Variant::SIGNAL; + } +}; + +template <class T> +class VariantConstructorToArray { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != GetTypeInfo<T>::VARIANT_TYPE) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = GetTypeInfo<T>::VARIANT_TYPE; + return; + } + + VariantTypeChanger<Array>::change(&r_ret); + Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(&r_ret); + const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr[i] = src_arr[i]; + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<Array>::change(r_ret); + Array &dst_arr = *VariantGetInternalPtr<Array>::get_ptr(r_ret); + const T &src_arr = *VariantGetInternalPtr<T>::get_ptr(p_args[0]); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr[i] = src_arr[i]; + } + } + static void ptr_construct(void *base, const void **p_args) { + Array dst_arr; + T src_arr = PtrToArg<T>::convert(p_args[0]); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr[i] = src_arr[i]; + } + + PtrConstruct<Array>::construct(dst_arr, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return GetTypeInfo<T>::VARIANT_TYPE; + } + + static Variant::Type get_base_type() { + return Variant::ARRAY; + } +}; + +template <class T> +class VariantConstructorFromArray { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::ARRAY) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::ARRAY; + return; + } + + VariantTypeChanger<T>::change(&r_ret); + const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); + T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(&r_ret); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr.write[i] = src_arr[i]; + } + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change(r_ret); + const Array &src_arr = *VariantGetInternalPtr<Array>::get_ptr(p_args[0]); + T &dst_arr = *VariantGetInternalPtr<T>::get_ptr(r_ret); + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr.write[i] = src_arr[i]; + } + } + static void ptr_construct(void *base, const void **p_args) { + Array src_arr = PtrToArg<Array>::convert(p_args[0]); + T dst_arr; + + int size = src_arr.size(); + dst_arr.resize(size); + for (int i = 0; i < size; i++) { + dst_arr.write[i] = src_arr[i]; + } + + PtrConstruct<T>::construct(dst_arr, base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::ARRAY; + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + +class VariantConstructorNil { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + if (p_args[0]->get_type() != Variant::NIL) { + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; + r_error.argument = 0; + r_error.expected = Variant::NIL; + return; + } + + r_error.error = Callable::CallError::CALL_OK; + VariantInternal::clear(&r_ret); + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Variant>::construct(Variant(), base); + } + + static int get_argument_count() { + return 1; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::NIL; + } +}; + +template <class T> +class VariantConstructNoArgs { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantTypeChanger<T>::change_and_reset(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantTypeChanger<T>::change_and_reset(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<T>::construct(T(), base); + } + + static int get_argument_count() { + return 0; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return GetTypeInfo<T>::VARIANT_TYPE; + } +}; + +class VariantConstructNoArgsNil { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + ERR_FAIL_MSG("can't ptrcall nil constructor"); + } + + static int get_argument_count() { + return 0; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::NIL; + } +}; + +class VariantConstructNoArgsObject { +public: + static void construct(Variant &r_ret, const Variant **p_args, Callable::CallError &r_error) { + VariantInternal::clear(&r_ret); + VariantInternal::object_assign_null(&r_ret); + r_error.error = Callable::CallError::CALL_OK; + } + + static inline void validated_construct(Variant *r_ret, const Variant **p_args) { + VariantInternal::clear(r_ret); + VariantInternal::object_assign_null(r_ret); + } + static void ptr_construct(void *base, const void **p_args) { + PtrConstruct<Object *>::construct(nullptr, base); + } + + static int get_argument_count() { + return 0; + } + + static Variant::Type get_argument_type(int p_arg) { + return Variant::NIL; + } + + static Variant::Type get_base_type() { + return Variant::OBJECT; + } +}; + +#endif // VARIANT_CONSTRUCT_H diff --git a/core/variant/variant_internal.h b/core/variant/variant_internal.h index fb791f8c0c..78e1ad06ae 100644 --- a/core/variant/variant_internal.h +++ b/core/variant/variant_internal.h @@ -55,7 +55,7 @@ public: case Variant::BASIS: init_basis(v); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: init_transform(v); break; case Variant::STRING_NAME: @@ -138,14 +138,14 @@ public: _FORCE_INLINE_ static const Transform2D *get_transform2d(const Variant *v) { return v->_data._transform2d; } _FORCE_INLINE_ static Plane *get_plane(Variant *v) { return reinterpret_cast<Plane *>(v->_data._mem); } _FORCE_INLINE_ static const Plane *get_plane(const Variant *v) { return reinterpret_cast<const Plane *>(v->_data._mem); } - _FORCE_INLINE_ static Quat *get_quat(Variant *v) { return reinterpret_cast<Quat *>(v->_data._mem); } - _FORCE_INLINE_ static const Quat *get_quat(const Variant *v) { return reinterpret_cast<const Quat *>(v->_data._mem); } + _FORCE_INLINE_ static Quaternion *get_quaternion(Variant *v) { return reinterpret_cast<Quaternion *>(v->_data._mem); } + _FORCE_INLINE_ static const Quaternion *get_quaternion(const Variant *v) { return reinterpret_cast<const Quaternion *>(v->_data._mem); } _FORCE_INLINE_ static ::AABB *get_aabb(Variant *v) { return v->_data._aabb; } _FORCE_INLINE_ static const ::AABB *get_aabb(const Variant *v) { return v->_data._aabb; } _FORCE_INLINE_ static Basis *get_basis(Variant *v) { return v->_data._basis; } _FORCE_INLINE_ static const Basis *get_basis(const Variant *v) { return v->_data._basis; } - _FORCE_INLINE_ static Transform *get_transform(Variant *v) { return v->_data._transform; } - _FORCE_INLINE_ static const Transform *get_transform(const Variant *v) { return v->_data._transform; } + _FORCE_INLINE_ static Transform3D *get_transform(Variant *v) { return v->_data._transform3d; } + _FORCE_INLINE_ static const Transform3D *get_transform(const Variant *v) { return v->_data._transform3d; } // Misc types. _FORCE_INLINE_ static Color *get_color(Variant *v) { return reinterpret_cast<Color *>(v->_data._mem); } @@ -217,8 +217,8 @@ public: v->type = Variant::BASIS; } _FORCE_INLINE_ static void init_transform(Variant *v) { - v->_data._transform = memnew(Transform); - v->type = Variant::TRANSFORM; + v->_data._transform3d = memnew(Transform3D); + v->type = Variant::TRANSFORM3D; } _FORCE_INLINE_ static void init_string_name(Variant *v) { memnew_placement(v->_data._mem, StringName); @@ -285,7 +285,7 @@ public: v->clear(); } - static void object_assign(Variant *v, const Object *o); // Needs Reference, so it's implemented elsewhere. + static void object_assign(Variant *v, const Object *o); // Needs RefCounted, so it's implemented elsewhere. _FORCE_INLINE_ static void object_assign(Variant *v, const Variant *o) { object_assign(v, o->_get_obj().obj); @@ -320,12 +320,12 @@ public: return get_rect2(v); case Variant::RECT2I: return get_rect2i(v); - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: return get_transform(v); case Variant::TRANSFORM2D: return get_transform2d(v); - case Variant::QUAT: - return get_quat(v); + case Variant::QUATERNION: + return get_quaternion(v); case Variant::PLANE: return get_plane(v); case Variant::BASIS: @@ -398,12 +398,12 @@ public: return get_rect2(v); case Variant::RECT2I: return get_rect2i(v); - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: return get_transform(v); case Variant::TRANSFORM2D: return get_transform2d(v); - case Variant::QUAT: - return get_quat(v); + case Variant::QUATERNION: + return get_quaternion(v); case Variant::PLANE: return get_plane(v); case Variant::BASIS: @@ -590,9 +590,9 @@ struct VariantGetInternalPtr<Transform2D> { }; template <> -struct VariantGetInternalPtr<Transform> { - static Transform *get_ptr(Variant *v) { return VariantInternal::get_transform(v); } - static const Transform *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); } +struct VariantGetInternalPtr<Transform3D> { + static Transform3D *get_ptr(Variant *v) { return VariantInternal::get_transform(v); } + static const Transform3D *get_ptr(const Variant *v) { return VariantInternal::get_transform(v); } }; template <> @@ -602,9 +602,9 @@ struct VariantGetInternalPtr<Plane> { }; template <> -struct VariantGetInternalPtr<Quat> { - static Quat *get_ptr(Variant *v) { return VariantInternal::get_quat(v); } - static const Quat *get_ptr(const Variant *v) { return VariantInternal::get_quat(v); } +struct VariantGetInternalPtr<Quaternion> { + static Quaternion *get_ptr(Variant *v) { return VariantInternal::get_quaternion(v); } + static const Quaternion *get_ptr(const Variant *v) { return VariantInternal::get_quaternion(v); } }; template <> @@ -819,9 +819,9 @@ struct VariantInternalAccessor<Transform2D> { }; template <> -struct VariantInternalAccessor<Transform> { - static _FORCE_INLINE_ const Transform &get(const Variant *v) { return *VariantInternal::get_transform(v); } - static _FORCE_INLINE_ void set(Variant *v, const Transform &p_value) { *VariantInternal::get_transform(v) = p_value; } +struct VariantInternalAccessor<Transform3D> { + static _FORCE_INLINE_ const Transform3D &get(const Variant *v) { return *VariantInternal::get_transform(v); } + static _FORCE_INLINE_ void set(Variant *v, const Transform3D &p_value) { *VariantInternal::get_transform(v) = p_value; } }; template <> @@ -831,9 +831,9 @@ struct VariantInternalAccessor<Plane> { }; template <> -struct VariantInternalAccessor<Quat> { - static _FORCE_INLINE_ const Quat &get(const Variant *v) { return *VariantInternal::get_quat(v); } - static _FORCE_INLINE_ void set(Variant *v, const Quat &p_value) { *VariantInternal::get_quat(v) = p_value; } +struct VariantInternalAccessor<Quaternion> { + static _FORCE_INLINE_ const Quaternion &get(const Variant *v) { return *VariantInternal::get_quaternion(v); } + static _FORCE_INLINE_ void set(Variant *v, const Quaternion &p_value) { *VariantInternal::get_quaternion(v) = p_value; } }; template <> @@ -1067,8 +1067,8 @@ struct VariantInitializer<Plane> { }; template <> -struct VariantInitializer<Quat> { - static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quat>(v); } +struct VariantInitializer<Quaternion> { + static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_generic<Quaternion>(v); } }; template <> @@ -1082,7 +1082,7 @@ struct VariantInitializer<Basis> { }; template <> -struct VariantInitializer<Transform> { +struct VariantInitializer<Transform3D> { static _FORCE_INLINE_ void init(Variant *v) { VariantInternal::init_transform(v); } }; @@ -1241,8 +1241,8 @@ struct VariantZeroAssigner<Plane> { }; template <> -struct VariantZeroAssigner<Quat> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quat(v) = Quat(); } +struct VariantZeroAssigner<Quaternion> { + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_quaternion(v) = Quaternion(); } }; template <> @@ -1256,8 +1256,8 @@ struct VariantZeroAssigner<Basis> { }; template <> -struct VariantZeroAssigner<Transform> { - static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform(); } +struct VariantZeroAssigner<Transform3D> { + static _FORCE_INLINE_ void zero(Variant *v) { *VariantInternal::get_transform(v) = Transform3D(); } }; template <> diff --git a/core/variant/variant_op.cpp b/core/variant/variant_op.cpp index 8cfa793c0e..16c7428781 100644 --- a/core/variant/variant_op.cpp +++ b/core/variant/variant_op.cpp @@ -28,1342 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "variant.h" - -#include "core/core_string_names.h" -#include "core/debugger/engine_debugger.h" -#include "core/object/class_db.h" - -template <class R, class A, class B> -class OperatorEvaluatorAdd { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a + b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) + *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) + PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorSub { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a - b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) - *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) - PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorMul { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a * b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) * *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) * PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorXForm { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a.xform(b); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<A>::get_ptr(left)->xform(*VariantGetInternalPtr<B>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left).xform(PtrToArg<B>::convert(right)), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorXFormInv { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = b.xform_inv(a); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<B>::get_ptr(right)->xform_inv(*VariantGetInternalPtr<A>::get_ptr(left)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<B>::convert(right).xform_inv(PtrToArg<A>::convert(left)), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorDiv { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a / b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorDivNZ { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - if (b == 0) { - r_valid = false; - *r_ret = "Division by zero error"; - return; - } - *r_ret = a / b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorMod { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a % b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorModNZ { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - if (b == 0) { - r_valid = false; - *r_ret = "Module by zero error"; - return; - } - *r_ret = a % b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A> -class OperatorEvaluatorNeg { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = -a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = -*VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(-PtrToArg<A>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A> -class OperatorEvaluatorPos { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorShiftLeft { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - -#if defined(DEBUG_ENABLED) - if (b < 0 || a < 0) { - *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; - r_valid = false; - return; - } -#endif - *r_ret = a << b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) << *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) << PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorShiftRight { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - -#if defined(DEBUG_ENABLED) - if (b < 0 || a < 0) { - *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; - r_valid = false; - return; - } -#endif - *r_ret = a >> b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >> *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) >> PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorBitOr { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a | b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) | *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) | PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorBitAnd { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a & b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) & PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A, class B> -class OperatorEvaluatorBitXor { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a ^ b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) ^ *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(PtrToArg<A>::convert(left) ^ PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class R, class A> -class OperatorEvaluatorBitNeg { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = ~a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<R>::change(r_ret); - *VariantGetInternalPtr<R>::get_ptr(r_ret) = ~*VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<R>::encode(~PtrToArg<A>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } -}; - -template <class A, class B> -class OperatorEvaluatorEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a == b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorEqualObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.get_validated_object(); - const Object *b = p_right.get_validated_object(); - *r_ret = a == b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->get_validated_object(); - const Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorEqualObjectNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *a = p_left.get_validated_object(); - *r_ret = a == nullptr; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *a = left->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorEqualNilObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Object *b = p_right.get_validated_object(); - *r_ret = nullptr == b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(nullptr == PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorNotEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a != b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) != *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) != PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotEqualObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.get_validated_object(); - Object *b = p_right.get_validated_object(); - *r_ret = a != b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->get_validated_object(); - Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotEqualObjectNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *a = p_left.get_validated_object(); - *r_ret = a != nullptr; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *a = left->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != nullptr, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotEqualNilObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); - *r_ret = nullptr != b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *b = right->get_validated_object(); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(nullptr != PtrToArg<Object *>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorLess { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a < b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) < *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) < PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorLessEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a <= b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) <= *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) <= PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorGreater { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a > b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) > *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) > PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorGreaterEqual { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a >= b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >= *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) >= PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorAnd { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a && b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) && *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) && PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorOr { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = a || b; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) || *VariantGetInternalPtr<B>::get_ptr(right); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<A>::convert(left) || PtrToArg<B>::convert(right), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b))) -template <class A, class B> -class OperatorEvaluatorXor { -public: - _FORCE_INLINE_ static bool xor_op(const A &a, const B &b) { - return ((a) || (b)) && !((a) && (b)); - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - *r_ret = xor_op(a, b); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = xor_op(*VariantGetInternalPtr<A>::get_ptr(left), *VariantGetInternalPtr<B>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(xor_op(PtrToArg<A>::convert(left), PtrToArg<B>::convert(right)), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A> -class OperatorEvaluatorNot { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - *r_ret = !a; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<A>::convert(left)); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -//// CUSTOM //// - -class OperatorEvaluatorAddArray { -public: - _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) { - int asize = array_a.size(); - int bsize = array_b.size(); - sum.resize(asize + bsize); - for (int i = 0; i < asize; i++) { - sum[i] = array_a[i]; - } - for (int i = 0; i < bsize; i++) { - sum[i + asize] = array_b[i]; - } - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Array &array_a = *VariantGetInternalPtr<Array>::get_ptr(&p_left); - const Array &array_b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); - Array sum; - _add_arrays(sum, array_a, array_b); - *r_ret = sum; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<Array>::change(r_ret); - _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - Array ret; - _add_arrays(ret, PtrToArg<Array>::convert(left), PtrToArg<Array>::convert(right)); - PtrToArg<Array>::encode(ret, r_ret); - } - static Variant::Type get_return_type() { return Variant::ARRAY; } -}; - -template <class T> -class OperatorEvaluatorAppendArray { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Vector<T> &array_a = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_left); - const Vector<T> &array_b = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_right); - Vector<T> sum = array_a; - sum.append_array(array_b); - *r_ret = sum; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<Vector<T>>::change(r_ret); - *VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret) = *VariantGetInternalPtr<Vector<T>>::get_ptr(left); - VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret)->append_array(*VariantGetInternalPtr<Vector<T>>::get_ptr(right)); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - Vector<T> sum = PtrToArg<Vector<T>>::convert(left); - sum.append_array(PtrToArg<Vector<T>>::convert(right)); - PtrToArg<Vector<T>>::encode(sum, r_ret); - } - static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; } -}; - -class OperatorEvaluatorStringModNil { -public: - _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) { - Array values; - values.push_back(Variant()); - - String a = s.sprintf(values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - return a; - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, &r_valid); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), nullptr), r_ret); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -class OperatorEvaluatorStringModArray { -public: - _FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) { - String a = s.sprintf(p_values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - return a; - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -class OperatorEvaluatorStringModObject { -public: - _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) { - Array values; - values.push_back(p_object); - String a = s.sprintf(values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - - return a; - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, p_right.get_validated_object(), &r_valid); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -template <class T> -class OperatorEvaluatorStringModT { -public: - _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) { - Array values; - values.push_back(p_value); - String a = s.sprintf(values, r_valid); - if (r_valid) { - *r_valid = !*r_valid; - } - return a; - } - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - *r_ret = do_mod(a, *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<String>::change(r_ret); - *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret); - } - static Variant::Type get_return_type() { return Variant::STRING; } -}; - -template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> -class OperatorEvaluatorAlwaysTrue { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = true; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = true; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(true, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> -class OperatorEvaluatorAlwaysFalse { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = false; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(false, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -///// OR /////// - -_FORCE_INLINE_ static bool _operate_or(bool p_left, bool p_right) { - return p_left || p_right; -} - -_FORCE_INLINE_ static bool _operate_and(bool p_left, bool p_right) { - return p_left && p_right; -} - -_FORCE_INLINE_ static bool _operate_xor(bool p_left, bool p_right) { - return (p_left || p_right) && !(p_left && p_right); -} - -_FORCE_INLINE_ static bool _operate_get_nil(const Variant *p_ptr) { - return p_ptr->get_validated_object() != nullptr; -} - -_FORCE_INLINE_ static bool _operate_get_bool(const Variant *p_ptr) { - return *VariantGetInternalPtr<bool>::get_ptr(p_ptr); -} - -_FORCE_INLINE_ static bool _operate_get_int(const Variant *p_ptr) { - return *VariantGetInternalPtr<int64_t>::get_ptr(p_ptr) != 0; -} - -_FORCE_INLINE_ static bool _operate_get_float(const Variant *p_ptr) { - return *VariantGetInternalPtr<double>::get_ptr(p_ptr) != 0.0; -} - -_FORCE_INLINE_ static bool _operate_get_object(const Variant *p_ptr) { - return p_ptr->get_validated_object() != nullptr; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_nil(const void *p_ptr) { - return false; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_bool(const void *p_ptr) { - return PtrToArg<bool>::convert(p_ptr); -} - -_FORCE_INLINE_ static bool _operate_get_ptr_int(const void *p_ptr) { - return PtrToArg<int64_t>::convert(p_ptr) != 0; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_float(const void *p_ptr) { - return PtrToArg<double>::convert(p_ptr) != 0.0; -} - -_FORCE_INLINE_ static bool _operate_get_ptr_object(const void *p_ptr) { - return PtrToArg<Object *>::convert(p_ptr) != nullptr; -} - -#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \ - class m_class_name { \ - public: \ - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \ - *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \ - r_valid = true; \ - } \ - \ - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \ - VariantTypeChanger<bool>::change(r_ret); \ - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \ - } \ - \ - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { \ - PtrToArg<bool>::encode(m_op(_operate_get_ptr_##m_left(left), _operate_get_ptr_##m_right(right)), r_ret); \ - } \ - \ - static Variant::Type get_return_type() { \ - return Variant::BOOL; \ - } \ - }; - -// OR - -// nil -OP_EVALUATOR(OperatorEvaluatorNilXBoolOr, nil, bool, _operate_or) -OP_EVALUATOR(OperatorEvaluatorBoolXNilOr, bool, nil, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorNilXIntOr, nil, int, _operate_or) -OP_EVALUATOR(OperatorEvaluatorIntXNilOr, int, nil, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorNilXFloatOr, nil, float, _operate_or) -OP_EVALUATOR(OperatorEvaluatorFloatXNilOr, float, nil, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorObjectXNilOr, object, nil, _operate_or) -OP_EVALUATOR(OperatorEvaluatorNilXObjectOr, nil, object, _operate_or) - -// bool -OP_EVALUATOR(OperatorEvaluatorBoolXBoolOr, bool, bool, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorBoolXIntOr, bool, int, _operate_or) -OP_EVALUATOR(OperatorEvaluatorIntXBoolOr, int, bool, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorBoolXFloatOr, bool, float, _operate_or) -OP_EVALUATOR(OperatorEvaluatorFloatXBoolOr, float, bool, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorBoolXObjectOr, bool, object, _operate_or) -OP_EVALUATOR(OperatorEvaluatorObjectXBoolOr, object, bool, _operate_or) - -// int -OP_EVALUATOR(OperatorEvaluatorIntXIntOr, int, int, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorIntXFloatOr, int, float, _operate_or) -OP_EVALUATOR(OperatorEvaluatorFloatXIntOr, float, int, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorIntXObjectOr, int, object, _operate_or) -OP_EVALUATOR(OperatorEvaluatorObjectXIntOr, object, int, _operate_or) - -// float -OP_EVALUATOR(OperatorEvaluatorFloatXFloatOr, float, float, _operate_or) - -OP_EVALUATOR(OperatorEvaluatorFloatXObjectOr, float, object, _operate_or) -OP_EVALUATOR(OperatorEvaluatorObjectXFloatOr, object, float, _operate_or) - -// object -OP_EVALUATOR(OperatorEvaluatorObjectXObjectOr, object, object, _operate_or) - -// AND - -// nil -OP_EVALUATOR(OperatorEvaluatorNilXBoolAnd, nil, bool, _operate_and) -OP_EVALUATOR(OperatorEvaluatorBoolXNilAnd, bool, nil, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorNilXIntAnd, nil, int, _operate_and) -OP_EVALUATOR(OperatorEvaluatorIntXNilAnd, int, nil, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorNilXFloatAnd, nil, float, _operate_and) -OP_EVALUATOR(OperatorEvaluatorFloatXNilAnd, float, nil, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorObjectXNilAnd, object, nil, _operate_and) -OP_EVALUATOR(OperatorEvaluatorNilXObjectAnd, nil, object, _operate_and) - -// bool -OP_EVALUATOR(OperatorEvaluatorBoolXBoolAnd, bool, bool, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorBoolXIntAnd, bool, int, _operate_and) -OP_EVALUATOR(OperatorEvaluatorIntXBoolAnd, int, bool, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorBoolXFloatAnd, bool, float, _operate_and) -OP_EVALUATOR(OperatorEvaluatorFloatXBoolAnd, float, bool, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorBoolXObjectAnd, bool, object, _operate_and) -OP_EVALUATOR(OperatorEvaluatorObjectXBoolAnd, object, bool, _operate_and) - -// int -OP_EVALUATOR(OperatorEvaluatorIntXIntAnd, int, int, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorIntXFloatAnd, int, float, _operate_and) -OP_EVALUATOR(OperatorEvaluatorFloatXIntAnd, float, int, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorIntXObjectAnd, int, object, _operate_and) -OP_EVALUATOR(OperatorEvaluatorObjectXIntAnd, object, int, _operate_and) - -// float -OP_EVALUATOR(OperatorEvaluatorFloatXFloatAnd, float, float, _operate_and) - -OP_EVALUATOR(OperatorEvaluatorFloatXObjectAnd, float, object, _operate_and) -OP_EVALUATOR(OperatorEvaluatorObjectXFloatAnd, object, float, _operate_and) - -// object -OP_EVALUATOR(OperatorEvaluatorObjectXObjectAnd, object, object, _operate_and) - -// XOR - -// nil -OP_EVALUATOR(OperatorEvaluatorNilXBoolXor, nil, bool, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorBoolXNilXor, bool, nil, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorNilXIntXor, nil, int, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorIntXNilXor, int, nil, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorNilXFloatXor, nil, float, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorFloatXNilXor, float, nil, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorObjectXNilXor, object, nil, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorNilXObjectXor, nil, object, _operate_xor) - -// bool -OP_EVALUATOR(OperatorEvaluatorBoolXBoolXor, bool, bool, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorBoolXIntXor, bool, int, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorIntXBoolXor, int, bool, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorBoolXFloatXor, bool, float, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorFloatXBoolXor, float, bool, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorBoolXObjectXor, bool, object, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorObjectXBoolXor, object, bool, _operate_xor) - -// int -OP_EVALUATOR(OperatorEvaluatorIntXIntXor, int, int, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorIntXFloatXor, int, float, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorFloatXIntXor, float, int, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorIntXObjectXor, int, object, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorObjectXIntXor, object, int, _operate_xor) - -// float -OP_EVALUATOR(OperatorEvaluatorFloatXFloatXor, float, float, _operate_xor) - -OP_EVALUATOR(OperatorEvaluatorFloatXObjectXor, float, object, _operate_xor) -OP_EVALUATOR(OperatorEvaluatorObjectXFloatXor, object, float, _operate_xor) - -// object -OP_EVALUATOR(OperatorEvaluatorObjectXObjectXor, object, object, _operate_xor) - -class OperatorEvaluatorNotBool { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = !*VariantGetInternalPtr<bool>::get_ptr(&p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<bool>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<bool>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotInt { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = !*VariantGetInternalPtr<int64_t>::get_ptr(&p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<int64_t>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<int64_t>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotFloat { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = !*VariantGetInternalPtr<double>::get_ptr(&p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<double>::get_ptr(left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(!PtrToArg<double>::convert(left), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorNotObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - *r_ret = p_left.get_validated_object() == nullptr; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = left->get_validated_object() == nullptr; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -//// - -class OperatorEvaluatorInStringFind { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right); - - *r_ret = str_b.find(str_a) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left); - const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A, class B> -class OperatorEvaluatorInArrayFind { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); - - *r_ret = b.find(a) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const A &a = *VariantGetInternalPtr<A>::get_ptr(left); - const B &b = *VariantGetInternalPtr<B>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(a) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<B>::convert(right).find(PtrToArg<A>::convert(left)) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInArrayFindNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); - *r_ret = b.find(Variant()) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(Variant()) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(Variant()) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInArrayFindObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); - *r_ret = b.find(p_left) != -1; - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(*left) != -1; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(PtrToArg<Object *>::convert(left)) != -1, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -template <class A> -class OperatorEvaluatorInDictionaryHas { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); - const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); - - *r_ret = b.has(a); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); - const A &a = *VariantGetInternalPtr<A>::get_ptr(left); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(a); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<A>::convert(left)), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInDictionaryHasNil { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); - - *r_ret = b.has(Variant()); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(Variant()); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(Variant()), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorInDictionaryHasObject { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); - - *r_ret = b.has(p_left); - r_valid = true; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(*left); - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<Object *>::convert(left)), r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorObjectHasPropertyString { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); - if (!b) { - *r_ret = "Invalid base object for 'in'"; - r_valid = false; - return; - } - - const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); - - b->get(a, &r_valid); - *r_ret = r_valid; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *l = right->get_validated_object(); - ERR_FAIL_COND(l == nullptr); - const String &a = *VariantGetInternalPtr<String>::get_ptr(left); - - bool valid; - l->get(a, &valid); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - bool valid; - PtrToArg<Object *>::convert(right)->get(PtrToArg<String>::convert(left), &valid); - PtrToArg<bool>::encode(valid, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; - -class OperatorEvaluatorObjectHasPropertyStringName { -public: - static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { - Object *b = p_right.get_validated_object(); - if (!b) { - *r_ret = "Invalid base object for 'in'"; - r_valid = false; - return; - } - - const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left); - - b->get(a, &r_valid); - *r_ret = r_valid; - } - static void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { - Object *l = right->get_validated_object(); - ERR_FAIL_COND(l == nullptr); - const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left); - - bool valid; - l->get(a, &valid); - VariantTypeChanger<bool>::change(r_ret); - *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; - } - static void ptr_evaluate(const void *left, const void *right, void *r_ret) { - bool valid; - PtrToArg<Object *>::convert(right)->get(PtrToArg<StringName>::convert(left), &valid); - PtrToArg<bool>::encode(valid, r_ret); - } - static Variant::Type get_return_type() { return Variant::BOOL; } -}; +#include "variant_op.h" typedef void (*VariantEvaluatorFunction)(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid); @@ -1395,7 +60,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorAdd<Vector2i, Vector2i, Vector2i>>(Variant::OP_ADD, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorAdd<Vector3, Vector3, Vector3>>(Variant::OP_ADD, Variant::VECTOR3, Variant::VECTOR3); register_op<OperatorEvaluatorAdd<Vector3i, Vector3i, Vector3i>>(Variant::OP_ADD, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorAdd<Quat, Quat, Quat>>(Variant::OP_ADD, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorAdd<Quaternion, Quaternion, Quaternion>>(Variant::OP_ADD, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorAdd<Color, Color, Color>>(Variant::OP_ADD, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorAddArray>(Variant::OP_ADD, Variant::ARRAY, Variant::ARRAY); register_op<OperatorEvaluatorAppendArray<uint8_t>>(Variant::OP_ADD, Variant::PACKED_BYTE_ARRAY, Variant::PACKED_BYTE_ARRAY); @@ -1416,7 +81,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorSub<Vector2i, Vector2i, Vector2i>>(Variant::OP_SUBTRACT, Variant::VECTOR2I, Variant::VECTOR2I); register_op<OperatorEvaluatorSub<Vector3, Vector3, Vector3>>(Variant::OP_SUBTRACT, Variant::VECTOR3, Variant::VECTOR3); register_op<OperatorEvaluatorSub<Vector3i, Vector3i, Vector3i>>(Variant::OP_SUBTRACT, Variant::VECTOR3I, Variant::VECTOR3I); - register_op<OperatorEvaluatorSub<Quat, Quat, Quat>>(Variant::OP_SUBTRACT, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorSub<Quaternion, Quaternion, Quaternion>>(Variant::OP_SUBTRACT, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorSub<Color, Color, Color>>(Variant::OP_SUBTRACT, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<int64_t, int64_t, int64_t>>(Variant::OP_MULTIPLY, Variant::INT, Variant::INT); @@ -1449,15 +114,17 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorMul<Vector3i, Vector3i, int64_t>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::INT); register_op<OperatorEvaluatorMul<Vector3i, Vector3i, double>>(Variant::OP_MULTIPLY, Variant::VECTOR3I, Variant::FLOAT); - register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT); - register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT); register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT); register_op<OperatorEvaluatorMul<Color, Color, double>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::FLOAT); register_op<OperatorEvaluatorMul<Transform2D, Transform2D, Transform2D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::TRANSFORM2D); + register_op<OperatorEvaluatorMul<Transform2D, Transform2D, int64_t>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::INT); + register_op<OperatorEvaluatorMul<Transform2D, Transform2D, double>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::FLOAT); register_op<OperatorEvaluatorXForm<Vector2, Transform2D, Vector2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::VECTOR2); register_op<OperatorEvaluatorXFormInv<Vector2, Vector2, Transform2D>>(Variant::OP_MULTIPLY, Variant::VECTOR2, Variant::TRANSFORM2D); register_op<OperatorEvaluatorXForm<Rect2, Transform2D, Rect2>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::RECT2); @@ -1465,25 +132,29 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorXForm<Vector<Vector2>, Transform2D, Vector<Vector2>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM2D, Variant::PACKED_VECTOR2_ARRAY); register_op<OperatorEvaluatorXFormInv<Vector<Vector2>, Vector<Vector2>, Transform2D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR2_ARRAY, Variant::TRANSFORM2D); - register_op<OperatorEvaluatorMul<Transform, Transform, Transform>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<Vector3, Transform, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::VECTOR3); - register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<::AABB, Transform, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::AABB); - register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM); - register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM, Variant::PACKED_VECTOR3_ARRAY); - register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, Transform3D>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, int64_t>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::INT); + register_op<OperatorEvaluatorMul<Transform3D, Transform3D, double>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::FLOAT); + register_op<OperatorEvaluatorXForm<Vector3, Transform3D, Vector3>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::VECTOR3); + register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Transform3D>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<::AABB, Transform3D, ::AABB>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::AABB); + register_op<OperatorEvaluatorXFormInv<::AABB, ::AABB, Transform3D>>(Variant::OP_MULTIPLY, Variant::AABB, Variant::TRANSFORM3D); + register_op<OperatorEvaluatorXForm<Vector<Vector3>, Transform3D, Vector<Vector3>>>(Variant::OP_MULTIPLY, Variant::TRANSFORM3D, Variant::PACKED_VECTOR3_ARRAY); + register_op<OperatorEvaluatorXFormInv<Vector<Vector3>, Vector<Vector3>, Transform3D>>(Variant::OP_MULTIPLY, Variant::PACKED_VECTOR3_ARRAY, Variant::TRANSFORM3D); register_op<OperatorEvaluatorMul<Basis, Basis, Basis>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::BASIS); + register_op<OperatorEvaluatorMul<Basis, Basis, int64_t>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::INT); + register_op<OperatorEvaluatorMul<Basis, Basis, double>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::FLOAT); register_op<OperatorEvaluatorXForm<Vector3, Basis, Vector3>>(Variant::OP_MULTIPLY, Variant::BASIS, Variant::VECTOR3); register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Basis>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::BASIS); - register_op<OperatorEvaluatorMul<Quat, Quat, Quat>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, int64_t>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::INT); - register_op<OperatorEvaluatorMul<Quat, int64_t, Quat>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUAT); - register_op<OperatorEvaluatorMul<Quat, Quat, double>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::FLOAT); - register_op<OperatorEvaluatorMul<Quat, double, Quat>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUAT); - register_op<OperatorEvaluatorXForm<Vector3, Quat, Vector3>>(Variant::OP_MULTIPLY, Variant::QUAT, Variant::VECTOR3); - register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quat>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUAT); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, Quaternion>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, int64_t>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::INT); + register_op<OperatorEvaluatorMul<Quaternion, int64_t, Quaternion>>(Variant::OP_MULTIPLY, Variant::INT, Variant::QUATERNION); + register_op<OperatorEvaluatorMul<Quaternion, Quaternion, double>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::FLOAT); + register_op<OperatorEvaluatorMul<Quaternion, double, Quaternion>>(Variant::OP_MULTIPLY, Variant::FLOAT, Variant::QUATERNION); + register_op<OperatorEvaluatorXForm<Vector3, Quaternion, Vector3>>(Variant::OP_MULTIPLY, Variant::QUATERNION, Variant::VECTOR3); + register_op<OperatorEvaluatorXFormInv<Vector3, Vector3, Quaternion>>(Variant::OP_MULTIPLY, Variant::VECTOR3, Variant::QUATERNION); register_op<OperatorEvaluatorMul<Color, Color, Color>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorMul<Color, Color, int64_t>>(Variant::OP_MULTIPLY, Variant::COLOR, Variant::INT); @@ -1516,8 +187,8 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, double>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::FLOAT); register_op<OperatorEvaluatorDivNZ<Vector3i, Vector3i, int64_t>>(Variant::OP_DIVIDE, Variant::VECTOR3I, Variant::INT); - register_op<OperatorEvaluatorDiv<Quat, Quat, double>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::FLOAT); - register_op<OperatorEvaluatorDiv<Quat, Quat, int64_t>>(Variant::OP_DIVIDE, Variant::QUAT, Variant::INT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, double>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::FLOAT); + register_op<OperatorEvaluatorDiv<Quaternion, Quaternion, int64_t>>(Variant::OP_DIVIDE, Variant::QUATERNION, Variant::INT); register_op<OperatorEvaluatorDiv<Color, Color, Color>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorDiv<Color, Color, double>>(Variant::OP_DIVIDE, Variant::COLOR, Variant::FLOAT); @@ -1544,10 +215,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorStringModT<Vector3i>>(Variant::OP_MODULE, Variant::STRING, Variant::VECTOR3I); register_op<OperatorEvaluatorStringModT<Transform2D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM2D); register_op<OperatorEvaluatorStringModT<Plane>>(Variant::OP_MODULE, Variant::STRING, Variant::PLANE); - register_op<OperatorEvaluatorStringModT<Quat>>(Variant::OP_MODULE, Variant::STRING, Variant::QUAT); + register_op<OperatorEvaluatorStringModT<Quaternion>>(Variant::OP_MODULE, Variant::STRING, Variant::QUATERNION); register_op<OperatorEvaluatorStringModT<::AABB>>(Variant::OP_MODULE, Variant::STRING, Variant::AABB); register_op<OperatorEvaluatorStringModT<Basis>>(Variant::OP_MODULE, Variant::STRING, Variant::BASIS); - register_op<OperatorEvaluatorStringModT<Transform>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM); + register_op<OperatorEvaluatorStringModT<Transform3D>>(Variant::OP_MODULE, Variant::STRING, Variant::TRANSFORM3D); register_op<OperatorEvaluatorStringModT<Color>>(Variant::OP_MODULE, Variant::STRING, Variant::COLOR); register_op<OperatorEvaluatorStringModT<StringName>>(Variant::OP_MODULE, Variant::STRING, Variant::STRING_NAME); @@ -1574,7 +245,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNeg<Vector2i, Vector2i>>(Variant::OP_NEGATE, Variant::VECTOR2I, Variant::NIL); register_op<OperatorEvaluatorNeg<Vector3, Vector3>>(Variant::OP_NEGATE, Variant::VECTOR3, Variant::NIL); register_op<OperatorEvaluatorNeg<Vector3i, Vector3i>>(Variant::OP_NEGATE, Variant::VECTOR3I, Variant::NIL); - register_op<OperatorEvaluatorNeg<Quat, Quat>>(Variant::OP_NEGATE, Variant::QUAT, Variant::NIL); + register_op<OperatorEvaluatorNeg<Quaternion, Quaternion>>(Variant::OP_NEGATE, Variant::QUATERNION, Variant::NIL); register_op<OperatorEvaluatorNeg<Plane, Plane>>(Variant::OP_NEGATE, Variant::PLANE, Variant::NIL); register_op<OperatorEvaluatorNeg<Color, Color>>(Variant::OP_NEGATE, Variant::COLOR, Variant::NIL); @@ -1584,7 +255,7 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorPos<Vector2i, Vector2i>>(Variant::OP_POSITIVE, Variant::VECTOR2I, Variant::NIL); register_op<OperatorEvaluatorPos<Vector3, Vector3>>(Variant::OP_POSITIVE, Variant::VECTOR3, Variant::NIL); register_op<OperatorEvaluatorPos<Vector3i, Vector3i>>(Variant::OP_POSITIVE, Variant::VECTOR3I, Variant::NIL); - register_op<OperatorEvaluatorPos<Quat, Quat>>(Variant::OP_POSITIVE, Variant::QUAT, Variant::NIL); + register_op<OperatorEvaluatorPos<Quaternion, Quaternion>>(Variant::OP_POSITIVE, Variant::QUATERNION, Variant::NIL); register_op<OperatorEvaluatorPos<Plane, Plane>>(Variant::OP_POSITIVE, Variant::PLANE, Variant::NIL); register_op<OperatorEvaluatorPos<Color, Color>>(Variant::OP_POSITIVE, Variant::COLOR, Variant::NIL); @@ -1612,10 +283,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorEqual<Vector3i, Vector3i>>(Variant::OP_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorEqual<Transform2D, Transform2D>>(Variant::OP_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D); register_op<OperatorEvaluatorEqual<Plane, Plane>>(Variant::OP_EQUAL, Variant::PLANE, Variant::PLANE); - register_op<OperatorEvaluatorEqual<Quat, Quat>>(Variant::OP_EQUAL, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorEqual<Quaternion, Quaternion>>(Variant::OP_EQUAL, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorEqual<::AABB, ::AABB>>(Variant::OP_EQUAL, Variant::AABB, Variant::AABB); register_op<OperatorEvaluatorEqual<Basis, Basis>>(Variant::OP_EQUAL, Variant::BASIS, Variant::BASIS); - register_op<OperatorEvaluatorEqual<Transform, Transform>>(Variant::OP_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM); + register_op<OperatorEvaluatorEqual<Transform3D, Transform3D>>(Variant::OP_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D); register_op<OperatorEvaluatorEqual<Color, Color>>(Variant::OP_EQUAL, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorEqual<StringName, String>>(Variant::OP_EQUAL, Variant::STRING_NAME, Variant::STRING); @@ -1658,10 +329,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorNotEqual<Vector3i, Vector3i>>(Variant::OP_NOT_EQUAL, Variant::VECTOR3I, Variant::VECTOR3I); register_op<OperatorEvaluatorNotEqual<Transform2D, Transform2D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM2D, Variant::TRANSFORM2D); register_op<OperatorEvaluatorNotEqual<Plane, Plane>>(Variant::OP_NOT_EQUAL, Variant::PLANE, Variant::PLANE); - register_op<OperatorEvaluatorNotEqual<Quat, Quat>>(Variant::OP_NOT_EQUAL, Variant::QUAT, Variant::QUAT); + register_op<OperatorEvaluatorNotEqual<Quaternion, Quaternion>>(Variant::OP_NOT_EQUAL, Variant::QUATERNION, Variant::QUATERNION); register_op<OperatorEvaluatorNotEqual<::AABB, ::AABB>>(Variant::OP_NOT_EQUAL, Variant::AABB, Variant::AABB); register_op<OperatorEvaluatorNotEqual<Basis, Basis>>(Variant::OP_NOT_EQUAL, Variant::BASIS, Variant::BASIS); - register_op<OperatorEvaluatorNotEqual<Transform, Transform>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM, Variant::TRANSFORM); + register_op<OperatorEvaluatorNotEqual<Transform3D, Transform3D>>(Variant::OP_NOT_EQUAL, Variant::TRANSFORM3D, Variant::TRANSFORM3D); register_op<OperatorEvaluatorNotEqual<Color, Color>>(Variant::OP_NOT_EQUAL, Variant::COLOR, Variant::COLOR); register_op<OperatorEvaluatorNotEqual<StringName, String>>(Variant::OP_NOT_EQUAL, Variant::STRING_NAME, Variant::STRING); @@ -1849,10 +520,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInDictionaryHas<Vector3i>>(Variant::OP_IN, Variant::VECTOR3I, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Transform2D>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Plane>>(Variant::OP_IN, Variant::PLANE, Variant::DICTIONARY); - register_op<OperatorEvaluatorInDictionaryHas<Quat>>(Variant::OP_IN, Variant::QUAT, Variant::DICTIONARY); + register_op<OperatorEvaluatorInDictionaryHas<Quaternion>>(Variant::OP_IN, Variant::QUATERNION, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<::AABB>>(Variant::OP_IN, Variant::AABB, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Basis>>(Variant::OP_IN, Variant::BASIS, Variant::DICTIONARY); - register_op<OperatorEvaluatorInDictionaryHas<Transform>>(Variant::OP_IN, Variant::TRANSFORM, Variant::DICTIONARY); + register_op<OperatorEvaluatorInDictionaryHas<Transform3D>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<Color>>(Variant::OP_IN, Variant::COLOR, Variant::DICTIONARY); register_op<OperatorEvaluatorInDictionaryHas<StringName>>(Variant::OP_IN, Variant::STRING_NAME, Variant::DICTIONARY); @@ -1886,10 +557,10 @@ void Variant::_register_variant_operators() { register_op<OperatorEvaluatorInArrayFind<Vector3i, Array>>(Variant::OP_IN, Variant::VECTOR3I, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Transform2D, Array>>(Variant::OP_IN, Variant::TRANSFORM2D, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Plane, Array>>(Variant::OP_IN, Variant::PLANE, Variant::ARRAY); - register_op<OperatorEvaluatorInArrayFind<Quat, Array>>(Variant::OP_IN, Variant::QUAT, Variant::ARRAY); + register_op<OperatorEvaluatorInArrayFind<Quaternion, Array>>(Variant::OP_IN, Variant::QUATERNION, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<::AABB, Array>>(Variant::OP_IN, Variant::AABB, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Basis, Array>>(Variant::OP_IN, Variant::BASIS, Variant::ARRAY); - register_op<OperatorEvaluatorInArrayFind<Transform, Array>>(Variant::OP_IN, Variant::TRANSFORM, Variant::ARRAY); + register_op<OperatorEvaluatorInArrayFind<Transform3D, Array>>(Variant::OP_IN, Variant::TRANSFORM3D, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<Color, Array>>(Variant::OP_IN, Variant::COLOR, Variant::ARRAY); register_op<OperatorEvaluatorInArrayFind<StringName, Array>>(Variant::OP_IN, Variant::STRING_NAME, Variant::ARRAY); @@ -1990,8 +661,8 @@ static const char *_op_names[Variant::OP_MAX] = { "-", "*", "/", - "-", - "+", + "unary-", + "unary+", "%", "<<", ">>", diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h new file mode 100644 index 0000000000..e744e76ea3 --- /dev/null +++ b/core/variant/variant_op.h @@ -0,0 +1,1316 @@ +/*************************************************************************/ +/* variant_op.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef VARIANT_OP_H +#define VARIANT_OP_H + +#include "variant.h" + +#include "core/core_string_names.h" +#include "core/debugger/engine_debugger.h" +#include "core/object/class_db.h" + +template <class R, class A, class B> +class OperatorEvaluatorAdd { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a + b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) + *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) + PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorSub { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a - b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) - *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) - PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorMul { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a * b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) * *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) * PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorXForm { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a.xform(b); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<A>::get_ptr(left)->xform(*VariantGetInternalPtr<B>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left).xform(PtrToArg<B>::convert(right)), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorXFormInv { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = b.xform_inv(a); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = VariantGetInternalPtr<B>::get_ptr(right)->xform_inv(*VariantGetInternalPtr<A>::get_ptr(left)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<B>::convert(right).xform_inv(PtrToArg<A>::convert(left)), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorDiv { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorDivNZ { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + if (b == 0) { + r_valid = false; + *r_ret = "Division by zero error"; + return; + } + *r_ret = a / b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) / *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) / PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorMod { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a % b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorModNZ { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + if (b == 0) { + r_valid = false; + *r_ret = "Module by zero error"; + return; + } + *r_ret = a % b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) % *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) % PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A> +class OperatorEvaluatorNeg { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = -a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = -*VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(-PtrToArg<A>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A> +class OperatorEvaluatorPos { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorShiftLeft { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + +#if defined(DEBUG_ENABLED) + if (b < 0 || a < 0) { + *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; + r_valid = false; + return; + } +#endif + *r_ret = a << b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) << *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) << PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorShiftRight { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + +#if defined(DEBUG_ENABLED) + if (b < 0 || a < 0) { + *r_ret = "Invalid operands for bit shifting. Only positive operands are supported."; + r_valid = false; + return; + } +#endif + *r_ret = a >> b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >> *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) >> PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorBitOr { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a | b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) | *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) | PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorBitAnd { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a & b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) & *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) & PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A, class B> +class OperatorEvaluatorBitXor { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a ^ b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) ^ *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(PtrToArg<A>::convert(left) ^ PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class R, class A> +class OperatorEvaluatorBitNeg { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = ~a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<R>::get_ptr(r_ret) = ~*VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<R>::encode(~PtrToArg<A>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<R>::VARIANT_TYPE; } +}; + +template <class A, class B> +class OperatorEvaluatorEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a == b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) == *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) == PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorEqualObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Object *a = p_left.get_validated_object(); + const Object *b = p_right.get_validated_object(); + *r_ret = a == b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Object *a = left->get_validated_object(); + const Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorEqualObjectNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Object *a = p_left.get_validated_object(); + *r_ret = a == nullptr; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Object *a = left->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a == nullptr; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorEqualNilObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Object *b = p_right.get_validated_object(); + *r_ret = nullptr == b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr == b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(nullptr == PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorNotEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a != b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) != *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) != PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotEqualObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *a = p_left.get_validated_object(); + Object *b = p_right.get_validated_object(); + *r_ret = a != b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *a = left->get_validated_object(); + Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotEqualObjectNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *a = p_left.get_validated_object(); + *r_ret = a != nullptr; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *a = left->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = a != nullptr; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) != nullptr, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotEqualNilObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *b = p_right.get_validated_object(); + *r_ret = nullptr != b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *b = right->get_validated_object(); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = nullptr != b; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(nullptr != PtrToArg<Object *>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorLess { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a < b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) < *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) < PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorLessEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a <= b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) <= *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) <= PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorGreater { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a > b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) > *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) > PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorGreaterEqual { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a >= b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) >= *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) >= PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorAnd { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a && b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) && *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) && PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorOr { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = a || b; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = *VariantGetInternalPtr<A>::get_ptr(left) || *VariantGetInternalPtr<B>::get_ptr(right); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<A>::convert(left) || PtrToArg<B>::convert(right), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +#define XOR_OP(m_a, m_b) (((m_a) || (m_b)) && !((m_a) && (m_b))) +template <class A, class B> +class OperatorEvaluatorXor { +public: + _FORCE_INLINE_ static bool xor_op(const A &a, const B &b) { + return ((a) || (b)) && !((a) && (b)); + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + *r_ret = xor_op(a, b); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = xor_op(*VariantGetInternalPtr<A>::get_ptr(left), *VariantGetInternalPtr<B>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(xor_op(PtrToArg<A>::convert(left), PtrToArg<B>::convert(right)), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A> +class OperatorEvaluatorNot { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + *r_ret = !a; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<A>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<A>::convert(left)); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +//// CUSTOM //// + +class OperatorEvaluatorAddArray { +public: + _FORCE_INLINE_ static void _add_arrays(Array &sum, const Array &array_a, const Array &array_b) { + int asize = array_a.size(); + int bsize = array_b.size(); + sum.resize(asize + bsize); + for (int i = 0; i < asize; i++) { + sum[i] = array_a[i]; + } + for (int i = 0; i < bsize; i++) { + sum[i + asize] = array_b[i]; + } + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Array &array_a = *VariantGetInternalPtr<Array>::get_ptr(&p_left); + const Array &array_b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); + Array sum; + _add_arrays(sum, array_a, array_b); + *r_ret = sum; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + _add_arrays(*VariantGetInternalPtr<Array>::get_ptr(r_ret), *VariantGetInternalPtr<Array>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + Array ret; + _add_arrays(ret, PtrToArg<Array>::convert(left), PtrToArg<Array>::convert(right)); + PtrToArg<Array>::encode(ret, r_ret); + } + static Variant::Type get_return_type() { return Variant::ARRAY; } +}; + +template <class T> +class OperatorEvaluatorAppendArray { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Vector<T> &array_a = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_left); + const Vector<T> &array_b = *VariantGetInternalPtr<Vector<T>>::get_ptr(&p_right); + Vector<T> sum = array_a; + sum.append_array(array_b); + *r_ret = sum; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret) = *VariantGetInternalPtr<Vector<T>>::get_ptr(left); + VariantGetInternalPtr<Vector<T>>::get_ptr(r_ret)->append_array(*VariantGetInternalPtr<Vector<T>>::get_ptr(right)); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + Vector<T> sum = PtrToArg<Vector<T>>::convert(left); + sum.append_array(PtrToArg<Vector<T>>::convert(right)); + PtrToArg<Vector<T>>::encode(sum, r_ret); + } + static Variant::Type get_return_type() { return GetTypeInfo<Vector<T>>::VARIANT_TYPE; } +}; + +class OperatorEvaluatorStringModNil { +public: + _FORCE_INLINE_ static String do_mod(const String &s, bool *r_valid) { + Array values; + values.push_back(Variant()); + + String a = s.sprintf(values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + return a; + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + *r_ret = do_mod(a, &r_valid); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), nullptr); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), nullptr), r_ret); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +class OperatorEvaluatorStringModArray { +public: + _FORCE_INLINE_ static String do_mod(const String &s, const Array &p_values, bool *r_valid) { + String a = s.sprintf(p_values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + return a; + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + *r_ret = do_mod(a, *VariantGetInternalPtr<Array>::get_ptr(&p_right), &r_valid); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<Array>::get_ptr(right), nullptr); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Array>::convert(right), nullptr), r_ret); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +class OperatorEvaluatorStringModObject { +public: + _FORCE_INLINE_ static String do_mod(const String &s, const Object *p_object, bool *r_valid) { + Array values; + values.push_back(p_object); + String a = s.sprintf(values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + + return a; + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + *r_ret = do_mod(a, p_right.get_validated_object(), &r_valid); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), right->get_validated_object(), nullptr); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<Object *>::convert(right), nullptr), r_ret); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +template <class T> +class OperatorEvaluatorStringModT { +public: + _FORCE_INLINE_ static String do_mod(const String &s, const T &p_value, bool *r_valid) { + Array values; + values.push_back(p_value); + String a = s.sprintf(values, r_valid); + if (r_valid) { + *r_valid = !*r_valid; + } + return a; + } + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + *r_ret = do_mod(a, *VariantGetInternalPtr<T>::get_ptr(&p_right), &r_valid); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<String>::get_ptr(r_ret) = do_mod(*VariantGetInternalPtr<String>::get_ptr(left), *VariantGetInternalPtr<T>::get_ptr(right), nullptr); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<String>::encode(do_mod(PtrToArg<String>::convert(left), PtrToArg<T>::convert(right), nullptr), r_ret); + } + static Variant::Type get_return_type() { return Variant::STRING; } +}; + +template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> +class OperatorEvaluatorAlwaysTrue { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = true; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = true; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(true, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <Variant::Operator op, Variant::Type type_left, Variant::Type type_right> +class OperatorEvaluatorAlwaysFalse { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = false; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = false; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(false, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +///// OR /////// + +_FORCE_INLINE_ static bool _operate_or(bool p_left, bool p_right) { + return p_left || p_right; +} + +_FORCE_INLINE_ static bool _operate_and(bool p_left, bool p_right) { + return p_left && p_right; +} + +_FORCE_INLINE_ static bool _operate_xor(bool p_left, bool p_right) { + return (p_left || p_right) && !(p_left && p_right); +} + +_FORCE_INLINE_ static bool _operate_get_nil(const Variant *p_ptr) { + return p_ptr->get_validated_object() != nullptr; +} + +_FORCE_INLINE_ static bool _operate_get_bool(const Variant *p_ptr) { + return *VariantGetInternalPtr<bool>::get_ptr(p_ptr); +} + +_FORCE_INLINE_ static bool _operate_get_int(const Variant *p_ptr) { + return *VariantGetInternalPtr<int64_t>::get_ptr(p_ptr) != 0; +} + +_FORCE_INLINE_ static bool _operate_get_float(const Variant *p_ptr) { + return *VariantGetInternalPtr<double>::get_ptr(p_ptr) != 0.0; +} + +_FORCE_INLINE_ static bool _operate_get_object(const Variant *p_ptr) { + return p_ptr->get_validated_object() != nullptr; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_nil(const void *p_ptr) { + return false; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_bool(const void *p_ptr) { + return PtrToArg<bool>::convert(p_ptr); +} + +_FORCE_INLINE_ static bool _operate_get_ptr_int(const void *p_ptr) { + return PtrToArg<int64_t>::convert(p_ptr) != 0; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_float(const void *p_ptr) { + return PtrToArg<double>::convert(p_ptr) != 0.0; +} + +_FORCE_INLINE_ static bool _operate_get_ptr_object(const void *p_ptr) { + return PtrToArg<Object *>::convert(p_ptr) != nullptr; +} + +#define OP_EVALUATOR(m_class_name, m_left, m_right, m_op) \ + class m_class_name { \ + public: \ + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { \ + *r_ret = m_op(_operate_get_##m_left(&p_left), _operate_get_##m_right(&p_right)); \ + r_valid = true; \ + } \ + \ + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { \ + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = m_op(_operate_get_##m_left(left), _operate_get_##m_right(right)); \ + } \ + \ + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { \ + PtrToArg<bool>::encode(m_op(_operate_get_ptr_##m_left(left), _operate_get_ptr_##m_right(right)), r_ret); \ + } \ + \ + static Variant::Type get_return_type() { \ + return Variant::BOOL; \ + } \ + }; + +// OR + +// nil +OP_EVALUATOR(OperatorEvaluatorNilXBoolOr, nil, bool, _operate_or) +OP_EVALUATOR(OperatorEvaluatorBoolXNilOr, bool, nil, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorNilXIntOr, nil, int, _operate_or) +OP_EVALUATOR(OperatorEvaluatorIntXNilOr, int, nil, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorNilXFloatOr, nil, float, _operate_or) +OP_EVALUATOR(OperatorEvaluatorFloatXNilOr, float, nil, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorObjectXNilOr, object, nil, _operate_or) +OP_EVALUATOR(OperatorEvaluatorNilXObjectOr, nil, object, _operate_or) + +// bool +OP_EVALUATOR(OperatorEvaluatorBoolXBoolOr, bool, bool, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorBoolXIntOr, bool, int, _operate_or) +OP_EVALUATOR(OperatorEvaluatorIntXBoolOr, int, bool, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorBoolXFloatOr, bool, float, _operate_or) +OP_EVALUATOR(OperatorEvaluatorFloatXBoolOr, float, bool, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorBoolXObjectOr, bool, object, _operate_or) +OP_EVALUATOR(OperatorEvaluatorObjectXBoolOr, object, bool, _operate_or) + +// int +OP_EVALUATOR(OperatorEvaluatorIntXIntOr, int, int, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorIntXFloatOr, int, float, _operate_or) +OP_EVALUATOR(OperatorEvaluatorFloatXIntOr, float, int, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorIntXObjectOr, int, object, _operate_or) +OP_EVALUATOR(OperatorEvaluatorObjectXIntOr, object, int, _operate_or) + +// float +OP_EVALUATOR(OperatorEvaluatorFloatXFloatOr, float, float, _operate_or) + +OP_EVALUATOR(OperatorEvaluatorFloatXObjectOr, float, object, _operate_or) +OP_EVALUATOR(OperatorEvaluatorObjectXFloatOr, object, float, _operate_or) + +// object +OP_EVALUATOR(OperatorEvaluatorObjectXObjectOr, object, object, _operate_or) + +// AND + +// nil +OP_EVALUATOR(OperatorEvaluatorNilXBoolAnd, nil, bool, _operate_and) +OP_EVALUATOR(OperatorEvaluatorBoolXNilAnd, bool, nil, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorNilXIntAnd, nil, int, _operate_and) +OP_EVALUATOR(OperatorEvaluatorIntXNilAnd, int, nil, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorNilXFloatAnd, nil, float, _operate_and) +OP_EVALUATOR(OperatorEvaluatorFloatXNilAnd, float, nil, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorObjectXNilAnd, object, nil, _operate_and) +OP_EVALUATOR(OperatorEvaluatorNilXObjectAnd, nil, object, _operate_and) + +// bool +OP_EVALUATOR(OperatorEvaluatorBoolXBoolAnd, bool, bool, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorBoolXIntAnd, bool, int, _operate_and) +OP_EVALUATOR(OperatorEvaluatorIntXBoolAnd, int, bool, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorBoolXFloatAnd, bool, float, _operate_and) +OP_EVALUATOR(OperatorEvaluatorFloatXBoolAnd, float, bool, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorBoolXObjectAnd, bool, object, _operate_and) +OP_EVALUATOR(OperatorEvaluatorObjectXBoolAnd, object, bool, _operate_and) + +// int +OP_EVALUATOR(OperatorEvaluatorIntXIntAnd, int, int, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorIntXFloatAnd, int, float, _operate_and) +OP_EVALUATOR(OperatorEvaluatorFloatXIntAnd, float, int, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorIntXObjectAnd, int, object, _operate_and) +OP_EVALUATOR(OperatorEvaluatorObjectXIntAnd, object, int, _operate_and) + +// float +OP_EVALUATOR(OperatorEvaluatorFloatXFloatAnd, float, float, _operate_and) + +OP_EVALUATOR(OperatorEvaluatorFloatXObjectAnd, float, object, _operate_and) +OP_EVALUATOR(OperatorEvaluatorObjectXFloatAnd, object, float, _operate_and) + +// object +OP_EVALUATOR(OperatorEvaluatorObjectXObjectAnd, object, object, _operate_and) + +// XOR + +// nil +OP_EVALUATOR(OperatorEvaluatorNilXBoolXor, nil, bool, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorBoolXNilXor, bool, nil, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorNilXIntXor, nil, int, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorIntXNilXor, int, nil, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorNilXFloatXor, nil, float, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorFloatXNilXor, float, nil, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorObjectXNilXor, object, nil, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorNilXObjectXor, nil, object, _operate_xor) + +// bool +OP_EVALUATOR(OperatorEvaluatorBoolXBoolXor, bool, bool, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorBoolXIntXor, bool, int, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorIntXBoolXor, int, bool, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorBoolXFloatXor, bool, float, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorFloatXBoolXor, float, bool, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorBoolXObjectXor, bool, object, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorObjectXBoolXor, object, bool, _operate_xor) + +// int +OP_EVALUATOR(OperatorEvaluatorIntXIntXor, int, int, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorIntXFloatXor, int, float, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorFloatXIntXor, float, int, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorIntXObjectXor, int, object, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorObjectXIntXor, object, int, _operate_xor) + +// float +OP_EVALUATOR(OperatorEvaluatorFloatXFloatXor, float, float, _operate_xor) + +OP_EVALUATOR(OperatorEvaluatorFloatXObjectXor, float, object, _operate_xor) +OP_EVALUATOR(OperatorEvaluatorObjectXFloatXor, object, float, _operate_xor) + +// object +OP_EVALUATOR(OperatorEvaluatorObjectXObjectXor, object, object, _operate_xor) + +class OperatorEvaluatorNotBool { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = !*VariantGetInternalPtr<bool>::get_ptr(&p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<bool>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<bool>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotInt { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = !*VariantGetInternalPtr<int64_t>::get_ptr(&p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<int64_t>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<int64_t>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotFloat { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = !*VariantGetInternalPtr<double>::get_ptr(&p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = !*VariantGetInternalPtr<double>::get_ptr(left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(!PtrToArg<double>::convert(left), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorNotObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + *r_ret = p_left.get_validated_object() == nullptr; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = left->get_validated_object() == nullptr; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Object *>::convert(left) == nullptr, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +//// + +class OperatorEvaluatorInStringFind { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const String &str_a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + const String &str_b = *VariantGetInternalPtr<String>::get_ptr(&p_right); + + *r_ret = str_b.find(str_a) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const String &str_a = *VariantGetInternalPtr<String>::get_ptr(left); + const String &str_b = *VariantGetInternalPtr<String>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = str_b.find(str_a) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<String>::convert(right).find(PtrToArg<String>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A, class B> +class OperatorEvaluatorInArrayFind { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(&p_right); + + *r_ret = b.find(a) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const A &a = *VariantGetInternalPtr<A>::get_ptr(left); + const B &b = *VariantGetInternalPtr<B>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(a) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<B>::convert(right).find(PtrToArg<A>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInArrayFindNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); + *r_ret = b.find(Variant()) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(Variant()) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(Variant()) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInArrayFindObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(&p_right); + *r_ret = b.find(p_left) != -1; + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Array &b = *VariantGetInternalPtr<Array>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.find(*left) != -1; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Array>::convert(right).find(PtrToArg<Object *>::convert(left)) != -1, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +template <class A> +class OperatorEvaluatorInDictionaryHas { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); + const A &a = *VariantGetInternalPtr<A>::get_ptr(&p_left); + + *r_ret = b.has(a); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); + const A &a = *VariantGetInternalPtr<A>::get_ptr(left); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(a); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<A>::convert(left)), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInDictionaryHasNil { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); + + *r_ret = b.has(Variant()); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(Variant()); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(Variant()), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorInDictionaryHasObject { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(&p_right); + + *r_ret = b.has(p_left); + r_valid = true; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + const Dictionary &b = *VariantGetInternalPtr<Dictionary>::get_ptr(right); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = b.has(*left); + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + PtrToArg<bool>::encode(PtrToArg<Dictionary>::convert(right).has(PtrToArg<Object *>::convert(left)), r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorObjectHasPropertyString { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *b = p_right.get_validated_object(); + if (!b) { + *r_ret = "Invalid base object for 'in'"; + r_valid = false; + return; + } + + const String &a = *VariantGetInternalPtr<String>::get_ptr(&p_left); + + b->get(a, &r_valid); + *r_ret = r_valid; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *l = right->get_validated_object(); + ERR_FAIL_COND(l == nullptr); + const String &a = *VariantGetInternalPtr<String>::get_ptr(left); + + bool valid; + l->get(a, &valid); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + bool valid; + PtrToArg<Object *>::convert(right)->get(PtrToArg<String>::convert(left), &valid); + PtrToArg<bool>::encode(valid, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +class OperatorEvaluatorObjectHasPropertyStringName { +public: + static void evaluate(const Variant &p_left, const Variant &p_right, Variant *r_ret, bool &r_valid) { + Object *b = p_right.get_validated_object(); + if (!b) { + *r_ret = "Invalid base object for 'in'"; + r_valid = false; + return; + } + + const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(&p_left); + + b->get(a, &r_valid); + *r_ret = r_valid; + } + static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) { + Object *l = right->get_validated_object(); + ERR_FAIL_COND(l == nullptr); + const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left); + + bool valid; + l->get(a, &valid); + *VariantGetInternalPtr<bool>::get_ptr(r_ret) = valid; + } + static void ptr_evaluate(const void *left, const void *right, void *r_ret) { + bool valid; + PtrToArg<Object *>::convert(right)->get(PtrToArg<StringName>::convert(left), &valid); + PtrToArg<bool>::encode(valid, r_ret); + } + static Variant::Type get_return_type() { return Variant::BOOL; } +}; + +#endif // VARIANT_OP_H diff --git a/core/variant/variant_parser.cpp b/core/variant/variant_parser.cpp index edaeddbf27..86d5ae7f38 100644 --- a/core/variant/variant_parser.cpp +++ b/core/variant/variant_parser.cpp @@ -190,10 +190,13 @@ Error VariantParser::get_token(Stream *p_stream, Token &r_token, int &line, Stri r_token.type = TK_COLOR; return OK; } - case '@': { +#ifndef DISABLE_DEPRECATED + case '@': // Compatibility with 3.x StringNames. +#endif + case '&': { // StringName. cchar = p_stream->get_char(); if (cchar != '"') { - r_err_str = "Expected '\"' after '@'"; + r_err_str = "Expected '\"' after '&'"; r_token.type = TK_ERROR; return ERR_PARSE_ERROR; } @@ -614,7 +617,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = Plane(args[0], args[1], args[2], args[3]); - } else if (id == "Quat") { + } else if (id == "Quaternion" || id == "Quat") { // "Quat" kept for compatibility Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); if (err) { @@ -626,7 +629,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - value = Quat(args[0], args[1], args[2], args[3]); + value = Quaternion(args[0], args[1], args[2], args[3]); } else if (id == "AABB" || id == "Rect3") { Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); @@ -653,7 +656,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, } value = Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); - } else if (id == "Transform") { + } else if (id == "Transform3D" || id == "Transform") { // "Transform" kept for compatibility with Godot <4. Vector<real_t> args; Error err = _parse_construct<real_t>(p_stream, args, line, r_err_str); if (err) { @@ -665,7 +668,7 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, return ERR_PARSE_ERROR; } - value = Transform(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); + value = Transform3D(Basis(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]), Vector3(args[9], args[10], args[11])); } else if (id == "Color") { Vector<float> args; Error err = _parse_construct<float>(p_stream, args, line, r_err_str); @@ -735,14 +738,14 @@ Error VariantParser::parse_value(Token &token, Variant &value, Stream *p_stream, String type = token.value; - Object *obj = ClassDB::instance(type); + Object *obj = ClassDB::instantiate(type); if (!obj) { - r_err_str = "Can't instance Object() of type: " + type; + r_err_str = "Can't instantiate Object() of type: " + type; return ERR_PARSE_ERROR; } - REF ref = REF(Object::cast_to<Reference>(obj)); + REF ref = REF(Object::cast_to<RefCounted>(obj)); get_token(p_stream, token, line, r_err_str); if (token.type != TK_COMMA) { @@ -1201,16 +1204,32 @@ Error VariantParser::_parse_tag(Token &token, Stream *p_stream, int &line, Strin r_tag.name = ""; r_tag.fields.clear(); - while (true) { - char32_t c = p_stream->get_char(); - if (p_stream->is_eof()) { - r_err_str = "Unexpected EOF while parsing simple tag"; - return ERR_PARSE_ERROR; + if (p_stream->is_utf8()) { + CharString cs; + while (true) { + char c = p_stream->get_char(); + if (p_stream->is_eof()) { + r_err_str = "Unexpected EOF while parsing simple tag"; + return ERR_PARSE_ERROR; + } + if (c == ']') { + break; + } + cs += c; } - if (c == ']') { - break; + r_tag.name.parse_utf8(cs.get_data(), cs.length()); + } else { + while (true) { + char32_t c = p_stream->get_char(); + if (p_stream->is_eof()) { + r_err_str = "Unexpected EOF while parsing simple tag"; + return ERR_PARSE_ERROR; + } + if (c == ']') { + break; + } + r_tag.name += String::chr(c); } - r_tag.name += String::chr(c); } r_tag.name = r_tag.name.strip_edges(); @@ -1420,47 +1439,47 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::VECTOR2: { Vector2 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector2( " + rtosfix(v.x) + ", " + rtosfix(v.y) + " )"); + p_store_string_func(p_store_string_ud, "Vector2(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ")"); } break; case Variant::VECTOR2I: { Vector2i v = p_variant; - p_store_string_func(p_store_string_ud, "Vector2i( " + itos(v.x) + ", " + itos(v.y) + " )"); + p_store_string_func(p_store_string_ud, "Vector2i(" + itos(v.x) + ", " + itos(v.y) + ")"); } break; case Variant::RECT2: { Rect2 aabb = p_variant; - p_store_string_func(p_store_string_ud, "Rect2( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + " )"); + p_store_string_func(p_store_string_ud, "Rect2(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ")"); } break; case Variant::RECT2I: { Rect2i aabb = p_variant; - p_store_string_func(p_store_string_ud, "Rect2i( " + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + " )"); + p_store_string_func(p_store_string_ud, "Rect2i(" + itos(aabb.position.x) + ", " + itos(aabb.position.y) + ", " + itos(aabb.size.x) + ", " + itos(aabb.size.y) + ")"); } break; case Variant::VECTOR3: { Vector3 v = p_variant; - p_store_string_func(p_store_string_ud, "Vector3( " + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + " )"); + p_store_string_func(p_store_string_ud, "Vector3(" + rtosfix(v.x) + ", " + rtosfix(v.y) + ", " + rtosfix(v.z) + ")"); } break; case Variant::VECTOR3I: { Vector3i v = p_variant; - p_store_string_func(p_store_string_ud, "Vector3i( " + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + " )"); + p_store_string_func(p_store_string_ud, "Vector3i(" + itos(v.x) + ", " + itos(v.y) + ", " + itos(v.z) + ")"); } break; case Variant::PLANE: { Plane p = p_variant; - p_store_string_func(p_store_string_ud, "Plane( " + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + " )"); + p_store_string_func(p_store_string_ud, "Plane(" + rtosfix(p.normal.x) + ", " + rtosfix(p.normal.y) + ", " + rtosfix(p.normal.z) + ", " + rtosfix(p.d) + ")"); } break; case Variant::AABB: { AABB aabb = p_variant; - p_store_string_func(p_store_string_ud, "AABB( " + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + " )"); + p_store_string_func(p_store_string_ud, "AABB(" + rtosfix(aabb.position.x) + ", " + rtosfix(aabb.position.y) + ", " + rtosfix(aabb.position.z) + ", " + rtosfix(aabb.size.x) + ", " + rtosfix(aabb.size.y) + ", " + rtosfix(aabb.size.z) + ")"); } break; - case Variant::QUAT: { - Quat quat = p_variant; - p_store_string_func(p_store_string_ud, "Quat( " + rtosfix(quat.x) + ", " + rtosfix(quat.y) + ", " + rtosfix(quat.z) + ", " + rtosfix(quat.w) + " )"); + case Variant::QUATERNION: { + Quaternion quaternion = p_variant; + p_store_string_func(p_store_string_ud, "Quaternion(" + rtosfix(quaternion.x) + ", " + rtosfix(quaternion.y) + ", " + rtosfix(quaternion.z) + ", " + rtosfix(quaternion.w) + ")"); } break; case Variant::TRANSFORM2D: { - String s = "Transform2D( "; + String s = "Transform2D("; Transform2D m3 = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { @@ -1471,11 +1490,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } } - p_store_string_func(p_store_string_ud, s + " )"); + p_store_string_func(p_store_string_ud, s + ")"); } break; case Variant::BASIS: { - String s = "Basis( "; + String s = "Basis("; Basis m3 = p_variant; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -1486,12 +1505,12 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } } - p_store_string_func(p_store_string_ud, s + " )"); + p_store_string_func(p_store_string_ud, s + ")"); } break; - case Variant::TRANSFORM: { - String s = "Transform( "; - Transform t = p_variant; + case Variant::TRANSFORM3D: { + String s = "Transform3D("; + Transform3D t = p_variant; Basis &m3 = t.basis; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -1504,19 +1523,19 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str s = s + ", " + rtosfix(t.origin.x) + ", " + rtosfix(t.origin.y) + ", " + rtosfix(t.origin.z); - p_store_string_func(p_store_string_ud, s + " )"); + p_store_string_func(p_store_string_ud, s + ")"); } break; // misc types case Variant::COLOR: { Color c = p_variant; - p_store_string_func(p_store_string_ud, "Color( " + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + " )"); + p_store_string_func(p_store_string_ud, "Color(" + rtosfix(c.r) + ", " + rtosfix(c.g) + ", " + rtosfix(c.b) + ", " + rtosfix(c.a) + ")"); } break; case Variant::STRING_NAME: { String str = p_variant; - str = "@\"" + str.c_escape() + "\""; + str = "&\"" + str.c_escape() + "\""; p_store_string_func(p_store_string_ud, str); } break; @@ -1550,7 +1569,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str if (res_text == String() && res->get_path().is_resource_file()) { //external resource String path = res->get_path(); - res_text = "Resource( \"" + path + "\")"; + res_text = "Resource(\"" + path + "\")"; } //could come up with some sort of text @@ -1613,7 +1632,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } break; case Variant::ARRAY: { - p_store_string_func(p_store_string_ud, "[ "); + p_store_string_func(p_store_string_ud, "["); Array array = p_variant; int len = array.size(); for (int i = 0; i < len; i++) { @@ -1622,12 +1641,12 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str } write(array[i], p_store_string_func, p_store_string_ud, p_encode_res_func, p_encode_res_ud); } - p_store_string_func(p_store_string_ud, " ]"); + p_store_string_func(p_store_string_ud, "]"); } break; case Variant::PACKED_BYTE_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedByteArray( "); + p_store_string_func(p_store_string_ud, "PackedByteArray("); String s; Vector<uint8_t> data = p_variant; int len = data.size(); @@ -1641,11 +1660,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_INT32_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedInt32Array( "); + p_store_string_func(p_store_string_ud, "PackedInt32Array("); Vector<int32_t> data = p_variant; int32_t len = data.size(); const int32_t *ptr = data.ptr(); @@ -1658,11 +1677,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_INT64_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedInt64Array( "); + p_store_string_func(p_store_string_ud, "PackedInt64Array("); Vector<int64_t> data = p_variant; int64_t len = data.size(); const int64_t *ptr = data.ptr(); @@ -1675,11 +1694,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, itos(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_FLOAT32_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedFloat32Array( "); + p_store_string_func(p_store_string_ud, "PackedFloat32Array("); Vector<float> data = p_variant; int len = data.size(); const float *ptr = data.ptr(); @@ -1691,11 +1710,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_FLOAT64_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedFloat64Array( "); + p_store_string_func(p_store_string_ud, "PackedFloat64Array("); Vector<double> data = p_variant; int len = data.size(); const double *ptr = data.ptr(); @@ -1707,11 +1726,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i])); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_STRING_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedStringArray( "); + p_store_string_func(p_store_string_ud, "PackedStringArray("); Vector<String> data = p_variant; int len = data.size(); const String *ptr = data.ptr(); @@ -1727,11 +1746,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, "\"" + str.c_escape() + "\""); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_VECTOR2_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedVector2Array( "); + p_store_string_func(p_store_string_ud, "PackedVector2Array("); Vector<Vector2> data = p_variant; int len = data.size(); const Vector2 *ptr = data.ptr(); @@ -1743,11 +1762,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y)); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_VECTOR3_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedVector3Array( "); + p_store_string_func(p_store_string_ud, "PackedVector3Array("); Vector<Vector3> data = p_variant; int len = data.size(); const Vector3 *ptr = data.ptr(); @@ -1759,12 +1778,11 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i].x) + ", " + rtosfix(ptr[i].y) + ", " + rtosfix(ptr[i].z)); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; case Variant::PACKED_COLOR_ARRAY: { - p_store_string_func(p_store_string_ud, "PackedColorArray( "); - + p_store_string_func(p_store_string_ud, "PackedColorArray("); Vector<Color> data = p_variant; int len = data.size(); const Color *ptr = data.ptr(); @@ -1776,7 +1794,7 @@ Error VariantWriter::write(const Variant &p_variant, StoreStringFunc p_store_str p_store_string_func(p_store_string_ud, rtosfix(ptr[i].r) + ", " + rtosfix(ptr[i].g) + ", " + rtosfix(ptr[i].b) + ", " + rtosfix(ptr[i].a)); } - p_store_string_func(p_store_string_ud, " )"); + p_store_string_func(p_store_string_ud, ")"); } break; default: { diff --git a/core/variant/variant_parser.h b/core/variant/variant_parser.h index 5703f0200c..05fc29b5e0 100644 --- a/core/variant/variant_parser.h +++ b/core/variant/variant_parser.h @@ -31,8 +31,8 @@ #ifndef VARIANT_PARSER_H #define VARIANT_PARSER_H +#include "core/io/file_access.h" #include "core/io/resource.h" -#include "core/os/file_access.h" #include "core/variant/variant.h" class VariantParser { diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp index 9ab8602782..de1deace63 100644 --- a/core/variant/variant_setget.cpp +++ b/core/variant/variant_setget.cpp @@ -28,282 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "variant.h" - -#include "core/core_string_names.h" -#include "core/debugger/engine_debugger.h" -#include "core/object/class_db.h" -#include "core/templates/local_vector.h" -#include "core/variant/variant_internal.h" - -/**** NAMED SETTERS AND GETTERS ****/ - -#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_member = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == Variant::FLOAT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \ - valid = true; \ - } else if (value->get_type() == Variant::INT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_member = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_custom = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == Variant::FLOAT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \ - valid = true; \ - } else if (value->get_type() == Variant::INT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_custom = PtrToArg<m_member_type>::convert(member); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_setter(PtrToArg<m_member_type>::convert(member)); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == Variant::FLOAT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \ - valid = true; \ - } else if (value->get_type() == Variant::INT) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_setter(PtrToArg<m_member_type>::convert(member)); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \ - struct VariantSetGet_##m_base_type##_##m_member { \ - static void get(const Variant *base, Variant *member) { \ - VariantTypeAdjust<m_member_type>::adjust(member); \ - *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \ - } \ - static void ptr_get(const void *base, void *member) { \ - PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \ - } \ - static void set(Variant *base, const Variant *value, bool &valid) { \ - if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - valid = true; \ - } else { \ - valid = false; \ - } \ - } \ - static void validated_set(Variant *base, const Variant *value) { \ - VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ - } \ - static void ptr_set(void *base, const void *member) { \ - m_base_type b = PtrToArg<m_base_type>::convert(base); \ - b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \ - PtrToArg<m_base_type>::encode(b, base); \ - } \ - static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ - }; - -SETGET_NUMBER_STRUCT(Vector2, double, x) -SETGET_NUMBER_STRUCT(Vector2, double, y) - -SETGET_NUMBER_STRUCT(Vector2i, int64_t, x) -SETGET_NUMBER_STRUCT(Vector2i, int64_t, y) - -SETGET_NUMBER_STRUCT(Vector3, double, x) -SETGET_NUMBER_STRUCT(Vector3, double, y) -SETGET_NUMBER_STRUCT(Vector3, double, z) - -SETGET_NUMBER_STRUCT(Vector3i, int64_t, x) -SETGET_NUMBER_STRUCT(Vector3i, int64_t, y) -SETGET_NUMBER_STRUCT(Vector3i, int64_t, z) - -SETGET_STRUCT(Rect2, Vector2, position) -SETGET_STRUCT(Rect2, Vector2, size) -SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end) - -SETGET_STRUCT(Rect2i, Vector2i, position) -SETGET_STRUCT(Rect2i, Vector2i, size) -SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end) - -SETGET_STRUCT(AABB, Vector3, position) -SETGET_STRUCT(AABB, Vector3, size) -SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end) - -SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0]) -SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1]) -SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2]) - -SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x) -SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y) -SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z) -SETGET_STRUCT(Plane, Vector3, normal) -SETGET_NUMBER_STRUCT(Plane, double, d) - -SETGET_NUMBER_STRUCT(Quat, double, x) -SETGET_NUMBER_STRUCT(Quat, double, y) -SETGET_NUMBER_STRUCT(Quat, double, z) -SETGET_NUMBER_STRUCT(Quat, double, w) - -SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0) -SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1) -SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2) - -SETGET_STRUCT(Transform, Basis, basis) -SETGET_STRUCT(Transform, Vector3, origin) - -SETGET_NUMBER_STRUCT(Color, double, r) -SETGET_NUMBER_STRUCT(Color, double, g) -SETGET_NUMBER_STRUCT(Color, double, b) -SETGET_NUMBER_STRUCT(Color, double, a) - -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8) -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8) -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8) -SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8) - -SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h) -SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s) -SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v) +#include "variant_setget.h" struct VariantSetterGetterInfo { void (*setter)(Variant *base, const Variant *value, bool &valid); @@ -326,7 +51,7 @@ static void register_member(Variant::Type p_type, const StringName &p_member) { sgi.ptr_setter = T::ptr_set; sgi.getter = T::get; - sgi.validated_getter = T::get; + sgi.validated_getter = T::validated_get; sgi.ptr_getter = T::ptr_get; sgi.member_type = T::get_type(); @@ -374,17 +99,17 @@ void register_named_setters_getters() { REGISTER_MEMBER(Plane, d); REGISTER_MEMBER(Plane, normal); - REGISTER_MEMBER(Quat, x); - REGISTER_MEMBER(Quat, y); - REGISTER_MEMBER(Quat, z); - REGISTER_MEMBER(Quat, w); + REGISTER_MEMBER(Quaternion, x); + REGISTER_MEMBER(Quaternion, y); + REGISTER_MEMBER(Quaternion, z); + REGISTER_MEMBER(Quaternion, w); REGISTER_MEMBER(Basis, x); REGISTER_MEMBER(Basis, y); REGISTER_MEMBER(Basis, z); - REGISTER_MEMBER(Transform, basis); - REGISTER_MEMBER(Transform, origin); + REGISTER_MEMBER(Transform3D, basis); + REGISTER_MEMBER(Transform3D, origin); REGISTER_MEMBER(Color, r); REGISTER_MEMBER(Color, g); @@ -975,7 +700,7 @@ INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2, double, real_t, 2) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector2i, int64_t, int32_t, 2) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3, double, real_t, 3) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Vector3i, int64_t, int32_t, 3) -INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quat, double, real_t, 4) +INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Quaternion, double, real_t, 4) INDEXED_SETGET_STRUCT_BULTIN_NUMERIC(Color, double, float, 4) INDEXED_SETGET_STRUCT_BULTIN_ACCESSOR(Transform2D, Vector2, .elements, 3) @@ -1037,7 +762,7 @@ void register_indexed_setters_getters() { REGISTER_INDEXED_MEMBER(Vector2i); REGISTER_INDEXED_MEMBER(Vector3); REGISTER_INDEXED_MEMBER(Vector3i); - REGISTER_INDEXED_MEMBER(Quat); + REGISTER_INDEXED_MEMBER(Quaternion); REGISTER_INDEXED_MEMBER(Color); REGISTER_INDEXED_MEMBER(Transform2D); REGISTER_INDEXED_MEMBER(Basis); @@ -1146,7 +871,7 @@ struct VariantKeyedSetGetDictionary { *r_valid = true; return VariantGetInternalPtr<Dictionary>::get_ptr(base)->has(*key); } - static bool ptr_has(const void *base, const void *key) { + static uint32_t ptr_has(const void *base, const void *key) { /* avoid ptrconvert for performance*/ const Dictionary &v = *reinterpret_cast<const Dictionary *>(base); return v.has(PtrToArg<Variant>::convert(key)); @@ -1196,7 +921,7 @@ struct VariantKeyedSetGetObject { obj->getvar(*key, &exists); return exists; } - static bool ptr_has(const void *base, const void *key) { + static uint32_t ptr_has(const void *base, const void *key) { const Object *obj = PtrToArg<Object *>::convert(base); ERR_FAIL_COND_V(!obj, false); bool valid; @@ -1453,7 +1178,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } @@ -1680,7 +1405,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } @@ -1865,7 +1590,7 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { return Variant(); } #ifdef DEBUG_ENABLED - if (EngineDebugger::is_active() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (EngineDebugger::is_active() && !_get_obj().id.is_ref_counted() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_valid = false; return Variant(); } @@ -2135,10 +1860,10 @@ void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c); } return; - case QUAT: { - Quat empty_rot; - const Quat *qa = reinterpret_cast<const Quat *>(a._data._mem); - const Quat *qb = reinterpret_cast<const Quat *>(b._data._mem); + case QUATERNION: { + Quaternion empty_rot; + const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem); + const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem); r_dst = *qa * empty_rot.slerp(*qb, c); } return; @@ -2295,8 +2020,8 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & r_dst = a; } return; - case QUAT: { - r_dst = reinterpret_cast<const Quat *>(a._data._mem)->slerp(*reinterpret_cast<const Quat *>(b._data._mem), c); + case QUATERNION: { + r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c); } return; case AABB: { @@ -2304,11 +2029,11 @@ void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant & } return; case BASIS: { - r_dst = Transform(*a._data._basis).interpolate_with(Transform(*b._data._basis), c).basis; + r_dst = Transform3D(*a._data._basis).interpolate_with(Transform3D(*b._data._basis), c).basis; } return; - case TRANSFORM: { - r_dst = a._data._transform->interpolate_with(*b._data._transform, c); + case TRANSFORM3D: { + r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c); } return; case COLOR: { diff --git a/core/variant/variant_setget.h b/core/variant/variant_setget.h new file mode 100644 index 0000000000..dbf24ab3e3 --- /dev/null +++ b/core/variant/variant_setget.h @@ -0,0 +1,332 @@ +/*************************************************************************/ +/* variant_setget.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef VARIANT_SETGET_H +#define VARIANT_SETGET_H + +#include "variant.h" + +#include "core/core_string_names.h" +#include "core/debugger/engine_debugger.h" +#include "core/object/class_db.h" +#include "core/templates/local_vector.h" +#include "core/variant/variant_internal.h" + +/**** NAMED SETTERS AND GETTERS ****/ + +#define SETGET_STRUCT(m_base_type, m_member_type, m_member) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_member = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_NUMBER_STRUCT(m_base_type, m_member_type, m_member) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_member, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == Variant::FLOAT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<double>::get_ptr(value); \ + valid = true; \ + } else if (value->get_type() == Variant::INT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_member = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_member = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_custom = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_NUMBER_STRUCT_CUSTOM(m_base_type, m_member_type, m_member, m_custom) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom; \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_custom, member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == Variant::FLOAT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<double>::get_ptr(value); \ + valid = true; \ + } else if (value->get_type() == Variant::INT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<int64_t>::get_ptr(value); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_custom = *VariantGetInternalPtr<m_member_type>::get_ptr(value); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_custom = PtrToArg<m_member_type>::convert(member); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_setter(PtrToArg<m_member_type>::convert(member)); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_NUMBER_STRUCT_FUNC(m_base_type, m_member_type, m_member, m_setter, m_getter) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(); \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(), member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == Variant::FLOAT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<double>::get_ptr(value)); \ + valid = true; \ + } else if (value->get_type() == Variant::INT) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<int64_t>::get_ptr(value)); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(*VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_setter(PtrToArg<m_member_type>::convert(member)); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +#define SETGET_STRUCT_FUNC_INDEX(m_base_type, m_member_type, m_member, m_setter, m_getter, m_index) \ + struct VariantSetGet_##m_base_type##_##m_member { \ + static void get(const Variant *base, Variant *member) { \ + VariantTypeAdjust<m_member_type>::adjust(member); \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \ + } \ + static inline void validated_get(const Variant *base, Variant *member) { \ + *VariantGetInternalPtr<m_member_type>::get_ptr(member) = VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_getter(m_index); \ + } \ + static void ptr_get(const void *base, void *member) { \ + PtrToArg<m_member_type>::encode(PtrToArg<m_base_type>::convert(base).m_getter(m_index), member); \ + } \ + static void set(Variant *base, const Variant *value, bool &valid) { \ + if (value->get_type() == GetTypeInfo<m_member_type>::VARIANT_TYPE) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + valid = true; \ + } else { \ + valid = false; \ + } \ + } \ + static inline void validated_set(Variant *base, const Variant *value) { \ + VariantGetInternalPtr<m_base_type>::get_ptr(base)->m_setter(m_index, *VariantGetInternalPtr<m_member_type>::get_ptr(value)); \ + } \ + static void ptr_set(void *base, const void *member) { \ + m_base_type b = PtrToArg<m_base_type>::convert(base); \ + b.m_setter(m_index, PtrToArg<m_member_type>::convert(member)); \ + PtrToArg<m_base_type>::encode(b, base); \ + } \ + static Variant::Type get_type() { return GetTypeInfo<m_member_type>::VARIANT_TYPE; } \ + }; + +SETGET_NUMBER_STRUCT(Vector2, double, x) +SETGET_NUMBER_STRUCT(Vector2, double, y) + +SETGET_NUMBER_STRUCT(Vector2i, int64_t, x) +SETGET_NUMBER_STRUCT(Vector2i, int64_t, y) + +SETGET_NUMBER_STRUCT(Vector3, double, x) +SETGET_NUMBER_STRUCT(Vector3, double, y) +SETGET_NUMBER_STRUCT(Vector3, double, z) + +SETGET_NUMBER_STRUCT(Vector3i, int64_t, x) +SETGET_NUMBER_STRUCT(Vector3i, int64_t, y) +SETGET_NUMBER_STRUCT(Vector3i, int64_t, z) + +SETGET_STRUCT(Rect2, Vector2, position) +SETGET_STRUCT(Rect2, Vector2, size) +SETGET_STRUCT_FUNC(Rect2, Vector2, end, set_end, get_end) + +SETGET_STRUCT(Rect2i, Vector2i, position) +SETGET_STRUCT(Rect2i, Vector2i, size) +SETGET_STRUCT_FUNC(Rect2i, Vector2i, end, set_end, get_end) + +SETGET_STRUCT(AABB, Vector3, position) +SETGET_STRUCT(AABB, Vector3, size) +SETGET_STRUCT_FUNC(AABB, Vector3, end, set_end, get_end) + +SETGET_STRUCT_CUSTOM(Transform2D, Vector2, x, elements[0]) +SETGET_STRUCT_CUSTOM(Transform2D, Vector2, y, elements[1]) +SETGET_STRUCT_CUSTOM(Transform2D, Vector2, origin, elements[2]) + +SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, x, normal.x) +SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, y, normal.y) +SETGET_NUMBER_STRUCT_CUSTOM(Plane, double, z, normal.z) +SETGET_STRUCT(Plane, Vector3, normal) +SETGET_NUMBER_STRUCT(Plane, double, d) + +SETGET_NUMBER_STRUCT(Quaternion, double, x) +SETGET_NUMBER_STRUCT(Quaternion, double, y) +SETGET_NUMBER_STRUCT(Quaternion, double, z) +SETGET_NUMBER_STRUCT(Quaternion, double, w) + +SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, x, set_axis, get_axis, 0) +SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, y, set_axis, get_axis, 1) +SETGET_STRUCT_FUNC_INDEX(Basis, Vector3, z, set_axis, get_axis, 2) + +SETGET_STRUCT(Transform3D, Basis, basis) +SETGET_STRUCT(Transform3D, Vector3, origin) + +SETGET_NUMBER_STRUCT(Color, double, r) +SETGET_NUMBER_STRUCT(Color, double, g) +SETGET_NUMBER_STRUCT(Color, double, b) +SETGET_NUMBER_STRUCT(Color, double, a) + +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, r8, set_r8, get_r8) +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, g8, set_g8, get_g8) +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, b8, set_b8, get_b8) +SETGET_NUMBER_STRUCT_FUNC(Color, int64_t, a8, set_a8, get_a8) + +SETGET_NUMBER_STRUCT_FUNC(Color, double, h, set_h, get_h) +SETGET_NUMBER_STRUCT_FUNC(Color, double, s, set_s, get_s) +SETGET_NUMBER_STRUCT_FUNC(Color, double, v, set_v, get_v) + +#endif // VARIANT_SETGET_H diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 553f2b23a2..1f69e81d99 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -32,7 +32,7 @@ #include "core/core_string_names.h" #include "core/io/marshalls.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/templates/oa_hash_map.h" #include "core/variant/binder_common.h" @@ -1348,8 +1348,8 @@ String Variant::get_utility_function_argument_name(const StringName &p_name, int if (!bfi) { return String(); } - ERR_FAIL_COND_V(bfi->is_vararg, String()); ERR_FAIL_INDEX_V(p_arg, bfi->argnames.size(), String()); + ERR_FAIL_COND_V(bfi->is_vararg, String()); return bfi->argnames[p_arg]; } @@ -1379,6 +1379,23 @@ bool Variant::is_utility_function_vararg(const StringName &p_name) { return bfi->is_vararg; } +uint32_t Variant::get_utility_function_hash(const StringName &p_name) { + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + ERR_FAIL_COND_V(!bfi, 0); + + uint32_t hash = hash_djb2_one_32(bfi->is_vararg); + hash = hash_djb2_one_32(bfi->returns_value, hash); + if (bfi->returns_value) { + hash = hash_djb2_one_32(bfi->return_type, hash); + } + hash = hash_djb2_one_32(bfi->argcount, hash); + for (int i = 0; i < bfi->argcount; i++) { + hash = hash_djb2_one_32(bfi->get_arg_type(i), hash); + } + + return hash; +} + void Variant::get_utility_function_list(List<StringName> *r_functions) { for (List<StringName>::Element *E = utility_function_name_table.front(); E; E = E->next()) { r_functions->push_back(E->get()); diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index e210fa8808..66511f5845 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -778,7 +778,7 @@ <return type="float"> </return> <description> - Returns a random floating point value on the interval [code][0, 1][/code]. + Returns a random floating point value between [code]0.0[/code] and [code]1.0[/code] (inclusive). [codeblock] randf() # Returns e.g. 0.375671 [/codeblock] @@ -792,7 +792,7 @@ <argument index="1" name="to" type="float"> </argument> <description> - Random range, any floating point value between [code]from[/code] and [code]to[/code]. + Returns a random floating point value on the interval between [code]from[/code] and [code]to[/code] (inclusive). [codeblock] prints(randf_range(-10, 10), randf_range(-10, 10)) # Prints e.g. -3.844535 7.45315 [/codeblock] @@ -819,7 +819,7 @@ <argument index="1" name="to" type="int"> </argument> <description> - Random range, any 32-bit integer value between [code]from[/code] and [code]to[/code] (inclusive). If [code]to[/code] is lesser than [code]from[/code] they are swapped. + Returns a random signed 32-bit integer between [code]from[/code] and [code]to[/code] (inclusive). If [code]to[/code] is lesser than [code]from[/code], they are swapped. [codeblock] print(randi_range(0, 1)) # Prints 0 or 1 print(randi_range(-10, 1000)) # Prints any number from -10 to 1000 @@ -1066,11 +1066,13 @@ <description> Returns the internal type of the given Variant object, using the [enum Variant.Type] values. [codeblock] - p = parse_json('["a", "b", "c"]') - if typeof(p) == TYPE_ARRAY: - print(p[0]) # Prints a + var json = JSON.new() + json.parse('["a", "b", "c"]') + var result = json.get_data() + if typeof(result) == TYPE_ARRAY: + print(result[0]) # Prints a else: - print("unexpected results") + print("Unexpected result") [/codeblock] </description> </method> @@ -1211,9 +1213,6 @@ <member name="InputMap" type="InputMap" setter="" getter=""> The [InputMap] singleton. </member> - <member name="JSON" type="JSON" setter="" getter=""> - The [JSON] singleton. - </member> <member name="JavaClassWrapper" type="JavaClassWrapper" setter="" getter=""> The [JavaClassWrapper] singleton. [b]Note:[/b] Only implemented on Android. @@ -1225,6 +1224,8 @@ <member name="Marshalls" type="Marshalls" setter="" getter=""> The [Marshalls] singleton. </member> + <member name="NativeExtensionManager" type="NativeExtensionManager" setter="" getter=""> + </member> <member name="NavigationMeshGenerator" type="NavigationMeshGenerator" setter="" getter=""> The [NavigationMeshGenerator] singleton. </member> @@ -1261,6 +1262,9 @@ <member name="TextServerManager" type="TextServerManager" setter="" getter=""> The [TextServerManager] singleton. </member> + <member name="Time" type="Time" setter="" getter=""> + The [Time] singleton. + </member> <member name="TranslationServer" type="TranslationServer" setter="" getter=""> The [TranslationServer] singleton. </member> @@ -2406,74 +2410,72 @@ </constant> <constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint"> Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_lesser"[/code]. + Additionally, other keywords can be included: "exp" for exponential range editing, "radians" for editing radian angles in degrees, "degrees" to hint at an angle and "noslider" to hide the slider. </constant> - <constant name="PROPERTY_HINT_EXP_RANGE" value="2" enum="PropertyHint"> - Hints that an integer or float property should be within an exponential range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"0.01,100,0.01,or_greater"[/code]. - </constant> - <constant name="PROPERTY_HINT_ENUM" value="3" enum="PropertyHint"> + <constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint"> Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string such as [code]"Hello,Something,Else"[/code]. </constant> - <constant name="PROPERTY_HINT_EXP_EASING" value="4" enum="PropertyHint"> + <constant name="PROPERTY_HINT_EXP_EASING" value="3" enum="PropertyHint"> Hints that a float property should be edited via an exponential easing function. The hint string can include [code]"attenuation"[/code] to flip the curve horizontally and/or [code]"inout"[/code] to also include in/out easing. </constant> - <constant name="PROPERTY_HINT_LENGTH" value="5" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LENGTH" value="4" enum="PropertyHint"> Deprecated hint, unused. </constant> - <constant name="PROPERTY_HINT_KEY_ACCEL" value="6" enum="PropertyHint"> + <constant name="PROPERTY_HINT_KEY_ACCEL" value="5" enum="PropertyHint"> Deprecated hint, unused. </constant> - <constant name="PROPERTY_HINT_FLAGS" value="7" enum="PropertyHint"> + <constant name="PROPERTY_HINT_FLAGS" value="6" enum="PropertyHint"> Hints that an integer property is a bitmask with named bit flags. For example, to allow toggling bits 0, 1, 2 and 4, the hint could be something like [code]"Bit0,Bit1,Bit2,,Bit4"[/code]. </constant> - <constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="8" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LAYERS_2D_RENDER" value="7" enum="PropertyHint"> Hints that an integer property is a bitmask using the optionally named 2D render layers. </constant> - <constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="9" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LAYERS_2D_PHYSICS" value="8" enum="PropertyHint"> Hints that an integer property is a bitmask using the optionally named 2D physics layers. </constant> - <constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="10" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LAYERS_2D_NAVIGATION" value="9" enum="PropertyHint"> Hints that an integer property is a bitmask using the optionally named 2D navigation layers. </constant> - <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="11" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LAYERS_3D_RENDER" value="10" enum="PropertyHint"> Hints that an integer property is a bitmask using the optionally named 3D render layers. </constant> - <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="12" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LAYERS_3D_PHYSICS" value="11" enum="PropertyHint"> Hints that an integer property is a bitmask using the optionally named 3D physics layers. </constant> - <constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="13" enum="PropertyHint"> + <constant name="PROPERTY_HINT_LAYERS_3D_NAVIGATION" value="12" enum="PropertyHint"> Hints that an integer property is a bitmask using the optionally named 2D navigation layers. </constant> - <constant name="PROPERTY_HINT_FILE" value="14" enum="PropertyHint"> + <constant name="PROPERTY_HINT_FILE" value="13" enum="PropertyHint"> Hints that a string property is a path to a file. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code]. </constant> - <constant name="PROPERTY_HINT_DIR" value="15" enum="PropertyHint"> + <constant name="PROPERTY_HINT_DIR" value="14" enum="PropertyHint"> Hints that a string property is a path to a directory. Editing it will show a file dialog for picking the path. </constant> - <constant name="PROPERTY_HINT_GLOBAL_FILE" value="16" enum="PropertyHint"> + <constant name="PROPERTY_HINT_GLOBAL_FILE" value="15" enum="PropertyHint"> Hints that a string property is an absolute path to a file outside the project folder. Editing it will show a file dialog for picking the path. The hint string can be a set of filters with wildcards like [code]"*.png,*.jpg"[/code]. </constant> - <constant name="PROPERTY_HINT_GLOBAL_DIR" value="17" enum="PropertyHint"> + <constant name="PROPERTY_HINT_GLOBAL_DIR" value="16" enum="PropertyHint"> Hints that a string property is an absolute path to a directory outside the project folder. Editing it will show a file dialog for picking the path. </constant> - <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="18" enum="PropertyHint"> + <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="17" enum="PropertyHint"> Hints that a property is an instance of a [Resource]-derived type, optionally specified via the hint string (e.g. [code]"Texture2D"[/code]). Editing it will show a popup menu of valid resource types to instantiate. </constant> - <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="19" enum="PropertyHint"> + <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="18" enum="PropertyHint"> Hints that a string property is text with line breaks. Editing it will show a text input field where line breaks can be typed. </constant> - <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="20" enum="PropertyHint"> + <constant name="PROPERTY_HINT_PLACEHOLDER_TEXT" value="19" enum="PropertyHint"> Hints that a string property should have a placeholder text visible on its input field, whenever the property is empty. The hint string is the placeholder text to use. </constant> - <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="21" enum="PropertyHint"> + <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="20" enum="PropertyHint"> Hints that a color property should be edited without changing its alpha component, i.e. only R, G and B channels are edited. </constant> - <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="22" enum="PropertyHint"> + <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="21" enum="PropertyHint"> Hints that an image is compressed using lossy compression. </constant> - <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="23" enum="PropertyHint"> + <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="22" enum="PropertyHint"> Hints that an image is compressed using lossless compression. </constant> - <constant name="PROPERTY_HINT_TYPE_STRING" value="25" enum="PropertyHint"> + <constant name="PROPERTY_HINT_TYPE_STRING" value="24" enum="PropertyHint"> Hint that a property represents a particular type. If a property is [constant TYPE_STRING], allows to set a type from the create dialog. If you need to create an [Array] to contain elements of a specific type, the [code]hint_string[/code] must encode nested types using [code]":"[/code] and [code]"/"[/code] for specifying [Resource] types. For instance: [codeblock] hint_string = "%s:" % [TYPE_INT] # Array of inteters. @@ -2596,8 +2598,8 @@ <constant name="TYPE_PLANE" value="12" enum="Variant.Type"> Variable is of type [Plane]. </constant> - <constant name="TYPE_QUAT" value="13" enum="Variant.Type"> - Variable is of type [Quat]. + <constant name="TYPE_QUATERNION" value="13" enum="Variant.Type"> + Variable is of type [Quaternion]. </constant> <constant name="TYPE_AABB" value="14" enum="Variant.Type"> Variable is of type [AABB]. @@ -2605,8 +2607,8 @@ <constant name="TYPE_BASIS" value="15" enum="Variant.Type"> Variable is of type [Basis]. </constant> - <constant name="TYPE_TRANSFORM" value="16" enum="Variant.Type"> - Variable is of type [Transform]. + <constant name="TYPE_TRANSFORM3D" value="16" enum="Variant.Type"> + Variable is of type [Transform3D]. </constant> <constant name="TYPE_COLOR" value="17" enum="Variant.Type"> Variable is of type [Color]. diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml index a28bde9946..03607661df 100644 --- a/doc/classes/AABB.xml +++ b/doc/classes/AABB.xml @@ -242,7 +242,7 @@ <method name="operator *" qualifiers="operator"> <return type="AABB"> </return> - <argument index="0" name="right" type="Transform"> + <argument index="0" name="right" type="Transform3D"> </argument> <description> </description> @@ -257,13 +257,13 @@ </method> </methods> <members> - <member name="end" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> + <member name="end" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)"> Ending corner. This is calculated as [code]position + size[/code]. Setting this value will change the size. </member> - <member name="position" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> + <member name="position" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)"> Beginning corner. Typically has values lower than [member end]. </member> - <member name="size" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> + <member name="size" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)"> Size from [member position] to [member end]. Typically, all components are positive. If the size is negative, you can use [method abs] to fix it. </member> diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml index f577bab992..e179c97677 100644 --- a/doc/classes/AESContext.xml +++ b/doc/classes/AESContext.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AESContext" inherits="Reference" version="4.0"> +<class name="AESContext" inherits="RefCounted" version="4.0"> <brief_description> Interface to low level AES encryption features. </brief_description> @@ -101,7 +101,7 @@ </argument> <argument index="1" name="key" type="PackedByteArray"> </argument> - <argument index="2" name="iv" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="2" name="iv" type="PackedByteArray" default="PackedByteArray()"> </argument> <description> Start the AES context in the given [code]mode[/code]. A [code]key[/code] of either 16 or 32 bytes must always be provided, while an [code]iv[/code] (initialization vector) of exactly 16 bytes, is only needed when [code]mode[/code] is either [constant MODE_CBC_ENCRYPT] or [constant MODE_CBC_DECRYPT]. diff --git a/doc/classes/AStar.xml b/doc/classes/AStar.xml index fce2b90197..cc7f7072b9 100644 --- a/doc/classes/AStar.xml +++ b/doc/classes/AStar.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AStar" inherits="Reference" version="4.0"> +<class name="AStar" inherits="RefCounted" version="4.0"> <brief_description> An implementation of A* to find the shortest paths among connected points in space. </brief_description> diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml index 3efd2f604c..9edc300169 100644 --- a/doc/classes/AStar2D.xml +++ b/doc/classes/AStar2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AStar2D" inherits="Reference" version="4.0"> +<class name="AStar2D" inherits="RefCounted" version="4.0"> <brief_description> AStar class representation that uses 2D vectors as edges. </brief_description> diff --git a/doc/classes/AcceptDialog.xml b/doc/classes/AcceptDialog.xml index f4cf246713..fd1e2ba104 100644 --- a/doc/classes/AcceptDialog.xml +++ b/doc/classes/AcceptDialog.xml @@ -21,6 +21,7 @@ <description> Adds a button with label [code]text[/code] and a custom [code]action[/code] to the dialog and returns the created button. [code]action[/code] will be passed to the [signal custom_action] signal when pressed. If [code]true[/code], [code]right[/code] will place the button to the right of any sibling buttons. + You can use [method remove_button] method to remove a button created with this method from the dialog. </description> </method> <method name="add_cancel_button"> @@ -30,6 +31,7 @@ </argument> <description> Adds a button with label [code]name[/code] and a cancel action to the dialog and returns the created button. + You can use [method remove_button] method to remove a button created with this method from the dialog. </description> </method> <method name="get_label"> @@ -49,12 +51,21 @@ <method name="register_text_enter"> <return type="void"> </return> - <argument index="0" name="line_edit" type="Node"> + <argument index="0" name="line_edit" type="Control"> </argument> <description> Registers a [LineEdit] in the dialog. When the enter key is pressed, the dialog will be accepted. </description> </method> + <method name="remove_button"> + <return type="void"> + </return> + <argument index="0" name="button" type="Control"> + </argument> + <description> + Removes the [code]button[/code] from the dialog. Does NOT free the [code]button[/code]. The [code]button[/code] must be a [Button] added with [method add_button] or [method add_cancel_button] method. After removal, pressing the [code]button[/code] will no longer emit this dialog's [signal custom_action] or [signal cancelled] signals. + </description> + </method> </methods> <members> <member name="dialog_autowrap" type="bool" setter="set_autowrap" getter="has_autowrap" default="false"> diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml index 969e9cc85b..7662e8368b 100644 --- a/doc/classes/AnimatedSprite2D.xml +++ b/doc/classes/AnimatedSprite2D.xml @@ -22,7 +22,7 @@ <method name="play"> <return type="void"> </return> - <argument index="0" name="anim" type="StringName" default="@"""> + <argument index="0" name="anim" type="StringName" default="&"""> </argument> <argument index="1" name="backwards" type="bool" default="false"> </argument> @@ -39,7 +39,7 @@ </method> </methods> <members> - <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@"default""> + <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&"default""> The current animation from the [code]frames[/code] resource. If this value changes, the [code]frame[/code] counter is reset. </member> <member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true"> @@ -57,7 +57,7 @@ <member name="frames" type="SpriteFrames" setter="set_sprite_frames" getter="get_sprite_frames"> The [SpriteFrames] resource containing the animation(s). </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The texture's drawing offset. </member> <member name="playing" type="bool" setter="_set_playing" getter="_is_playing" default="false"> diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml index 02ccab4e05..39ab317b79 100644 --- a/doc/classes/AnimatedSprite3D.xml +++ b/doc/classes/AnimatedSprite3D.xml @@ -20,7 +20,7 @@ <method name="play"> <return type="void"> </return> - <argument index="0" name="anim" type="StringName" default="@"""> + <argument index="0" name="anim" type="StringName" default="&"""> </argument> <description> Plays the animation named [code]anim[/code]. If no [code]anim[/code] is provided, the current animation is played. @@ -35,7 +35,7 @@ </method> </methods> <members> - <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@"default""> + <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&"default""> The current animation from the [code]frames[/code] resource. If this value changes, the [code]frame[/code] counter is reset. </member> <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0"> diff --git a/doc/classes/Animation.xml b/doc/classes/Animation.xml index 7ceb21d22e..894e784397 100644 --- a/doc/classes/Animation.xml +++ b/doc/classes/Animation.xml @@ -213,9 +213,9 @@ </argument> <argument index="2" name="value" type="float"> </argument> - <argument index="3" name="in_handle" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="3" name="in_handle" type="Vector2" default="Vector2(0, 0)"> </argument> - <argument index="4" name="out_handle" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="4" name="out_handle" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Inserts a Bezier Track key at the given [code]time[/code] in seconds. The [code]track_idx[/code] must be the index of a Bezier Track. @@ -640,7 +640,7 @@ </argument> <argument index="2" name="location" type="Vector3"> </argument> - <argument index="3" name="rotation" type="Quat"> + <argument index="3" name="rotation" type="Quaternion"> </argument> <argument index="4" name="scale" type="Vector3"> </argument> @@ -656,7 +656,7 @@ <argument index="1" name="time_sec" type="float"> </argument> <description> - Returns the interpolated value of a transform track at a given time (in seconds). An array consisting of 3 elements: position ([Vector3]), rotation ([Quat]) and scale ([Vector3]). + Returns the interpolated value of a transform track at a given time (in seconds). An array consisting of 3 elements: position ([Vector3]), rotation ([Quaternion]) and scale ([Vector3]). </description> </method> <method name="value_track_get_key_indices" qualifiers="const"> @@ -727,8 +727,8 @@ <constant name="TYPE_VALUE" value="0" enum="TrackType"> Value tracks set values in node properties, but only those which can be Interpolated. </constant> - <constant name="TYPE_TRANSFORM" value="1" enum="TrackType"> - Transform tracks are used to change node local transforms or skeleton pose bones. Transitions are interpolated. + <constant name="TYPE_TRANSFORM3D" value="1" enum="TrackType"> + Transform3D tracks are used to change node local transforms or skeleton pose bones of 3D nodes. Transitions are interpolated. </constant> <constant name="TYPE_METHOD" value="2" enum="TrackType"> Method tracks call functions with given arguments per key. diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index 8204b456d9..fddd8989ab 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -11,6 +11,65 @@ <link title="AnimationTree">https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html</link> </tutorials> <methods> + <method name="_get_caption" qualifiers="virtual"> + <return type="String"> + </return> + <description> + Gets the text caption for this node (used by some editors). + </description> + </method> + <method name="_get_child_by_name" qualifiers="virtual"> + <return type="Object"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <description> + Gets a child node by index (used by editors inheriting from [AnimationRootNode]). + </description> + </method> + <method name="_get_child_nodes" qualifiers="virtual"> + <return type="Dictionary"> + </return> + <description> + Gets all children nodes in order as a [code]name: node[/code] dictionary. Only useful when inheriting [AnimationRootNode]. + </description> + </method> + <method name="_get_parameter_default_value" qualifiers="virtual"> + <return type="Variant"> + </return> + <argument index="0" name="name" type="StringName"> + </argument> + <description> + Gets the default value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. + </description> + </method> + <method name="_get_parameter_list" qualifiers="virtual"> + <return type="Array"> + </return> + <description> + Gets the property information for parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. Format is similar to [method Object.get_property_list]. + </description> + </method> + <method name="_has_filter" qualifiers="virtual"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node. + </description> + </method> + <method name="_process" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="time" type="float"> + </argument> + <argument index="1" name="seek" type="bool"> + </argument> + <description> + User-defined callback called when a custom node is processed. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. + Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory. + This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called). + </description> + </method> <method name="add_input"> <return type="void"> </return> @@ -77,29 +136,6 @@ Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition. </description> </method> - <method name="get_caption" qualifiers="virtual"> - <return type="String"> - </return> - <description> - Gets the text caption for this node (used by some editors). - </description> - </method> - <method name="get_child_by_name" qualifiers="virtual"> - <return type="Object"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <description> - Gets a child node by index (used by editors inheriting from [AnimationRootNode]). - </description> - </method> - <method name="get_child_nodes" qualifiers="virtual"> - <return type="Dictionary"> - </return> - <description> - Gets all children nodes in order as a [code]name: node[/code] dictionary. Only useful when inheriting [AnimationRootNode]. - </description> - </method> <method name="get_input_count" qualifiers="const"> <return type="int"> </return> @@ -125,29 +161,6 @@ Gets the value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. </description> </method> - <method name="get_parameter_default_value" qualifiers="virtual"> - <return type="Variant"> - </return> - <argument index="0" name="name" type="StringName"> - </argument> - <description> - Gets the default value of a parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. - </description> - </method> - <method name="get_parameter_list" qualifiers="virtual"> - <return type="Array"> - </return> - <description> - Gets the property information for parameter. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees. Format is similar to [method Object.get_property_list]. - </description> - </method> - <method name="has_filter" qualifiers="virtual"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] whether you want the blend tree editor to display filter editing on this node. - </description> - </method> <method name="is_path_filtered" qualifiers="const"> <return type="bool"> </return> @@ -157,19 +170,6 @@ Returns [code]true[/code] whether a given path is filtered. </description> </method> - <method name="process" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="time" type="float"> - </argument> - <argument index="1" name="seek" type="bool"> - </argument> - <description> - User-defined callback called when a custom node is processed. The [code]time[/code] parameter is a relative delta, unless [code]seek[/code] is [code]true[/code], in which case it is absolute. - Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory. - This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called). - </description> - </method> <method name="remove_input"> <return type="void"> </return> diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml index 3f0843c112..75dae6a48e 100644 --- a/doc/classes/AnimationNodeAnimation.xml +++ b/doc/classes/AnimationNodeAnimation.xml @@ -14,7 +14,7 @@ <methods> </methods> <members> - <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="@"""> + <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&"""> Animation to use as an output. It is one of the animations provided by [member AnimationTree.anim_player]. </member> </members> diff --git a/doc/classes/AnimationNodeBlendSpace2D.xml b/doc/classes/AnimationNodeBlendSpace2D.xml index abbc8cb2e6..1a6d2bd755 100644 --- a/doc/classes/AnimationNodeBlendSpace2D.xml +++ b/doc/classes/AnimationNodeBlendSpace2D.xml @@ -132,13 +132,13 @@ <member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="AnimationNodeBlendSpace2D.BlendMode" default="0"> Controls the interpolation between animations. See [enum BlendMode] constants. </member> - <member name="max_space" type="Vector2" setter="set_max_space" getter="get_max_space" default="Vector2( 1, 1 )"> + <member name="max_space" type="Vector2" setter="set_max_space" getter="get_max_space" default="Vector2(1, 1)"> The blend space's X and Y axes' upper limit for the points' position. See [method add_blend_point]. </member> - <member name="min_space" type="Vector2" setter="set_min_space" getter="get_min_space" default="Vector2( -1, -1 )"> + <member name="min_space" type="Vector2" setter="set_min_space" getter="get_min_space" default="Vector2(-1, -1)"> The blend space's X and Y axes' lower limit for the points' position. See [method add_blend_point]. </member> - <member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2( 0.1, 0.1 )"> + <member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2(0.1, 0.1)"> Position increment to snap to when moving a point. </member> <member name="x_label" type="String" setter="set_x_label" getter="get_x_label" default=""x""> diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml index 8f87ce453f..a90e8647bb 100644 --- a/doc/classes/AnimationNodeBlendTree.xml +++ b/doc/classes/AnimationNodeBlendTree.xml @@ -17,7 +17,7 @@ </argument> <argument index="1" name="node" type="AnimationNode"> </argument> - <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Adds an [AnimationNode] at the given [code]position[/code]. The [code]name[/code] is used to identify the created sub-node later. @@ -107,7 +107,7 @@ </method> </methods> <members> - <member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2( 0, 0 )"> + <member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2(0, 0)"> The global offset of all sub-nodes. </member> </members> diff --git a/doc/classes/AnimationNodeStateMachine.xml b/doc/classes/AnimationNodeStateMachine.xml index e08e288c59..8e070142c4 100644 --- a/doc/classes/AnimationNodeStateMachine.xml +++ b/doc/classes/AnimationNodeStateMachine.xml @@ -28,7 +28,7 @@ </argument> <argument index="1" name="node" type="AnimationNode"> </argument> - <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Adds a new node to the graph. The [code]position[/code] is used for display in the editor. diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 2f0ebd7de6..7f07afecee 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -10,7 +10,7 @@ <methods> </methods> <members> - <member name="advance_condition" type="StringName" setter="set_advance_condition" getter="get_advance_condition" default="@"""> + <member name="advance_condition" type="StringName" setter="set_advance_condition" getter="get_advance_condition" default="&"""> Turn on auto advance when this condition is set. The provided name will become a boolean parameter on the [AnimationTree] that can be controlled from code (see [url=https://docs.godotengine.org/en/latest/tutorials/animation/animation_tree.html#controlling-from-code][/url]). For example, if [member AnimationTree.tree_root] is an [AnimationNodeStateMachine] and [member advance_condition] is set to [code]"idle"[/code]: [codeblocks] [gdscript] diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml index 7696f36009..8a94eee54c 100644 --- a/doc/classes/AnimationPlayer.xml +++ b/doc/classes/AnimationPlayer.xml @@ -275,7 +275,8 @@ <argument index="1" name="new_name" type="StringName"> </argument> <description> - If the currently being played animation changes, this signal will notify of such change. + Emitted when a queued animation plays after the previous animation was finished. See [method queue]. + [b]Note:[/b] The signal is not emitted when the animation is changed via [method play] or from [AnimationTree]. </description> </signal> <signal name="animation_finished"> diff --git a/doc/classes/AnimationTrackEditPlugin.xml b/doc/classes/AnimationTrackEditPlugin.xml index 8490d48718..7b96808581 100644 --- a/doc/classes/AnimationTrackEditPlugin.xml +++ b/doc/classes/AnimationTrackEditPlugin.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AnimationTrackEditPlugin" inherits="Reference" version="4.0"> +<class name="AnimationTrackEditPlugin" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml index 2517941133..af7d8d73e8 100644 --- a/doc/classes/AnimationTree.xml +++ b/doc/classes/AnimationTree.xml @@ -21,10 +21,10 @@ </description> </method> <method name="get_root_motion_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> - Retrieve the motion of the [member root_motion_track] as a [Transform] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM], returns an identity transformation. + Retrieve the motion of the [member root_motion_track] as a [Transform3D] that can be used elsewhere. If [member root_motion_track] is not a path to a track of type [constant Animation.TYPE_TRANSFORM3D], returns an identity transformation. </description> </method> <method name="rename_parameter"> @@ -50,7 +50,7 @@ </member> <member name="root_motion_track" type="NodePath" setter="set_root_motion_track" getter="get_root_motion_track" default="NodePath("")"> The path to the Animation track used for root motion. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. To specify a track that controls properties or bones, append its name after the path, separated by [code]":"[/code]. For example, [code]"character/skeleton:ankle"[/code] or [code]"character/mesh:transform/local"[/code]. - If the track has type [constant Animation.TYPE_TRANSFORM], the transformation will be cancelled visually, and the animation will appear to stay in place. + If the track has type [constant Animation.TYPE_TRANSFORM3D], the transformation will be cancelled visually, and the animation will appear to stay in place. </member> <member name="tree_root" type="AnimationNode" setter="set_tree_root" getter="get_tree_root"> The root animation node of this [AnimationTree]. See [AnimationNode]. diff --git a/doc/classes/Area2D.xml b/doc/classes/Area2D.xml index f7a116b934..f52c810ad2 100644 --- a/doc/classes/Area2D.xml +++ b/doc/classes/Area2D.xml @@ -54,7 +54,7 @@ The rate at which objects stop spinning in this area. Represents the angular velocity lost per second. See [member ProjectSettings.physics/2d/default_angular_damp] for more details about damping. </member> - <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="@"Master""> + <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="&"Master""> The name of the area's audio bus. </member> <member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false"> @@ -69,7 +69,7 @@ <member name="gravity_point" type="bool" setter="set_gravity_is_point" getter="is_gravity_a_point" default="false"> If [code]true[/code], gravity is calculated from a point (set via [member gravity_vec]). See also [member space_override]. </member> - <member name="gravity_vec" type="Vector2" setter="set_gravity_vector" getter="get_gravity_vector" default="Vector2( 0, 1 )"> + <member name="gravity_vec" type="Vector2" setter="set_gravity_vector" getter="get_gravity_vector" default="Vector2(0, 1)"> The area's gravity vector (not normalized). If gravity is a point (see [member gravity_point]), this will be the point of attraction. </member> <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.1"> diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml index 108387823b..cc31b6c203 100644 --- a/doc/classes/Area3D.xml +++ b/doc/classes/Area3D.xml @@ -52,7 +52,7 @@ The rate at which objects stop spinning in this area. Represents the angular velocity lost per second. See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping. </member> - <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="@"Master""> + <member name="audio_bus_name" type="StringName" setter="set_audio_bus_name" getter="get_audio_bus_name" default="&"Master""> The name of the area's audio bus. </member> <member name="audio_bus_override" type="bool" setter="set_audio_bus_override" getter="is_overriding_audio_bus" default="false"> @@ -67,7 +67,7 @@ <member name="gravity_point" type="bool" setter="set_gravity_is_point" getter="is_gravity_a_point" default="false"> If [code]true[/code], gravity is calculated from a point (set via [member gravity_vec]). See also [member space_override]. </member> - <member name="gravity_vec" type="Vector3" setter="set_gravity_vector" getter="get_gravity_vector" default="Vector3( 0, -1, 0 )"> + <member name="gravity_vec" type="Vector3" setter="set_gravity_vector" getter="get_gravity_vector" default="Vector3(0, -1, 0)"> The area's gravity vector (not normalized). If gravity is a point (see [member gravity_point]), this will be the point of attraction. </member> <member name="linear_damp" type="float" setter="set_linear_damp" getter="get_linear_damp" default="0.1"> @@ -89,7 +89,7 @@ <member name="reverb_bus_enable" type="bool" setter="set_use_reverb_bus" getter="is_using_reverb_bus" default="false"> If [code]true[/code], the area applies reverb to its associated audio. </member> - <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus" getter="get_reverb_bus" default="@"Master""> + <member name="reverb_bus_name" type="StringName" setter="set_reverb_bus" getter="get_reverb_bus" default="&"Master""> The reverb bus name to use for this area's associated audio. </member> <member name="reverb_bus_uniformity" type="float" setter="set_reverb_uniformity" getter="get_reverb_uniformity" default="0.0"> diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml index 49775fa28b..543ec096c7 100644 --- a/doc/classes/Array.xml +++ b/doc/classes/Array.xml @@ -33,8 +33,8 @@ [/gdscript] [csharp] // Array concatenation is not possible with C# arrays, but is with Godot.Collections.Array. - var array1 = new Godot.Collections.Array("One", 2); - var array2 = new Godot.Collections.Array(3, "Four"); + var array1 = new Godot.Collections.Array{"One", 2}; + var array2 = new Godot.Collections.Array{3, "Four"}; GD.Print(array1 + array2); // Prints [One, 2, 3, Four] [/csharp] [/codeblocks] diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml index 7c1c4656f8..7fbf53c7d1 100644 --- a/doc/classes/ArrayMesh.xml +++ b/doc/classes/ArrayMesh.xml @@ -43,7 +43,7 @@ [/csharp] [/codeblocks] The [MeshInstance3D] is ready to be added to the [SceneTree] to be shown. - See also [ImmediateGeometry3D], [MeshDataTool] and [SurfaceTool] for procedural geometry generation. + See also [ImmediateMesh], [MeshDataTool] and [SurfaceTool] for procedural geometry generation. [b]Note:[/b] Godot uses clockwise [url=https://learnopengl.com/Advanced-OpenGL/Face-culling]winding order[/url] for front faces of triangle primitive modes. </description> <tutorials> @@ -66,7 +66,7 @@ </argument> <argument index="1" name="arrays" type="Array"> </argument> - <argument index="2" name="blend_shapes" type="Array" default="[ ]"> + <argument index="2" name="blend_shapes" type="Array" default="[]"> </argument> <argument index="3" name="lods" type="Dictionary" default="{ }"> @@ -77,7 +77,6 @@ Creates a new surface. Surfaces are created to be rendered using a [code]primitive[/code], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface. The [code]arrays[/code] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used. - Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data, and the index array defines the order of the vertices. </description> </method> <method name="clear_blend_shapes"> @@ -113,7 +112,7 @@ <method name="lightmap_unwrap"> <return type="int" enum="Error"> </return> - <argument index="0" name="transform" type="Transform"> + <argument index="0" name="transform" type="Transform3D"> </argument> <argument index="1" name="texel_size" type="float"> </argument> @@ -203,7 +202,31 @@ Sets a name for a given surface. </description> </method> - <method name="surface_update_region"> + <method name="surface_update_attribute_region"> + <return type="void"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <argument index="1" name="offset" type="int"> + </argument> + <argument index="2" name="data" type="PackedByteArray"> + </argument> + <description> + </description> + </method> + <method name="surface_update_skin_region"> + <return type="void"> + </return> + <argument index="0" name="surf_idx" type="int"> + </argument> + <argument index="1" name="offset" type="int"> + </argument> + <argument index="2" name="data" type="PackedByteArray"> + </argument> + <description> + </description> + </method> + <method name="surface_update_vertex_region"> <return type="void"> </return> <argument index="0" name="surf_idx" type="int"> @@ -213,8 +236,6 @@ <argument index="2" name="data" type="PackedByteArray"> </argument> <description> - Updates a specified region of mesh arrays on the GPU. - [b]Warning:[/b] Only use if you know what you are doing. You can easily cause crashes by calling this function with improper arguments. </description> </method> </methods> @@ -222,7 +243,7 @@ <member name="blend_shape_mode" type="int" setter="set_blend_shape_mode" getter="get_blend_shape_mode" enum="Mesh.BlendShapeMode" default="1"> Sets the blend shape mode to one of [enum Mesh.BlendShapeMode]. </member> - <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB( 0, 0, 0, 0, 0, 0 )"> + <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB(0, 0, 0, 0, 0, 0)"> Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices. </member> <member name="shadow_mesh" type="ArrayMesh" setter="set_shadow_mesh" getter="get_shadow_mesh"> diff --git a/doc/classes/AtlasTexture.xml b/doc/classes/AtlasTexture.xml index 9865319419..b49c0e4278 100644 --- a/doc/classes/AtlasTexture.xml +++ b/doc/classes/AtlasTexture.xml @@ -18,10 +18,10 @@ <member name="filter_clip" type="bool" setter="set_filter_clip" getter="has_filter_clip" default="false"> If [code]true[/code], clips the area outside of the region to avoid bleeding of the surrounding texture pixels. </member> - <member name="margin" type="Rect2" setter="set_margin" getter="get_margin" default="Rect2( 0, 0, 0, 0 )"> + <member name="margin" type="Rect2" setter="set_margin" getter="get_margin" default="Rect2(0, 0, 0, 0)"> The margin around the region. The [Rect2]'s [member Rect2.size] parameter ("w" and "h" in the editor) resizes the texture so it fits within the margin. </member> - <member name="region" type="Rect2" setter="set_region" getter="get_region" default="Rect2( 0, 0, 0, 0 )"> + <member name="region" type="Rect2" setter="set_region" getter="get_region" default="Rect2(0, 0, 0, 0)"> The AtlasTexture's used region. </member> </members> diff --git a/doc/classes/AudioEffectCompressor.xml b/doc/classes/AudioEffectCompressor.xml index 3117978d8a..4e924bcb65 100644 --- a/doc/classes/AudioEffectCompressor.xml +++ b/doc/classes/AudioEffectCompressor.xml @@ -32,7 +32,7 @@ <member name="release_ms" type="float" setter="set_release_ms" getter="get_release_ms" default="250.0"> Compressor's delay time to stop reducing the signal after the signal level falls below the threshold, in milliseconds. Value can range from 20 to 2000. </member> - <member name="sidechain" type="StringName" setter="set_sidechain" getter="get_sidechain" default="@"""> + <member name="sidechain" type="StringName" setter="set_sidechain" getter="get_sidechain" default="&"""> Reduce the sound level using another audio bus for threshold detection. </member> <member name="threshold" type="float" setter="set_threshold" getter="get_threshold" default="0.0"> diff --git a/doc/classes/AudioEffectInstance.xml b/doc/classes/AudioEffectInstance.xml index dc76880a36..9ab6028901 100644 --- a/doc/classes/AudioEffectInstance.xml +++ b/doc/classes/AudioEffectInstance.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioEffectInstance" inherits="Reference" version="4.0"> +<class name="AudioEffectInstance" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/AudioEffectPitchShift.xml b/doc/classes/AudioEffectPitchShift.xml index 917556fded..9c28a01650 100644 --- a/doc/classes/AudioEffectPitchShift.xml +++ b/doc/classes/AudioEffectPitchShift.xml @@ -13,23 +13,30 @@ </methods> <members> <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectPitchShift.FFTSize" default="3"> + The size of the [url=https://en.wikipedia.org/wiki/Fast_Fourier_transform]Fast Fourier transform[/url] buffer. Higher values smooth out the effect over time, but have greater latency. The effects of this higher latency are especially noticeable on sounds that have sudden amplitude changes. </member> <member name="oversampling" type="int" setter="set_oversampling" getter="get_oversampling" default="4"> + The oversampling factor to use. Higher values result in better quality, but are more demanding on the CPU and may cause audio cracking if the CPU can't keep up. </member> <member name="pitch_scale" type="float" setter="set_pitch_scale" getter="get_pitch_scale" default="1.0"> - Pitch value. Can range from 0 (-1 octave) to 16 (+16 octaves). + The pitch scale to use. [code]1.0[/code] is the default pitch and plays sounds unaltered. [member pitch_scale] can range from [code]0.0[/code] (infinitely low pitch, inaudible) to [code]16[/code] (16 times higher than the initial pitch). </member> </members> <constants> <constant name="FFT_SIZE_256" value="0" enum="FFTSize"> + Use a buffer of 256 samples for the Fast Fourier transform. Lowest latency, but least stable over time. </constant> <constant name="FFT_SIZE_512" value="1" enum="FFTSize"> + Use a buffer of 512 samples for the Fast Fourier transform. Low latency, but less stable over time. </constant> <constant name="FFT_SIZE_1024" value="2" enum="FFTSize"> + Use a buffer of 1024 samples for the Fast Fourier transform. This is a compromise between latency and stability over time. </constant> <constant name="FFT_SIZE_2048" value="3" enum="FFTSize"> + Use a buffer of 2048 samples for the Fast Fourier transform. High latency, but stable over time. </constant> <constant name="FFT_SIZE_4096" value="4" enum="FFTSize"> + Use a buffer of 4096 samples for the Fast Fourier transform. Highest latency, but most stable over time. </constant> <constant name="FFT_SIZE_MAX" value="5" enum="FFTSize"> Represents the size of the [enum FFTSize] enum. diff --git a/doc/classes/AudioEffectSpectrumAnalyzer.xml b/doc/classes/AudioEffectSpectrumAnalyzer.xml index 79a8932e25..10d29ff8ab 100644 --- a/doc/classes/AudioEffectSpectrumAnalyzer.xml +++ b/doc/classes/AudioEffectSpectrumAnalyzer.xml @@ -1,31 +1,43 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AudioEffectSpectrumAnalyzer" inherits="AudioEffect" version="4.0"> <brief_description> + Audio effect that can be used for real-time audio visualizations. </brief_description> <description> + This audio effect does not affect sound output, but can be used for real-time audio visualizations. + See also [AudioStreamGenerator] for procedurally generating sounds. </description> <tutorials> + <link title="https://godotengine.org/asset-library/asset/528">Audio Spectrum Demo</link> + <link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link> </tutorials> <methods> </methods> <members> <member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length" default="2.0"> + The length of the buffer to keep (in seconds). Higher values keep data around for longer, but require more memory. </member> <member name="fft_size" type="int" setter="set_fft_size" getter="get_fft_size" enum="AudioEffectSpectrumAnalyzer.FFTSize" default="2"> + The size of the [url=https://en.wikipedia.org/wiki/Fast_Fourier_transform]Fast Fourier transform[/url] buffer. Higher values smooth out the spectrum analysis over time, but have greater latency. The effects of this higher latency are especially noticeable with sudden amplitude changes. </member> <member name="tap_back_pos" type="float" setter="set_tap_back_pos" getter="get_tap_back_pos" default="0.01"> </member> </members> <constants> <constant name="FFT_SIZE_256" value="0" enum="FFTSize"> + Use a buffer of 256 samples for the Fast Fourier transform. Lowest latency, but least stable over time. </constant> <constant name="FFT_SIZE_512" value="1" enum="FFTSize"> + Use a buffer of 512 samples for the Fast Fourier transform. Low latency, but less stable over time. </constant> <constant name="FFT_SIZE_1024" value="2" enum="FFTSize"> + Use a buffer of 1024 samples for the Fast Fourier transform. This is a compromise between latency and stability over time. </constant> <constant name="FFT_SIZE_2048" value="3" enum="FFTSize"> + Use a buffer of 2048 samples for the Fast Fourier transform. High latency, but stable over time. </constant> <constant name="FFT_SIZE_4096" value="4" enum="FFTSize"> + Use a buffer of 4096 samples for the Fast Fourier transform. Highest latency, but most stable over time. </constant> <constant name="FFT_SIZE_MAX" value="5" enum="FFTSize"> Represents the size of the [enum FFTSize] enum. diff --git a/doc/classes/AudioStreamGenerator.xml b/doc/classes/AudioStreamGenerator.xml index a273beb5af..8464bc8a85 100644 --- a/doc/classes/AudioStreamGenerator.xml +++ b/doc/classes/AudioStreamGenerator.xml @@ -1,18 +1,27 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AudioStreamGenerator" inherits="AudioStream" version="4.0"> <brief_description> + Audio stream that generates sounds procedurally. </brief_description> <description> + This audio stream does not play back sounds, but expects a script to generate audio data for it instead. See also [AudioStreamGeneratorPlayback]. + See also [AudioEffectSpectrumAnalyzer] for performing real-time audio spectrum analysis. + [b]Note:[/b] Due to performance constraints, this class is best used from C# or from a compiled language via GDNative. If you still want to use this class from GDScript, consider using a lower [member mix_rate] such as 11,025 Hz or 22,050 Hz. </description> <tutorials> <link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link> + <link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link> </tutorials> <methods> </methods> <members> <member name="buffer_length" type="float" setter="set_buffer_length" getter="get_buffer_length" default="0.5"> + The length of the buffer to generate (in seconds). Lower values result in less latency, but require the script to generate audio data faster, resulting in increased CPU usage and more risk for audio cracking if the CPU can't keep up. </member> <member name="mix_rate" type="float" setter="set_mix_rate" getter="get_mix_rate" default="44100.0"> + The sample rate to use (in Hz). Higher values are more demanding for the CPU to generate, but result in better quality. + In games, common sample rates in use are [code]11025[/code], [code]16000[/code], [code]22050[/code], [code]32000[/code], [code]44100[/code], and [code]48000[/code]. + According to the [url=https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem]Nyquist-Shannon sampling theorem[/url], there is no quality difference to human hearing when going past 40,000 Hz (since most humans can only hear up to ~20,000 Hz, often less). If you are generating lower-pitched sounds such as voices, lower sample rates such as [code]32000[/code] or [code]22050[/code] may be usable with no loss in quality. </member> </members> <constants> diff --git a/doc/classes/AudioStreamGeneratorPlayback.xml b/doc/classes/AudioStreamGeneratorPlayback.xml index cd8e8735b6..503f72a048 100644 --- a/doc/classes/AudioStreamGeneratorPlayback.xml +++ b/doc/classes/AudioStreamGeneratorPlayback.xml @@ -1,11 +1,14 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="AudioStreamGeneratorPlayback" inherits="AudioStreamPlaybackResampled" version="4.0"> <brief_description> + Plays back audio generated using [AudioStreamGenerator]. </brief_description> <description> + This class is meant to be used with [AudioStreamGenerator] to play back the generated audio in real-time. </description> <tutorials> - <link title="Audio generator demo project">https://github.com/godotengine/godot-demo-projects/tree/master/audio/generator</link> + <link title="Audio Generator Demo">https://godotengine.org/asset-library/asset/526</link> + <link title="https://godotengine.org/article/godot-32-will-get-new-audio-features">Godot 3.2 will get new audio features</link> </tutorials> <methods> <method name="can_push_buffer" qualifiers="const"> @@ -14,18 +17,21 @@ <argument index="0" name="amount" type="int"> </argument> <description> + Returns [code]true[/code] if a buffer of the size [code]amount[/code] can be pushed to the audio sample data buffer without overflowing it, [code]false[/code] otherwise. </description> </method> <method name="clear_buffer"> <return type="void"> </return> <description> + Clears the audio sample data buffer. </description> </method> <method name="get_frames_available" qualifiers="const"> <return type="int"> </return> <description> + Returns the number of audio data frames left to play. If this returned number reaches [code]0[/code], the audio will stop playing until frames are added again. Therefore, make sure your script can always generate and push new audio frames fast enough to avoid audio cracking. </description> </method> <method name="get_skips" qualifiers="const"> @@ -40,6 +46,7 @@ <argument index="0" name="frames" type="PackedVector2Array"> </argument> <description> + Pushes several audio data frames to the buffer. This is usually more efficient than [method push_frame] in C# and compiled languages via GDNative, but [method push_buffer] may be [i]less[/i] efficient in GDScript. </description> </method> <method name="push_frame"> @@ -48,6 +55,7 @@ <argument index="0" name="frame" type="Vector2"> </argument> <description> + Pushes a single audio data frame to the buffer. This is usually less efficient than [method push_buffer] in C# and compiled languages via GDNative, but [method push_frame] may be [i]more[/i] efficient in GDScript. </description> </method> </methods> diff --git a/doc/classes/AudioStreamPlayback.xml b/doc/classes/AudioStreamPlayback.xml index da75ff206c..cb01aa75e8 100644 --- a/doc/classes/AudioStreamPlayback.xml +++ b/doc/classes/AudioStreamPlayback.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioStreamPlayback" inherits="Reference" version="4.0"> +<class name="AudioStreamPlayback" inherits="RefCounted" version="4.0"> <brief_description> Meta class for playing back audio. </brief_description> diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml index 113cc64b9d..7c7f7e0cea 100644 --- a/doc/classes/AudioStreamPlayer.xml +++ b/doc/classes/AudioStreamPlayer.xml @@ -60,7 +60,7 @@ <member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false"> If [code]true[/code], audio plays when added to scene tree. </member> - <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@"Master""> + <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> Bus on which this audio is playing. </member> <member name="mix_target" type="int" setter="set_mix_target" getter="get_mix_target" enum="AudioStreamPlayer.MixTarget" default="0"> diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml index e7c276f463..b1e18ab550 100644 --- a/doc/classes/AudioStreamPlayer2D.xml +++ b/doc/classes/AudioStreamPlayer2D.xml @@ -62,7 +62,7 @@ <member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false"> If [code]true[/code], audio plays when added to scene tree. </member> - <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@"Master""> + <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> Bus on which this audio is playing. </member> <member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="2000.0"> diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml index a1759bd588..3bd20b4b9b 100644 --- a/doc/classes/AudioStreamPlayer3D.xml +++ b/doc/classes/AudioStreamPlayer3D.xml @@ -69,7 +69,7 @@ <member name="autoplay" type="bool" setter="set_autoplay" getter="is_autoplay_enabled" default="false"> If [code]true[/code], audio plays when the AudioStreamPlayer3D node is added to scene tree. </member> - <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@"Master""> + <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> The bus on which this audio is playing. </member> <member name="doppler_tracking" type="int" setter="set_doppler_tracking" getter="get_doppler_tracking" enum="AudioStreamPlayer3D.DopplerTracking" default="0"> diff --git a/doc/classes/AudioStreamSample.xml b/doc/classes/AudioStreamSample.xml index c12e1bd05c..5a0e71a0f8 100644 --- a/doc/classes/AudioStreamSample.xml +++ b/doc/classes/AudioStreamSample.xml @@ -5,7 +5,7 @@ </brief_description> <description> AudioStreamSample stores sound samples loaded from WAV files. To play the stored sound, use an [AudioStreamPlayer] (for non-positional audio) or [AudioStreamPlayer2D]/[AudioStreamPlayer3D] (for positional audio). The sound can be looped. - This class can also be used to store dynamically-generated PCM audio data. + This class can also be used to store dynamically-generated PCM audio data. See also [AudioStreamGenerator] for procedural audio generation. </description> <tutorials> </tutorials> @@ -22,7 +22,7 @@ </method> </methods> <members> - <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()"> Contains the audio data in bytes. [b]Note:[/b] This property expects signed PCM8 data. To convert unsigned PCM8 to signed PCM8, subtract 128 from each byte. </member> @@ -39,7 +39,9 @@ The loop mode. This information will be imported automatically from the WAV file if present. See [enum LoopMode] constants for values. </member> <member name="mix_rate" type="int" setter="set_mix_rate" getter="get_mix_rate" default="44100"> - The sample rate for mixing this audio. + The sample rate for mixing this audio. Higher values require more storage space, but result in better quality. + In games, common sample rates in use are [code]11025[/code], [code]16000[/code], [code]22050[/code], [code]32000[/code], [code]44100[/code], and [code]48000[/code]. + According to the [url=https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem]Nyquist-Shannon sampling theorem[/url], there is no quality difference to human hearing when going past 40,000 Hz (since most humans can only hear up to ~20,000 Hz, often less). If you are using lower-pitched sounds such as voices, lower sample rates such as [code]32000[/code] or [code]22050[/code] may be usable with no loss in quality. </member> <member name="stereo" type="bool" setter="set_stereo" getter="is_stereo" default="false"> If [code]true[/code], audio is stereo. diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml index 9a70b8f20c..55ee573811 100644 --- a/doc/classes/BackBufferCopy.xml +++ b/doc/classes/BackBufferCopy.xml @@ -15,7 +15,7 @@ <member name="copy_mode" type="int" setter="set_copy_mode" getter="get_copy_mode" enum="BackBufferCopy.CopyMode" default="1"> Buffer mode. See [enum CopyMode] constants. </member> - <member name="rect" type="Rect2" setter="set_rect" getter="get_rect" default="Rect2( -100, -100, 200, 200 )"> + <member name="rect" type="Rect2" setter="set_rect" getter="get_rect" default="Rect2(-100, -100, 200, 200)"> The area covered by the BackBufferCopy. Only used if [member copy_mode] is [constant COPY_MODE_RECT]. </member> </members> diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 0a7b4c5dab..2a378ed03e 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -72,7 +72,7 @@ </method> </methods> <members> - <member name="albedo_color" type="Color" setter="set_albedo" getter="get_albedo" default="Color( 1, 1, 1, 1 )"> + <member name="albedo_color" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)"> The material's base color. </member> <member name="albedo_tex_force_srgb" type="bool" setter="set_flag" getter="get_flag" default="false"> @@ -117,7 +117,7 @@ <member name="ao_texture_channel" type="int" setter="set_ao_texture_channel" getter="get_ao_texture_channel" enum="BaseMaterial3D.TextureChannel" default="0"> Specifies the channel of the [member ao_texture] in which the ambient occlusion information is stored. This is useful when you store the information for multiple effects in a single texture. For example if you stored metallic in the red channel, roughness in the blue, and ambient occlusion in the green you could reduce the number of textures you use. </member> - <member name="backlight" type="Color" setter="set_backlight" getter="get_backlight" default="Color( 0, 0, 0, 1 )"> + <member name="backlight" type="Color" setter="set_backlight" getter="get_backlight" default="Color(0, 0, 0, 1)"> The color used by the backlight effect. Represents the light passing through an object. </member> <member name="backlight_enabled" type="bool" setter="set_feature" getter="get_feature" default="false"> @@ -195,11 +195,11 @@ <member name="distance_fade_mode" type="int" setter="set_distance_fade" getter="get_distance_fade" enum="BaseMaterial3D.DistanceFadeMode" default="0"> Specifies which type of fade to use. Can be any of the [enum DistanceFadeMode]s. </member> - <member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color( 0, 0, 0, 1 )"> + <member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color(0, 0, 0, 1)"> The emitted light's color. See [member emission_enabled]. </member> <member name="emission_enabled" type="bool" setter="set_feature" getter="get_feature" default="false"> - If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [GIProbe] is used and this object is used in baked lighting. + If [code]true[/code], the body emits light. Emitting light makes the object appear brighter. The object can also cast light on other objects if a [VoxelGI] is used and this object is used in baked lighting. </member> <member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy" default="1.0"> The emitted light's strength. See [member emission_enabled]. @@ -345,9 +345,7 @@ </member> <member name="subsurf_scatter_transmittance_boost" type="float" setter="set_transmittance_boost" getter="get_transmittance_boost" default="0.0"> </member> - <member name="subsurf_scatter_transmittance_color" type="Color" setter="set_transmittance_color" getter="get_transmittance_color" default="Color( 1, 1, 1, 1 )"> - </member> - <member name="subsurf_scatter_transmittance_curve" type="float" setter="set_transmittance_curve" getter="get_transmittance_curve" default="1.0"> + <member name="subsurf_scatter_transmittance_color" type="Color" setter="set_transmittance_color" getter="get_transmittance_color" default="Color(1, 1, 1, 1)"> </member> <member name="subsurf_scatter_transmittance_depth" type="float" setter="set_transmittance_depth" getter="get_transmittance_depth" default="0.1"> </member> @@ -370,10 +368,10 @@ If [code]true[/code], render point size can be changed. [b]Note:[/b] this is only effective for objects whose geometry is point-based rather than triangle-based. See also [member point_size]. </member> - <member name="uv1_offset" type="Vector3" setter="set_uv1_offset" getter="get_uv1_offset" default="Vector3( 0, 0, 0 )"> + <member name="uv1_offset" type="Vector3" setter="set_uv1_offset" getter="get_uv1_offset" default="Vector3(0, 0, 0)"> How much to offset the [code]UV[/code] coordinates. This amount will be added to [code]UV[/code] in the vertex function. This can be used to offset a texture. </member> - <member name="uv1_scale" type="Vector3" setter="set_uv1_scale" getter="get_uv1_scale" default="Vector3( 1, 1, 1 )"> + <member name="uv1_scale" type="Vector3" setter="set_uv1_scale" getter="get_uv1_scale" default="Vector3(1, 1, 1)"> How much to scale the [code]UV[/code] coordinates. This is multiplied by [code]UV[/code] in the vertex function. </member> <member name="uv1_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false"> @@ -385,10 +383,10 @@ <member name="uv1_world_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false"> If [code]true[/code], triplanar mapping for [code]UV[/code] is calculated in world space rather than object local space. See also [member uv1_triplanar]. </member> - <member name="uv2_offset" type="Vector3" setter="set_uv2_offset" getter="get_uv2_offset" default="Vector3( 0, 0, 0 )"> + <member name="uv2_offset" type="Vector3" setter="set_uv2_offset" getter="get_uv2_offset" default="Vector3(0, 0, 0)"> How much to offset the [code]UV2[/code] coordinates. This amount will be added to [code]UV2[/code] in the vertex function. This can be used to offset a texture. </member> - <member name="uv2_scale" type="Vector3" setter="set_uv2_scale" getter="get_uv2_scale" default="Vector3( 1, 1, 1 )"> + <member name="uv2_scale" type="Vector3" setter="set_uv2_scale" getter="get_uv2_scale" default="Vector3(1, 1, 1)"> How much to scale the [code]UV2[/code] coordinates. This is multiplied by [code]UV2[/code] in the vertex function. </member> <member name="uv2_triplanar" type="bool" setter="set_flag" getter="get_flag" default="false"> @@ -671,10 +669,7 @@ <constant name="DIFFUSE_LAMBERT_WRAP" value="2" enum="DiffuseMode"> Extends Lambert to cover more than 90 degrees when roughness increases. </constant> - <constant name="DIFFUSE_OREN_NAYAR" value="3" enum="DiffuseMode"> - Attempts to use roughness to emulate microsurfacing. - </constant> - <constant name="DIFFUSE_TOON" value="4" enum="DiffuseMode"> + <constant name="DIFFUSE_TOON" value="3" enum="DiffuseMode"> Uses a hard cut for lighting, with smoothing affected by roughness. </constant> <constant name="SPECULAR_SCHLICK_GGX" value="0" enum="SpecularMode"> diff --git a/doc/classes/Basis.xml b/doc/classes/Basis.xml index 55ae58ee3a..bd1abe914d 100644 --- a/doc/classes/Basis.xml +++ b/doc/classes/Basis.xml @@ -4,7 +4,7 @@ 3×3 matrix datatype. </brief_description> <description> - 3×3 matrix used for 3D rotation and scale. Almost always used as an orthogonal basis for a Transform. + 3×3 matrix used for 3D rotation and scale. Almost always used as an orthogonal basis for a [Transform3D]. Contains 3 vector fields X, Y and Z as its columns, which are typically interpreted as the local basis vectors of a transformation. For such use, it is composed of a scaling and a rotation matrix, in that order (M = R.S). Can also be accessed as array of 3D vectors. These vectors are normally orthogonal to each other, but are not necessarily normalized (due to scaling). For more information, read the "Matrices and transforms" documentation article. @@ -53,13 +53,13 @@ </argument> <description> Constructs a pure rotation basis matrix from the given Euler angles (in the YXZ convention: when *composing*, first Y, then X, and Z last), given in the vector format as (X angle, Y angle, Z angle). - Consider using the [Quat] constructor instead, which uses a quaternion instead of Euler angles. + Consider using the [Quaternion] constructor instead, which uses a quaternion instead of Euler angles. </description> </method> <method name="Basis" qualifiers="constructor"> <return type="Basis"> </return> - <argument index="0" name="from" type="Quat"> + <argument index="0" name="from" type="Quaternion"> </argument> <description> Constructs a pure rotation basis matrix from the given quaternion. @@ -91,7 +91,7 @@ </return> <description> Returns the basis's rotation in the form of Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last). The returned vector contains the rotation angles in the format (X angle, Y angle, Z angle). - Consider using the [method get_rotation_quat] method instead, which returns a [Quat] quaternion instead of Euler angles. + Consider using the [method get_rotation_quaternion] method instead, which returns a [Quaternion] quaternion instead of Euler angles. </description> </method> <method name="get_orthogonal_index" qualifiers="const"> @@ -101,8 +101,8 @@ This function considers a discretization of rotations into 24 points on unit sphere, lying along the vectors (x,y,z) with each component being either -1, 0, or 1, and returns the index of the point best representing the orientation of the object. It is mainly used by the [GridMap] editor. For further details, refer to the Godot source code. </description> </method> - <method name="get_rotation_quat" qualifiers="const"> - <return type="Quat"> + <method name="get_rotation_quaternion" qualifiers="const"> + <return type="Quaternion"> </return> <description> Returns the basis's rotation in the form of a quaternion. See [method get_euler] if you need Euler angles, but keep in mind quaternions should generally be preferred to Euler angles. @@ -155,6 +155,24 @@ <description> </description> </method> + <method name="operator *" qualifiers="operator"> + <return type="Basis"> + </return> + <argument index="0" name="right" type="float"> + </argument> + <description> + This operator multiplies all components of the [Basis], which scales it uniformly. + </description> + </method> + <method name="operator *" qualifiers="operator"> + <return type="Basis"> + </return> + <argument index="0" name="right" type="int"> + </argument> + <description> + This operator multiplies all components of the [Basis], which scales it uniformly. + </description> + </method> <method name="operator ==" qualifiers="operator"> <return type="bool"> </return> @@ -245,28 +263,28 @@ </method> </methods> <members> - <member name="x" type="Vector3" setter="" getter="" default="Vector3( 1, 0, 0 )"> + <member name="x" type="Vector3" setter="" getter="" default="Vector3(1, 0, 0)"> The basis matrix's X vector (column 0). Equivalent to array index [code]0[/code]. </member> - <member name="y" type="Vector3" setter="" getter="" default="Vector3( 0, 1, 0 )"> + <member name="y" type="Vector3" setter="" getter="" default="Vector3(0, 1, 0)"> The basis matrix's Y vector (column 1). Equivalent to array index [code]1[/code]. </member> - <member name="z" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 1 )"> + <member name="z" type="Vector3" setter="" getter="" default="Vector3(0, 0, 1)"> The basis matrix's Z vector (column 2). Equivalent to array index [code]2[/code]. </member> </members> <constants> - <constant name="IDENTITY" value="Basis( 1, 0, 0, 0, 1, 0, 0, 0, 1 )"> + <constant name="IDENTITY" value="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)"> The identity basis, with no rotation or scaling applied. This is identical to calling [code]Basis()[/code] without any parameters. This constant can be used to make your code clearer, and for consistency with C#. </constant> - <constant name="FLIP_X" value="Basis( -1, 0, 0, 0, 1, 0, 0, 0, 1 )"> + <constant name="FLIP_X" value="Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1)"> The basis that will flip something along the X axis when used in a transformation. </constant> - <constant name="FLIP_Y" value="Basis( 1, 0, 0, 0, -1, 0, 0, 0, 1 )"> + <constant name="FLIP_Y" value="Basis(1, 0, 0, 0, -1, 0, 0, 0, 1)"> The basis that will flip something along the Y axis when used in a transformation. </constant> - <constant name="FLIP_Z" value="Basis( 1, 0, 0, 0, 1, 0, 0, 0, -1 )"> + <constant name="FLIP_Z" value="Basis(1, 0, 0, 0, 1, 0, 0, 0, -1)"> The basis that will flip something along the Z axis when used in a transformation. </constant> </constants> diff --git a/doc/classes/BitMap.xml b/doc/classes/BitMap.xml index 27ead07e6f..83e598d2ba 100644 --- a/doc/classes/BitMap.xml +++ b/doc/classes/BitMap.xml @@ -71,6 +71,12 @@ <argument index="1" name="epsilon" type="float" default="2.0"> </argument> <description> + Creates an [Array] of polygons covering a rectangular portion of the bitmap. It uses a marching squares algorithm, followed by Ramer-Douglas-Peucker (RDP) reduction of the number of vertices. Each polygon is described as a [PackedVector2Array] of its vertices. + To get polygons covering the whole bitmap, pass: + [codeblock] + Rect2(Vector2(), get_size()) + [/codeblock] + [code]epsilon[/code] is passed to RDP to control how accurately the polygons cover the bitmap: a lower [code]epsilon[/code] corresponds to more points in the polygons. </description> </method> <method name="set_bit"> diff --git a/doc/classes/Bone2D.xml b/doc/classes/Bone2D.xml index 910d488dfd..b8d5544d59 100644 --- a/doc/classes/Bone2D.xml +++ b/doc/classes/Bone2D.xml @@ -19,6 +19,28 @@ Stores the node's current transforms in [member rest]. </description> </method> + <method name="get_autocalculate_length_and_angle" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether this [code]Bone2D[/code] node is going to autocalculate its length and bone angle using its first [code]Bone2D[/code] child node, if one exists. If there are no [code]Bone2D[/code] children, then it cannot autocalculate these values and will print a warning. + </description> + </method> + <method name="get_bone_angle" qualifiers="const"> + <return type="float"> + </return> + <description> + Returns the angle of the bone in the [code]Bone2D[/code] node. + [b]Note:[/b] This is different from the [code]Bone2D[/code]'s rotation. The bone angle is the rotation of the bone shown by the [code]Bone2D[/code] gizmo, and because [code]Bone2D[/code] bones are based on positions, this can vary from the actual rotation of the [code]Bone2D[/code] node. + </description> + </method> + <method name="get_default_length" qualifiers="const"> + <return type="float"> + </return> + <description> + Deprecated. Please use [code]get_length[/code] instead. + </description> + </method> <method name="get_index_in_skeleton" qualifiers="const"> <return type="int"> </return> @@ -26,6 +48,13 @@ Returns the node's index as part of the entire skeleton. See [Skeleton2D]. </description> </method> + <method name="get_length" qualifiers="const"> + <return type="float"> + </return> + <description> + Returns the length of the bone in the [code]Bone2D[/code] node. + </description> + </method> <method name="get_skeleton_rest" qualifiers="const"> <return type="Transform2D"> </return> @@ -33,12 +62,46 @@ Returns the node's [member rest] [code]Transform2D[/code] if it doesn't have a parent, or its rest pose relative to its parent. </description> </method> + <method name="set_autocalculate_length_and_angle"> + <return type="void"> + </return> + <argument index="0" name="auto_calculate" type="bool"> + </argument> + <description> + When set to [code]true[/code], the [code]Bone2D[/code] node will attempt to automatically calculate the bone angle and length using the first child [code]Bone2D[/code] node, if one exists. If none exist, the [code]Bone2D[/code] cannot automatically calculate these values and will print a warning. + </description> + </method> + <method name="set_bone_angle"> + <return type="void"> + </return> + <argument index="0" name="angle" type="float"> + </argument> + <description> + Sets the bone angle for the [code]Bone2D[/code] node. This is typically set to the rotation from the [code]Bone2D[/code] node to a child [code]Bone2D[/code] node. + [b]Note:[/b] This is different from the [code]Bone2D[/code]'s rotation. The bone angle is the rotation of the bone shown by the [code]Bone2D[/code] gizmo, and because [code]Bone2D[/code] bones are based on positions, this can vary from the actual rotation of the [code]Bone2D[/code] node. + </description> + </method> + <method name="set_default_length"> + <return type="void"> + </return> + <argument index="0" name="default_length" type="float"> + </argument> + <description> + Deprecated. Please use [code]set_length[/code] instead. + </description> + </method> + <method name="set_length"> + <return type="void"> + </return> + <argument index="0" name="length" type="float"> + </argument> + <description> + Sets the length of the bone in the [code]Bone2D[/code] node. + </description> + </method> </methods> <members> - <member name="default_length" type="float" setter="set_default_length" getter="get_default_length" default="16.0"> - Length of the bone's representation drawn in the editor's viewport in pixels. - </member> - <member name="rest" type="Transform2D" setter="set_rest" getter="get_rest" default="Transform2D( 0, 0, 0, 0, 0, 0 )"> + <member name="rest" type="Transform2D" setter="set_rest" getter="get_rest" default="Transform2D(0, 0, 0, 0, 0, 0)"> Rest transform of the bone. You can reset the node's transforms to this value using [method apply_rest]. </member> </members> diff --git a/doc/classes/BoxMesh.xml b/doc/classes/BoxMesh.xml index 1404477b46..dda5e2f1e5 100644 --- a/doc/classes/BoxMesh.xml +++ b/doc/classes/BoxMesh.xml @@ -13,7 +13,7 @@ <methods> </methods> <members> - <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> + <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)"> The box's width, height and depth. </member> <member name="subdivide_depth" type="int" setter="set_subdivide_depth" getter="get_subdivide_depth" default="0"> diff --git a/doc/classes/BoxShape3D.xml b/doc/classes/BoxShape3D.xml index f5051413ce..5704de905b 100644 --- a/doc/classes/BoxShape3D.xml +++ b/doc/classes/BoxShape3D.xml @@ -14,7 +14,7 @@ <methods> </methods> <members> - <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> + <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)"> The box's width, height and depth. </member> </members> diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index 51c35b15ce..239e0bb2d9 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -85,6 +85,9 @@ <member name="icon" type="Texture2D" setter="set_button_icon" getter="get_button_icon"> Button's icon, if text is present the icon will be placed before the text. </member> + <member name="icon_align" type="int" setter="set_icon_align" getter="get_icon_align" enum="Button.TextAlign" default="0"> + Specifies if the icon should be aligned to the left, right, or center of a button. Uses the same [enum TextAlign] constants as the text alignment. If centered, text will draw on top of the icon. + </member> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. </member> @@ -116,22 +119,22 @@ <theme_item name="font" type="Font"> [Font] of the [Button]'s text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Default text [Color] of the [Button]. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.2)"> Text [Color] used when the [Button] is disabled. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Text [Color] used when the [Button] is being hovered. </theme_item> - <theme_item name="font_hover_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_hover_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [Button] is being hovered and pressed. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [Button]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [Button] is being pressed. </theme_item> <theme_item name="font_size" type="int"> @@ -143,19 +146,19 @@ <theme_item name="hseparation" type="int" default="2"> The horizontal space between [Button]'s icon and text. </theme_item> - <theme_item name="icon_disabled_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="icon_disabled_color" type="Color" default="Color(1, 1, 1, 1)"> Icon modulate [Color] used when the [Button] is disabled. </theme_item> - <theme_item name="icon_hover_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="icon_hover_color" type="Color" default="Color(1, 1, 1, 1)"> Icon modulate [Color] used when the [Button] is being hovered. </theme_item> - <theme_item name="icon_hover_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="icon_hover_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Icon modulate [Color] used when the [Button] is being hovered and pressed. </theme_item> - <theme_item name="icon_normal_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="icon_normal_color" type="Color" default="Color(1, 1, 1, 1)"> Default icon modulate [Color] of the [Button]. </theme_item> - <theme_item name="icon_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="icon_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Icon modulate [Color] used when the [Button] is being pressed. </theme_item> <theme_item name="normal" type="StyleBox"> diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml index 9e70978db8..9620e9abd1 100644 --- a/doc/classes/CPUParticles2D.xml +++ b/doc/classes/CPUParticles2D.xml @@ -148,7 +148,7 @@ <member name="anim_speed_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0"> Animation speed randomness ratio. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> Each particle's initial color. If [member texture] is defined, it will be multiplied by this color. </member> <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> @@ -163,7 +163,7 @@ <member name="damping_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0"> Damping randomness ratio. </member> - <member name="direction" type="Vector2" setter="set_direction" getter="get_direction" default="Vector2( 1, 0 )"> + <member name="direction" type="Vector2" setter="set_direction" getter="get_direction" default="Vector2(1, 0)"> Unit vector specifying the particles' emission direction. </member> <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="CPUParticles2D.DrawOrder" default="0"> @@ -199,7 +199,7 @@ <member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true"> If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect. </member> - <member name="gravity" type="Vector2" setter="set_gravity" getter="get_gravity" default="Vector2( 0, 980 )"> + <member name="gravity" type="Vector2" setter="set_gravity" getter="get_gravity" default="Vector2(0, 980)"> Gravity applied to every particle. </member> <member name="hue_variation" type="float" setter="set_param" getter="get_param" default="0.0"> diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml index 0512efa8c2..7509775d20 100644 --- a/doc/classes/CPUParticles3D.xml +++ b/doc/classes/CPUParticles3D.xml @@ -147,7 +147,7 @@ <member name="anim_speed_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0"> Animation speed randomness ratio. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> Unused for 3D particles. </member> <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp"> @@ -162,7 +162,7 @@ <member name="damping_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0"> Damping randomness ratio. </member> - <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3( 1, 0, 0 )"> + <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3(1, 0, 0)"> Unit vector specifying the particles' emission direction. </member> <member name="draw_order" type="int" setter="set_draw_order" getter="get_draw_order" enum="CPUParticles3D.DrawOrder" default="0"> @@ -171,13 +171,13 @@ <member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents"> The rectangle's extents if [member emission_shape] is set to [constant EMISSION_SHAPE_BOX]. </member> - <member name="emission_colors" type="PackedColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PackedColorArray( )"> + <member name="emission_colors" type="PackedColorArray" setter="set_emission_colors" getter="get_emission_colors" default="PackedColorArray()"> Sets the [Color]s to modulate particles by when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]. </member> <member name="emission_normals" type="PackedVector3Array" setter="set_emission_normals" getter="get_emission_normals"> Sets the direction the particles will be emitted in when using [constant EMISSION_SHAPE_DIRECTED_POINTS]. </member> - <member name="emission_points" type="PackedVector3Array" setter="set_emission_points" getter="get_emission_points" default="PackedVector3Array( )"> + <member name="emission_points" type="PackedVector3Array" setter="set_emission_points" getter="get_emission_points" default="PackedVector3Array()"> Sets the initial positions to spawn particles when using [constant EMISSION_SHAPE_POINTS] or [constant EMISSION_SHAPE_DIRECTED_POINTS]. </member> <member name="emission_shape" type="int" setter="set_emission_shape" getter="get_emission_shape" enum="CPUParticles3D.EmissionShape" default="0"> @@ -201,7 +201,7 @@ <member name="fract_delta" type="bool" setter="set_fractional_delta" getter="get_fractional_delta" default="true"> If [code]true[/code], results in fractional delta calculation which has a smoother particles display effect. </member> - <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )"> + <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3(0, -9.8, 0)"> Gravity applied to every particle. </member> <member name="hue_variation" type="float" setter="set_param" getter="get_param" default="0.0"> diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml index cbab1a8f50..3c61e8278f 100644 --- a/doc/classes/Callable.xml +++ b/doc/classes/Callable.xml @@ -133,6 +133,13 @@ Returns [code]true[/code] if this [Callable] is a standard callable, referencing an object and a method using a [StringName]. </description> </method> + <method name="is_valid" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the object exists and has a valid function assigned, or is a custom callable. + </description> + </method> <method name="operator !=" qualifiers="operator"> <return type="bool"> </return> diff --git a/doc/classes/CallbackTweener.xml b/doc/classes/CallbackTweener.xml new file mode 100644 index 0000000000..8ac285c3df --- /dev/null +++ b/doc/classes/CallbackTweener.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="CallbackTweener" inherits="Tweener" version="4.0"> + <brief_description> + Calls the specified method after optional delay. + </brief_description> + <description> + [CallbackTweener] is used to call a method in a tweening sequence. See [method Tween.tween_callback] for more usage information. + [b]Note:[/b] [method Tween.tween_callback] is the only correct way to create [CallbackTweener]. Any [CallbackTweener] created manually will not function correctly. + </description> + <tutorials> + </tutorials> + <methods> + <method name="set_delay"> + <return type="CallbackTweener"> + </return> + <argument index="0" name="delay" type="float"> + </argument> + <description> + Makes the callback call delayed by given time in seconds. Example: + [codeblock] + var tween = get_tree().create_tween() + tween.tween_callback(queue_free).set_delay(2) #this will call queue_free() after 2 seconds + [/codeblock] + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/Camera2D.xml b/doc/classes/Camera2D.xml index d40567bdcb..4620b3d93c 100644 --- a/doc/classes/Camera2D.xml +++ b/doc/classes/Camera2D.xml @@ -161,11 +161,13 @@ </member> <member name="limit_smoothed" type="bool" setter="set_limit_smoothing_enabled" getter="is_limit_smoothing_enabled" default="false"> If [code]true[/code], the camera smoothly stops when reaches its limits. + This has no effect if smoothing is disabled. + [b]Note:[/b] To immediately update the camera's position to be within limits without smoothing, even with this setting enabled, invoke [method reset_smoothing]. </member> <member name="limit_top" type="int" setter="set_limit" getter="get_limit" default="-10000000"> Top scroll limit in pixels. The camera stops moving when reaching this value. </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The camera's offset, useful for looking around or camera shake animations. </member> <member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="Camera2D.Camera2DProcessCallback" default="1"> @@ -180,7 +182,7 @@ <member name="smoothing_speed" type="float" setter="set_follow_smoothing" getter="get_follow_smoothing" default="5.0"> Speed in pixels per second of the camera's smoothing effect when [member smoothing_enabled] is [code]true[/code]. </member> - <member name="zoom" type="Vector2" setter="set_zoom" getter="get_zoom" default="Vector2( 1, 1 )"> + <member name="zoom" type="Vector2" setter="set_zoom" getter="get_zoom" default="Vector2(1, 1)"> The camera's zoom relative to the viewport. Values larger than [code]Vector2(1, 1)[/code] zoom out and smaller values zoom in. For an example, use [code]Vector2(0.5, 0.5)[/code] for a 2× zoom-in, and [code]Vector2(4, 4)[/code] for a 4× zoom-out. </member> </members> diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml index 9f1d6d8e31..afba478a20 100644 --- a/doc/classes/Camera3D.xml +++ b/doc/classes/Camera3D.xml @@ -27,7 +27,7 @@ </description> </method> <method name="get_camera_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> Gets the camera transform. Subclassed cameras such as [ClippedCamera3D] may provide different transforms than the [Node] transform. @@ -55,10 +55,19 @@ <argument index="0" name="world_point" type="Vector3"> </argument> <description> - Returns [code]true[/code] if the given position is behind the camera. + Returns [code]true[/code] if the given position is behind the camera (the blue part of the linked diagram). [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/camera3d_position_frustum.png]See this diagram[/url] for an overview of position query methods. [b]Note:[/b] A position which returns [code]false[/code] may still be outside the camera's field of view. </description> </method> + <method name="is_position_in_frustum" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="world_point" type="Vector3"> + </argument> + <description> + Returns [code]true[/code] if the given position is inside the camera's frustum (the green part of the linked diagram). [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/camera3d_position_frustum.png]See this diagram[/url] for an overview of position query methods. + </description> + </method> <method name="make_current"> <return type="void"> </return> @@ -200,7 +209,7 @@ - ~107.51 degrees in a 16:9 viewport - ~121.63 degrees in a 21:9 viewport </member> - <member name="frustum_offset" type="Vector2" setter="set_frustum_offset" getter="get_frustum_offset" default="Vector2( 0, 0 )"> + <member name="frustum_offset" type="Vector2" setter="set_frustum_offset" getter="get_frustum_offset" default="Vector2(0, 0)"> The camera's frustum offset. This can be changed from the default to create "tilted frustum" effects such as [url=https://zdoom.org/wiki/Y-shearing]Y-shearing[/url]. </member> <member name="h_offset" type="float" setter="set_h_offset" getter="get_h_offset" default="0.0"> diff --git a/doc/classes/CameraFeed.xml b/doc/classes/CameraFeed.xml index 4fc124592f..fc7dcd3772 100644 --- a/doc/classes/CameraFeed.xml +++ b/doc/classes/CameraFeed.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CameraFeed" inherits="Reference" version="4.0"> +<class name="CameraFeed" inherits="RefCounted" version="4.0"> <brief_description> A camera feed gives you access to a single physical camera attached to your device. </brief_description> diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 87b157db4e..d0950ae741 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -24,6 +24,21 @@ Overridable function called by the engine (if defined) to draw the canvas item. </description> </method> + <method name="draw_animation_slice"> + <return type="void"> + </return> + <argument index="0" name="animation_length" type="float"> + </argument> + <argument index="1" name="slice_begin" type="float"> + </argument> + <argument index="2" name="slice_end" type="float"> + </argument> + <argument index="3" name="offset" type="float" default="0.0"> + </argument> + <description> + Subsequent drawing commands will be ignored unless they fall within the specified animation slice. This is a faster way to implement animations that loop on background rather than redrawing constantly. + </description> + </method> <method name="draw_arc"> <return type="void"> </return> @@ -60,11 +75,11 @@ </argument> <argument index="4" name="size" type="int" default="-1"> </argument> - <argument index="5" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="5" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="6" name="outline_size" type="int" default="0"> </argument> - <argument index="7" name="outline_modulate" type="Color" default="Color( 1, 1, 1, 0 )"> + <argument index="7" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)"> </argument> <description> Draws a string character using a custom font. Returns the advance, depending on the character width and kerning with an optional next character. @@ -90,7 +105,7 @@ </argument> <argument index="1" name="color" type="Color"> </argument> - <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array( )"> + <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()"> </argument> <argument index="3" name="texture" type="Texture2D" default="null"> </argument> @@ -98,6 +113,13 @@ Draws a colored polygon of any amount of points, convex or concave. </description> </method> + <method name="draw_end_animation"> + <return type="void"> + </return> + <description> + After submitting all animations slices via [method draw_animation_slice], this function can be used to revert drawing to its default state (all subsequent drawing commands will be visible). If you don't care about this particular use case, usage of this function after submitting the slices is not required. + </description> + </method> <method name="draw_line"> <return type="void"> </return> @@ -120,9 +142,9 @@ </argument> <argument index="1" name="texture" type="Texture2D"> </argument> - <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )"> + <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)"> </argument> - <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draws a [Mesh] in 2D, using the provided texture. See [MeshInstance2D] for related documentation. @@ -171,11 +193,11 @@ </argument> <argument index="6" name="size" type="int" default="-1"> </argument> - <argument index="7" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="8" name="outline_size" type="int" default="0"> </argument> - <argument index="9" name="outline_modulate" type="Color" default="Color( 1, 1, 1, 0 )"> + <argument index="9" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)"> </argument> <argument index="10" name="flags" type="int" default="51"> </argument> @@ -201,7 +223,7 @@ </argument> <argument index="1" name="colors" type="PackedColorArray"> </argument> - <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array( )"> + <argument index="2" name="uvs" type="PackedVector2Array" default="PackedVector2Array()"> </argument> <argument index="3" name="texture" type="Texture2D" default="null"> </argument> @@ -279,7 +301,7 @@ </argument> <argument index="1" name="rotation" type="float" default="0.0"> </argument> - <argument index="2" name="scale" type="Vector2" default="Vector2( 1, 1 )"> + <argument index="2" name="scale" type="Vector2" default="Vector2(1, 1)"> </argument> <description> Sets a custom transform for drawing via components. Anything drawn afterwards will be transformed by this. @@ -309,11 +331,11 @@ </argument> <argument index="5" name="size" type="int" default="-1"> </argument> - <argument index="6" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="7" name="outline_size" type="int" default="0"> </argument> - <argument index="8" name="outline_modulate" type="Color" default="Color( 1, 1, 1, 0 )"> + <argument index="8" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)"> </argument> <argument index="9" name="flags" type="int" default="3"> </argument> @@ -359,7 +381,7 @@ </argument> <argument index="1" name="position" type="Vector2"> </argument> - <argument index="2" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draws a texture at a given position. @@ -374,7 +396,7 @@ </argument> <argument index="2" name="tile" type="bool"> </argument> - <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="4" name="transpose" type="bool" default="false"> </argument> @@ -391,7 +413,7 @@ </argument> <argument index="2" name="src_rect" type="Rect2"> </argument> - <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="4" name="transpose" type="bool" default="false"> </argument> @@ -573,10 +595,10 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> The material applied to textures on this [CanvasItem]. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color( 1, 1, 1, 1 )"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> The color applied to textures on this [CanvasItem]. </member> - <member name="self_modulate" type="Color" setter="set_self_modulate" getter="get_self_modulate" default="Color( 1, 1, 1, 1 )"> + <member name="self_modulate" type="Color" setter="set_self_modulate" getter="get_self_modulate" default="Color(1, 1, 1, 1)"> The color applied to textures on this [CanvasItem]. This is not inherited by children [CanvasItem]s. </member> <member name="show_behind_parent" type="bool" setter="set_draw_behind_parent" getter="is_draw_behind_parent_enabled" default="false"> diff --git a/doc/classes/CanvasLayer.xml b/doc/classes/CanvasLayer.xml index 9d952cdba3..eb99368079 100644 --- a/doc/classes/CanvasLayer.xml +++ b/doc/classes/CanvasLayer.xml @@ -33,19 +33,16 @@ <member name="layer" type="int" setter="set_layer" getter="get_layer" default="1"> Layer index for draw order. Lower values are drawn first. </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The layer's base offset. </member> <member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0"> The layer's rotation in radians. </member> - <member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees" default="0.0"> - The layer's rotation in degrees. - </member> - <member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2( 1, 1 )"> + <member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)"> The layer's scale. </member> - <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, 1, 0, 0 )"> + <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D(1, 0, 0, 1, 0, 0)"> The layer's transform. </member> </members> diff --git a/doc/classes/CanvasModulate.xml b/doc/classes/CanvasModulate.xml index 19f8912cd8..3540fa423f 100644 --- a/doc/classes/CanvasModulate.xml +++ b/doc/classes/CanvasModulate.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> The tint color to apply. </member> </members> diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml index 0ca132746b..f7147d9f0b 100644 --- a/doc/classes/CanvasTexture.xml +++ b/doc/classes/CanvasTexture.xml @@ -13,7 +13,7 @@ </member> <member name="normal_texture" type="Texture2D" setter="set_normal_texture" getter="get_normal_texture"> </member> - <member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color( 1, 1, 1, 1 )"> + <member name="specular_color" type="Color" setter="set_specular_color" getter="get_specular_color" default="Color(1, 1, 1, 1)"> </member> <member name="specular_shininess" type="float" setter="set_specular_shininess" getter="get_specular_shininess" default="1.0"> </member> diff --git a/doc/classes/CharFXTransform.xml b/doc/classes/CharFXTransform.xml index 7b57dc05f8..1f63b530b1 100644 --- a/doc/classes/CharFXTransform.xml +++ b/doc/classes/CharFXTransform.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="CharFXTransform" inherits="Reference" version="4.0"> +<class name="CharFXTransform" inherits="RefCounted" version="4.0"> <brief_description> Controls how an individual character will be displayed in a [RichTextEffect]. </brief_description> @@ -13,7 +13,7 @@ <methods> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> The color the character will be drawn with. </member> <member name="elapsed_time" type="float" setter="set_elapsed_time" getter="get_elapsed_time" default="0.0"> @@ -33,13 +33,13 @@ <member name="glyph_index" type="int" setter="set_glyph_index" getter="get_glyph_index" default="0"> Font specific glyph index. </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The position offset the character will be drawn with (in pixels). </member> <member name="outline" type="bool" setter="set_outline" getter="is_outline" default="false"> If [code]true[/code], FX transform is called for outline drawing. Setting this property won't affect drawing. </member> - <member name="range" type="Vector2i" setter="set_range" getter="get_range" default="Vector2i( 0, 0 )"> + <member name="range" type="Vector2i" setter="set_range" getter="get_range" default="Vector2i(0, 0)"> Absolute character range in the string, corresponding to the glyph. Setting this property won't affect drawing. </member> <member name="visible" type="bool" setter="set_visibility" getter="is_visible" default="true"> diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml new file mode 100644 index 0000000000..b2d8aba174 --- /dev/null +++ b/doc/classes/CharacterBody2D.xml @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="CharacterBody2D" inherits="PhysicsBody2D" version="4.0"> + <brief_description> + Character body 2D node. + </brief_description> + <description> + Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a static body. However, they have two main uses: + [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. + [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [member StaticBody3D.kinematic_motion] when enabled), which allows them to be moved by code and push other bodies on their path. + </description> + <tutorials> + <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link> + <link title="Using KinematicBody2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_kinematic_body_2d.html</link> + <link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link> + <link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link> + </tutorials> + <methods> + <method name="get_floor_normal" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code]. + </description> + </method> + <method name="get_floor_velocity" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code]. + </description> + </method> + <method name="get_slide_collision"> + <return type="KinematicCollision2D"> + </return> + <argument index="0" name="slide_idx" type="int"> + </argument> + <description> + Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1). + [b]Example usage:[/b] + [codeblocks] + [gdscript] + for i in get_slide_count(): + var collision = get_slide_collision(i) + print("Collided with: ", collision.collider.name) + [/gdscript] + [csharp] + for (int i = 0; i < GetSlideCount(); i++) + { + KinematicCollision2D collision = GetSlideCollision(i); + GD.Print("Collided with: ", (collision.Collider as Node).Name); + } + [/csharp] + [/codeblocks] + </description> + </method> + <method name="get_slide_count" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the number of times the body collided and changed direction during the last call to [method move_and_slide]. + </description> + </method> + <method name="is_on_ceiling" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the body collided with the ceiling on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code]. + </description> + </method> + <method name="is_on_floor" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code]. + </description> + </method> + <method name="is_on_wall" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code]. + </description> + </method> + <method name="move_and_slide"> + <return type="void"> + </return> + <description> + Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. + This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. + Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision]. + </description> + </method> + </methods> + <members> + <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08"> + Extra margin used for collision recovery when calling [method move_and_slide]. + If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. + A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. + A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies. + </member> + <member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398"> + Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees. + </member> + <member name="infinite_inertia" type="bool" setter="set_infinite_inertia_enabled" getter="is_infinite_inertia_enabled" default="true"> + If [code]true[/code], the body will be able to push [RigidBody2D] nodes when calling [method move_and_slide], but it also won't detect any collisions with them. If [code]false[/code], it will interact with [RigidBody2D] nodes like with [StaticBody2D]. + </member> + <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)"> + Current velocity vector in pixels per second, used and modified during calls to [method move_and_slide]. + </member> + <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4"> + Maximum number of times the body can change direction before it stops when calling [method move_and_slide]. + </member> + <member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> + If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method PhysicsBody2D.move_and_collide] functions. + </member> + <member name="snap" type="Vector2" setter="set_snap" getter="get_snap" default="Vector2(0, 0)"> + When set to a value different from [code]Vector2(0, 0)[/code], the body is kept attached to slopes when calling [method move_and_slide]. + As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code]Vector2(0, 0)[/code]. + </member> + <member name="stop_on_slope" type="bool" setter="set_stop_on_slope_enabled" getter="is_stop_on_slope_enabled" default="false"> + If [code]true[/code], the body will not slide on slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still. + </member> + <member name="up_direction" type="Vector2" setter="set_up_direction" getter="get_up_direction" default="Vector2(0, -1)"> + Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector2.UP[/code]. If set to [code]Vector2(0, 0)[/code], everything is considered a wall. This is useful for topdown games. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml new file mode 100644 index 0000000000..c76e02fac0 --- /dev/null +++ b/doc/classes/CharacterBody3D.xml @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="CharacterBody3D" inherits="PhysicsBody3D" version="4.0"> + <brief_description> + Character body 3D node. + </brief_description> + <description> + Character bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a rigid body, these are the same as a static body. However, they have two main uses: + [b]Kinematic characters:[/b] Character bodies have an API for moving objects with walls and slopes detection ([method move_and_slide] method), in addition to collision detection (also done with [method PhysicsBody3D.move_and_collide]). This makes them really useful to implement characters that move in specific ways and collide with the world, but don't require advanced physics. + [b]Kinematic motion:[/b] Character bodies can also be used for kinematic motion (same functionality as [member StaticBody3D.kinematic_motion] when enabled), which allows them to be moved by code and push other bodies on their path. + </description> + <tutorials> + <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link> + <link title="3D Kinematic Character Demo">https://godotengine.org/asset-library/asset/126</link> + <link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link> + <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link> + <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> + </tutorials> + <methods> + <method name="get_floor_normal" qualifiers="const"> + <return type="Vector3"> + </return> + <description> + Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code]. + </description> + </method> + <method name="get_floor_velocity" qualifiers="const"> + <return type="Vector3"> + </return> + <description> + Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code]. + </description> + </method> + <method name="get_slide_collision"> + <return type="KinematicCollision3D"> + </return> + <argument index="0" name="slide_idx" type="int"> + </argument> + <description> + Returns a [KinematicCollision3D], which contains information about a collision that occurred during the last call to [method move_and_slide]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1). + </description> + </method> + <method name="get_slide_count" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the number of times the body collided and changed direction during the last call to [method move_and_slide]. + </description> + </method> + <method name="is_on_ceiling" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the body collided with the ceiling on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code]. + </description> + </method> + <method name="is_on_floor" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code]. + </description> + </method> + <method name="is_on_wall" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide]. Otherwise, returns [code]false[/code]. + </description> + </method> + <method name="move_and_slide"> + <return type="void"> + </return> + <description> + Moves the body based on [member linear_velocity]. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [CharacterBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. + This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. + Modifies [member linear_velocity] if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision]. + </description> + </method> + </methods> + <members> + <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001"> + Extra margin used for collision recovery when calling [method move_and_slide]. + If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. + A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. + A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of character bodies. + </member> + <member name="floor_max_angle" type="float" setter="set_floor_max_angle" getter="get_floor_max_angle" default="0.785398"> + Maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. The default value equals 45 degrees. + </member> + <member name="infinite_inertia" type="bool" setter="set_infinite_inertia_enabled" getter="is_infinite_inertia_enabled" default="true"> + If [code]true[/code], the body will be able to push [RigidBody3D] nodes when calling [method move_and_slide], but it also won't detect any collisions with them. If [code]false[/code], it will interact with [RigidBody3D] nodes like with [StaticBody3D]. + </member> + <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)"> + Current velocity vector (typically meters per second), used and modified during calls to [method move_and_slide]. + </member> + <member name="max_slides" type="int" setter="set_max_slides" getter="get_max_slides" default="4"> + Maximum number of times the body can change direction before it stops when calling [method move_and_slide]. + </member> + <member name="snap" type="Vector3" setter="set_snap" getter="get_snap" default="Vector3(0, 0, 0)"> + When set to a value different from [code]Vector3(0, 0, 0)[/code], the body is kept attached to slopes when calling [method move_and_slide]. + As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code]Vector3(0, 0, 0)[/code]. + </member> + <member name="stop_on_slope" type="bool" setter="set_stop_on_slope_enabled" getter="is_stop_on_slope_enabled" default="false"> + If [code]true[/code], the body will not slide on slopes when you include gravity in [code]linear_velocity[/code] when calling [method move_and_slide] and the body is standing still. + </member> + <member name="up_direction" type="Vector3" setter="set_up_direction" getter="get_up_direction" default="Vector3(0, 1, 0)"> + Direction vector used to determine what is a wall and what is a floor (or a ceiling), rather than a wall, when calling [method move_and_slide]. Defaults to [code]Vector3.UP[/code]. If set to [code]Vector3(0, 0, 0)[/code], everything is considered a wall. This is useful for topdown games. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/CheckBox.xml b/doc/classes/CheckBox.xml index 05e412e9da..90f3725172 100644 --- a/doc/classes/CheckBox.xml +++ b/doc/classes/CheckBox.xml @@ -35,22 +35,22 @@ <theme_item name="font" type="Font"> The [Font] to use for the [CheckBox] text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> The [CheckBox] text's font color. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.2)"> The [CheckBox] text's font color when it's disabled. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> The [CheckBox] text's font color when it's hovered. </theme_item> - <theme_item name="font_hover_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_hover_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> The [CheckBox] text's font color when it's hovered and pressed. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [CheckBox]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> The [CheckBox] text's font color when it's pressed. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/CheckButton.xml b/doc/classes/CheckButton.xml index 46e590a115..7fa7093b32 100644 --- a/doc/classes/CheckButton.xml +++ b/doc/classes/CheckButton.xml @@ -30,22 +30,22 @@ <theme_item name="font" type="Font"> The [Font] to use for the [CheckButton] text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> The [CheckButton] text's font color. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.2)"> The [CheckButton] text's font color when it's disabled. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> The [CheckButton] text's font color when it's hovered. </theme_item> - <theme_item name="font_hover_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_hover_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> The [CheckButton] text's font color when it's hovered and pressed. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [CheckButton]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> The [CheckButton] text's font color when it's pressed. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/ClassDB.xml b/doc/classes/ClassDB.xml index 860bdc7c8f..028781d313 100644 --- a/doc/classes/ClassDB.xml +++ b/doc/classes/ClassDB.xml @@ -9,7 +9,7 @@ <tutorials> </tutorials> <methods> - <method name="can_instance" qualifiers="const"> + <method name="can_instantiate" qualifiers="const"> <return type="bool"> </return> <argument index="0" name="class" type="StringName"> @@ -187,7 +187,7 @@ Returns the parent class of [code]class[/code]. </description> </method> - <method name="instance" qualifiers="const"> + <method name="instantiate" qualifiers="const"> <return type="Variant"> </return> <argument index="0" name="class" type="StringName"> diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml index 4076198df6..30fd47cdb6 100644 --- a/doc/classes/CodeEdit.xml +++ b/doc/classes/CodeEdit.xml @@ -45,7 +45,7 @@ </argument> <argument index="2" name="insert_text" type="String"> </argument> - <argument index="3" name="text_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="text_color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="4" name="icon" type="Resource" default="null"> </argument> @@ -86,6 +86,15 @@ Line only denotes if the region should continue until the end of the line or carry over on to the next line. If the end key is blank this is automatically set to [code]true[/code]. </description> </method> + <method name="can_fold_line" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Returns if the given line is foldable, that is, it has indented lines right below it or a comment / string block. + </description> + </method> <method name="cancel_code_completion"> <return type="void"> </return> @@ -134,6 +143,36 @@ Inserts the selected entry into the text. If [code]replace[/code] is true, any existing text is replaced rather then merged. </description> </method> + <method name="do_indent"> + <return type="void"> + </return> + <description> + Perform an indent as if the user activated the "ui_text_indent" action. + </description> + </method> + <method name="do_unindent"> + <return type="void"> + </return> + <description> + Perform an unindent as if the user activated the "ui_text_unindent" action. + </description> + </method> + <method name="fold_all_lines"> + <return type="void"> + </return> + <description> + Folds all lines that are possible to be folded (see [method can_fold_line]). + </description> + </method> + <method name="fold_line"> + <return type="void"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Folds the given line, if possible (see [method can_fold_line]). + </description> + </method> <method name="get_bookmarked_lines" qualifiers="const"> <return type="Array"> </return> @@ -184,7 +223,7 @@ Gets the end key for a string or comment region index. </description> </method> - <method name="get_delimiter_end_postion" qualifiers="const"> + <method name="get_delimiter_end_position" qualifiers="const"> <return type="Vector2"> </return> <argument index="0" name="line" type="int"> @@ -204,7 +243,7 @@ Gets the start key for a string or comment region index. </description> </method> - <method name="get_delimiter_start_postion" qualifiers="const"> + <method name="get_delimiter_start_position" qualifiers="const"> <return type="Vector2"> </return> <argument index="0" name="line" type="int"> @@ -221,6 +260,13 @@ <description> </description> </method> + <method name="get_folded_lines" qualifiers="const"> + <return type="int[]"> + </return> + <description> + Return all lines that are current folded. + </description> + </method> <method name="get_text_for_code_completion" qualifiers="const"> <return type="String"> </return> @@ -246,6 +292,13 @@ Returns [code]true[/code] if string [code]start_key[/code] exists. </description> </method> + <method name="indent_lines"> + <return type="void"> + </return> + <description> + Indents selected lines, or in the case of no selection the caret line by one. + </description> + </method> <method name="is_in_comment" qualifiers="const"> <return type="int"> </return> @@ -292,6 +345,15 @@ <description> </description> </method> + <method name="is_line_folded" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Returns whether the line at the specified index is folded or not. + </description> + </method> <method name="remove_comment_delimiter"> <return type="void"> </return> @@ -376,6 +438,37 @@ <description> </description> </method> + <method name="toggle_foldable_line"> + <return type="void"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Toggle the folding of the code block at the given line. + </description> + </method> + <method name="unfold_all_lines"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="unfold_line"> + <return type="void"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Unfolds all lines that were previously folded. + </description> + </method> + <method name="unindent_lines"> + <return type="void"> + </return> + <description> + Unindents selected lines, or in the case of no selection the caret line by one. + </description> + </method> <method name="update_code_completion_options"> <return type="void"> </return> @@ -391,13 +484,13 @@ <member name="code_completion_enabled" type="bool" setter="set_code_completion_enabled" getter="is_code_completion_enabled" default="false"> Sets whether code completion is allowed. </member> - <member name="code_completion_prefixes" type="String[]" setter="set_code_completion_prefixes" getter="get_code_comletion_prefixes" default="[ ]"> + <member name="code_completion_prefixes" type="String[]" setter="set_code_completion_prefixes" getter="get_code_comletion_prefixes" default="[]"> Sets prefixes that will trigger code completion. </member> - <member name="delimiter_comments" type="String[]" setter="set_comment_delimiters" getter="get_comment_delimiters" default="[ ]"> + <member name="delimiter_comments" type="String[]" setter="set_comment_delimiters" getter="get_comment_delimiters" default="[]"> Sets the comment delimiters. All existing comment delimiters will be removed. </member> - <member name="delimiter_strings" type="String[]" setter="set_string_delimiters" getter="get_string_delimiters" default="[ ]"> + <member name="delimiter_strings" type="String[]" setter="set_string_delimiters" getter="get_string_delimiters" default="[]"> Sets the string delimiters. All existing string delimiters will be removed. </member> <member name="draw_bookmarks" type="bool" setter="set_draw_bookmarks_gutter" getter="is_drawing_bookmarks_gutter" default="false"> @@ -410,8 +503,23 @@ </member> <member name="draw_line_numbers" type="bool" setter="set_draw_line_numbers" getter="is_draw_line_numbers_enabled" default="false"> </member> + <member name="indent_automatic" type="bool" setter="set_auto_indent_enabled" getter="is_auto_indent_enabled" default="false"> + Sets whether automatic indent are enabled, this will add an extra indent if a prefix or brace is found. + </member> + <member name="indent_automatic_prefixes" type="String[]" setter="set_auto_indent_prefixes" getter="get_auto_indent_prefixes" default="["(", ":", "[", "{"]"> + Prefixes to trigger an automatic indent. + </member> + <member name="indent_size" type="int" setter="set_indent_size" getter="get_indent_size" default="4"> + Size of tabs, if [code]indent_use_spaces[/code] is enabled the amount of spaces to use. + </member> + <member name="indent_use_spaces" type="bool" setter="set_indent_using_spaces" getter="is_indent_using_spaces" default="false"> + Use spaces instead of tabs for indentation. + </member> <member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" override="true" enum="Control.LayoutDirection" default="2" /> - <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" override="true" default="[ ]" /> + <member name="line_folding" type="bool" setter="set_line_folding_enabled" getter="is_line_folding_enabled" default="true"> + Sets whether line folding is allowed. + </member> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" override="true" default="[]" /> <member name="text_direction" type="int" setter="set_text_direction" getter="get_text_direction" override="true" enum="Control.TextDirection" default="1" /> <member name="zero_pad_line_numbers" type="bool" setter="set_line_numbers_zero_padded" getter="is_line_numbers_zero_padded" default="false"> </member> @@ -452,69 +560,71 @@ </constant> </constants> <theme_items> - <theme_item name="background_color" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="background_color" type="Color" default="Color(0, 0, 0, 0)"> </theme_item> <theme_item name="bookmark" type="Texture2D"> </theme_item> - <theme_item name="bookmark_color" type="Color" default="Color( 0.5, 0.64, 1, 0.8 )"> + <theme_item name="bookmark_color" type="Color" default="Color(0.5, 0.64, 1, 0.8)"> </theme_item> - <theme_item name="brace_mismatch_color" type="Color" default="Color( 1, 0.2, 0.2, 1 )"> + <theme_item name="brace_mismatch_color" type="Color" default="Color(1, 0.2, 0.2, 1)"> </theme_item> <theme_item name="breakpoint" type="Texture2D"> </theme_item> - <theme_item name="breakpoint_color" type="Color" default="Color( 0.9, 0.29, 0.3, 1 )"> + <theme_item name="breakpoint_color" type="Color" default="Color(0.9, 0.29, 0.3, 1)"> </theme_item> <theme_item name="can_fold" type="Texture2D"> </theme_item> - <theme_item name="caret_background_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="caret_background_color" type="Color" default="Color(0, 0, 0, 1)"> </theme_item> - <theme_item name="caret_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="caret_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> </theme_item> - <theme_item name="code_folding_color" type="Color" default="Color( 0.8, 0.8, 0.8, 0.8 )"> + <theme_item name="code_folding_color" type="Color" default="Color(0.8, 0.8, 0.8, 0.8)"> </theme_item> <theme_item name="completion" type="StyleBox"> </theme_item> - <theme_item name="completion_background_color" type="Color" default="Color( 0.17, 0.16, 0.2, 1 )"> + <theme_item name="completion_background_color" type="Color" default="Color(0.17, 0.16, 0.2, 1)"> </theme_item> - <theme_item name="completion_existing_color" type="Color" default="Color( 0.87, 0.87, 0.87, 0.13 )"> + <theme_item name="completion_existing_color" type="Color" default="Color(0.87, 0.87, 0.87, 0.13)"> </theme_item> - <theme_item name="completion_font_color" type="Color" default="Color( 0.67, 0.67, 0.67, 1 )"> + <theme_item name="completion_font_color" type="Color" default="Color(0.67, 0.67, 0.67, 1)"> </theme_item> <theme_item name="completion_lines" type="int" default="7"> </theme_item> <theme_item name="completion_max_width" type="int" default="50"> </theme_item> - <theme_item name="completion_scroll_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="completion_scroll_color" type="Color" default="Color(1, 1, 1, 1)"> </theme_item> <theme_item name="completion_scroll_width" type="int" default="3"> </theme_item> - <theme_item name="completion_selected_color" type="Color" default="Color( 0.26, 0.26, 0.27, 1 )"> + <theme_item name="completion_selected_color" type="Color" default="Color(0.26, 0.26, 0.27, 1)"> </theme_item> - <theme_item name="current_line_color" type="Color" default="Color( 0.25, 0.25, 0.26, 0.8 )"> + <theme_item name="current_line_color" type="Color" default="Color(0.25, 0.25, 0.26, 0.8)"> </theme_item> <theme_item name="executing_line" type="Texture2D"> </theme_item> - <theme_item name="executing_line_color" type="Color" default="Color( 0.98, 0.89, 0.27, 1 )"> + <theme_item name="executing_line_color" type="Color" default="Color(0.98, 0.89, 0.27, 1)"> </theme_item> <theme_item name="focus" type="StyleBox"> </theme_item> <theme_item name="folded" type="Texture2D"> </theme_item> + <theme_item name="folded_eol_icon" type="Texture2D"> + </theme_item> <theme_item name="font" type="Font"> </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [CodeEdit]. </theme_item> - <theme_item name="font_readonly_color" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )"> + <theme_item name="font_readonly_color" type="Color" default="Color(0.88, 0.88, 0.88, 0.5)"> </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(0, 0, 0, 1)"> </theme_item> <theme_item name="font_size" type="int"> Font size of the [CodeEdit]'s text. </theme_item> - <theme_item name="line_number_color" type="Color" default="Color( 0.67, 0.67, 0.67, 0.4 )"> + <theme_item name="line_number_color" type="Color" default="Color(0.67, 0.67, 0.67, 0.4)"> </theme_item> <theme_item name="line_spacing" type="int" default="4"> </theme_item> @@ -525,15 +635,15 @@ </theme_item> <theme_item name="read_only" type="StyleBox"> </theme_item> - <theme_item name="safe_line_number_color" type="Color" default="Color( 0.67, 0.78, 0.67, 0.6 )"> + <theme_item name="safe_line_number_color" type="Color" default="Color(0.67, 0.78, 0.67, 0.6)"> </theme_item> - <theme_item name="selection_color" type="Color" default="Color( 0.49, 0.49, 0.49, 1 )"> + <theme_item name="selection_color" type="Color" default="Color(0.49, 0.49, 0.49, 1)"> </theme_item> <theme_item name="space" type="Texture2D"> </theme_item> <theme_item name="tab" type="Texture2D"> </theme_item> - <theme_item name="word_highlighted_color" type="Color" default="Color( 0.8, 0.9, 0.9, 0.15 )"> + <theme_item name="word_highlighted_color" type="Color" default="Color(0.8, 0.9, 0.9, 0.15)"> </theme_item> </theme_items> </class> diff --git a/doc/classes/CodeHighlighter.xml b/doc/classes/CodeHighlighter.xml index f078e4e5b0..0406c25ffd 100644 --- a/doc/classes/CodeHighlighter.xml +++ b/doc/classes/CodeHighlighter.xml @@ -149,7 +149,7 @@ <member name="color_regions" type="Dictionary" setter="set_color_regions" getter="get_color_regions" default="{}"> Sets the color regions. All existing regions will be removed. The [Dictionary] key is the region start and end key, separated by a space. The value is the region color. </member> - <member name="function_color" type="Color" setter="set_function_color" getter="get_function_color" default="Color( 0, 0, 0, 1 )"> + <member name="function_color" type="Color" setter="set_function_color" getter="get_function_color" default="Color(0, 0, 0, 1)"> Sets color for functions. A function is a non-keyword string followed by a '('. </member> <member name="keyword_colors" type="Dictionary" setter="set_keyword_colors" getter="get_keyword_colors" default="{}"> @@ -158,13 +158,13 @@ <member name="member_keyword_colors" type="Dictionary" setter="set_member_keyword_colors" getter="get_member_keyword_colors" default="{}"> Sets the member keyword colors. All existing member keyword will be removed. The [Dictionary] key is the member keyword. The value is the member keyword color. </member> - <member name="member_variable_color" type="Color" setter="set_member_variable_color" getter="get_member_variable_color" default="Color( 0, 0, 0, 1 )"> + <member name="member_variable_color" type="Color" setter="set_member_variable_color" getter="get_member_variable_color" default="Color(0, 0, 0, 1)"> Sets color for member variables. A member variable is non-keyword, non-function string proceeded with a '.'. </member> - <member name="number_color" type="Color" setter="set_number_color" getter="get_number_color" default="Color( 0, 0, 0, 1 )"> + <member name="number_color" type="Color" setter="set_number_color" getter="get_number_color" default="Color(0, 0, 0, 1)"> Sets the color for numbers. </member> - <member name="symbol_color" type="Color" setter="set_symbol_color" getter="get_symbol_color" default="Color( 0, 0, 0, 1 )"> + <member name="symbol_color" type="Color" setter="set_symbol_color" getter="get_symbol_color" default="Color(0, 0, 0, 1)"> Sets the color for symbols. </member> </members> diff --git a/doc/classes/CollisionObject2D.xml b/doc/classes/CollisionObject2D.xml index 7c4c75bf0f..e96124c9eb 100644 --- a/doc/classes/CollisionObject2D.xml +++ b/doc/classes/CollisionObject2D.xml @@ -266,6 +266,9 @@ The physics layers this CollisionObject2D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer]. [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> + <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject2D.DisableMode" default="0"> + Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes. + </member> <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" default="true"> If [code]true[/code], this object is pickable. A pickable object can detect the mouse pointer entering/leaving, and if the mouse is inside it, report input events. Requires at least one [code]collision_layer[/code] bit to be set. </member> @@ -294,5 +297,16 @@ </signal> </signals> <constants> + <constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [CollisionObject2D]. + Automatically re-added to the physics simulation when the [Node] is processed again. + </constant> + <constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody2D] can't be affected by forces or other bodies while static. + Automatically set [PhysicsBody2D] back to its original mode when the [Node] is processed again. + </constant> + <constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation. + </constant> </constants> </class> diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml index 522eec5cbe..dfd1e85e56 100644 --- a/doc/classes/CollisionObject3D.xml +++ b/doc/classes/CollisionObject3D.xml @@ -16,14 +16,14 @@ </argument> <argument index="1" name="event" type="InputEvent"> </argument> - <argument index="2" name="click_position" type="Vector3"> + <argument index="2" name="position" type="Vector3"> </argument> - <argument index="3" name="click_normal" type="Vector3"> + <argument index="3" name="normal" type="Vector3"> </argument> <argument index="4" name="shape_idx" type="int"> </argument> <description> - Accepts unhandled [InputEvent]s. [code]click_position[/code] is the clicked location in world space and [code]click_normal[/code] is the normal vector extending from the clicked surface of the [Shape3D] at [code]shape_idx[/code]. Connect to the [code]input_event[/code] signal to easily pick up these events. + Receives unhandled [InputEvent]s. [code]position[/code] is the location in world space of the mouse pointer on the surface of the shape with index [code]shape_idx[/code] and [code]normal[/code] is the normal vector of the surface at that point. Connect to the [signal input_event] signal to easily pick up these events. </description> </method> <method name="create_shape_owner"> @@ -179,12 +179,12 @@ </description> </method> <method name="shape_owner_get_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="owner_id" type="int"> </argument> <description> - Returns the shape owner's [Transform]. + Returns the shape owner's [Transform3D]. </description> </method> <method name="shape_owner_remove_shape"> @@ -214,10 +214,10 @@ </return> <argument index="0" name="owner_id" type="int"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> - Sets the [Transform] of the given shape owner. + Sets the [Transform3D] of the given shape owner. </description> </method> </methods> @@ -230,6 +230,9 @@ The physics layers this CollisionObject3D scans. Collision objects can scan one or more of 32 different layers. See also [member collision_layer]. [b]Note:[/b] A contact is detected if object A is in any of the layers that object B scans, or object B is in any layers that object A scans. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> + <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="CollisionObject3D.DisableMode" default="0"> + Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes. + </member> <member name="input_capture_on_drag" type="bool" setter="set_capture_input_on_drag" getter="get_capture_input_on_drag" default="false"> If [code]true[/code], the [CollisionObject3D] will continue to receive input events as the mouse is dragged across its shapes. </member> @@ -243,14 +246,14 @@ </argument> <argument index="1" name="event" type="InputEvent"> </argument> - <argument index="2" name="click_position" type="Vector3"> + <argument index="2" name="position" type="Vector3"> </argument> - <argument index="3" name="click_normal" type="Vector3"> + <argument index="3" name="normal" type="Vector3"> </argument> <argument index="4" name="shape_idx" type="int"> </argument> <description> - Emitted when [method _input_event] receives an event. See its description for details. + Emitted when the object receives an unhandled [InputEvent]. [code]position[/code] is the location in world space of the mouse pointer on the surface of the shape with index [code]shape_idx[/code] and [code]normal[/code] is the normal vector of the surface at that point. </description> </signal> <signal name="mouse_entered"> @@ -265,5 +268,16 @@ </signal> </signals> <constants> + <constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [CollisionObject3D]. + Automatically re-added to the physics simulation when the [Node] is processed again. + </constant> + <constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody3D] can't be affected by forces or other bodies while static. + Automatically set [PhysicsBody3D] back to its original mode when the [Node] is processed again. + </constant> + <constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation. + </constant> </constants> </class> diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml index 242cdb8c80..4607ab3fbd 100644 --- a/doc/classes/CollisionPolygon2D.xml +++ b/doc/classes/CollisionPolygon2D.xml @@ -23,7 +23,7 @@ <member name="one_way_collision_margin" type="float" setter="set_one_way_collision_margin" getter="get_one_way_collision_margin" default="1.0"> The margin used for one-way collision (in pixels). Higher values will make the shape thicker, and work better for colliders that enter the polygon at a high velocity. </member> - <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( )"> + <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array()"> The polygon's list of vertices. The final point will be connected to the first. The returned value is a clone of the [PackedVector2Array], not a reference. </member> </members> diff --git a/doc/classes/CollisionPolygon3D.xml b/doc/classes/CollisionPolygon3D.xml index 38f4c5fe5c..cf0e55e712 100644 --- a/doc/classes/CollisionPolygon3D.xml +++ b/doc/classes/CollisionPolygon3D.xml @@ -20,7 +20,7 @@ <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04"> The collision margin for the generated [Shape3D]. See [member Shape3D.margin] for more details. </member> - <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( )"> + <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array()"> Array of vertices which define the polygon. [b]Note:[/b] The returned value is a copy of the original. Methods which mutate the size or properties of the return value will not impact the original polygon. To change properties of the polygon, assign it to a temporary variable and make changes before reassigning the [code]polygon[/code] member. </member> diff --git a/doc/classes/Color.xml b/doc/classes/Color.xml index ddff92e6fc..7b1415e40d 100644 --- a/doc/classes/Color.xml +++ b/doc/classes/Color.xml @@ -80,14 +80,16 @@ </argument> <argument index="2" name="b" type="float"> </argument> + <argument index="3" name="a" type="float"> + </argument> <description> - Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1. + Constructs a [Color] from RGBA values, typically between 0 and 1. [codeblocks] [gdscript] - var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)` + var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)` [/gdscript] [csharp] - var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)` + var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)` [/csharp] [/codeblocks] </description> @@ -101,16 +103,14 @@ </argument> <argument index="2" name="b" type="float"> </argument> - <argument index="3" name="a" type="float"> - </argument> <description> - Constructs a [Color] from RGBA values, typically between 0 and 1. + Constructs a [Color] from RGB values, typically between 0 and 1. Alpha will be 1. [codeblocks] [gdscript] - var color = Color(0.2, 1.0, 0.7, 0.8) # Similar to `Color8(51, 255, 178, 204)` + var color = Color(0.2, 1.0, 0.7) # Similar to `Color8(51, 255, 178, 255)` [/gdscript] [csharp] - var color = new Color(0.2f, 1.0f, 0.7f, 0.8f); // Similar to `Color.Color8(51, 255, 178, 255, 204)` + var color = new Color(0.2f, 1.0f, 0.7f); // Similar to `Color.Color8(51, 255, 178, 255)` [/csharp] [/codeblocks] </description> @@ -139,9 +139,9 @@ <method name="clamp" qualifiers="const"> <return type="Color"> </return> - <argument index="0" name="min" type="Color" default="Color( 0, 0, 0, 0 )"> + <argument index="0" name="min" type="Color" default="Color(0, 0, 0, 0)"> </argument> - <argument index="1" name="max" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="1" name="max" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Returns a new color with all components clamped between the components of [code]min[/code] and [code]max[/code], by running [method @GlobalScope.clamp] on each component. @@ -349,12 +349,6 @@ <method name="operator +" qualifiers="operator"> <return type="Color"> </return> - <description> - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="Color"> - </return> <argument index="0" name="right" type="Color"> </argument> <description> @@ -363,12 +357,6 @@ <method name="operator -" qualifiers="operator"> <return type="Color"> </return> - <description> - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="Color"> - </return> <argument index="0" name="right" type="Color"> </argument> <description> @@ -414,6 +402,18 @@ <description> </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="Color"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="Color"> + </return> + <description> + </description> + </method> <method name="to_abgr32" qualifiers="const"> <return type="int"> </return> @@ -575,442 +575,442 @@ </member> </members> <constants> - <constant name="ALICE_BLUE" value="Color( 0.94, 0.97, 1, 1 )"> + <constant name="ALICE_BLUE" value="Color(0.94, 0.97, 1, 1)"> Alice blue color. </constant> - <constant name="ANTIQUE_WHITE" value="Color( 0.98, 0.92, 0.84, 1 )"> + <constant name="ANTIQUE_WHITE" value="Color(0.98, 0.92, 0.84, 1)"> Antique white color. </constant> - <constant name="AQUA" value="Color( 0, 1, 1, 1 )"> + <constant name="AQUA" value="Color(0, 1, 1, 1)"> Aqua color. </constant> - <constant name="AQUAMARINE" value="Color( 0.5, 1, 0.83, 1 )"> + <constant name="AQUAMARINE" value="Color(0.5, 1, 0.83, 1)"> Aquamarine color. </constant> - <constant name="AZURE" value="Color( 0.94, 1, 1, 1 )"> + <constant name="AZURE" value="Color(0.94, 1, 1, 1)"> Azure color. </constant> - <constant name="BEIGE" value="Color( 0.96, 0.96, 0.86, 1 )"> + <constant name="BEIGE" value="Color(0.96, 0.96, 0.86, 1)"> Beige color. </constant> - <constant name="BISQUE" value="Color( 1, 0.89, 0.77, 1 )"> + <constant name="BISQUE" value="Color(1, 0.89, 0.77, 1)"> Bisque color. </constant> - <constant name="BLACK" value="Color( 0, 0, 0, 1 )"> + <constant name="BLACK" value="Color(0, 0, 0, 1)"> Black color. </constant> - <constant name="BLANCHED_ALMOND" value="Color( 1, 0.92, 0.8, 1 )"> + <constant name="BLANCHED_ALMOND" value="Color(1, 0.92, 0.8, 1)"> Blanched almond color. </constant> - <constant name="BLUE" value="Color( 0, 0, 1, 1 )"> + <constant name="BLUE" value="Color(0, 0, 1, 1)"> Blue color. </constant> - <constant name="BLUE_VIOLET" value="Color( 0.54, 0.17, 0.89, 1 )"> + <constant name="BLUE_VIOLET" value="Color(0.54, 0.17, 0.89, 1)"> Blue violet color. </constant> - <constant name="BROWN" value="Color( 0.65, 0.16, 0.16, 1 )"> + <constant name="BROWN" value="Color(0.65, 0.16, 0.16, 1)"> Brown color. </constant> - <constant name="BURLYWOOD" value="Color( 0.87, 0.72, 0.53, 1 )"> + <constant name="BURLYWOOD" value="Color(0.87, 0.72, 0.53, 1)"> Burlywood color. </constant> - <constant name="CADET_BLUE" value="Color( 0.37, 0.62, 0.63, 1 )"> + <constant name="CADET_BLUE" value="Color(0.37, 0.62, 0.63, 1)"> Cadet blue color. </constant> - <constant name="CHARTREUSE" value="Color( 0.5, 1, 0, 1 )"> + <constant name="CHARTREUSE" value="Color(0.5, 1, 0, 1)"> Chartreuse color. </constant> - <constant name="CHOCOLATE" value="Color( 0.82, 0.41, 0.12, 1 )"> + <constant name="CHOCOLATE" value="Color(0.82, 0.41, 0.12, 1)"> Chocolate color. </constant> - <constant name="CORAL" value="Color( 1, 0.5, 0.31, 1 )"> + <constant name="CORAL" value="Color(1, 0.5, 0.31, 1)"> Coral color. </constant> - <constant name="CORNFLOWER_BLUE" value="Color( 0.39, 0.58, 0.93, 1 )"> + <constant name="CORNFLOWER_BLUE" value="Color(0.39, 0.58, 0.93, 1)"> Cornflower blue color. </constant> - <constant name="CORNSILK" value="Color( 1, 0.97, 0.86, 1 )"> + <constant name="CORNSILK" value="Color(1, 0.97, 0.86, 1)"> Cornsilk color. </constant> - <constant name="CRIMSON" value="Color( 0.86, 0.08, 0.24, 1 )"> + <constant name="CRIMSON" value="Color(0.86, 0.08, 0.24, 1)"> Crimson color. </constant> - <constant name="CYAN" value="Color( 0, 1, 1, 1 )"> + <constant name="CYAN" value="Color(0, 1, 1, 1)"> Cyan color. </constant> - <constant name="DARK_BLUE" value="Color( 0, 0, 0.55, 1 )"> + <constant name="DARK_BLUE" value="Color(0, 0, 0.55, 1)"> Dark blue color. </constant> - <constant name="DARK_CYAN" value="Color( 0, 0.55, 0.55, 1 )"> + <constant name="DARK_CYAN" value="Color(0, 0.55, 0.55, 1)"> Dark cyan color. </constant> - <constant name="DARK_GOLDENROD" value="Color( 0.72, 0.53, 0.04, 1 )"> + <constant name="DARK_GOLDENROD" value="Color(0.72, 0.53, 0.04, 1)"> Dark goldenrod color. </constant> - <constant name="DARK_GRAY" value="Color( 0.66, 0.66, 0.66, 1 )"> + <constant name="DARK_GRAY" value="Color(0.66, 0.66, 0.66, 1)"> Dark gray color. </constant> - <constant name="DARK_GREEN" value="Color( 0, 0.39, 0, 1 )"> + <constant name="DARK_GREEN" value="Color(0, 0.39, 0, 1)"> Dark green color. </constant> - <constant name="DARK_KHAKI" value="Color( 0.74, 0.72, 0.42, 1 )"> + <constant name="DARK_KHAKI" value="Color(0.74, 0.72, 0.42, 1)"> Dark khaki color. </constant> - <constant name="DARK_MAGENTA" value="Color( 0.55, 0, 0.55, 1 )"> + <constant name="DARK_MAGENTA" value="Color(0.55, 0, 0.55, 1)"> Dark magenta color. </constant> - <constant name="DARK_OLIVE_GREEN" value="Color( 0.33, 0.42, 0.18, 1 )"> + <constant name="DARK_OLIVE_GREEN" value="Color(0.33, 0.42, 0.18, 1)"> Dark olive green color. </constant> - <constant name="DARK_ORANGE" value="Color( 1, 0.55, 0, 1 )"> + <constant name="DARK_ORANGE" value="Color(1, 0.55, 0, 1)"> Dark orange color. </constant> - <constant name="DARK_ORCHID" value="Color( 0.6, 0.2, 0.8, 1 )"> + <constant name="DARK_ORCHID" value="Color(0.6, 0.2, 0.8, 1)"> Dark orchid color. </constant> - <constant name="DARK_RED" value="Color( 0.55, 0, 0, 1 )"> + <constant name="DARK_RED" value="Color(0.55, 0, 0, 1)"> Dark red color. </constant> - <constant name="DARK_SALMON" value="Color( 0.91, 0.59, 0.48, 1 )"> + <constant name="DARK_SALMON" value="Color(0.91, 0.59, 0.48, 1)"> Dark salmon color. </constant> - <constant name="DARK_SEA_GREEN" value="Color( 0.56, 0.74, 0.56, 1 )"> + <constant name="DARK_SEA_GREEN" value="Color(0.56, 0.74, 0.56, 1)"> Dark sea green color. </constant> - <constant name="DARK_SLATE_BLUE" value="Color( 0.28, 0.24, 0.55, 1 )"> + <constant name="DARK_SLATE_BLUE" value="Color(0.28, 0.24, 0.55, 1)"> Dark slate blue color. </constant> - <constant name="DARK_SLATE_GRAY" value="Color( 0.18, 0.31, 0.31, 1 )"> + <constant name="DARK_SLATE_GRAY" value="Color(0.18, 0.31, 0.31, 1)"> Dark slate gray color. </constant> - <constant name="DARK_TURQUOISE" value="Color( 0, 0.81, 0.82, 1 )"> + <constant name="DARK_TURQUOISE" value="Color(0, 0.81, 0.82, 1)"> Dark turquoise color. </constant> - <constant name="DARK_VIOLET" value="Color( 0.58, 0, 0.83, 1 )"> + <constant name="DARK_VIOLET" value="Color(0.58, 0, 0.83, 1)"> Dark violet color. </constant> - <constant name="DEEP_PINK" value="Color( 1, 0.08, 0.58, 1 )"> + <constant name="DEEP_PINK" value="Color(1, 0.08, 0.58, 1)"> Deep pink color. </constant> - <constant name="DEEP_SKY_BLUE" value="Color( 0, 0.75, 1, 1 )"> + <constant name="DEEP_SKY_BLUE" value="Color(0, 0.75, 1, 1)"> Deep sky blue color. </constant> - <constant name="DIM_GRAY" value="Color( 0.41, 0.41, 0.41, 1 )"> + <constant name="DIM_GRAY" value="Color(0.41, 0.41, 0.41, 1)"> Dim gray color. </constant> - <constant name="DODGER_BLUE" value="Color( 0.12, 0.56, 1, 1 )"> + <constant name="DODGER_BLUE" value="Color(0.12, 0.56, 1, 1)"> Dodger blue color. </constant> - <constant name="FIREBRICK" value="Color( 0.7, 0.13, 0.13, 1 )"> + <constant name="FIREBRICK" value="Color(0.7, 0.13, 0.13, 1)"> Firebrick color. </constant> - <constant name="FLORAL_WHITE" value="Color( 1, 0.98, 0.94, 1 )"> + <constant name="FLORAL_WHITE" value="Color(1, 0.98, 0.94, 1)"> Floral white color. </constant> - <constant name="FOREST_GREEN" value="Color( 0.13, 0.55, 0.13, 1 )"> + <constant name="FOREST_GREEN" value="Color(0.13, 0.55, 0.13, 1)"> Forest green color. </constant> - <constant name="FUCHSIA" value="Color( 1, 0, 1, 1 )"> + <constant name="FUCHSIA" value="Color(1, 0, 1, 1)"> Fuchsia color. </constant> - <constant name="GAINSBORO" value="Color( 0.86, 0.86, 0.86, 1 )"> + <constant name="GAINSBORO" value="Color(0.86, 0.86, 0.86, 1)"> Gainsboro color. </constant> - <constant name="GHOST_WHITE" value="Color( 0.97, 0.97, 1, 1 )"> + <constant name="GHOST_WHITE" value="Color(0.97, 0.97, 1, 1)"> Ghost white color. </constant> - <constant name="GOLD" value="Color( 1, 0.84, 0, 1 )"> + <constant name="GOLD" value="Color(1, 0.84, 0, 1)"> Gold color. </constant> - <constant name="GOLDENROD" value="Color( 0.85, 0.65, 0.13, 1 )"> + <constant name="GOLDENROD" value="Color(0.85, 0.65, 0.13, 1)"> Goldenrod color. </constant> - <constant name="GRAY" value="Color( 0.75, 0.75, 0.75, 1 )"> + <constant name="GRAY" value="Color(0.75, 0.75, 0.75, 1)"> Gray color. </constant> - <constant name="GREEN" value="Color( 0, 1, 0, 1 )"> + <constant name="GREEN" value="Color(0, 1, 0, 1)"> Green color. </constant> - <constant name="GREEN_YELLOW" value="Color( 0.68, 1, 0.18, 1 )"> + <constant name="GREEN_YELLOW" value="Color(0.68, 1, 0.18, 1)"> Green yellow color. </constant> - <constant name="HONEYDEW" value="Color( 0.94, 1, 0.94, 1 )"> + <constant name="HONEYDEW" value="Color(0.94, 1, 0.94, 1)"> Honeydew color. </constant> - <constant name="HOT_PINK" value="Color( 1, 0.41, 0.71, 1 )"> + <constant name="HOT_PINK" value="Color(1, 0.41, 0.71, 1)"> Hot pink color. </constant> - <constant name="INDIAN_RED" value="Color( 0.8, 0.36, 0.36, 1 )"> + <constant name="INDIAN_RED" value="Color(0.8, 0.36, 0.36, 1)"> Indian red color. </constant> - <constant name="INDIGO" value="Color( 0.29, 0, 0.51, 1 )"> + <constant name="INDIGO" value="Color(0.29, 0, 0.51, 1)"> Indigo color. </constant> - <constant name="IVORY" value="Color( 1, 1, 0.94, 1 )"> + <constant name="IVORY" value="Color(1, 1, 0.94, 1)"> Ivory color. </constant> - <constant name="KHAKI" value="Color( 0.94, 0.9, 0.55, 1 )"> + <constant name="KHAKI" value="Color(0.94, 0.9, 0.55, 1)"> Khaki color. </constant> - <constant name="LAVENDER" value="Color( 0.9, 0.9, 0.98, 1 )"> + <constant name="LAVENDER" value="Color(0.9, 0.9, 0.98, 1)"> Lavender color. </constant> - <constant name="LAVENDER_BLUSH" value="Color( 1, 0.94, 0.96, 1 )"> + <constant name="LAVENDER_BLUSH" value="Color(1, 0.94, 0.96, 1)"> Lavender blush color. </constant> - <constant name="LAWN_GREEN" value="Color( 0.49, 0.99, 0, 1 )"> + <constant name="LAWN_GREEN" value="Color(0.49, 0.99, 0, 1)"> Lawn green color. </constant> - <constant name="LEMON_CHIFFON" value="Color( 1, 0.98, 0.8, 1 )"> + <constant name="LEMON_CHIFFON" value="Color(1, 0.98, 0.8, 1)"> Lemon chiffon color. </constant> - <constant name="LIGHT_BLUE" value="Color( 0.68, 0.85, 0.9, 1 )"> + <constant name="LIGHT_BLUE" value="Color(0.68, 0.85, 0.9, 1)"> Light blue color. </constant> - <constant name="LIGHT_CORAL" value="Color( 0.94, 0.5, 0.5, 1 )"> + <constant name="LIGHT_CORAL" value="Color(0.94, 0.5, 0.5, 1)"> Light coral color. </constant> - <constant name="LIGHT_CYAN" value="Color( 0.88, 1, 1, 1 )"> + <constant name="LIGHT_CYAN" value="Color(0.88, 1, 1, 1)"> Light cyan color. </constant> - <constant name="LIGHT_GOLDENROD" value="Color( 0.98, 0.98, 0.82, 1 )"> + <constant name="LIGHT_GOLDENROD" value="Color(0.98, 0.98, 0.82, 1)"> Light goldenrod color. </constant> - <constant name="LIGHT_GRAY" value="Color( 0.83, 0.83, 0.83, 1 )"> + <constant name="LIGHT_GRAY" value="Color(0.83, 0.83, 0.83, 1)"> Light gray color. </constant> - <constant name="LIGHT_GREEN" value="Color( 0.56, 0.93, 0.56, 1 )"> + <constant name="LIGHT_GREEN" value="Color(0.56, 0.93, 0.56, 1)"> Light green color. </constant> - <constant name="LIGHT_PINK" value="Color( 1, 0.71, 0.76, 1 )"> + <constant name="LIGHT_PINK" value="Color(1, 0.71, 0.76, 1)"> Light pink color. </constant> - <constant name="LIGHT_SALMON" value="Color( 1, 0.63, 0.48, 1 )"> + <constant name="LIGHT_SALMON" value="Color(1, 0.63, 0.48, 1)"> Light salmon color. </constant> - <constant name="LIGHT_SEA_GREEN" value="Color( 0.13, 0.7, 0.67, 1 )"> + <constant name="LIGHT_SEA_GREEN" value="Color(0.13, 0.7, 0.67, 1)"> Light sea green color. </constant> - <constant name="LIGHT_SKY_BLUE" value="Color( 0.53, 0.81, 0.98, 1 )"> + <constant name="LIGHT_SKY_BLUE" value="Color(0.53, 0.81, 0.98, 1)"> Light sky blue color. </constant> - <constant name="LIGHT_SLATE_GRAY" value="Color( 0.47, 0.53, 0.6, 1 )"> + <constant name="LIGHT_SLATE_GRAY" value="Color(0.47, 0.53, 0.6, 1)"> Light slate gray color. </constant> - <constant name="LIGHT_STEEL_BLUE" value="Color( 0.69, 0.77, 0.87, 1 )"> + <constant name="LIGHT_STEEL_BLUE" value="Color(0.69, 0.77, 0.87, 1)"> Light steel blue color. </constant> - <constant name="LIGHT_YELLOW" value="Color( 1, 1, 0.88, 1 )"> + <constant name="LIGHT_YELLOW" value="Color(1, 1, 0.88, 1)"> Light yellow color. </constant> - <constant name="LIME" value="Color( 0, 1, 0, 1 )"> + <constant name="LIME" value="Color(0, 1, 0, 1)"> Lime color. </constant> - <constant name="LIME_GREEN" value="Color( 0.2, 0.8, 0.2, 1 )"> + <constant name="LIME_GREEN" value="Color(0.2, 0.8, 0.2, 1)"> Lime green color. </constant> - <constant name="LINEN" value="Color( 0.98, 0.94, 0.9, 1 )"> + <constant name="LINEN" value="Color(0.98, 0.94, 0.9, 1)"> Linen color. </constant> - <constant name="MAGENTA" value="Color( 1, 0, 1, 1 )"> + <constant name="MAGENTA" value="Color(1, 0, 1, 1)"> Magenta color. </constant> - <constant name="MAROON" value="Color( 0.69, 0.19, 0.38, 1 )"> + <constant name="MAROON" value="Color(0.69, 0.19, 0.38, 1)"> Maroon color. </constant> - <constant name="MEDIUM_AQUAMARINE" value="Color( 0.4, 0.8, 0.67, 1 )"> + <constant name="MEDIUM_AQUAMARINE" value="Color(0.4, 0.8, 0.67, 1)"> Medium aquamarine color. </constant> - <constant name="MEDIUM_BLUE" value="Color( 0, 0, 0.8, 1 )"> + <constant name="MEDIUM_BLUE" value="Color(0, 0, 0.8, 1)"> Medium blue color. </constant> - <constant name="MEDIUM_ORCHID" value="Color( 0.73, 0.33, 0.83, 1 )"> + <constant name="MEDIUM_ORCHID" value="Color(0.73, 0.33, 0.83, 1)"> Medium orchid color. </constant> - <constant name="MEDIUM_PURPLE" value="Color( 0.58, 0.44, 0.86, 1 )"> + <constant name="MEDIUM_PURPLE" value="Color(0.58, 0.44, 0.86, 1)"> Medium purple color. </constant> - <constant name="MEDIUM_SEA_GREEN" value="Color( 0.24, 0.7, 0.44, 1 )"> + <constant name="MEDIUM_SEA_GREEN" value="Color(0.24, 0.7, 0.44, 1)"> Medium sea green color. </constant> - <constant name="MEDIUM_SLATE_BLUE" value="Color( 0.48, 0.41, 0.93, 1 )"> + <constant name="MEDIUM_SLATE_BLUE" value="Color(0.48, 0.41, 0.93, 1)"> Medium slate blue color. </constant> - <constant name="MEDIUM_SPRING_GREEN" value="Color( 0, 0.98, 0.6, 1 )"> + <constant name="MEDIUM_SPRING_GREEN" value="Color(0, 0.98, 0.6, 1)"> Medium spring green color. </constant> - <constant name="MEDIUM_TURQUOISE" value="Color( 0.28, 0.82, 0.8, 1 )"> + <constant name="MEDIUM_TURQUOISE" value="Color(0.28, 0.82, 0.8, 1)"> Medium turquoise color. </constant> - <constant name="MEDIUM_VIOLET_RED" value="Color( 0.78, 0.08, 0.52, 1 )"> + <constant name="MEDIUM_VIOLET_RED" value="Color(0.78, 0.08, 0.52, 1)"> Medium violet red color. </constant> - <constant name="MIDNIGHT_BLUE" value="Color( 0.1, 0.1, 0.44, 1 )"> + <constant name="MIDNIGHT_BLUE" value="Color(0.1, 0.1, 0.44, 1)"> Midnight blue color. </constant> - <constant name="MINT_CREAM" value="Color( 0.96, 1, 0.98, 1 )"> + <constant name="MINT_CREAM" value="Color(0.96, 1, 0.98, 1)"> Mint cream color. </constant> - <constant name="MISTY_ROSE" value="Color( 1, 0.89, 0.88, 1 )"> + <constant name="MISTY_ROSE" value="Color(1, 0.89, 0.88, 1)"> Misty rose color. </constant> - <constant name="MOCCASIN" value="Color( 1, 0.89, 0.71, 1 )"> + <constant name="MOCCASIN" value="Color(1, 0.89, 0.71, 1)"> Moccasin color. </constant> - <constant name="NAVAJO_WHITE" value="Color( 1, 0.87, 0.68, 1 )"> + <constant name="NAVAJO_WHITE" value="Color(1, 0.87, 0.68, 1)"> Navajo white color. </constant> - <constant name="NAVY_BLUE" value="Color( 0, 0, 0.5, 1 )"> + <constant name="NAVY_BLUE" value="Color(0, 0, 0.5, 1)"> Navy blue color. </constant> - <constant name="OLD_LACE" value="Color( 0.99, 0.96, 0.9, 1 )"> + <constant name="OLD_LACE" value="Color(0.99, 0.96, 0.9, 1)"> Old lace color. </constant> - <constant name="OLIVE" value="Color( 0.5, 0.5, 0, 1 )"> + <constant name="OLIVE" value="Color(0.5, 0.5, 0, 1)"> Olive color. </constant> - <constant name="OLIVE_DRAB" value="Color( 0.42, 0.56, 0.14, 1 )"> + <constant name="OLIVE_DRAB" value="Color(0.42, 0.56, 0.14, 1)"> Olive drab color. </constant> - <constant name="ORANGE" value="Color( 1, 0.65, 0, 1 )"> + <constant name="ORANGE" value="Color(1, 0.65, 0, 1)"> Orange color. </constant> - <constant name="ORANGE_RED" value="Color( 1, 0.27, 0, 1 )"> + <constant name="ORANGE_RED" value="Color(1, 0.27, 0, 1)"> Orange red color. </constant> - <constant name="ORCHID" value="Color( 0.85, 0.44, 0.84, 1 )"> + <constant name="ORCHID" value="Color(0.85, 0.44, 0.84, 1)"> Orchid color. </constant> - <constant name="PALE_GOLDENROD" value="Color( 0.93, 0.91, 0.67, 1 )"> + <constant name="PALE_GOLDENROD" value="Color(0.93, 0.91, 0.67, 1)"> Pale goldenrod color. </constant> - <constant name="PALE_GREEN" value="Color( 0.6, 0.98, 0.6, 1 )"> + <constant name="PALE_GREEN" value="Color(0.6, 0.98, 0.6, 1)"> Pale green color. </constant> - <constant name="PALE_TURQUOISE" value="Color( 0.69, 0.93, 0.93, 1 )"> + <constant name="PALE_TURQUOISE" value="Color(0.69, 0.93, 0.93, 1)"> Pale turquoise color. </constant> - <constant name="PALE_VIOLET_RED" value="Color( 0.86, 0.44, 0.58, 1 )"> + <constant name="PALE_VIOLET_RED" value="Color(0.86, 0.44, 0.58, 1)"> Pale violet red color. </constant> - <constant name="PAPAYA_WHIP" value="Color( 1, 0.94, 0.84, 1 )"> + <constant name="PAPAYA_WHIP" value="Color(1, 0.94, 0.84, 1)"> Papaya whip color. </constant> - <constant name="PEACH_PUFF" value="Color( 1, 0.85, 0.73, 1 )"> + <constant name="PEACH_PUFF" value="Color(1, 0.85, 0.73, 1)"> Peach puff color. </constant> - <constant name="PERU" value="Color( 0.8, 0.52, 0.25, 1 )"> + <constant name="PERU" value="Color(0.8, 0.52, 0.25, 1)"> Peru color. </constant> - <constant name="PINK" value="Color( 1, 0.75, 0.8, 1 )"> + <constant name="PINK" value="Color(1, 0.75, 0.8, 1)"> Pink color. </constant> - <constant name="PLUM" value="Color( 0.87, 0.63, 0.87, 1 )"> + <constant name="PLUM" value="Color(0.87, 0.63, 0.87, 1)"> Plum color. </constant> - <constant name="POWDER_BLUE" value="Color( 0.69, 0.88, 0.9, 1 )"> + <constant name="POWDER_BLUE" value="Color(0.69, 0.88, 0.9, 1)"> Powder blue color. </constant> - <constant name="PURPLE" value="Color( 0.63, 0.13, 0.94, 1 )"> + <constant name="PURPLE" value="Color(0.63, 0.13, 0.94, 1)"> Purple color. </constant> - <constant name="REBECCA_PURPLE" value="Color( 0.4, 0.2, 0.6, 1 )"> + <constant name="REBECCA_PURPLE" value="Color(0.4, 0.2, 0.6, 1)"> Rebecca purple color. </constant> - <constant name="RED" value="Color( 1, 0, 0, 1 )"> + <constant name="RED" value="Color(1, 0, 0, 1)"> Red color. </constant> - <constant name="ROSY_BROWN" value="Color( 0.74, 0.56, 0.56, 1 )"> + <constant name="ROSY_BROWN" value="Color(0.74, 0.56, 0.56, 1)"> Rosy brown color. </constant> - <constant name="ROYAL_BLUE" value="Color( 0.25, 0.41, 0.88, 1 )"> + <constant name="ROYAL_BLUE" value="Color(0.25, 0.41, 0.88, 1)"> Royal blue color. </constant> - <constant name="SADDLE_BROWN" value="Color( 0.55, 0.27, 0.07, 1 )"> + <constant name="SADDLE_BROWN" value="Color(0.55, 0.27, 0.07, 1)"> Saddle brown color. </constant> - <constant name="SALMON" value="Color( 0.98, 0.5, 0.45, 1 )"> + <constant name="SALMON" value="Color(0.98, 0.5, 0.45, 1)"> Salmon color. </constant> - <constant name="SANDY_BROWN" value="Color( 0.96, 0.64, 0.38, 1 )"> + <constant name="SANDY_BROWN" value="Color(0.96, 0.64, 0.38, 1)"> Sandy brown color. </constant> - <constant name="SEA_GREEN" value="Color( 0.18, 0.55, 0.34, 1 )"> + <constant name="SEA_GREEN" value="Color(0.18, 0.55, 0.34, 1)"> Sea green color. </constant> - <constant name="SEASHELL" value="Color( 1, 0.96, 0.93, 1 )"> + <constant name="SEASHELL" value="Color(1, 0.96, 0.93, 1)"> Seashell color. </constant> - <constant name="SIENNA" value="Color( 0.63, 0.32, 0.18, 1 )"> + <constant name="SIENNA" value="Color(0.63, 0.32, 0.18, 1)"> Sienna color. </constant> - <constant name="SILVER" value="Color( 0.75, 0.75, 0.75, 1 )"> + <constant name="SILVER" value="Color(0.75, 0.75, 0.75, 1)"> Silver color. </constant> - <constant name="SKY_BLUE" value="Color( 0.53, 0.81, 0.92, 1 )"> + <constant name="SKY_BLUE" value="Color(0.53, 0.81, 0.92, 1)"> Sky blue color. </constant> - <constant name="SLATE_BLUE" value="Color( 0.42, 0.35, 0.8, 1 )"> + <constant name="SLATE_BLUE" value="Color(0.42, 0.35, 0.8, 1)"> Slate blue color. </constant> - <constant name="SLATE_GRAY" value="Color( 0.44, 0.5, 0.56, 1 )"> + <constant name="SLATE_GRAY" value="Color(0.44, 0.5, 0.56, 1)"> Slate gray color. </constant> - <constant name="SNOW" value="Color( 1, 0.98, 0.98, 1 )"> + <constant name="SNOW" value="Color(1, 0.98, 0.98, 1)"> Snow color. </constant> - <constant name="SPRING_GREEN" value="Color( 0, 1, 0.5, 1 )"> + <constant name="SPRING_GREEN" value="Color(0, 1, 0.5, 1)"> Spring green color. </constant> - <constant name="STEEL_BLUE" value="Color( 0.27, 0.51, 0.71, 1 )"> + <constant name="STEEL_BLUE" value="Color(0.27, 0.51, 0.71, 1)"> Steel blue color. </constant> - <constant name="TAN" value="Color( 0.82, 0.71, 0.55, 1 )"> + <constant name="TAN" value="Color(0.82, 0.71, 0.55, 1)"> Tan color. </constant> - <constant name="TEAL" value="Color( 0, 0.5, 0.5, 1 )"> + <constant name="TEAL" value="Color(0, 0.5, 0.5, 1)"> Teal color. </constant> - <constant name="THISTLE" value="Color( 0.85, 0.75, 0.85, 1 )"> + <constant name="THISTLE" value="Color(0.85, 0.75, 0.85, 1)"> Thistle color. </constant> - <constant name="TOMATO" value="Color( 1, 0.39, 0.28, 1 )"> + <constant name="TOMATO" value="Color(1, 0.39, 0.28, 1)"> Tomato color. </constant> - <constant name="TRANSPARENT" value="Color( 1, 1, 1, 0 )"> + <constant name="TRANSPARENT" value="Color(1, 1, 1, 0)"> Transparent color (white with zero alpha). </constant> - <constant name="TURQUOISE" value="Color( 0.25, 0.88, 0.82, 1 )"> + <constant name="TURQUOISE" value="Color(0.25, 0.88, 0.82, 1)"> Turquoise color. </constant> - <constant name="VIOLET" value="Color( 0.93, 0.51, 0.93, 1 )"> + <constant name="VIOLET" value="Color(0.93, 0.51, 0.93, 1)"> Violet color. </constant> - <constant name="WEB_GRAY" value="Color( 0.5, 0.5, 0.5, 1 )"> + <constant name="WEB_GRAY" value="Color(0.5, 0.5, 0.5, 1)"> Web gray color. </constant> - <constant name="WEB_GREEN" value="Color( 0, 0.5, 0, 1 )"> + <constant name="WEB_GREEN" value="Color(0, 0.5, 0, 1)"> Web green color. </constant> - <constant name="WEB_MAROON" value="Color( 0.5, 0, 0, 1 )"> + <constant name="WEB_MAROON" value="Color(0.5, 0, 0, 1)"> Web maroon color. </constant> - <constant name="WEB_PURPLE" value="Color( 0.5, 0, 0.5, 1 )"> + <constant name="WEB_PURPLE" value="Color(0.5, 0, 0.5, 1)"> Web purple color. </constant> - <constant name="WHEAT" value="Color( 0.96, 0.87, 0.7, 1 )"> + <constant name="WHEAT" value="Color(0.96, 0.87, 0.7, 1)"> Wheat color. </constant> - <constant name="WHITE" value="Color( 1, 1, 1, 1 )"> + <constant name="WHITE" value="Color(1, 1, 1, 1)"> White color. </constant> - <constant name="WHITE_SMOKE" value="Color( 0.96, 0.96, 0.96, 1 )"> + <constant name="WHITE_SMOKE" value="Color(0.96, 0.96, 0.96, 1)"> White smoke color. </constant> - <constant name="YELLOW" value="Color( 1, 1, 0, 1 )"> + <constant name="YELLOW" value="Color(1, 1, 0, 1)"> Yellow color. </constant> - <constant name="YELLOW_GREEN" value="Color( 0.6, 0.8, 0.2, 1 )"> + <constant name="YELLOW_GREEN" value="Color(0.6, 0.8, 0.2, 1)"> Yellow green color. </constant> </constants> diff --git a/doc/classes/ColorPicker.xml b/doc/classes/ColorPicker.xml index fddfd27573..2111358ef4 100644 --- a/doc/classes/ColorPicker.xml +++ b/doc/classes/ColorPicker.xml @@ -38,7 +38,7 @@ </method> </methods> <members> - <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(1, 1, 1, 1)"> The currently selected color. </member> <member name="deferred_mode" type="bool" setter="set_deferred_mode" getter="is_deferred_mode" default="false"> diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index e49027e61d..09b828366f 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -28,7 +28,7 @@ </method> </methods> <members> - <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color( 0, 0, 0, 1 )"> + <member name="color" type="Color" setter="set_pick_color" getter="get_pick_color" default="Color(0, 0, 0, 1)"> The currently selected color. </member> <member name="edit_alpha" type="bool" setter="set_edit_alpha" getter="is_editing_alpha" default="true"> @@ -70,19 +70,19 @@ <theme_item name="font" type="Font"> [Font] of the [ColorPickerButton]'s text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_color" type="Color" default="Color(1, 1, 1, 1)"> Default text [Color] of the [ColorPickerButton]. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.3 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.3)"> Text [Color] used when the [ColorPickerButton] is disabled. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [ColorPickerButton] is being hovered. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [ColorPickerButton]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 0.8, 0.8, 0.8, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(0.8, 0.8, 0.8, 1)"> Text [Color] used when the [ColorPickerButton] is being pressed. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/ColorRect.xml b/doc/classes/ColorRect.xml index 09ba4c8b26..84955fed8a 100644 --- a/doc/classes/ColorRect.xml +++ b/doc/classes/ColorRect.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> The fill color. [codeblocks] [gdscript] diff --git a/doc/classes/ConcavePolygonShape2D.xml b/doc/classes/ConcavePolygonShape2D.xml index 9999d086da..e6b2e1845d 100644 --- a/doc/classes/ConcavePolygonShape2D.xml +++ b/doc/classes/ConcavePolygonShape2D.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="segments" type="PackedVector2Array" setter="set_segments" getter="get_segments" default="PackedVector2Array( )"> + <member name="segments" type="PackedVector2Array" setter="set_segments" getter="get_segments" default="PackedVector2Array()"> The array of points that make up the [ConcavePolygonShape2D]'s line segments. </member> </members> diff --git a/doc/classes/ConcavePolygonShape3D.xml b/doc/classes/ConcavePolygonShape3D.xml index a9687abedc..b510905d1f 100644 --- a/doc/classes/ConcavePolygonShape3D.xml +++ b/doc/classes/ConcavePolygonShape3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> Concave polygon shape resource, which can be set into a [PhysicsBody3D] or area. This shape is created by feeding a list of triangles. - Note: when used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [KinematicBody3D] or [RigidBody3D] with a mode other than Static. + Note: when used for collision, [ConcavePolygonShape3D] is intended to work with static [PhysicsBody3D] nodes like [StaticBody3D] and will not work with [CharacterBody3D] or [RigidBody3D] with a mode other than Static. </description> <tutorials> <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> diff --git a/doc/classes/ConfigFile.xml b/doc/classes/ConfigFile.xml index 38948a2d6e..76855fc19f 100644 --- a/doc/classes/ConfigFile.xml +++ b/doc/classes/ConfigFile.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ConfigFile" inherits="Reference" version="4.0"> +<class name="ConfigFile" inherits="RefCounted" version="4.0"> <brief_description> Helper class to handle INI-style files. </brief_description> @@ -9,7 +9,7 @@ [section] some_key=42 string_example="Hello World3D!" - a_vector=Vector3( 1, 0, 2 ) + a_vector=Vector3(1, 0, 2) [/codeblock] The stored data can be saved to or parsed from a file, though ConfigFile objects can also be used directly without accessing the filesystem. The following example shows how to parse an INI-style file from the system, read its contents and store new values in it: diff --git a/doc/classes/ConfirmationDialog.xml b/doc/classes/ConfirmationDialog.xml index 9d8977cef1..0253ef21df 100644 --- a/doc/classes/ConfirmationDialog.xml +++ b/doc/classes/ConfirmationDialog.xml @@ -27,8 +27,8 @@ </method> </methods> <members> - <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" override="true" default="Vector2i( 200, 70 )" /> - <member name="size" type="Vector2i" setter="set_size" getter="get_size" override="true" default="Vector2i( 200, 100 )" /> + <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" override="true" default="Vector2i(200, 70)" /> + <member name="size" type="Vector2i" setter="set_size" getter="get_size" override="true" default="Vector2i(200, 100)" /> <member name="title" type="String" setter="set_title" getter="get_title" override="true" default=""Please Confirm..."" /> </members> <constants> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index a9a230b78f..47e26b7a2e 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -22,12 +22,87 @@ <link title="All GUI Demos">https://github.com/godotengine/godot-demo-projects/tree/master/gui</link> </tutorials> <methods> - <method name="_clips_input" qualifiers="virtual"> + <method name="_can_drop_data" qualifiers="virtual"> <return type="bool"> </return> + <argument index="0" name="position" type="Vector2"> + </argument> + <argument index="1" name="data" type="Variant"> + </argument> <description> - Virtual method to be implemented by the user. Returns whether [method _gui_input] should not be called for children controls outside this control's rectangle. Input will be clipped to the Rect of this [Control]. Similar to [member rect_clip_content], but doesn't affect visibility. - If not overridden, defaults to [code]false[/code]. + Godot calls this method to test if [code]data[/code] from a control's [method _get_drag_data] can be dropped at [code]position[/code]. [code]position[/code] is local to this control. + This method should only be used to test the data. Process the data in [method _drop_data]. + [codeblocks] + [gdscript] + func _can_drop_data(position, data): + # Check position if it is relevant to you + # Otherwise, just check data + return typeof(data) == TYPE_DICTIONARY and data.has("expected") + [/gdscript] + [csharp] + public override bool CanDropData(Vector2 position, object data) + { + // Check position if it is relevant to you + // Otherwise, just check data + return data is Godot.Collections.Dictionary && (data as Godot.Collections.Dictionary).Contains("expected"); + } + [/csharp] + [/codeblocks] + </description> + </method> + <method name="_drop_data" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="position" type="Vector2"> + </argument> + <argument index="1" name="data" type="Variant"> + </argument> + <description> + Godot calls this method to pass you the [code]data[/code] from a control's [method _get_drag_data] result. Godot first calls [method _can_drop_data] to test if [code]data[/code] is allowed to drop at [code]position[/code] where [code]position[/code] is local to this control. + [codeblocks] + [gdscript] + func _can_drop_data(position, data): + return typeof(data) == TYPE_DICTIONARY and data.has("color") + func _drop_data(position, data): + var color = data["color"] + [/gdscript] + [csharp] + public override bool CanDropData(Vector2 position, object data) + { + return data is Godot.Collections.Dictionary && (data as Godot.Collections.Dictionary).Contains("color"); + } + public override void DropData(Vector2 position, object data) + { + Color color = (Color)(data as Godot.Collections.Dictionary)["color"]; + } + [/csharp] + [/codeblocks] + </description> + </method> + <method name="_get_drag_data" qualifiers="virtual"> + <return type="Variant"> + </return> + <argument index="0" name="position" type="Vector2"> + </argument> + <description> + Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Returns [code]null[/code] if there is no data to drag. Controls that want to receive drop data should implement [method _can_drop_data] and [method _drop_data]. [code]position[/code] is local to this control. Drag may be forced with [method force_drag]. + A preview that will follow the mouse that should represent the data can be set with [method set_drag_preview]. A good time to set the preview is in this method. + [codeblocks] + [gdscript] + func _get_drag_data(position): + var mydata = make_data() # This is your custom method generating the drag data. + set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data. + return mydata + [/gdscript] + [csharp] + public override object GetDragData(Vector2 position) + { + object mydata = MakeData(); // This is your custom method generating the drag data. + SetDragPreview(MakePreview(mydata)); // This is your custom method generating the preview of the drag data. + return mydata; + } + [/csharp] + [/codeblocks] </description> </method> <method name="_get_minimum_size" qualifiers="virtual"> @@ -68,11 +143,22 @@ [/csharp] [/codeblocks] The event won't trigger if: - * clicking outside the control (see [method has_point]); + * clicking outside the control (see [method _has_point]); * control has [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE]; * control is obstructed by another [Control] on top of it, which doesn't have [member mouse_filter] set to [constant MOUSE_FILTER_IGNORE]; * control's parent has [member mouse_filter] set to [constant MOUSE_FILTER_STOP] or has accepted the event; - * it happens outside parent's rectangle and the parent has either [member rect_clip_content] or [method _clips_input] enabled. + * it happens outside parent's rectangle and the parent has either [member rect_clip_content] enabled. + </description> + </method> + <method name="_has_point" qualifiers="virtual const"> + <return type="bool"> + </return> + <argument index="0" name="" type="Vector2"> + </argument> + <description> + Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control. + If not overridden, default behavior is checking if the point is within control's Rect. + [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code]. </description> </method> <method name="_make_custom_tooltip" qualifiers="virtual"> @@ -107,14 +193,14 @@ [codeblocks] [gdscript] func _make_custom_tooltip(for_text): - var tooltip = preload("res://SomeTooltipScene.tscn").instance() + var tooltip = preload("res://SomeTooltipScene.tscn").instantiate() tooltip.get_node("Label").text = for_text return tooltip [/gdscript] [csharp] public override Godot.Control _MakeCustomTooltip(String forText) { - Node tooltip = ResourceLoader.Load<PackedScene>("res://SomeTooltipScene.tscn").Instance(); + Node tooltip = ResourceLoader.Load<PackedScene>("res://SomeTooltipScene.tscn").Instantiate(); tooltip.GetNode<Label>("Label").Text = forText; return tooltip; } @@ -249,63 +335,6 @@ [/codeblocks] </description> </method> - <method name="can_drop_data" qualifiers="virtual"> - <return type="bool"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <description> - Godot calls this method to test if [code]data[/code] from a control's [method get_drag_data] can be dropped at [code]position[/code]. [code]position[/code] is local to this control. - This method should only be used to test the data. Process the data in [method drop_data]. - [codeblocks] - [gdscript] - func can_drop_data(position, data): - # Check position if it is relevant to you - # Otherwise, just check data - return typeof(data) == TYPE_DICTIONARY and data.has("expected") - [/gdscript] - [csharp] - public override bool CanDropData(Vector2 position, object data) - { - // Check position if it is relevant to you - // Otherwise, just check data - return data is Godot.Collections.Dictionary && (data as Godot.Collections.Dictionary).Contains("expected"); - } - [/csharp] - [/codeblocks] - </description> - </method> - <method name="drop_data" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <description> - Godot calls this method to pass you the [code]data[/code] from a control's [method get_drag_data] result. Godot first calls [method can_drop_data] to test if [code]data[/code] is allowed to drop at [code]position[/code] where [code]position[/code] is local to this control. - [codeblocks] - [gdscript] - func can_drop_data(position, data): - return typeof(data) == TYPE_DICTIONARY and data.has("color") - func drop_data(position, data): - var color = data["color"] - [/gdscript] - [csharp] - public override bool CanDropData(Vector2 position, object data) - { - return data is Godot.Collections.Dictionary && (data as Godot.Collections.Dictionary).Contains("color"); - } - public override void DropData(Vector2 position, object data) - { - Color color = (Color)(data as Godot.Collections.Dictionary)["color"]; - } - [/csharp] - [/codeblocks] - </description> - </method> <method name="find_next_valid_focus" qualifiers="const"> <return type="Control"> </return> @@ -328,8 +357,8 @@ <argument index="1" name="preview" type="Control"> </argument> <description> - Forces drag and bypasses [method get_drag_data] and [method set_drag_preview] by passing [code]data[/code] and [code]preview[/code]. Drag will start even if the mouse is neither over nor pressed on this control. - The methods [method can_drop_data] and [method drop_data] must be implemented on controls that want to receive drop data. + Forces drag and bypasses [method _get_drag_data] and [method set_drag_preview] by passing [code]data[/code] and [code]preview[/code]. Drag will start even if the mouse is neither over nor pressed on this control. + The methods [method _can_drop_data] and [method _drop_data] must be implemented on controls that want to receive drop data. </description> </method> <method name="get_anchor" qualifiers="const"> @@ -358,38 +387,12 @@ <method name="get_cursor_shape" qualifiers="const"> <return type="int" enum="Control.CursorShape"> </return> - <argument index="0" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="0" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Returns the mouse cursor shape the control displays on mouse hover. See [enum CursorShape]. </description> </method> - <method name="get_drag_data" qualifiers="virtual"> - <return type="Variant"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <description> - Godot calls this method to get data that can be dragged and dropped onto controls that expect drop data. Returns [code]null[/code] if there is no data to drag. Controls that want to receive drop data should implement [method can_drop_data] and [method drop_data]. [code]position[/code] is local to this control. Drag may be forced with [method force_drag]. - A preview that will follow the mouse that should represent the data can be set with [method set_drag_preview]. A good time to set the preview is in this method. - [codeblocks] - [gdscript] - func get_drag_data(position): - var mydata = make_data() # This is your custom method generating the drag data. - set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data. - return mydata - [/gdscript] - [csharp] - public override object GetDragData(Vector2 position) - { - object mydata = MakeData(); // This is your custom method generating the drag data. - SetDragPreview(MakePreview(mydata)); // This is your custom method generating the preview of the drag data. - return mydata; - } - [/csharp] - [/codeblocks] - </description> - </method> <method name="get_end" qualifiers="const"> <return type="Vector2"> </return> @@ -538,7 +541,7 @@ <method name="get_tooltip" qualifiers="const"> <return type="String"> </return> - <argument index="0" name="at_position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="0" name="at_position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Returns the tooltip, which will appear when the cursor is resting over this control. See [member hint_tooltip]. @@ -577,17 +580,6 @@ Returns [code]true[/code] if this is the current focused control. See [member focus_mode]. </description> </method> - <method name="has_point" qualifiers="virtual"> - <return type="bool"> - </return> - <argument index="0" name="point" type="Vector2"> - </argument> - <description> - Virtual method to be implemented by the user. Returns whether the given [code]point[/code] is inside this control. - If not overridden, default behavior is checking if the point is within control's Rect. - [b]Note:[/b] If you want to check if a point is inside the control, you can use [code]get_rect().has_point(point)[/code]. - </description> - </method> <method name="has_theme_color" qualifiers="const"> <return type="bool"> </return> @@ -856,7 +848,7 @@ </argument> <description> Forwards the handling of this control's drag and drop to [code]target[/code] control. - Forwarding can be implemented in the target control similar to the methods [method get_drag_data], [method can_drop_data], and [method drop_data] but with two differences: + Forwarding can be implemented in the target control similar to the methods [method _get_drag_data], [method _can_drop_data], and [method _drop_data] but with two differences: 1. The function name must be suffixed with [b]_fw[/b] 2. The function must take an extra argument that is the control doing the forwarding [codeblocks] @@ -871,13 +863,13 @@ # TargetControl.gd extends Control - func can_drop_data_fw(position, data, from_control): + func _can_drop_data_fw(position, data, from_control): return true - func drop_data_fw(position, data, from_control): + func _drop_data_fw(position, data, from_control): my_handle_data(data) # Your handler method. - func get_drag_data_fw(position, from_control): + func _get_drag_data_fw(position, from_control): set_drag_preview(my_preview) return my_data() [/gdscript] @@ -922,12 +914,12 @@ <argument index="0" name="control" type="Control"> </argument> <description> - Shows the given control at the mouse pointer. A good time to call this method is in [method get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended. + Shows the given control at the mouse pointer. A good time to call this method is in [method _get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended. [codeblocks] [gdscript] export (Color, RGBA) var color = Color(1, 0, 0, 1) - func get_drag_data(position): + func _get_drag_data(position): # Use a control that is not in the tree var cpb = ColorPickerButton.new() cpb.color = color @@ -1055,7 +1047,7 @@ Anchors the right edge of the node to the origin, the center or the end of its parent control. It changes how the right offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. </member> <member name="anchor_top" type="float" setter="_set_anchor" getter="get_anchor" default="0.0"> - Anchors the top edge of the node to the origin, the center or the end of its parent control. It changes how the top offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. + Anchors the top edge of the node to the origin, the center or the end of its parent control. It changes how the top offset updates when the node moves or changes size. You can use one of the [enum Anchor] constants for convenience. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0"> The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard signals. @@ -1067,7 +1059,7 @@ Tells Godot which node it should give keyboard focus to if the user presses the left arrow on the keyboard or left on a gamepad by default. You can change the key by editing the [code]ui_left[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the left of this one. </member> <member name="focus_neighbor_right" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")"> - Tells Godot which node it should give keyboard focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [code]ui_right[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one. + Tells Godot which node it should give keyboard focus to if the user presses the right arrow on the keyboard or right on a gamepad by default. You can change the key by editing the [code]ui_right[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one. </member> <member name="focus_neighbor_top" type="NodePath" setter="set_focus_neighbor" getter="get_focus_neighbor" default="NodePath("")"> Tells Godot which node it should give keyboard focus to if the user presses the top arrow on the keyboard or top on a gamepad by default. You can change the key by editing the [code]ui_top[/code] input action. The node must be a [Control]. If this property is not set, Godot will give focus to the closest [Control] to the bottom of this one. @@ -1135,32 +1127,29 @@ Offsets are often controlled by one or multiple parent [Container] nodes, so you should not modify them manually if your node is a direct child of a [Container]. Offsets update automatically when you move or resize the node. </member> <member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false"> - Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered. + Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered and won't receive input. </member> <member name="rect_global_position" type="Vector2" setter="_set_global_position" getter="get_global_position"> The node's global position, relative to the world (usually to the top-left corner of the window). </member> - <member name="rect_min_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2( 0, 0 )"> + <member name="rect_min_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)"> The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes. </member> - <member name="rect_pivot_offset" type="Vector2" setter="set_pivot_offset" getter="get_pivot_offset" default="Vector2( 0, 0 )"> + <member name="rect_pivot_offset" type="Vector2" setter="set_pivot_offset" getter="get_pivot_offset" default="Vector2(0, 0)"> By default, the node's pivot is its top-left corner. When you change its [member rect_scale], it will scale around this pivot. Set this property to [member rect_size] / 2 to center the pivot in the node's rectangle. </member> - <member name="rect_position" type="Vector2" setter="_set_position" getter="get_position" default="Vector2( 0, 0 )"> + <member name="rect_position" type="Vector2" setter="_set_position" getter="get_position" default="Vector2(0, 0)"> The node's position, relative to its parent. It corresponds to the rectangle's top-left corner. The property is not affected by [member rect_pivot_offset]. </member> <member name="rect_rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0"> The node's rotation around its pivot, in radians. See [member rect_pivot_offset] to change the pivot's position. </member> - <member name="rect_rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees" default="0.0"> - The node's rotation around its pivot, in degrees. See [member rect_pivot_offset] to change the pivot's position. - </member> - <member name="rect_scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2( 1, 1 )"> + <member name="rect_scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)"> The node's scale, relative to its [member rect_size]. Change this property to scale the node around its [member rect_pivot_offset]. The Control's [member hint_tooltip] will also scale according to this value. [b]Note:[/b] This property is mainly intended to be used for animation purposes. Text inside the Control will look pixelated or blurry when the Control is scaled. To support multiple resolutions in your project, use an appropriate viewport stretch mode as described in the [url=https://docs.godotengine.org/en/latest/tutorials/viewports/multiple_resolutions.html]documentation[/url] instead of scaling Controls individually. - [b]Note:[/b] If the Control node is a child of a [Container] node, the scale will be reset to [code]Vector2(1, 1)[/code] when the scene is instanced. To set the Control's scale when it's instanced, wait for one frame using [code]yield(get_tree(), "idle_frame")[/code] then set its [member rect_scale] property. + [b]Note:[/b] If the Control node is a child of a [Container] node, the scale will be reset to [code]Vector2(1, 1)[/code] when the scene is instantiated. To set the Control's scale when it's instantiated, wait for one frame using [code]yield(get_tree(), "idle_frame")[/code] then set its [member rect_scale] property. </member> - <member name="rect_size" type="Vector2" setter="_set_size" getter="get_size" default="Vector2( 0, 0 )"> + <member name="rect_size" type="Vector2" setter="_set_size" getter="get_size" default="Vector2(0, 0)"> The size of the node's bounding rectangle, in pixels. [Container] nodes update this property automatically. </member> <member name="size_flags_horizontal" type="int" setter="set_h_size_flags" getter="get_h_size_flags" default="1"> @@ -1175,7 +1164,7 @@ <member name="theme" type="Theme" setter="set_theme" getter="get_theme"> The [Theme] resource this node and all its [Control] children use. If a child node has its own [Theme] resource set, theme items are merged with child's definitions having higher priority. </member> - <member name="theme_custom_type" type="StringName" setter="set_theme_custom_type" getter="get_theme_custom_type" default="@"""> + <member name="theme_custom_type" type="StringName" setter="set_theme_custom_type" getter="get_theme_custom_type" default="&"""> The type name used by this [Control] to look up its own theme items. By default, the class name of the node is used (e.g. [code]Button[/code] for the [Button] control), as well as the class names of all parent classes (in order of inheritance). Setting this property gives the highest priority to the type of the specified name, then falls back on the class names. [b]Note:[/b] To look up [Control]'s own items use various [code]get_theme_*[/code] methods without specifying [code]theme_type[/code]. [b]Note:[/b] Theme items are looked for in the tree order, from branch to root, where each [Control] node is checked for its [member theme] property. The earliest match against any type/class name is returned. The project-level Theme and the default Theme are checked last. diff --git a/doc/classes/ConvexPolygonShape2D.xml b/doc/classes/ConvexPolygonShape2D.xml index 42951e2158..d53900e6c5 100644 --- a/doc/classes/ConvexPolygonShape2D.xml +++ b/doc/classes/ConvexPolygonShape2D.xml @@ -21,7 +21,7 @@ </method> </methods> <members> - <member name="points" type="PackedVector2Array" setter="set_points" getter="get_points" default="PackedVector2Array( )"> + <member name="points" type="PackedVector2Array" setter="set_points" getter="get_points" default="PackedVector2Array()"> The polygon's list of vertices. Can be in either clockwise or counterclockwise order. </member> </members> diff --git a/doc/classes/ConvexPolygonShape3D.xml b/doc/classes/ConvexPolygonShape3D.xml index e18d716255..a5c86526b0 100644 --- a/doc/classes/ConvexPolygonShape3D.xml +++ b/doc/classes/ConvexPolygonShape3D.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="points" type="PackedVector3Array" setter="set_points" getter="get_points" default="PackedVector3Array( )"> + <member name="points" type="PackedVector3Array" setter="set_points" getter="get_points" default="PackedVector3Array()"> The list of 3D points forming the convex polygon shape. </member> </members> diff --git a/doc/classes/Crypto.xml b/doc/classes/Crypto.xml index 1f6cb40cde..deda6116f4 100644 --- a/doc/classes/Crypto.xml +++ b/doc/classes/Crypto.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Crypto" inherits="Reference" version="4.0"> +<class name="Crypto" inherits="RefCounted" version="4.0"> <brief_description> Access to advanced cryptographic functionalities. </brief_description> diff --git a/doc/classes/Curve2D.xml b/doc/classes/Curve2D.xml index b33f3b4ffc..c9fcbd2892 100644 --- a/doc/classes/Curve2D.xml +++ b/doc/classes/Curve2D.xml @@ -15,9 +15,9 @@ </return> <argument index="0" name="position" type="Vector2"> </argument> - <argument index="1" name="in" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="1" name="in" type="Vector2" default="Vector2(0, 0)"> </argument> - <argument index="2" name="out" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="out" type="Vector2" default="Vector2(0, 0)"> </argument> <argument index="3" name="at_position" type="int" default="-1"> </argument> diff --git a/doc/classes/Curve3D.xml b/doc/classes/Curve3D.xml index fcd150ad57..fdf96b4262 100644 --- a/doc/classes/Curve3D.xml +++ b/doc/classes/Curve3D.xml @@ -15,9 +15,9 @@ </return> <argument index="0" name="position" type="Vector3"> </argument> - <argument index="1" name="in" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="1" name="in" type="Vector3" default="Vector3(0, 0, 0)"> </argument> - <argument index="2" name="out" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="2" name="out" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <argument index="3" name="at_position" type="int" default="-1"> </argument> diff --git a/doc/classes/Curve3Texture.xml b/doc/classes/Curve3Texture.xml new file mode 100644 index 0000000000..1b352dff0d --- /dev/null +++ b/doc/classes/Curve3Texture.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="Curve3Texture" inherits="Texture2D" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="curve_x" type="Curve" setter="set_curve_x" getter="get_curve_x"> + </member> + <member name="curve_y" type="Curve" setter="set_curve_y" getter="get_curve_y"> + </member> + <member name="curve_z" type="Curve" setter="set_curve_z" getter="get_curve_z"> + </member> + <member name="width" type="int" setter="set_width" getter="get_width" default="2048"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/CurveTexture.xml b/doc/classes/CurveTexture.xml index bc6b69d2d1..54065fe0f9 100644 --- a/doc/classes/CurveTexture.xml +++ b/doc/classes/CurveTexture.xml @@ -14,10 +14,16 @@ <member name="curve" type="Curve" setter="set_curve" getter="get_curve"> The [code]curve[/code] rendered onto the texture. </member> + <member name="texture_mode" type="int" setter="set_texture_mode" getter="get_texture_mode" enum="CurveTexture.TextureMode" default="0"> + </member> <member name="width" type="int" setter="set_width" getter="get_width" default="2048"> The width of the texture. </member> </members> <constants> + <constant name="TEXTURE_MODE_RGB" value="0" enum="TextureMode"> + </constant> + <constant name="TEXTURE_MODE_RED" value="1" enum="TextureMode"> + </constant> </constants> </class> diff --git a/doc/classes/CylinderMesh.xml b/doc/classes/CylinderMesh.xml index 3a81e98c3a..827fb5c10c 100644 --- a/doc/classes/CylinderMesh.xml +++ b/doc/classes/CylinderMesh.xml @@ -4,7 +4,7 @@ Class representing a cylindrical [PrimitiveMesh]. </brief_description> <description> - Class representing a cylindrical [PrimitiveMesh]. This class can be used to create cones by setting either the [member top_radius] or [member bottom_radius] properties to 0.0. + Class representing a cylindrical [PrimitiveMesh]. This class can be used to create cones by setting either the [member top_radius] or [member bottom_radius] properties to [code]0.0[/code]. </description> <tutorials> </tutorials> @@ -12,19 +12,19 @@ </methods> <members> <member name="bottom_radius" type="float" setter="set_bottom_radius" getter="get_bottom_radius" default="1.0"> - Bottom radius of the cylinder. + Bottom radius of the cylinder. If set to [code]0.0[/code], the bottom faces will not be generated, resulting in a conic shape. </member> <member name="height" type="float" setter="set_height" getter="get_height" default="2.0"> Full height of the cylinder. </member> <member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="64"> - Number of radial segments on the cylinder. + Number of radial segments on the cylinder. Higher values result in a more detailed cylinder/cone at the cost of performance. </member> <member name="rings" type="int" setter="set_rings" getter="get_rings" default="4"> - Number of edge rings along the height of the cylinder. + Number of edge rings along the height of the cylinder. Changing [member rings] does not have any visual impact unless a shader or procedural mesh tool is used to alter the vertex data. Higher values result in more subdivisions, which can be used to create smoother-looking effects with shaders or procedural mesh tools (at the cost of performance). When not altering the vertex data using a shader or procedural mesh tool, [member rings] should be kept to its default value. </member> <member name="top_radius" type="float" setter="set_top_radius" getter="get_top_radius" default="1.0"> - Top radius of the cylinder. + Top radius of the cylinder. If set to [code]0.0[/code], the top faces will not be generated, resulting in a conic shape. </member> </members> <constants> diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml index 91a04b1f28..28d68d309f 100644 --- a/doc/classes/DTLSServer.xml +++ b/doc/classes/DTLSServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="DTLSServer" inherits="Reference" version="4.0"> +<class name="DTLSServer" inherits="RefCounted" version="4.0"> <brief_description> Helper class to implement a DTLS server. </brief_description> diff --git a/doc/classes/Decal.xml b/doc/classes/Decal.xml index 14c35ae6d3..e84cea7c30 100644 --- a/doc/classes/Decal.xml +++ b/doc/classes/Decal.xml @@ -79,13 +79,13 @@ <member name="emission_energy" type="float" setter="set_emission_energy" getter="get_emission_energy" default="1.0"> Energy multiplier for the emission texture. This will make the decal emit light at a higher intensity. </member> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> Sets the size of the [AABB] used by the decal. The AABB goes from [code]-extents[/code] to [code]extents[/code]. </member> <member name="lower_fade" type="float" setter="set_lower_fade" getter="get_lower_fade" default="0.3"> Sets the curve over which the decal will fade as the surface gets further from the center of the [AABB]. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color( 1, 1, 1, 1 )"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> Changes the [Color] of the Decal by multiplying it with this value. </member> <member name="normal_fade" type="float" setter="set_normal_fade" getter="get_normal_fade" default="0.0"> diff --git a/doc/classes/DirectionalLight3D.xml b/doc/classes/DirectionalLight3D.xml index 233b1f0c16..4f51adb8fc 100644 --- a/doc/classes/DirectionalLight3D.xml +++ b/doc/classes/DirectionalLight3D.xml @@ -15,9 +15,6 @@ <member name="directional_shadow_blend_splits" type="bool" setter="set_blend_splits" getter="is_blend_splits_enabled" default="false"> If [code]true[/code], shadow detail is sacrificed in exchange for smoother transitions between splits. </member> - <member name="directional_shadow_depth_range" type="int" setter="set_shadow_depth_range" getter="get_shadow_depth_range" enum="DirectionalLight3D.ShadowDepthRange" default="0"> - Optimizes shadow rendering for detail versus movement. See [enum ShadowDepthRange]. - </member> <member name="directional_shadow_fade_start" type="float" setter="set_param" getter="get_param" default="0.8"> Proportion of [member directional_shadow_max_distance] at which point the shadow starts to fade. At [member directional_shadow_max_distance] the shadow will disappear. </member> @@ -55,11 +52,5 @@ <constant name="SHADOW_PARALLEL_4_SPLITS" value="2" enum="ShadowMode"> Splits the view frustum in 4 areas, each with its own shadow map. This is the slowest directional shadow mode. </constant> - <constant name="SHADOW_DEPTH_RANGE_STABLE" value="0" enum="ShadowDepthRange"> - Keeps the shadow stable when the camera moves, at the cost of lower effective shadow resolution. - </constant> - <constant name="SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="ShadowDepthRange"> - Tries to achieve maximum shadow resolution. May result in saw effect on shadow edges. This mode typically works best in games where the camera will often move at high speeds, such as most racing games. - </constant> </constants> </class> diff --git a/doc/classes/Directory.xml b/doc/classes/Directory.xml index 2c61d723cd..dae8d83f0c 100644 --- a/doc/classes/Directory.xml +++ b/doc/classes/Directory.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Directory" inherits="Reference" version="4.0"> +<class name="Directory" inherits="RefCounted" version="4.0"> <brief_description> Type used to handle the filesystem. </brief_description> diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 6c1cd37beb..17b51d5cbe 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -44,9 +44,11 @@ </return> <argument index="0" name="mode" type="int" enum="DisplayServer.WindowMode"> </argument> - <argument index="1" name="flags" type="int"> + <argument index="1" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode"> </argument> - <argument index="2" name="rect" type="Rect2i" default="Rect2i( 0, 0, 0, 0 )"> + <argument index="2" name="flags" type="int"> + </argument> + <argument index="3" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)"> </argument> <description> </description> @@ -64,7 +66,7 @@ </argument> <argument index="1" name="shape" type="int" enum="DisplayServer.CursorShape" default="0"> </argument> - <argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)"> </argument> <description> </description> @@ -436,7 +438,7 @@ </description> </method> <method name="mouse_get_button_state" qualifiers="const"> - <return type="int"> + <return type="int" enum="MouseButton"> </return> <description> </description> @@ -650,7 +652,7 @@ </return> <argument index="0" name="existing_text" type="String"> </argument> - <argument index="1" name="position" type="Rect2" default="Rect2i( 0, 0, 0, 0 )"> + <argument index="1" name="position" type="Rect2" default="Rect2i(0, 0, 0, 0)"> </argument> <argument index="2" name="multiline" type="bool" default="false"> </argument> @@ -671,34 +673,6 @@ [b]Note:[/b] This method is implemented on Android, iOS and UWP. </description> </method> - <method name="vsync_is_enabled" qualifiers="const"> - <return type="bool"> - </return> - <description> - </description> - </method> - <method name="vsync_is_using_via_compositor" qualifiers="const"> - <return type="bool"> - </return> - <description> - </description> - </method> - <method name="vsync_set_enabled"> - <return type="void"> - </return> - <argument index="0" name="enabled" type="bool"> - </argument> - <description> - </description> - </method> - <method name="vsync_set_use_via_compositor"> - <return type="void"> - </return> - <argument index="0" name="enabled" type="bool"> - </argument> - <description> - </description> - </method> <method name="window_attach_instance_id"> <return type="void"> </return> @@ -791,6 +765,15 @@ <description> </description> </method> + <method name="window_get_vsync_mode" qualifiers="const"> + <return type="int" enum="DisplayServer.VSyncMode"> + </return> + <argument index="0" name="window_id" type="int" default="0"> + </argument> + <description> + Returns the VSync mode of the given window. + </description> + </method> <method name="window_move_to_foreground"> <return type="void"> </return> @@ -995,6 +978,19 @@ <description> </description> </method> + <method name="window_set_vsync_mode"> + <return type="void"> + </return> + <argument index="0" name="vsync_mode" type="int" enum="DisplayServer.VSyncMode"> + </argument> + <argument index="1" name="window_id" type="int" default="0"> + </argument> + <description> + Sets the VSync mode of the given window. + See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application. + Depending on the platform and used renderer, the engine will fall back to [constant VSYNC_ENABLED], if the desired mode is not supported. + </description> + </method> <method name="window_set_window_event_callback"> <return type="void"> </return> @@ -1151,5 +1147,18 @@ </constant> <constant name="WINDOW_EVENT_DPI_CHANGE" value="6" enum="WindowEvent"> </constant> + <constant name="VSYNC_DISABLED" value="0" enum="VSyncMode"> + No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible). + </constant> + <constant name="VSYNC_ENABLED" value="1" enum="VSyncMode"> + Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible). + </constant> + <constant name="VSYNC_ADAPTIVE" value="2" enum="VSyncMode"> + Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible), otherwise vertical synchronization is enabled to avoid tearing. + </constant> + <constant name="VSYNC_MAILBOX" value="3" enum="VSyncMode"> + Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible). + Although not guaranteed, the images can be rendered as fast as possible, which may reduce input lag. + </constant> </constants> </class> diff --git a/doc/classes/EditorDebuggerPlugin.xml b/doc/classes/EditorDebuggerPlugin.xml index b97933e582..9484d33252 100644 --- a/doc/classes/EditorDebuggerPlugin.xml +++ b/doc/classes/EditorDebuggerPlugin.xml @@ -38,7 +38,7 @@ <return type="bool"> </return> <description> - Returns [code]true[/code] if there is an instance of the game running with the attached debugger otherwise [code]false[/code]. + Returns [code]true[/code] if there is an instance of the game running with the attached debugger otherwise [code]false[/code]. </description> </method> <method name="register_message_capture"> diff --git a/doc/classes/EditorExportPlugin.xml b/doc/classes/EditorExportPlugin.xml index b29734de1c..d9e3003fbb 100644 --- a/doc/classes/EditorExportPlugin.xml +++ b/doc/classes/EditorExportPlugin.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorExportPlugin" inherits="Reference" version="4.0"> +<class name="EditorExportPlugin" inherits="RefCounted" version="4.0"> <brief_description> A script that is executed when exporting the project. </brief_description> diff --git a/doc/classes/EditorFeatureProfile.xml b/doc/classes/EditorFeatureProfile.xml index e05a685dd7..0cd839f370 100644 --- a/doc/classes/EditorFeatureProfile.xml +++ b/doc/classes/EditorFeatureProfile.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorFeatureProfile" inherits="Reference" version="4.0"> +<class name="EditorFeatureProfile" inherits="RefCounted" version="4.0"> <brief_description> An editor feature profile which can be used to disable specific features. </brief_description> diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index aa64ab4043..a532e9bc2b 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -5,45 +5,45 @@ </brief_description> <description> EditorImportPlugins provide a way to extend the editor's resource import functionality. Use them to import resources from custom files or to provide alternatives to the editor's existing importers. Register your [EditorPlugin] with [method EditorPlugin.add_import_plugin]. - EditorImportPlugins work by associating with specific file extensions and a resource type. See [method get_recognized_extensions] and [method get_resource_type]. They may optionally specify some import presets that affect the import process. EditorImportPlugins are responsible for creating the resources and saving them in the [code].godot/imported[/code] directory. + EditorImportPlugins work by associating with specific file extensions and a resource type. See [method _get_recognized_extensions] and [method _get_resource_type]. They may optionally specify some import presets that affect the import process. EditorImportPlugins are responsible for creating the resources and saving them in the [code].godot/imported[/code] directory. Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec": [codeblocks] [gdscript] tool extends EditorImportPlugin - func get_importer_name(): + func _get_importer_name(): return "my.special.plugin" - func get_visible_name(): + func _get_visible_name(): return "Special Mesh" - func get_recognized_extensions(): + func _get_recognized_extensions(): return ["special", "spec"] - func get_save_extension(): + func _get_save_extension(): return "mesh" - func get_resource_type(): + func _get_resource_type(): return "Mesh" - func get_preset_count(): + func _get_preset_count(): return 1 - func get_preset_name(i): + func _get_preset_name(i): return "Default" - func get_import_options(i): + func _get_import_options(i): return [{"name": "my_option", "default_value": false}] - func import(source_file, save_path, options, platform_variants, gen_files): + func _import(source_file, save_path, options, platform_variants, gen_files): var file = File.new() if file.open(source_file, File.READ) != OK: return FAILED var mesh = ArrayMesh.new() # Fill the Mesh with data read in "file", left as an exercise to the reader. - var filename = save_path + "." + get_save_extension() + var filename = save_path + "." + _get_save_extension() return ResourceSaver.save(filename, mesh) [/gdscript] [csharp] @@ -92,7 +92,7 @@ return new Godot.Collections.Array{new Godot.Collections.Dictionary{{"name", "myOption"}, {"defaultValue", false}}}; } - public override int Import(String sourceFile, String savePath, Godot.Collections.Dictionary options, Godot.Collections.Array platformVariants, Godot.Collections.Array genFiles) + public override int Import(String sourceFile, String savePath, Godot.Collections.Dictionary options, Godot.Collections.Array platformVariants, Godot.Collections.Array genFiles) { var file = new File(); if (file.Open(sourceFile, File.ModeFlags.Read) != Error.Ok) @@ -113,7 +113,7 @@ <link title="Import plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/import_plugins.html</link> </tutorials> <methods> - <method name="get_import_options" qualifiers="virtual"> + <method name="_get_import_options" qualifiers="virtual"> <return type="Array"> </return> <argument index="0" name="preset" type="int"> @@ -122,21 +122,21 @@ Gets the options and default values for the preset at this index. Returns an Array of Dictionaries with the following keys: [code]name[/code], [code]default_value[/code], [code]property_hint[/code] (optional), [code]hint_string[/code] (optional), [code]usage[/code] (optional). </description> </method> - <method name="get_import_order" qualifiers="virtual"> + <method name="_get_import_order" qualifiers="virtual"> <return type="int"> </return> <description> Gets the order of this importer to be run when importing resources. Higher values will be called later. Use this to ensure the importer runs after the dependencies are already imported. </description> </method> - <method name="get_importer_name" qualifiers="virtual"> + <method name="_get_importer_name" qualifiers="virtual"> <return type="String"> </return> <description> Gets the unique name of the importer. </description> </method> - <method name="get_option_visibility" qualifiers="virtual"> + <method name="_get_option_visibility" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="option" type="String"> @@ -147,7 +147,7 @@ This method can be overridden to hide specific import options if conditions are met. This is mainly useful for hiding options that depend on others if one of them is disabled. For example: [codeblocks] [gdscript] - func get_option_visibility(option, options): + func _get_option_visibility(option, options): # Only show the lossy quality setting if the compression mode is set to "Lossy". if option == "compress/lossy_quality" and options.has("compress/mode"): return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set @@ -170,14 +170,14 @@ Return [code]true[/code] to make all options always visible. </description> </method> - <method name="get_preset_count" qualifiers="virtual"> + <method name="_get_preset_count" qualifiers="virtual"> <return type="int"> </return> <description> - Gets the number of initial presets defined by the plugin. Use [method get_import_options] to get the default options for the preset and [method get_preset_name] to get the name of the preset. + Gets the number of initial presets defined by the plugin. Use [method _get_import_options] to get the default options for the preset and [method _get_preset_name] to get the name of the preset. </description> </method> - <method name="get_preset_name" qualifiers="virtual"> + <method name="_get_preset_name" qualifiers="virtual"> <return type="String"> </return> <argument index="0" name="preset" type="int"> @@ -186,42 +186,42 @@ Gets the name of the options preset at this index. </description> </method> - <method name="get_priority" qualifiers="virtual"> + <method name="_get_priority" qualifiers="virtual"> <return type="float"> </return> <description> Gets the priority of this plugin for the recognized extension. Higher priority plugins will be preferred. The default priority is [code]1.0[/code]. </description> </method> - <method name="get_recognized_extensions" qualifiers="virtual"> + <method name="_get_recognized_extensions" qualifiers="virtual"> <return type="Array"> </return> <description> Gets the list of file extensions to associate with this loader (case-insensitive). e.g. [code]["obj"][/code]. </description> </method> - <method name="get_resource_type" qualifiers="virtual"> + <method name="_get_resource_type" qualifiers="virtual"> <return type="String"> </return> <description> Gets the Godot resource type associated with this loader. e.g. [code]"Mesh"[/code] or [code]"Animation"[/code]. </description> </method> - <method name="get_save_extension" qualifiers="virtual"> + <method name="_get_save_extension" qualifiers="virtual"> <return type="String"> </return> <description> Gets the extension used to save this resource in the [code].godot/imported[/code] directory. </description> </method> - <method name="get_visible_name" qualifiers="virtual"> + <method name="_get_visible_name" qualifiers="virtual"> <return type="String"> </return> <description> Gets the name to display in the import window. You should choose this name as a continuation to "Import as", e.g. "Import as Special Mesh". </description> </method> - <method name="import" qualifiers="virtual"> + <method name="_import" qualifiers="virtual"> <return type="int"> </return> <argument index="0" name="source_file" type="String"> diff --git a/doc/classes/EditorInspectorPlugin.xml b/doc/classes/EditorInspectorPlugin.xml index 8204dc931e..c992d0fbb4 100644 --- a/doc/classes/EditorInspectorPlugin.xml +++ b/doc/classes/EditorInspectorPlugin.xml @@ -1,106 +1,100 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorInspectorPlugin" inherits="Reference" version="4.0"> +<class name="EditorInspectorPlugin" inherits="RefCounted" version="4.0"> <brief_description> Plugin for adding custom property editors on inspector. </brief_description> <description> These plugins allow adding custom property editors to [EditorInspector]. Plugins are registered via [method EditorPlugin.add_inspector_plugin]. - When an object is edited, the [method can_handle] function is called and must return [code]true[/code] if the object type is supported. - If supported, the function [method parse_begin] will be called, allowing to place custom controls at the beginning of the class. - Subsequently, the [method parse_category] and [method parse_property] are called for every category and property. They offer the ability to add custom controls to the inspector too. - Finally, [method parse_end] will be called. + When an object is edited, the [method _can_handle] function is called and must return [code]true[/code] if the object type is supported. + If supported, the function [method _parse_begin] will be called, allowing to place custom controls at the beginning of the class. + Subsequently, the [method _parse_category] and [method _parse_property] are called for every category and property. They offer the ability to add custom controls to the inspector too. + Finally, [method _parse_end] will be called. On each of these calls, the "add" functions can be called. </description> <tutorials> </tutorials> <methods> - <method name="add_custom_control"> - <return type="void"> + <method name="_can_handle" qualifiers="virtual"> + <return type="bool"> </return> - <argument index="0" name="control" type="Control"> + <argument index="0" name="object" type="Object"> </argument> <description> - Adds a custom control, not necessarily a property editor. + Returns [code]true[/code] if this object can be handled by this plugin. </description> </method> - <method name="add_property_editor"> + <method name="_parse_begin" qualifiers="virtual"> <return type="void"> </return> - <argument index="0" name="property" type="String"> - </argument> - <argument index="1" name="editor" type="Control"> - </argument> <description> - Adds a property editor, this must inherit [EditorProperty]. + Called to allow adding controls at the beginning of the list. </description> </method> - <method name="add_property_editor_for_multiple_properties"> + <method name="_parse_category" qualifiers="virtual"> <return type="void"> </return> - <argument index="0" name="label" type="String"> - </argument> - <argument index="1" name="properties" type="PackedStringArray"> - </argument> - <argument index="2" name="editor" type="Control"> + <argument index="0" name="category" type="String"> </argument> <description> - Adds an editor that allows modifying multiple properties, this must inherit [EditorProperty]. + Called to allow adding controls at the beginning of the category. </description> </method> - <method name="can_handle" qualifiers="virtual"> - <return type="bool"> + <method name="_parse_end" qualifiers="virtual"> + <return type="void"> </return> - <argument index="0" name="object" type="Object"> - </argument> <description> - Returns [code]true[/code] if this object can be handled by this plugin. + Called to allow adding controls at the end of the list. </description> </method> - <method name="parse_begin" qualifiers="virtual"> - <return type="void"> + <method name="_parse_property" qualifiers="virtual"> + <return type="bool"> </return> - <argument index="0" name="object" type="Object"> + <argument index="0" name="type" type="int"> + </argument> + <argument index="1" name="path" type="String"> + </argument> + <argument index="2" name="hint" type="int"> + </argument> + <argument index="3" name="hint_text" type="String"> + </argument> + <argument index="4" name="usage" type="int"> </argument> <description> - Called to allow adding controls at the beginning of the list. + Called to allow adding property specific editors to the inspector. Usually these inherit [EditorProperty]. Returning [code]true[/code] removes the built-in editor for this property, otherwise allows to insert a custom editor before the built-in one. </description> </method> - <method name="parse_category" qualifiers="virtual"> + <method name="add_custom_control"> <return type="void"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="category" type="String"> + <argument index="0" name="control" type="Control"> </argument> <description> - Called to allow adding controls at the beginning of the category. + Adds a custom control, not necessarily a property editor. </description> </method> - <method name="parse_end" qualifiers="virtual"> + <method name="add_property_editor"> <return type="void"> </return> + <argument index="0" name="property" type="String"> + </argument> + <argument index="1" name="editor" type="Control"> + </argument> <description> - Called to allow adding controls at the end of the list. + Adds a property editor, this must inherit [EditorProperty]. </description> </method> - <method name="parse_property" qualifiers="virtual"> - <return type="bool"> + <method name="add_property_editor_for_multiple_properties"> + <return type="void"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="type" type="int"> - </argument> - <argument index="2" name="path" type="String"> - </argument> - <argument index="3" name="hint" type="int"> + <argument index="0" name="label" type="String"> </argument> - <argument index="4" name="hint_text" type="String"> + <argument index="1" name="properties" type="PackedStringArray"> </argument> - <argument index="5" name="usage" type="int"> + <argument index="2" name="editor" type="Control"> </argument> <description> - Called to allow adding property specific editors to the inspector. Usually these inherit [EditorProperty]. Returning [code]true[/code] removes the built-in editor for this property, otherwise allows to insert a custom editor before the built-in one. + Adds an editor that allows modifying multiple properties, this must inherit [EditorProperty]. </description> </method> </methods> diff --git a/doc/classes/EditorNode3DGizmo.xml b/doc/classes/EditorNode3DGizmo.xml index 45541b9263..221b5e44d6 100644 --- a/doc/classes/EditorNode3DGizmo.xml +++ b/doc/classes/EditorNode3DGizmo.xml @@ -9,13 +9,76 @@ <tutorials> </tutorials> <methods> + <method name="_commit_handle" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <argument index="1" name="restore" type="Variant"> + </argument> + <argument index="2" name="cancel" type="bool" default="false"> + </argument> + <description> + Commit a handle being edited (handles must have been previously added by [method add_handles]). + If the [code]cancel[/code] parameter is [code]true[/code], an option to restore the edited value to the original is provided. + </description> + </method> + <method name="_get_handle_name" qualifiers="virtual"> + <return type="String"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <description> + Gets the name of an edited handle (handles must have been previously added by [method add_handles]). + Handles can be named for reference to the user when editing. + </description> + </method> + <method name="_get_handle_value" qualifiers="virtual"> + <return type="Variant"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <description> + Gets actual value of a handle. This value can be anything and used for eventually undoing the motion when calling [method _commit_handle]. + </description> + </method> + <method name="_is_handle_highlighted" qualifiers="virtual"> + <return type="bool"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <description> + Returns [code]true[/code] if the handle at index [code]index[/code] is highlighted by being hovered with the mouse. + </description> + </method> + <method name="_redraw" qualifiers="virtual"> + <return type="void"> + </return> + <description> + This function is called when the [Node3D] this gizmo refers to changes (the [method Node3D.update_gizmo] is called). + </description> + </method> + <method name="_set_handle" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="index" type="int"> + </argument> + <argument index="1" name="camera" type="Camera3D"> + </argument> + <argument index="2" name="point" type="Vector2"> + </argument> + <description> + This function is used when the user drags a gizmo handle (previously added with [method add_handles]) in screen coordinates. + The [Camera3D] is also provided so screen coordinates can be converted to raycasts. + </description> + </method> <method name="add_collision_segments"> <return type="void"> </return> <argument index="0" name="segments" type="PackedVector3Array"> </argument> <description> - Adds the specified [code]segments[/code] to the gizmo's collision shape for picking. Call this function during [method redraw]. + Adds the specified [code]segments[/code] to the gizmo's collision shape for picking. Call this function during [method _redraw]. </description> </method> <method name="add_collision_triangles"> @@ -24,7 +87,7 @@ <argument index="0" name="triangles" type="TriangleMesh"> </argument> <description> - Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be generated from a regular [Mesh] too. Call this function during [method redraw]. + Adds collision triangles to the gizmo for picking. A [TriangleMesh] can be generated from a regular [Mesh] too. Call this function during [method _redraw]. </description> </method> <method name="add_handles"> @@ -40,7 +103,7 @@ </argument> <description> Adds a list of handles (points) which can be used to deform the object being edited. - There are virtual functions which will be called upon editing of these handles. Call this function during [method redraw]. + There are virtual functions which will be called upon editing of these handles. Call this function during [method _redraw]. </description> </method> <method name="add_lines"> @@ -52,10 +115,10 @@ </argument> <argument index="2" name="billboard" type="bool" default="false"> </argument> - <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> - Adds lines to the gizmo (as sets of 2 points), with a given material. The lines are used for visualizing the gizmo. Call this function during [method redraw]. + Adds lines to the gizmo (as sets of 2 points), with a given material. The lines are used for visualizing the gizmo. Call this function during [method _redraw]. </description> </method> <method name="add_mesh"> @@ -70,7 +133,7 @@ <argument index="3" name="material" type="Material" default="null"> </argument> <description> - Adds a mesh to the gizmo with the specified [code]billboard[/code] state, [code]skeleton[/code] and [code]material[/code]. If [code]billboard[/code] is [code]true[/code], the mesh will rotate to always face the camera. Call this function during [method redraw]. + Adds a mesh to the gizmo with the specified [code]billboard[/code] state, [code]skeleton[/code] and [code]material[/code]. If [code]billboard[/code] is [code]true[/code], the mesh will rotate to always face the camera. Call this function during [method _redraw]. </description> </method> <method name="add_unscaled_billboard"> @@ -80,10 +143,10 @@ </argument> <argument index="1" name="default_scale" type="float" default="1"> </argument> - <argument index="2" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> - Adds an unscaled billboard for visualization. Call this function during [method redraw]. + Adds an unscaled billboard for visualization. Call this function during [method _redraw]. </description> </method> <method name="clear"> @@ -93,39 +156,6 @@ Removes everything in the gizmo including meshes, collisions and handles. </description> </method> - <method name="commit_handle" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="restore" type="Variant"> - </argument> - <argument index="2" name="cancel" type="bool" default="false"> - </argument> - <description> - Commit a handle being edited (handles must have been previously added by [method add_handles]). - If the [code]cancel[/code] parameter is [code]true[/code], an option to restore the edited value to the original is provided. - </description> - </method> - <method name="get_handle_name" qualifiers="virtual"> - <return type="String"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <description> - Gets the name of an edited handle (handles must have been previously added by [method add_handles]). - Handles can be named for reference to the user when editing. - </description> - </method> - <method name="get_handle_value" qualifiers="virtual"> - <return type="Variant"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <description> - Gets actual value of a handle. This value can be anything and used for eventually undoing the motion when calling [method commit_handle]. - </description> - </method> <method name="get_plugin" qualifiers="const"> <return type="EditorNode3DGizmoPlugin"> </return> @@ -140,36 +170,6 @@ Returns the Node3D node associated with this gizmo. </description> </method> - <method name="is_handle_highlighted" qualifiers="virtual"> - <return type="bool"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <description> - Returns [code]true[/code] if the handle at index [code]index[/code] is highlighted by being hovered with the mouse. - </description> - </method> - <method name="redraw" qualifiers="virtual"> - <return type="void"> - </return> - <description> - This function is called when the [Node3D] this gizmo refers to changes (the [method Node3D.update_gizmo] is called). - </description> - </method> - <method name="set_handle" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="index" type="int"> - </argument> - <argument index="1" name="camera" type="Camera3D"> - </argument> - <argument index="2" name="point" type="Vector2"> - </argument> - <description> - This function is used when the user drags a gizmo handle (previously added with [method add_handles]) in screen coordinates. - The [Camera3D] is also provided so screen coordinates can be converted to raycasts. - </description> - </method> <method name="set_hidden"> <return type="void"> </return> diff --git a/doc/classes/EditorNode3DGizmoPlugin.xml b/doc/classes/EditorNode3DGizmoPlugin.xml index 34657a1c08..41c94cbbc6 100644 --- a/doc/classes/EditorNode3DGizmoPlugin.xml +++ b/doc/classes/EditorNode3DGizmoPlugin.xml @@ -10,25 +10,14 @@ <link title="Spatial gizmo plugins">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/spatial_gizmos.html</link> </tutorials> <methods> - <method name="add_material"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="material" type="StandardMaterial3D"> - </argument> - <description> - Adds a new material to the internal material list for the plugin. It can then be accessed with [method get_material]. Should not be overridden. - </description> - </method> - <method name="can_be_hidden" qualifiers="virtual"> + <method name="_can_be_hidden" qualifiers="virtual"> <return type="bool"> </return> <description> Override this method to define whether the gizmo can be hidden or not. Returns [code]true[/code] if not overridden. </description> </method> - <method name="commit_handle" qualifiers="virtual"> + <method name="_commit_handle" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="gizmo" type="EditorNode3DGizmo"> @@ -43,69 +32,23 @@ Override this method to commit gizmo handles. Called for this plugin's active gizmos. </description> </method> - <method name="create_gizmo" qualifiers="virtual"> + <method name="_create_gizmo" qualifiers="virtual"> <return type="EditorNode3DGizmo"> </return> <argument index="0" name="spatial" type="Node3D"> </argument> <description> - Override this method to return a custom [EditorNode3DGizmo] for the spatial nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method has_gizmo]. - </description> - </method> - <method name="create_handle_material"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="billboard" type="bool" default="false"> - </argument> - <argument index="2" name="texture" type="Texture2D" default="null"> - </argument> - <description> - Creates a handle material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_handles]. Should not be overridden. - You can optionally provide a texture to use instead of the default icon. + Override this method to return a custom [EditorNode3DGizmo] for the spatial nodes of your choice, return [code]null[/code] for the rest of nodes. See also [method _has_gizmo]. </description> </method> - <method name="create_icon_material"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="texture" type="Texture2D"> - </argument> - <argument index="2" name="on_top" type="bool" default="false"> - </argument> - <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> - </argument> - <description> - Creates an icon material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_unscaled_billboard]. Should not be overridden. - </description> - </method> - <method name="create_material"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="color" type="Color"> - </argument> - <argument index="2" name="billboard" type="bool" default="false"> - </argument> - <argument index="3" name="on_top" type="bool" default="false"> - </argument> - <argument index="4" name="use_vertex_color" type="bool" default="false"> - </argument> - <description> - Creates an unshaded material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_mesh] and [method EditorNode3DGizmo.add_lines]. Should not be overridden. - </description> - </method> - <method name="get_gizmo_name" qualifiers="virtual"> + <method name="_get_gizmo_name" qualifiers="virtual"> <return type="String"> </return> <description> Override this method to provide the name that will appear in the gizmo visibility menu. </description> </method> - <method name="get_handle_name" qualifiers="virtual"> + <method name="_get_handle_name" qualifiers="virtual"> <return type="String"> </return> <argument index="0" name="gizmo" type="EditorNode3DGizmo"> @@ -116,7 +59,7 @@ Override this method to provide gizmo's handle names. Called for this plugin's active gizmos. </description> </method> - <method name="get_handle_value" qualifiers="virtual"> + <method name="_get_handle_value" qualifiers="virtual"> <return type="Variant"> </return> <argument index="0" name="gizmo" type="EditorNode3DGizmo"> @@ -127,18 +70,7 @@ Gets actual value of a handle from gizmo. Called for this plugin's active gizmos. </description> </method> - <method name="get_material"> - <return type="StandardMaterial3D"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="gizmo" type="EditorNode3DGizmo" default="null"> - </argument> - <description> - Gets material from the internal list of materials. If an [EditorNode3DGizmo] is provided, it will try to get the corresponding variant (selected and/or editable). - </description> - </method> - <method name="get_priority" qualifiers="virtual"> + <method name="_get_priority" qualifiers="virtual"> <return type="int"> </return> <description> @@ -146,7 +78,7 @@ All built-in editor gizmos return a priority of [code]-1[/code]. If not overridden, this method will return [code]0[/code], which means custom gizmos will automatically override built-in gizmos. </description> </method> - <method name="has_gizmo" qualifiers="virtual"> + <method name="_has_gizmo" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="spatial" type="Node3D"> @@ -155,7 +87,7 @@ Override this method to define which Node3D nodes have a gizmo from this plugin. Whenever a [Node3D] node is added to a scene this method is called, if it returns [code]true[/code] the node gets a generic [EditorNode3DGizmo] assigned and is added to this plugin's list of active gizmos. </description> </method> - <method name="is_handle_highlighted" qualifiers="virtual"> + <method name="_is_handle_highlighted" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="gizmo" type="EditorNode3DGizmo"> @@ -166,14 +98,14 @@ Gets whether a handle is highlighted or not. Called for this plugin's active gizmos. </description> </method> - <method name="is_selectable_when_hidden" qualifiers="virtual"> + <method name="_is_selectable_when_hidden" qualifiers="virtual"> <return type="bool"> </return> <description> Override this method to define whether Node3D with this gizmo should be selectable even when the gizmo is hidden. </description> </method> - <method name="redraw" qualifiers="virtual"> + <method name="_redraw" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="gizmo" type="EditorNode3DGizmo"> @@ -182,7 +114,7 @@ Callback to redraw the provided gizmo. Called for this plugin's active gizmos. </description> </method> - <method name="set_handle" qualifiers="virtual"> + <method name="_set_handle" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="gizmo" type="EditorNode3DGizmo"> @@ -197,6 +129,74 @@ Update the value of a handle after it has been updated. Called for this plugin's active gizmos. </description> </method> + <method name="add_material"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="material" type="StandardMaterial3D"> + </argument> + <description> + Adds a new material to the internal material list for the plugin. It can then be accessed with [method get_material]. Should not be overridden. + </description> + </method> + <method name="create_handle_material"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="billboard" type="bool" default="false"> + </argument> + <argument index="2" name="texture" type="Texture2D" default="null"> + </argument> + <description> + Creates a handle material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_handles]. Should not be overridden. + You can optionally provide a texture to use instead of the default icon. + </description> + </method> + <method name="create_icon_material"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="texture" type="Texture2D"> + </argument> + <argument index="2" name="on_top" type="bool" default="false"> + </argument> + <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)"> + </argument> + <description> + Creates an icon material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_unscaled_billboard]. Should not be overridden. + </description> + </method> + <method name="create_material"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <argument index="2" name="billboard" type="bool" default="false"> + </argument> + <argument index="3" name="on_top" type="bool" default="false"> + </argument> + <argument index="4" name="use_vertex_color" type="bool" default="false"> + </argument> + <description> + Creates an unshaded material with its variants (selected and/or editable) and adds them to the internal material list. They can then be accessed with [method get_material] and used in [method EditorNode3DGizmo.add_mesh] and [method EditorNode3DGizmo.add_lines]. Should not be overridden. + </description> + </method> + <method name="get_material"> + <return type="StandardMaterial3D"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="gizmo" type="EditorNode3DGizmo" default="null"> + </argument> + <description> + Gets material from the internal list of materials. If an [EditorNode3DGizmo] is provided, it will try to get the corresponding variant (selected and/or editable). + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index 6c40b7aa9d..753227513b 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -10,185 +10,7 @@ <link title="Editor plugins tutorial index">https://docs.godotengine.org/en/latest/tutorials/plugins/editor/index.html</link> </tutorials> <methods> - <method name="add_autoload_singleton"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="path" type="String"> - </argument> - <description> - Adds a script at [code]path[/code] to the Autoload list as [code]name[/code]. - </description> - </method> - <method name="add_control_to_bottom_panel"> - <return type="Button"> - </return> - <argument index="0" name="control" type="Control"> - </argument> - <argument index="1" name="title" type="String"> - </argument> - <description> - Adds a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [method Node.queue_free]. - </description> - </method> - <method name="add_control_to_container"> - <return type="void"> - </return> - <argument index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer"> - </argument> - <argument index="1" name="control" type="Control"> - </argument> - <description> - Adds a custom control to a container (see [enum CustomControlContainer]). There are many locations where custom controls can be added in the editor UI. - Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it). - When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_container] and free it with [method Node.queue_free]. - </description> - </method> - <method name="add_control_to_dock"> - <return type="void"> - </return> - <argument index="0" name="slot" type="int" enum="EditorPlugin.DockSlot"> - </argument> - <argument index="1" name="control" type="Control"> - </argument> - <description> - Adds the control to a specific dock slot (see [enum DockSlot] for options). - If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions. - When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_docks] and free it with [method Node.queue_free]. - </description> - </method> - <method name="add_custom_type"> - <return type="void"> - </return> - <argument index="0" name="type" type="String"> - </argument> - <argument index="1" name="base" type="String"> - </argument> - <argument index="2" name="script" type="Script"> - </argument> - <argument index="3" name="icon" type="Texture2D"> - </argument> - <description> - Adds a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed. - When given node or resource is selected, the base type will be instanced (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object. - You can use the virtual method [method handles] to check if your custom object is being edited by checking the script or using the [code]is[/code] keyword. - During run-time, this will be a simple object with a script so this function does not need to be called then. - </description> - </method> - <method name="add_debugger_plugin"> - <return type="void"> - </return> - <argument index="0" name="script" type="Script"> - </argument> - <description> - Adds a [Script] as debugger plugin to the Debugger. The script must extend [EditorDebuggerPlugin]. - </description> - </method> - <method name="add_export_plugin"> - <return type="void"> - </return> - <argument index="0" name="plugin" type="EditorExportPlugin"> - </argument> - <description> - Registers a new [EditorExportPlugin]. Export plugins are used to perform tasks when the project is being exported. - See [method add_inspector_plugin] for an example of how to register a plugin. - </description> - </method> - <method name="add_import_plugin"> - <return type="void"> - </return> - <argument index="0" name="importer" type="EditorImportPlugin"> - </argument> - <description> - Registers a new [EditorImportPlugin]. Import plugins are used to import custom and unsupported assets as a custom [Resource] type. - [b]Note:[/b] If you want to import custom 3D asset formats use [method add_scene_import_plugin] instead. - See [method add_inspector_plugin] for an example of how to register a plugin. - </description> - </method> - <method name="add_inspector_plugin"> - <return type="void"> - </return> - <argument index="0" name="plugin" type="EditorInspectorPlugin"> - </argument> - <description> - Registers a new [EditorInspectorPlugin]. Inspector plugins are used to extend [EditorInspector] and provide custom configuration tools for your object's properties. - [b]Note:[/b] Always use [method remove_inspector_plugin] to remove the registered [EditorInspectorPlugin] when your [EditorPlugin] is disabled to prevent leaks and an unexpected behavior. - [codeblocks] - [gdscript] - const MyInspectorPlugin = preload("res://addons/your_addon/path/to/your/script.gd") - var inspector_plugin = MyInspectorPlugin.new() - - func _enter_tree(): - add_inspector_plugin(inspector_plugin) - - func _exit_tree(): - remove_inspector_plugin(inspector_plugin) - [/gdscript] - [/codeblocks] - </description> - </method> - <method name="add_scene_import_plugin"> - <return type="void"> - </return> - <argument index="0" name="scene_importer" type="EditorSceneImporter"> - </argument> - <description> - Registers a new [EditorSceneImporter]. Scene importers are used to import custom 3D asset formats as scenes. - </description> - </method> - <method name="add_spatial_gizmo_plugin"> - <return type="void"> - </return> - <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin"> - </argument> - <description> - Registers a new [EditorNode3DGizmoPlugin]. Gizmo plugins are used to add custom gizmos to the 3D preview viewport for a [Node3D]. - See [method add_inspector_plugin] for an example of how to register a plugin. - </description> - </method> - <method name="add_tool_menu_item"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="callable" type="Callable"> - </argument> - <description> - Adds a custom menu item to [b]Project > Tools[/b] named [code]name[/code]. When clicked, the provided [code]callable[/code] will be called. - </description> - </method> - <method name="add_tool_submenu_item"> - <return type="void"> - </return> - <argument index="0" name="name" type="String"> - </argument> - <argument index="1" name="submenu" type="Object"> - </argument> - <description> - Adds a custom submenu under [b]Project > Tools >[/b] [code]name[/code]. [code]submenu[/code] should be an object of class [PopupMenu]. Use [code]remove_tool_menu_item(name)[/code] on plugin clean up to remove the menu. - </description> - </method> - <method name="add_translation_parser_plugin"> - <return type="void"> - </return> - <argument index="0" name="parser" type="EditorTranslationParserPlugin"> - </argument> - <description> - Registers a custom translation parser plugin for extracting translatable strings from custom files. - </description> - </method> - <method name="add_undo_redo_inspector_hook_callback"> - <return type="void"> - </return> - <argument index="0" name="callable" type="Callable"> - </argument> - <description> - Hooks a callback into the undo/redo action creation when a property is modified in the inspector. This allows, for example, to save other properties that may be lost when a given property is modified. - The callback should have 4 arguments: [Object] [code]undo_redo[/code], [Object] [code]modified_object[/code], [String] [code]property[/code] and [Variant] [code]new_value[/code]. They are, respectively, the [UndoRedo] object used by the inspector, the currently modified object, the name of the modified property and the new value the property is about to take. - </description> - </method> - <method name="apply_changes" qualifiers="virtual"> + <method name="_apply_changes" qualifiers="virtual"> <return type="void"> </return> <description> @@ -196,29 +18,29 @@ This is used, for example, in shader editors to let the plugin know that it must apply the shader code being written by the user to the object. </description> </method> - <method name="build" qualifiers="virtual"> + <method name="_build" qualifiers="virtual"> <return type="bool"> </return> <description> This method is called when the editor is about to run the project. The plugin can then perform required operations before the project runs. - This method must return a boolean. If this method returns [code]false[/code], the project will not run. The run is aborted immediately, so this also prevents all other plugins' [method build] methods from running. + This method must return a boolean. If this method returns [code]false[/code], the project will not run. The run is aborted immediately, so this also prevents all other plugins' [method _build] methods from running. </description> </method> - <method name="clear" qualifiers="virtual"> + <method name="_clear" qualifiers="virtual"> <return type="void"> </return> <description> Clear all the state and reset the object being edited to zero. This ensures your plugin does not keep editing a currently existing node, or a node from the wrong scene. </description> </method> - <method name="disable_plugin" qualifiers="virtual"> + <method name="_disable_plugin" qualifiers="virtual"> <return type="void"> </return> <description> Called by the engine when the user disables the [EditorPlugin] in the Plugin tab of the project settings window. </description> </method> - <method name="edit" qualifiers="virtual"> + <method name="_edit" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="object" type="Object"> @@ -227,14 +49,14 @@ This function is used for plugins that edit specific object types (nodes or resources). It requests the editor to edit the given object. </description> </method> - <method name="enable_plugin" qualifiers="virtual"> + <method name="_enable_plugin" qualifiers="virtual"> <return type="void"> </return> <description> Called by the engine when the user enables the [EditorPlugin] in the Plugin tab of the project settings window. </description> </method> - <method name="forward_canvas_draw_over_viewport" qualifiers="virtual"> + <method name="_forward_canvas_draw_over_viewport" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="overlay" type="Control"> @@ -243,11 +65,11 @@ Called by the engine when the 2D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays]. [codeblocks] [gdscript] - func forward_canvas_draw_over_viewport(overlay): + func _forward_canvas_draw_over_viewport(overlay): # Draw a circle at cursor position. overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white) - func forward_canvas_gui_input(event): + func _forward_canvas_gui_input(event): if event is InputEventMouseMotion: # Redraw viewport when cursor is moved. update_overlays() @@ -274,27 +96,27 @@ [/codeblocks] </description> </method> - <method name="forward_canvas_force_draw_over_viewport" qualifiers="virtual"> + <method name="_forward_canvas_force_draw_over_viewport" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="overlay" type="Control"> </argument> <description> - This method is the same as [method forward_canvas_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else. + This method is the same as [method _forward_canvas_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else. You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled]. </description> </method> - <method name="forward_canvas_gui_input" qualifiers="virtual"> + <method name="_forward_canvas_gui_input" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="event" type="InputEvent"> </argument> <description> - Called when there is a root node in the current edited scene, [method handles] is implemented and an [InputEvent] happens in the 2D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example: + Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 2D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example: [codeblocks] [gdscript] # Prevents the InputEvent to reach other Editor classes - func forward_canvas_gui_input(event): + func _forward_canvas_gui_input(event): return true [/gdscript] [csharp] @@ -309,7 +131,7 @@ [codeblocks] [gdscript] # Consumes InputEventMouseMotion and forwards other InputEvent types. - func forward_canvas_gui_input(event): + func _forward_canvas_gui_input(event): return event is InputEventMouseMotion [/gdscript] [csharp] @@ -322,7 +144,7 @@ [/codeblocks] </description> </method> - <method name="forward_spatial_draw_over_viewport" qualifiers="virtual"> + <method name="_forward_spatial_draw_over_viewport" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="overlay" type="Control"> @@ -331,11 +153,11 @@ Called by the engine when the 3D editor's viewport is updated. Use the [code]overlay[/code] [Control] for drawing. You can update the viewport manually by calling [method update_overlays]. [codeblocks] [gdscript] - func forward_spatial_draw_over_viewport(overlay): + func _forward_spatial_draw_over_viewport(overlay): # Draw a circle at cursor position. overlay.draw_circle(overlay.get_local_mouse_position(), 64) - func forward_spatial_gui_input(camera, event): + func _forward_spatial_gui_input(camera, event): if event is InputEventMouseMotion: # Redraw viewport when cursor is moved. update_overlays() @@ -362,17 +184,17 @@ [/codeblocks] </description> </method> - <method name="forward_spatial_force_draw_over_viewport" qualifiers="virtual"> + <method name="_forward_spatial_force_draw_over_viewport" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="overlay" type="Control"> </argument> <description> - This method is the same as [method forward_spatial_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else. + This method is the same as [method _forward_spatial_draw_over_viewport], except it draws on top of everything. Useful when you need an extra layer that shows over anything else. You need to enable calling of this method by using [method set_force_draw_over_forwarding_enabled]. </description> </method> - <method name="forward_spatial_gui_input" qualifiers="virtual"> + <method name="_forward_spatial_gui_input" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="camera" type="Camera3D"> @@ -380,11 +202,11 @@ <argument index="1" name="event" type="InputEvent"> </argument> <description> - Called when there is a root node in the current edited scene, [method handles] is implemented and an [InputEvent] happens in the 3D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example: + Called when there is a root node in the current edited scene, [method _handles] is implemented and an [InputEvent] happens in the 3D viewport. Intercepts the [InputEvent], if [code]return true[/code] [EditorPlugin] consumes the [code]event[/code], otherwise forwards [code]event[/code] to other Editor classes. Example: [codeblocks] [gdscript] # Prevents the InputEvent to reach other Editor classes. - func forward_spatial_gui_input(camera, event): + func _forward_spatial_gui_input(camera, event): return true [/gdscript] [csharp] @@ -399,7 +221,7 @@ [codeblocks] [gdscript] # Consumes InputEventMouseMotion and forwards other InputEvent types. - func forward_spatial_gui_input(camera, event): + func _forward_spatial_gui_input(camera, event): return event is InputEventMouseMotion [/gdscript] [csharp] @@ -412,21 +234,14 @@ [/codeblocks] </description> </method> - <method name="get_breakpoints" qualifiers="virtual"> + <method name="_get_breakpoints" qualifiers="virtual"> <return type="PackedStringArray"> </return> <description> This is for editors that edit script-based objects. You can return a list of breakpoints in the format ([code]script:line[/code]), for example: [code]res://path_to_script.gd:25[/code]. </description> </method> - <method name="get_editor_interface"> - <return type="EditorInterface"> - </return> - <description> - Returns the [EditorInterface] object that gives you control over Godot editor's window and its functionalities. - </description> - </method> - <method name="get_plugin_icon" qualifiers="virtual"> + <method name="_get_plugin_icon" qualifiers="virtual"> <return type="Texture2D"> </return> <description> @@ -435,7 +250,7 @@ Ideally, the plugin icon should be white with a transparent background and 16x16 pixels in size. [codeblocks] [gdscript] - func get_plugin_icon(): + func _get_plugin_icon(): # You can use a custom icon: return preload("res://addons/my_plugin/my_plugin_icon.svg") # Or use a built-in icon: @@ -453,7 +268,7 @@ [/codeblocks] </description> </method> - <method name="get_plugin_name" qualifiers="virtual"> + <method name="_get_plugin_name" qualifiers="virtual"> <return type="String"> </return> <description> @@ -461,75 +276,287 @@ For main screen plugins, this appears at the top of the screen, to the right of the "2D", "3D", "Script", and "AssetLib" buttons. </description> </method> - <method name="get_script_create_dialog"> - <return type="ScriptCreateDialog"> + <method name="_get_state" qualifiers="virtual"> + <return type="Dictionary"> </return> <description> - Gets the Editor's dialogue used for making scripts. - [b]Note:[/b] Users can configure it before use. + Gets the state of your plugin editor. This is used when saving the scene (so state is kept when opening it again) and for switching tabs (so state can be restored when the tab returns). </description> </method> - <method name="get_state" qualifiers="virtual"> - <return type="Dictionary"> + <method name="_get_window_layout" qualifiers="virtual"> + <return type="void"> </return> + <argument index="0" name="layout" type="ConfigFile"> + </argument> <description> - Gets the state of your plugin editor. This is used when saving the scene (so state is kept when opening it again) and for switching tabs (so state can be restored when the tab returns). + Gets the GUI layout of the plugin. This is used to save the project's editor layout when [method queue_save_layout] is called or the editor layout was changed(For example changing the position of a dock). </description> </method> - <method name="get_undo_redo"> - <return type="UndoRedo"> + <method name="_handles" qualifiers="virtual"> + <return type="bool"> </return> + <argument index="0" name="object" type="Object"> + </argument> <description> - Gets the undo/redo object. Most actions in the editor can be undoable, so use this object to make sure this happens when it's worth it. + Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method _edit] and [method _make_visible] called when the editor requests them. If you have declared the methods [method _forward_canvas_gui_input] and [method _forward_spatial_gui_input] these will be called too. + </description> + </method> + <method name="_has_main_screen" qualifiers="virtual"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if this is a main screen editor plugin (it goes in the workspace selector together with [b]2D[/b], [b]3D[/b], [b]Script[/b] and [b]AssetLib[/b]). + </description> + </method> + <method name="_make_visible" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="visible" type="bool"> + </argument> + <description> + This function will be called when the editor is requested to become visible. It is used for plugins that edit a specific object type. + Remember that you have to manage the visibility of all your editor controls manually. + </description> + </method> + <method name="_save_external_data" qualifiers="virtual"> + <return type="void"> + </return> + <description> + This method is called after the editor saves the project or when it's closed. It asks the plugin to save edited external scenes/resources. + </description> + </method> + <method name="_set_state" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="state" type="Dictionary"> + </argument> + <description> + Restore the state saved by [method _get_state]. </description> </method> - <method name="get_window_layout" qualifiers="virtual"> + <method name="_set_window_layout" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="layout" type="ConfigFile"> </argument> <description> - Gets the GUI layout of the plugin. This is used to save the project's editor layout when [method queue_save_layout] is called or the editor layout was changed(For example changing the position of a dock). + Restore the plugin GUI layout saved by [method _get_window_layout]. </description> </method> - <method name="handles" qualifiers="virtual"> - <return type="bool"> + <method name="add_autoload_singleton"> + <return type="void"> </return> - <argument index="0" name="object" type="Object"> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="path" type="String"> </argument> <description> - Implement this function if your plugin edits a specific type of object (Resource or Node). If you return [code]true[/code], then you will get the functions [method edit] and [method make_visible] called when the editor requests them. If you have declared the methods [method forward_canvas_gui_input] and [method forward_spatial_gui_input] these will be called too. + Adds a script at [code]path[/code] to the Autoload list as [code]name[/code]. </description> </method> - <method name="has_main_screen" qualifiers="virtual"> - <return type="bool"> + <method name="add_control_to_bottom_panel"> + <return type="Button"> </return> + <argument index="0" name="control" type="Control"> + </argument> + <argument index="1" name="title" type="String"> + </argument> <description> - Returns [code]true[/code] if this is a main screen editor plugin (it goes in the workspace selector together with [b]2D[/b], [b]3D[/b], [b]Script[/b] and [b]AssetLib[/b]). + Adds a control to the bottom panel (together with Output, Debug, Animation, etc). Returns a reference to the button added. It's up to you to hide/show the button when needed. When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_bottom_panel] and free it with [method Node.queue_free]. </description> </method> - <method name="hide_bottom_panel"> + <method name="add_control_to_container"> <return type="void"> </return> + <argument index="0" name="container" type="int" enum="EditorPlugin.CustomControlContainer"> + </argument> + <argument index="1" name="control" type="Control"> + </argument> <description> + Adds a custom control to a container (see [enum CustomControlContainer]). There are many locations where custom controls can be added in the editor UI. + Please remember that you have to manage the visibility of your custom controls yourself (and likely hide it after adding it). + When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_container] and free it with [method Node.queue_free]. </description> </method> - <method name="make_bottom_panel_item_visible"> + <method name="add_control_to_dock"> <return type="void"> </return> - <argument index="0" name="item" type="Control"> + <argument index="0" name="slot" type="int" enum="EditorPlugin.DockSlot"> + </argument> + <argument index="1" name="control" type="Control"> </argument> <description> + Adds the control to a specific dock slot (see [enum DockSlot] for options). + If the dock is repositioned and as long as the plugin is active, the editor will save the dock position on further sessions. + When your plugin is deactivated, make sure to remove your custom control with [method remove_control_from_docks] and free it with [method Node.queue_free]. </description> </method> - <method name="make_visible" qualifiers="virtual"> + <method name="add_custom_type"> <return type="void"> </return> - <argument index="0" name="visible" type="bool"> + <argument index="0" name="type" type="String"> + </argument> + <argument index="1" name="base" type="String"> + </argument> + <argument index="2" name="script" type="Script"> + </argument> + <argument index="3" name="icon" type="Texture2D"> </argument> <description> - This function will be called when the editor is requested to become visible. It is used for plugins that edit a specific object type. - Remember that you have to manage the visibility of all your editor controls manually. + Adds a custom type, which will appear in the list of nodes or resources. An icon can be optionally passed. + When given node or resource is selected, the base type will be instantiated (e.g. "Node3D", "Control", "Resource"), then the script will be loaded and set to this object. + You can use the virtual method [method _handles] to check if your custom object is being edited by checking the script or using the [code]is[/code] keyword. + During run-time, this will be a simple object with a script so this function does not need to be called then. + </description> + </method> + <method name="add_debugger_plugin"> + <return type="void"> + </return> + <argument index="0" name="script" type="Script"> + </argument> + <description> + Adds a [Script] as debugger plugin to the Debugger. The script must extend [EditorDebuggerPlugin]. + </description> + </method> + <method name="add_export_plugin"> + <return type="void"> + </return> + <argument index="0" name="plugin" type="EditorExportPlugin"> + </argument> + <description> + Registers a new [EditorExportPlugin]. Export plugins are used to perform tasks when the project is being exported. + See [method add_inspector_plugin] for an example of how to register a plugin. + </description> + </method> + <method name="add_import_plugin"> + <return type="void"> + </return> + <argument index="0" name="importer" type="EditorImportPlugin"> + </argument> + <description> + Registers a new [EditorImportPlugin]. Import plugins are used to import custom and unsupported assets as a custom [Resource] type. + [b]Note:[/b] If you want to import custom 3D asset formats use [method add_scene_import_plugin] instead. + See [method add_inspector_plugin] for an example of how to register a plugin. + </description> + </method> + <method name="add_inspector_plugin"> + <return type="void"> + </return> + <argument index="0" name="plugin" type="EditorInspectorPlugin"> + </argument> + <description> + Registers a new [EditorInspectorPlugin]. Inspector plugins are used to extend [EditorInspector] and provide custom configuration tools for your object's properties. + [b]Note:[/b] Always use [method remove_inspector_plugin] to remove the registered [EditorInspectorPlugin] when your [EditorPlugin] is disabled to prevent leaks and an unexpected behavior. + [codeblocks] + [gdscript] + const MyInspectorPlugin = preload("res://addons/your_addon/path/to/your/script.gd") + var inspector_plugin = MyInspectorPlugin.new() + + func _enter_tree(): + add_inspector_plugin(inspector_plugin) + + func _exit_tree(): + remove_inspector_plugin(inspector_plugin) + [/gdscript] + [/codeblocks] + </description> + </method> + <method name="add_scene_import_plugin"> + <return type="void"> + </return> + <argument index="0" name="scene_importer" type="EditorSceneImporter"> + </argument> + <description> + Registers a new [EditorSceneImporter]. Scene importers are used to import custom 3D asset formats as scenes. + </description> + </method> + <method name="add_spatial_gizmo_plugin"> + <return type="void"> + </return> + <argument index="0" name="plugin" type="EditorNode3DGizmoPlugin"> + </argument> + <description> + Registers a new [EditorNode3DGizmoPlugin]. Gizmo plugins are used to add custom gizmos to the 3D preview viewport for a [Node3D]. + See [method add_inspector_plugin] for an example of how to register a plugin. + </description> + </method> + <method name="add_tool_menu_item"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="callable" type="Callable"> + </argument> + <description> + Adds a custom menu item to [b]Project > Tools[/b] named [code]name[/code]. When clicked, the provided [code]callable[/code] will be called. + </description> + </method> + <method name="add_tool_submenu_item"> + <return type="void"> + </return> + <argument index="0" name="name" type="String"> + </argument> + <argument index="1" name="submenu" type="Object"> + </argument> + <description> + Adds a custom submenu under [b]Project > Tools >[/b] [code]name[/code]. [code]submenu[/code] should be an object of class [PopupMenu]. Use [code]remove_tool_menu_item(name)[/code] on plugin clean up to remove the menu. + </description> + </method> + <method name="add_translation_parser_plugin"> + <return type="void"> + </return> + <argument index="0" name="parser" type="EditorTranslationParserPlugin"> + </argument> + <description> + Registers a custom translation parser plugin for extracting translatable strings from custom files. + </description> + </method> + <method name="add_undo_redo_inspector_hook_callback"> + <return type="void"> + </return> + <argument index="0" name="callable" type="Callable"> + </argument> + <description> + Hooks a callback into the undo/redo action creation when a property is modified in the inspector. This allows, for example, to save other properties that may be lost when a given property is modified. + The callback should have 4 arguments: [Object] [code]undo_redo[/code], [Object] [code]modified_object[/code], [String] [code]property[/code] and [Variant] [code]new_value[/code]. They are, respectively, the [UndoRedo] object used by the inspector, the currently modified object, the name of the modified property and the new value the property is about to take. + </description> + </method> + <method name="get_editor_interface"> + <return type="EditorInterface"> + </return> + <description> + Returns the [EditorInterface] object that gives you control over Godot editor's window and its functionalities. + </description> + </method> + <method name="get_script_create_dialog"> + <return type="ScriptCreateDialog"> + </return> + <description> + Gets the Editor's dialogue used for making scripts. + [b]Note:[/b] Users can configure it before use. + </description> + </method> + <method name="get_undo_redo"> + <return type="UndoRedo"> + </return> + <description> + Gets the undo/redo object. Most actions in the editor can be undoable, so use this object to make sure this happens when it's worth it. + </description> + </method> + <method name="hide_bottom_panel"> + <return type="void"> + </return> + <description> + Minimizes the bottom panel. + </description> + </method> + <method name="make_bottom_panel_item_visible"> + <return type="void"> + </return> + <argument index="0" name="item" type="Control"> + </argument> + <description> + Makes a specific item in the bottom panel visible. </description> </method> <method name="queue_save_layout"> @@ -667,50 +694,25 @@ Removes a callback previsously added by [method add_undo_redo_inspector_hook_callback]. </description> </method> - <method name="save_external_data" qualifiers="virtual"> - <return type="void"> - </return> - <description> - This method is called after the editor saves the project or when it's closed. It asks the plugin to save edited external scenes/resources. - </description> - </method> <method name="set_force_draw_over_forwarding_enabled"> <return type="void"> </return> <description> - Enables calling of [method forward_canvas_force_draw_over_viewport] for the 2D editor and [method forward_spatial_force_draw_over_viewport] for the 3D editor when their viewports are updated. You need to call this method only once and it will work permanently for this plugin. + Enables calling of [method _forward_canvas_force_draw_over_viewport] for the 2D editor and [method _forward_spatial_force_draw_over_viewport] for the 3D editor when their viewports are updated. You need to call this method only once and it will work permanently for this plugin. </description> </method> <method name="set_input_event_forwarding_always_enabled"> <return type="void"> </return> <description> - Use this method if you always want to receive inputs from 3D view screen inside [method forward_spatial_gui_input]. It might be especially usable if your plugin will want to use raycast in the scene. - </description> - </method> - <method name="set_state" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="state" type="Dictionary"> - </argument> - <description> - Restore the state saved by [method get_state]. - </description> - </method> - <method name="set_window_layout" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="layout" type="ConfigFile"> - </argument> - <description> - Restore the plugin GUI layout saved by [method get_window_layout]. + Use this method if you always want to receive inputs from 3D view screen inside [method _forward_spatial_gui_input]. It might be especially usable if your plugin will want to use raycast in the scene. </description> </method> <method name="update_overlays" qualifiers="const"> <return type="int"> </return> <description> - Updates the overlays of the 2D and 3D editor viewport. Causes methods [method forward_canvas_draw_over_viewport], [method forward_canvas_force_draw_over_viewport], [method forward_spatial_draw_over_viewport] and [method forward_spatial_force_draw_over_viewport] to be called. + Updates the overlays of the 2D and 3D editor viewport. Causes methods [method _forward_canvas_draw_over_viewport], [method _forward_canvas_force_draw_over_viewport], [method _forward_spatial_draw_over_viewport] and [method _forward_spatial_force_draw_over_viewport] to be called. </description> </method> </methods> diff --git a/doc/classes/EditorProperty.xml b/doc/classes/EditorProperty.xml index f568263ff8..549d2c1628 100644 --- a/doc/classes/EditorProperty.xml +++ b/doc/classes/EditorProperty.xml @@ -9,6 +9,13 @@ <tutorials> </tutorials> <methods> + <method name="_update_property" qualifiers="virtual"> + <return type="void"> + </return> + <description> + When this virtual function is called, you must update your editor. + </description> + </method> <method name="add_focusable"> <return type="void"> </return> @@ -25,7 +32,7 @@ </argument> <argument index="1" name="value" type="Variant"> </argument> - <argument index="2" name="field" type="StringName" default="@"""> + <argument index="2" name="field" type="StringName" default="&"""> </argument> <argument index="3" name="changing" type="bool" default="false"> </argument> @@ -44,7 +51,7 @@ <return type="StringName"> </return> <description> - Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin.parse_property]), then this will return the property. + Gets the edited property. If your editor is for a single property (added via [method EditorInspectorPlugin._parse_property]), then this will return the property. </description> </method> <method name="get_tooltip_text" qualifiers="const"> @@ -63,13 +70,6 @@ Adds controls with this function if you want them on the bottom (below the label). </description> </method> - <method name="update_property" qualifiers="virtual"> - <return type="void"> - </return> - <description> - When this virtual function is called, you must update your editor. - </description> - </method> </methods> <members> <member name="checkable" type="bool" setter="set_checkable" getter="is_checkable" default="false"> @@ -101,7 +101,7 @@ <argument index="1" name="value" type="Array"> </argument> <description> - Emit it if you want multiple properties modified at the same time. Do not use if added via [method EditorInspectorPlugin.parse_property]. + Emit it if you want multiple properties modified at the same time. Do not use if added via [method EditorInspectorPlugin._parse_property]. </description> </signal> <signal name="object_id_selected"> diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml index 1976eb802c..1d7e98c99d 100644 --- a/doc/classes/EditorResourceConversionPlugin.xml +++ b/doc/classes/EditorResourceConversionPlugin.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorResourceConversionPlugin" inherits="Reference" version="4.0"> +<class name="EditorResourceConversionPlugin" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/EditorResourcePicker.xml b/doc/classes/EditorResourcePicker.xml index 30c73daa77..0029955819 100644 --- a/doc/classes/EditorResourcePicker.xml +++ b/doc/classes/EditorResourcePicker.xml @@ -10,28 +10,23 @@ <tutorials> </tutorials> <methods> - <method name="can_drop_data_fw" qualifiers="const"> - <return type="bool"> + <method name="_handle_menu_selected" qualifiers="virtual"> + <return type="void"> </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <argument index="2" name="from" type="Control"> + <argument index="0" name="id" type="int"> </argument> <description> + This virtual method can be implemented to handle context menu items not handled by default. See [method _set_create_options]. </description> </method> - <method name="drop_data_fw"> + <method name="_set_create_options" qualifiers="virtual"> <return type="void"> </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <argument index="2" name="from" type="Control"> + <argument index="0" name="menu_node" type="Object"> </argument> <description> + This virtual method is called when updating the context menu of [EditorResourcePicker]. Implement this method to override the "New ..." items with your own options. [code]menu_node[/code] is a reference to the [PopupMenu] node. + [b]Note:[/b] Implement [method _handle_menu_selected] to handle these custom items. </description> </method> <method name="get_allowed_types" qualifiers="const"> @@ -41,35 +36,6 @@ Returns a list of all allowed types and subtypes corresponding to the [member base_type]. If the [member base_type] is empty, an empty list is returned. </description> </method> - <method name="get_drag_data_fw"> - <return type="Variant"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="from" type="Control"> - </argument> - <description> - </description> - </method> - <method name="handle_menu_selected" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="id" type="int"> - </argument> - <description> - This virtual method can be implemented to handle context menu items not handled by default. See [method set_create_options]. - </description> - </method> - <method name="set_create_options" qualifiers="virtual"> - <return type="void"> - </return> - <argument index="0" name="menu_node" type="Object"> - </argument> - <description> - This virtual method is called when updating the context menu of [EditorResourcePicker]. Implement this method to override the "New ..." items with your own options. [code]menu_node[/code] is a reference to the [PopupMenu] node. - [b]Note:[/b] Implement [method handle_menu_selected] to handle these custom items. - </description> - </method> <method name="set_toggle_pressed"> <return type="void"> </return> diff --git a/doc/classes/EditorResourcePreviewGenerator.xml b/doc/classes/EditorResourcePreviewGenerator.xml index e935bf19fc..3594474e36 100644 --- a/doc/classes/EditorResourcePreviewGenerator.xml +++ b/doc/classes/EditorResourcePreviewGenerator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorResourcePreviewGenerator" inherits="Reference" version="4.0"> +<class name="EditorResourcePreviewGenerator" inherits="RefCounted" version="4.0"> <brief_description> Custom generator of previews. </brief_description> @@ -9,15 +9,15 @@ <tutorials> </tutorials> <methods> - <method name="can_generate_small_preview" qualifiers="virtual"> + <method name="_can_generate_small_preview" qualifiers="virtual"> <return type="bool"> </return> <description> - If this function returns [code]true[/code], the generator will call [method generate] or [method generate_from_path] for small previews as well. + If this function returns [code]true[/code], the generator will call [method _generate] or [method _generate_from_path] for small previews as well. By default, it returns [code]false[/code]. </description> </method> - <method name="generate" qualifiers="virtual"> + <method name="_generate" qualifiers="virtual"> <return type="Texture2D"> </return> <argument index="0" name="from" type="Resource"> @@ -30,7 +30,7 @@ Care must be taken because this function is always called from a thread (not the main thread). </description> </method> - <method name="generate_from_path" qualifiers="virtual"> + <method name="_generate_from_path" qualifiers="virtual"> <return type="Texture2D"> </return> <argument index="0" name="path" type="String"> @@ -38,20 +38,20 @@ <argument index="1" name="size" type="Vector2"> </argument> <description> - Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method generate]. + Generate a preview directly from a path with the specified size. Implementing this is optional, as default code will load and call [method _generate]. Returning an empty texture is an OK way to fail and let another generator take care. Care must be taken because this function is always called from a thread (not the main thread). </description> </method> - <method name="generate_small_preview_automatically" qualifiers="virtual"> + <method name="_generate_small_preview_automatically" qualifiers="virtual"> <return type="bool"> </return> <description> - If this function returns [code]true[/code], the generator will automatically generate the small previews from the normal preview texture generated by the methods [method generate] or [method generate_from_path]. + If this function returns [code]true[/code], the generator will automatically generate the small previews from the normal preview texture generated by the methods [method _generate] or [method _generate_from_path]. By default, it returns [code]false[/code]. </description> </method> - <method name="handles" qualifiers="virtual"> + <method name="_handles" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="type" type="String"> diff --git a/doc/classes/EditorSceneImporter.xml b/doc/classes/EditorSceneImporter.xml index aa55a1653d..8df3091057 100644 --- a/doc/classes/EditorSceneImporter.xml +++ b/doc/classes/EditorSceneImporter.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorSceneImporter" inherits="Reference" version="4.0"> +<class name="EditorSceneImporter" inherits="RefCounted" version="4.0"> <brief_description> Imports scenes from third-parties' 3D files. </brief_description> diff --git a/doc/classes/EditorSceneImporterMesh.xml b/doc/classes/EditorSceneImporterMesh.xml index 9daa3f16bc..90eca9072b 100644 --- a/doc/classes/EditorSceneImporterMesh.xml +++ b/doc/classes/EditorSceneImporterMesh.xml @@ -22,7 +22,7 @@ </argument> <argument index="1" name="arrays" type="Array"> </argument> - <argument index="2" name="blend_shapes" type="Array" default="[ ]"> + <argument index="2" name="blend_shapes" type="Array" default="[]"> </argument> <argument index="3" name="lods" type="Dictionary" default="{ }"> @@ -168,7 +168,7 @@ </method> </methods> <members> - <member name="_data" type="Dictionary" setter="_set_data" getter="_get_data" default="{"surfaces": [ ]}"> + <member name="_data" type="Dictionary" setter="_set_data" getter="_get_data" default="{"surfaces": []}"> </member> </members> <constants> diff --git a/doc/classes/EditorScenePostImport.xml b/doc/classes/EditorScenePostImport.xml index d1cdc4e43e..d2b5e84ff7 100644 --- a/doc/classes/EditorScenePostImport.xml +++ b/doc/classes/EditorScenePostImport.xml @@ -1,18 +1,18 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorScenePostImport" inherits="Reference" version="4.0"> +<class name="EditorScenePostImport" inherits="RefCounted" version="4.0"> <brief_description> Post-processes scenes after import. </brief_description> <description> Imported scenes can be automatically modified right after import by setting their [b]Custom Script[/b] Import property to a [code]tool[/code] script that inherits from this class. - The [method post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example: + The [method _post_import] callback receives the imported scene's root node and returns the modified version of the scene. Usage example: [codeblocks] [gdscript] tool # Needed so it runs in editor. extends EditorScenePostImport # This sample changes all node names. # Called right after the scene is imported and gets the root node. - func post_import(scene): + func _post_import(scene): # Change all node names to "modified_[oldnodename]" iterate(scene) return scene # Remember to return the imported scene @@ -55,14 +55,7 @@ <link title="Importing 3D scenes: Custom script">https://docs.godotengine.org/en/latest/getting_started/workflow/assets/importing_scenes.html#custom-script</link> </tutorials> <methods> - <method name="get_source_file" qualifiers="const"> - <return type="String"> - </return> - <description> - Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]). - </description> - </method> - <method name="post_import" qualifiers="virtual"> + <method name="_post_import" qualifiers="virtual"> <return type="Object"> </return> <argument index="0" name="scene" type="Object"> @@ -71,6 +64,13 @@ Called after the scene was imported. This method must return the modified version of the scene. </description> </method> + <method name="get_source_file" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the source file path which got imported (e.g. [code]res://scene.dae[/code]). + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/EditorScript.xml b/doc/classes/EditorScript.xml index 60ccf451b8..a91ea0eb14 100644 --- a/doc/classes/EditorScript.xml +++ b/doc/classes/EditorScript.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorScript" inherits="Reference" version="4.0"> +<class name="EditorScript" inherits="RefCounted" version="4.0"> <brief_description> Base script that can be used to add extension functions to the editor. </brief_description> diff --git a/doc/classes/EditorSpinSlider.xml b/doc/classes/EditorSpinSlider.xml index 935335943f..b86e5e5c6e 100644 --- a/doc/classes/EditorSpinSlider.xml +++ b/doc/classes/EditorSpinSlider.xml @@ -18,6 +18,9 @@ </member> <member name="read_only" type="bool" setter="set_read_only" getter="is_read_only" default="false"> </member> + <member name="suffix" type="String" setter="set_suffix" getter="get_suffix" default=""""> + The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed. + </member> </members> <constants> </constants> diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml index b80e81928f..d81b25345f 100644 --- a/doc/classes/EditorSyntaxHighlighter.xml +++ b/doc/classes/EditorSyntaxHighlighter.xml @@ -5,7 +5,7 @@ </brief_description> <description> Base syntax highlighter resource all editor syntax highlighters extend from, it is used in the [ScriptEditor]. - Add a syntax highlighter to an individual script by calling [method ScriptEditorBase.add_syntax_highlighter]. To apply to all scripts on open, call [method ScriptEditor.register_syntax_highlighter] + Add a syntax highlighter to an individual script by calling [method ScriptEditorBase._add_syntax_highlighter]. To apply to all scripts on open, call [method ScriptEditor.register_syntax_highlighter] </description> <tutorials> </tutorials> diff --git a/doc/classes/EditorTranslationParserPlugin.xml b/doc/classes/EditorTranslationParserPlugin.xml index c97459d9dc..a9f4e90e72 100644 --- a/doc/classes/EditorTranslationParserPlugin.xml +++ b/doc/classes/EditorTranslationParserPlugin.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorTranslationParserPlugin" inherits="Reference" version="4.0"> +<class name="EditorTranslationParserPlugin" inherits="RefCounted" version="4.0"> <brief_description> Plugin for adding custom parsers to extract strings that are to be translated from custom files (.csv, .json etc.). </brief_description> <description> - Plugins are registered via [method EditorPlugin.add_translation_parser_plugin] method. To define the parsing and string extraction logic, override the [method parse_file] method in script. + Plugins are registered via [method EditorPlugin.add_translation_parser_plugin] method. To define the parsing and string extraction logic, override the [method _parse_file] method in script. Add the extracted strings to argument [code]msgids[/code] or [code]msgids_context_plural[/code] if context or plural is used. When adding to [code]msgids_context_plural[/code], you must add the data using the format [code]["A", "B", "C"][/code], where [code]A[/code] represents the extracted string, [code]B[/code] represents the context, and [code]C[/code] represents the plural version of the extracted string. If you want to add only context but not plural, put [code]""[/code] for the plural slot. The idea is the same if you only want to add plural but not context. See the code below for concrete examples. The extracted strings will be written into a POT file selected by user under "POT Generation" in "Localization" tab in "Project Settings" menu. @@ -14,7 +14,7 @@ tool extends EditorTranslationParserPlugin - func parse_file(path, msgids, msgids_context_plural): + func _parse_file(path, msgids, msgids_context_plural): var file = File.new() file.open(path, File.READ) var text = file.get_as_text() @@ -23,7 +23,7 @@ msgids.append(s) #print("Extracted string: " + s) - func get_recognized_extensions(): + func _get_recognized_extensions(): return ["csv"] [/gdscript] [csharp] @@ -76,12 +76,12 @@ For example: [codeblocks] [gdscript] - func parse_file(path, msgids, msgids_context_plural): + func _parse_file(path, msgids, msgids_context_plural): var res = ResourceLoader.load(path, "Script") var text = res.source_code # Parsing logic. - func get_recognized_extensions(): + func _get_recognized_extensions(): return ["gd"] [/gdscript] [csharp] @@ -102,14 +102,14 @@ <tutorials> </tutorials> <methods> - <method name="get_recognized_extensions" qualifiers="virtual"> + <method name="_get_recognized_extensions" qualifiers="virtual"> <return type="Array"> </return> <description> Gets the list of file extensions to associate with this parser, e.g. [code]["csv"][/code]. </description> </method> - <method name="parse_file" qualifiers="virtual"> + <method name="_parse_file" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="path" type="String"> diff --git a/doc/classes/EncodedObjectAsID.xml b/doc/classes/EncodedObjectAsID.xml index 1e4fde453b..e3e36590a3 100644 --- a/doc/classes/EncodedObjectAsID.xml +++ b/doc/classes/EncodedObjectAsID.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EncodedObjectAsID" inherits="Reference" version="4.0"> +<class name="EncodedObjectAsID" inherits="RefCounted" version="4.0"> <brief_description> Holds a reference to an [Object]'s instance ID. </brief_description> diff --git a/doc/classes/Engine.xml b/doc/classes/Engine.xml index 1147b52102..c0a8407ece 100644 --- a/doc/classes/Engine.xml +++ b/doc/classes/Engine.xml @@ -171,6 +171,12 @@ </member> <member name="physics_jitter_fix" type="float" setter="set_physics_jitter_fix" getter="get_physics_jitter_fix" default="0.5"> Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. + [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics_jitter_fix] to [code]0[/code]. + </member> + <member name="print_error_messages" type="bool" setter="set_print_error_messages" getter="is_printing_error_messages" default="true"> + If [code]false[/code], stops printing error and warning messages to the console and editor Output log. This can be used to hide error and warning messages during unit test suite runs. This property is equivalent to the [member ProjectSettings.application/run/disable_stderr] project setting. + [b]Warning:[/b] If you set this to [code]false[/code] anywhere in the project, important error messages may be hidden even if they are emitted from other scripts. If this is set to [code]false[/code] in a [code]@tool[/code] script, this will also impact the editor itself. Do [i]not[/i] report bugs before ensuring error messages are enabled (as they are by default). + [b]Note:[/b] This property does not impact the editor's Errors tab when running a project from the editor. </member> <member name="target_fps" type="int" setter="set_target_fps" getter="get_target_fps" default="0"> The desired frames per second. If the hardware cannot keep up, this setting may not be respected. A value of 0 means no limit. diff --git a/doc/classes/EngineDebugger.xml b/doc/classes/EngineDebugger.xml index 7db36b89d0..50ccb6b075 100644 --- a/doc/classes/EngineDebugger.xml +++ b/doc/classes/EngineDebugger.xml @@ -61,7 +61,7 @@ </argument> <argument index="1" name="enable" type="bool"> </argument> - <argument index="2" name="arguments" type="Array" default="[ ]"> + <argument index="2" name="arguments" type="Array" default="[]"> </argument> <description> Calls the [code]toggle[/code] callable of the profiler with given [code]name[/code] and [code]arguments[/code]. Enables/Disables the same profiler depending on [code]enable[/code] argument. diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml index 6909fac2b7..ae87a62c84 100644 --- a/doc/classes/Environment.xml +++ b/doc/classes/Environment.xml @@ -55,13 +55,13 @@ <member name="adjustment_saturation" type="float" setter="set_adjustment_saturation" getter="get_adjustment_saturation" default="1.0"> The global color saturation value of the rendered scene (default value is 1). Effective only if [code]adjustment_enabled[/code] is [code]true[/code]. </member> - <member name="ambient_light_color" type="Color" setter="set_ambient_light_color" getter="get_ambient_light_color" default="Color( 0, 0, 0, 1 )"> + <member name="ambient_light_color" type="Color" setter="set_ambient_light_color" getter="get_ambient_light_color" default="Color(0, 0, 0, 1)"> The ambient light's [Color]. </member> <member name="ambient_light_energy" type="float" setter="set_ambient_light_energy" getter="get_ambient_light_energy" default="1.0"> The ambient light's energy. The higher the value, the stronger the light. </member> - <member name="ambient_light_occlusion_color" type="Color" setter="set_ao_color" getter="get_ao_color" default="Color( 0, 0, 0, 1 )"> + <member name="ambient_light_occlusion_color" type="Color" setter="set_ao_color" getter="get_ao_color" default="Color(0, 0, 0, 1)"> </member> <member name="ambient_light_sky_contribution" type="float" setter="set_ambient_light_sky_contribution" getter="get_ambient_light_sky_contribution" default="1.0"> Defines the amount of light that the sky brings on the scene. A value of 0 means that the sky's light emission has no effect on the scene illumination, thus all ambient illumination is provided by the ambient light. On the contrary, a value of 1 means that all the light that affects the scene is provided by the sky, thus the ambient light parameter has no effect on the scene. @@ -89,7 +89,7 @@ <member name="background_canvas_max_layer" type="int" setter="set_canvas_max_layer" getter="get_canvas_max_layer" default="0"> The maximum layer ID to display. Only effective when using the [constant BG_CANVAS] background mode. </member> - <member name="background_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color( 0, 0, 0, 1 )"> + <member name="background_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color(0, 0, 0, 1)"> The [Color] displayed for clear areas of the scene. Only effective when using the [constant BG_COLOR] background mode. </member> <member name="background_energy" type="float" setter="set_bg_energy" getter="get_bg_energy" default="1.0"> @@ -111,7 +111,7 @@ </member> <member name="fog_height_density" type="float" setter="set_fog_height_density" getter="get_fog_height_density" default="0.0"> </member> - <member name="fog_light_color" type="Color" setter="set_fog_light_color" getter="get_fog_light_color" default="Color( 0.5, 0.6, 0.7, 1 )"> + <member name="fog_light_color" type="Color" setter="set_fog_light_color" getter="get_fog_light_color" default="Color(0.5, 0.6, 0.7, 1)"> </member> <member name="fog_light_energy" type="float" setter="set_fog_light_energy" getter="get_fog_light_energy" default="1.0"> </member> @@ -200,13 +200,13 @@ </member> <member name="sky_custom_fov" type="float" setter="set_sky_custom_fov" getter="get_sky_custom_fov" default="0.0"> </member> - <member name="sky_rotation" type="Vector3" setter="set_sky_rotation" getter="get_sky_rotation" default="Vector3( 0, 0, 0 )"> + <member name="sky_rotation" type="Vector3" setter="set_sky_rotation" getter="get_sky_rotation" default="Vector3(0, 0, 0)"> </member> <member name="ss_reflections_depth_tolerance" type="float" setter="set_ssr_depth_tolerance" getter="get_ssr_depth_tolerance" default="0.2"> The depth tolerance for screen-space reflections. </member> <member name="ss_reflections_enabled" type="bool" setter="set_ssr_enabled" getter="is_ssr_enabled" default="false"> - If [code]true[/code], screen-space reflections are enabled. Screen-space reflections are more accurate than reflections from [GIProbe]s or [ReflectionProbe]s, but are slower and can't reflect surfaces occluded by others. + If [code]true[/code], screen-space reflections are enabled. Screen-space reflections are more accurate than reflections from [VoxelGI]s or [ReflectionProbe]s, but are slower and can't reflect surfaces occluded by others. </member> <member name="ss_reflections_fade_in" type="float" setter="set_ssr_fade_in" getter="get_ssr_fade_in" default="0.15"> The fade-in distance for screen-space reflections. Affects the area from the reflected material to the screen-space reflection). @@ -263,7 +263,7 @@ </member> <member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0"> </member> - <member name="volumetric_fog_light" type="Color" setter="set_volumetric_fog_light" getter="get_volumetric_fog_light" default="Color( 0, 0, 0, 1 )"> + <member name="volumetric_fog_light" type="Color" setter="set_volumetric_fog_light" getter="get_volumetric_fog_light" default="Color(0, 0, 0, 1)"> </member> <member name="volumetric_fog_light_energy" type="float" setter="set_volumetric_fog_light_energy" getter="get_volumetric_fog_light_energy" default="1.0"> </member> diff --git a/doc/classes/Expression.xml b/doc/classes/Expression.xml index d777c6fd9d..640b45dca4 100644 --- a/doc/classes/Expression.xml +++ b/doc/classes/Expression.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Expression" inherits="Reference" version="4.0"> +<class name="Expression" inherits="RefCounted" version="4.0"> <brief_description> A class that stores an expression you can execute. </brief_description> @@ -12,9 +12,9 @@ var expression = Expression.new() func _ready(): - $LineEdit.connect("text_entered", self, "_on_text_entered") + $LineEdit.connect("text_submitted", self, "_on_text_submitted") - func _on_text_entered(command): + func _on_text_submitted(command): var error = expression.parse(command) if error != OK: print(expression.get_error_text()) @@ -28,7 +28,7 @@ public override void _Ready() { - GetNode("LineEdit").Connect("text_entered", this, nameof(OnTextEntered)); + GetNode("LineEdit").Connect("text_submitted", this, nameof(OnTextEntered)); } private void OnTextEntered(string command) @@ -54,7 +54,7 @@ <method name="execute"> <return type="Variant"> </return> - <argument index="0" name="inputs" type="Array" default="[ ]"> + <argument index="0" name="inputs" type="Array" default="[]"> </argument> <argument index="1" name="base_instance" type="Object" default="null"> </argument> @@ -84,7 +84,7 @@ </return> <argument index="0" name="expression" type="String"> </argument> - <argument index="1" name="input_names" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="input_names" type="PackedStringArray" default="PackedStringArray()"> </argument> <description> Parses the expression and returns an [enum Error] code. diff --git a/doc/classes/File.xml b/doc/classes/File.xml index ea3b82dc54..f98c31dc7f 100644 --- a/doc/classes/File.xml +++ b/doc/classes/File.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="File" inherits="Reference" version="4.0"> +<class name="File" inherits="RefCounted" version="4.0"> <brief_description> Type to handle file reading and writing operations. </brief_description> @@ -188,7 +188,7 @@ <argument index="0" name="file" type="String"> </argument> <description> - Returns the last time the [code]file[/code] was modified in unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This unix timestamp can be converted to datetime by using [method OS.get_datetime_from_unix_time]. + Returns the last time the [code]file[/code] was modified in Unix timestamp format or returns a [String] "ERROR IN [code]file[/code]". This Unix timestamp can be converted to another format using the [Time] singleton. </description> </method> <method name="get_pascal_string"> @@ -486,6 +486,7 @@ </argument> <description> Stores any Variant value in the file. If [code]full_objects[/code] is [code]true[/code], encoding objects is allowed (and can potentially include code). + [b]Note:[/b] Not all properties are included. Only properties that are configured with the [constant PROPERTY_USAGE_STORAGE] flag set will be serialized. You can add a new usage flag to a property by overriding the [method Object._get_property_list] method in your class. You can also check how property usage is configured by calling [method Object._get_property_list]. See [enum PropertyUsageFlags] for the possible usage flags. </description> </method> </methods> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 966be0a981..8ccee1c82e 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -72,7 +72,7 @@ <member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="FileDialog.FileMode" default="4"> The dialog's open or save mode, which affects the selection behavior. See [enum FileMode]. </member> - <member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray( )"> + <member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray()"> The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code]. </member> <member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true"> @@ -139,16 +139,16 @@ <theme_item name="file" type="Texture2D"> Custom icon for files. </theme_item> - <theme_item name="file_icon_modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="file_icon_modulate" type="Color" default="Color(1, 1, 1, 1)"> The color modulation applied to the file icon. </theme_item> - <theme_item name="files_disabled" type="Color" default="Color( 0, 0, 0, 0.7 )"> + <theme_item name="files_disabled" type="Color" default="Color(0, 0, 0, 0.7)"> The color tint for disabled files (when the [FileDialog] is used in open folder mode). </theme_item> <theme_item name="folder" type="Texture2D"> Custom icon for folders. </theme_item> - <theme_item name="folder_icon_modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="folder_icon_modulate" type="Color" default="Color(1, 1, 1, 1)"> The color modulation applied to the folder icon. </theme_item> <theme_item name="forward_folder" type="Texture2D"> diff --git a/doc/classes/FileSystemDock.xml b/doc/classes/FileSystemDock.xml index c553f90e37..15f92e90e3 100644 --- a/doc/classes/FileSystemDock.xml +++ b/doc/classes/FileSystemDock.xml @@ -7,40 +7,6 @@ <tutorials> </tutorials> <methods> - <method name="can_drop_data_fw" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <argument index="2" name="from" type="Control"> - </argument> - <description> - </description> - </method> - <method name="drop_data_fw"> - <return type="void"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <argument index="2" name="from" type="Control"> - </argument> - <description> - </description> - </method> - <method name="get_drag_data_fw"> - <return type="Variant"> - </return> - <argument index="0" name="position" type="Vector2"> - </argument> - <argument index="1" name="from" type="Control"> - </argument> - <description> - </description> - </method> <method name="navigate_to_path"> <return type="void"> </return> diff --git a/doc/classes/Font.xml b/doc/classes/Font.xml index 20d5b6ce9b..186bfbb931 100644 --- a/doc/classes/Font.xml +++ b/doc/classes/Font.xml @@ -85,11 +85,11 @@ </argument> <argument index="4" name="size" type="int" default="-1"> </argument> - <argument index="5" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="5" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="6" name="outline_size" type="int" default="0"> </argument> - <argument index="7" name="outline_modulate" type="Color" default="Color( 1, 1, 1, 0 )"> + <argument index="7" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)"> </argument> <description> Draw a single Unicode character [code]char[/code] into a canvas item using the font, at a given position, with [code]modulate[/code] color, and optionally kerning if [code]next[/code] is passed. [code]position[/code] specifies the baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis. @@ -113,11 +113,11 @@ </argument> <argument index="6" name="size" type="int" default="-1"> </argument> - <argument index="7" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="7" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="8" name="outline_size" type="int" default="0"> </argument> - <argument index="9" name="outline_modulate" type="Color" default="Color( 1, 1, 1, 0 )"> + <argument index="9" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)"> </argument> <argument index="10" name="flags" type="int" default="51"> </argument> @@ -141,11 +141,11 @@ </argument> <argument index="5" name="size" type="int" default="-1"> </argument> - <argument index="6" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="6" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="7" name="outline_size" type="int" default="0"> </argument> - <argument index="8" name="outline_modulate" type="Color" default="Color( 1, 1, 1, 0 )"> + <argument index="8" name="outline_modulate" type="Color" default="Color(1, 1, 1, 0)"> </argument> <argument index="9" name="flags" type="int" default="3"> </argument> diff --git a/doc/classes/FontData.xml b/doc/classes/FontData.xml index e426c8fb36..0a2fb03750 100644 --- a/doc/classes/FontData.xml +++ b/doc/classes/FontData.xml @@ -61,7 +61,7 @@ </argument> <argument index="3" name="index" type="int"> </argument> - <argument index="4" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="4" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draws single glyph into a canvas item at the position, using [code]font[/code] at the size [code]size[/code]. @@ -82,7 +82,7 @@ </argument> <argument index="4" name="index" type="int"> </argument> - <argument index="5" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="5" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draws single glyph outline of size [code]outline_size[/code] into a canvas item at the position, using [code]font[/code] at the size [code]size[/code]. If outline drawing is not supported, nothing is drawn. diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml index ebd6d2b92c..8684a7f41a 100644 --- a/doc/classes/GPUParticles2D.xml +++ b/doc/classes/GPUParticles2D.xml @@ -80,7 +80,7 @@ </member> <member name="trail_sections" type="int" setter="set_trail_sections" getter="get_trail_sections" default="8"> </member> - <member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2( -100, -100, 200, 200 )"> + <member name="visibility_rect" type="Rect2" setter="set_visibility_rect" getter="get_visibility_rect" default="Rect2(-100, -100, 200, 200)"> The [Rect2] that determines the node's region which needs to be visible on screen for the particle system to be active. Grow the rect if particles suddenly appear/disappear when the node enters/exits the screen. The [Rect2] can be grown via code or with the [b]Particles → Generate Visibility Rect[/b] editor tool. </member> diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml index 76f0fdb406..55e9b33aa8 100644 --- a/doc/classes/GPUParticles3D.xml +++ b/doc/classes/GPUParticles3D.xml @@ -22,7 +22,7 @@ <method name="emit_particle"> <return type="void"> </return> - <argument index="0" name="xform" type="Transform"> + <argument index="0" name="xform" type="Transform3D"> </argument> <argument index="1" name="velocity" type="Vector3"> </argument> @@ -132,7 +132,7 @@ </member> <member name="transform_align" type="int" setter="set_transform_align" getter="get_transform_align" enum="GPUParticles3D.TransformAlign" default="0"> </member> - <member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB( -4, -4, -4, 8, 8, 8 )"> + <member name="visibility_aabb" type="AABB" setter="set_visibility_aabb" getter="get_visibility_aabb" default="AABB(-4, -4, -4, 8, 8, 8)"> The [AABB] that determines the node's region which needs to be visible on screen for the particle system to be active. Grow the box if particles suddenly appear/disappear when the node enters/exits the screen. The [AABB] can be grown via code or with the [b]Particles → Generate AABB[/b] editor tool. </member> diff --git a/doc/classes/GPUParticlesAttractorBox.xml b/doc/classes/GPUParticlesAttractorBox.xml index 68616f9bbd..49e6111c29 100644 --- a/doc/classes/GPUParticlesAttractorBox.xml +++ b/doc/classes/GPUParticlesAttractorBox.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> </member> </members> <constants> diff --git a/doc/classes/GPUParticlesAttractorVectorField.xml b/doc/classes/GPUParticlesAttractorVectorField.xml index cf5e375ea3..7364a4b09f 100644 --- a/doc/classes/GPUParticlesAttractorVectorField.xml +++ b/doc/classes/GPUParticlesAttractorVectorField.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> </member> <member name="texture" type="Texture3D" setter="set_texture" getter="get_texture"> </member> diff --git a/doc/classes/GPUParticlesCollisionBox.xml b/doc/classes/GPUParticlesCollisionBox.xml index 17fc124c41..58de18556e 100644 --- a/doc/classes/GPUParticlesCollisionBox.xml +++ b/doc/classes/GPUParticlesCollisionBox.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> </member> </members> <constants> diff --git a/doc/classes/GPUParticlesCollisionHeightField.xml b/doc/classes/GPUParticlesCollisionHeightField.xml index c6987515a9..0ddddda8e4 100644 --- a/doc/classes/GPUParticlesCollisionHeightField.xml +++ b/doc/classes/GPUParticlesCollisionHeightField.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> </member> <member name="follow_camera_enabled" type="bool" setter="set_follow_camera_mode" getter="is_follow_camera_mode_enabled" default="false"> </member> diff --git a/doc/classes/GPUParticlesCollisionSDF.xml b/doc/classes/GPUParticlesCollisionSDF.xml index c3cbe4b1c6..7ef6f5f3cd 100644 --- a/doc/classes/GPUParticlesCollisionSDF.xml +++ b/doc/classes/GPUParticlesCollisionSDF.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)"> </member> <member name="resolution" type="int" setter="set_resolution" getter="get_resolution" enum="GPUParticlesCollisionSDF.Resolution" default="2"> </member> diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml index b2c3bfc3ed..667ca2dacf 100644 --- a/doc/classes/GeometryInstance3D.xml +++ b/doc/classes/GeometryInstance3D.xml @@ -52,25 +52,21 @@ </member> <member name="lod_bias" type="float" setter="set_lod_bias" getter="get_lod_bias" default="1.0"> </member> - <member name="lod_max_distance" type="float" setter="set_lod_max_distance" getter="get_lod_max_distance" default="0.0"> - The GeometryInstance3D's max LOD distance. - [b]Note:[/b] This property currently has no effect. + <member name="material_override" type="Material" setter="set_material_override" getter="get_material_override"> + The material override for the whole geometry. + If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh. </member> - <member name="lod_max_hysteresis" type="float" setter="set_lod_max_hysteresis" getter="get_lod_max_hysteresis" default="0.0"> - The GeometryInstance3D's max LOD margin. - [b]Note:[/b] This property currently has no effect. + <member name="visibility_range_begin" type="float" setter="set_visibility_range_begin" getter="get_visibility_range_begin" default="0.0"> + Starting distance from which the GeometryInstance3D will be visible, taking [member visibility_range_begin_margin] into account as well. The default value of 0 is used to disable the range check. </member> - <member name="lod_min_distance" type="float" setter="set_lod_min_distance" getter="get_lod_min_distance" default="0.0"> - The GeometryInstance3D's min LOD distance. - [b]Note:[/b] This property currently has no effect. + <member name="visibility_range_begin_margin" type="float" setter="set_visibility_range_begin_margin" getter="get_visibility_range_begin_margin" default="0.0"> + Margin for the [member visibility_range_begin] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_begin] threshold by this amount. </member> - <member name="lod_min_hysteresis" type="float" setter="set_lod_min_hysteresis" getter="get_lod_min_hysteresis" default="0.0"> - The GeometryInstance3D's min LOD margin. - [b]Note:[/b] This property currently has no effect. + <member name="visibility_range_end" type="float" setter="set_visibility_range_end" getter="get_visibility_range_end" default="0.0"> + Distance from which the GeometryInstance3D will be hidden, taking [member visibility_range_end_margin] into account as well. The default value of 0 is used to disable the range check.. </member> - <member name="material_override" type="Material" setter="set_material_override" getter="get_material_override"> - The material override for the whole geometry. - If a material is assigned to this property, it will be used instead of any material set in any material slot of the mesh. + <member name="visibility_range_end_margin" type="float" setter="set_visibility_range_end_margin" getter="get_visibility_range_end_margin" default="0.0"> + Margin for the [member visibility_range_end] threshold. The GeometryInstance3D will only change its visibility state when it goes over or under the [member visibility_range_end] threshold by this amount. </member> </members> <constants> diff --git a/doc/classes/Gradient.xml b/doc/classes/Gradient.xml index 28c647a1c3..1f1f266c59 100644 --- a/doc/classes/Gradient.xml +++ b/doc/classes/Gradient.xml @@ -87,10 +87,10 @@ </method> </methods> <members> - <member name="colors" type="PackedColorArray" setter="set_colors" getter="get_colors" default="PackedColorArray( 0, 0, 0, 1, 1, 1, 1, 1 )"> + <member name="colors" type="PackedColorArray" setter="set_colors" getter="get_colors" default="PackedColorArray(0, 0, 0, 1, 1, 1, 1, 1)"> Gradient's colors returned as a [PackedColorArray]. </member> - <member name="offsets" type="PackedFloat32Array" setter="set_offsets" getter="get_offsets" default="PackedFloat32Array( 0, 1 )"> + <member name="offsets" type="PackedFloat32Array" setter="set_offsets" getter="get_offsets" default="PackedFloat32Array(0, 1)"> Gradient's offsets returned as a [PackedFloat32Array]. </member> </members> diff --git a/doc/classes/GraphEdit.xml b/doc/classes/GraphEdit.xml index b4536c0589..65701b3a6a 100644 --- a/doc/classes/GraphEdit.xml +++ b/doc/classes/GraphEdit.xml @@ -187,16 +187,19 @@ <member name="minimap_opacity" type="float" setter="set_minimap_opacity" getter="get_minimap_opacity" default="0.65"> The opacity of the minimap rectangle. </member> - <member name="minimap_size" type="Vector2" setter="set_minimap_size" getter="get_minimap_size" default="Vector2( 240, 160 )"> + <member name="minimap_size" type="Vector2" setter="set_minimap_size" getter="get_minimap_size" default="Vector2(240, 160)"> The size of the minimap rectangle. The map itself is based on the size of the grid area and is scaled to fit this rectangle. </member> <member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" override="true" default="true" /> <member name="right_disconnects" type="bool" setter="set_right_disconnects" getter="is_right_disconnects_enabled" default="false"> If [code]true[/code], enables disconnection of existing connections in the GraphEdit by dragging the right end. </member> - <member name="scroll_offset" type="Vector2" setter="set_scroll_ofs" getter="get_scroll_ofs" default="Vector2( 0, 0 )"> + <member name="scroll_offset" type="Vector2" setter="set_scroll_ofs" getter="get_scroll_ofs" default="Vector2(0, 0)"> The scroll offset. </member> + <member name="show_zoom_label" type="bool" setter="set_show_zoom_label" getter="is_showing_zoom_label" default="false"> + If [code]true[/code], makes a label with the current zoom level visible. The zoom value is displayed in percents. + </member> <member name="snap_distance" type="int" setter="set_snap" getter="get_snap" default="20"> The snapping distance in pixels. </member> @@ -206,6 +209,15 @@ <member name="zoom" type="float" setter="set_zoom" getter="get_zoom" default="1.0"> The current zoom value. </member> + <member name="zoom_max" type="float" setter="set_zoom_max" getter="get_zoom_max" default="2.0736"> + The upper zoom limit. + </member> + <member name="zoom_min" type="float" setter="set_zoom_min" getter="get_zoom_min" default="0.232568"> + The lower zoom limit. + </member> + <member name="zoom_step" type="float" setter="set_zoom_step" getter="get_zoom_step" default="1.2"> + The step of each zoom level. + </member> </members> <signals> <signal name="begin_node_move"> @@ -317,7 +329,7 @@ <constants> </constants> <theme_items> - <theme_item name="activity" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="activity" type="Color" default="Color(1, 1, 1, 1)"> </theme_item> <theme_item name="bezier_len_neg" type="int" default="160"> </theme_item> @@ -326,10 +338,10 @@ <theme_item name="bg" type="StyleBox"> The background drawn under the grid. </theme_item> - <theme_item name="grid_major" type="Color" default="Color( 1, 1, 1, 0.2 )"> + <theme_item name="grid_major" type="Color" default="Color(1, 1, 1, 0.2)"> Color of major grid lines. </theme_item> - <theme_item name="grid_minor" type="Color" default="Color( 1, 1, 1, 0.05 )"> + <theme_item name="grid_minor" type="Color" default="Color(1, 1, 1, 0.05)"> Color of minor grid lines. </theme_item> <theme_item name="minimap" type="Texture2D"> @@ -349,10 +361,10 @@ <theme_item name="reset" type="Texture2D"> The icon for the zoom reset button. </theme_item> - <theme_item name="selection_fill" type="Color" default="Color( 1, 1, 1, 0.3 )"> + <theme_item name="selection_fill" type="Color" default="Color(1, 1, 1, 0.3)"> The fill color of the selection rectangle. </theme_item> - <theme_item name="selection_stroke" type="Color" default="Color( 1, 1, 1, 0.8 )"> + <theme_item name="selection_stroke" type="Color" default="Color(1, 1, 1, 0.8)"> The outline color of the selection rectangle. </theme_item> <theme_item name="snap" type="Texture2D"> diff --git a/doc/classes/GraphNode.xml b/doc/classes/GraphNode.xml index 82ba45f11a..84eda7fcea 100644 --- a/doc/classes/GraphNode.xml +++ b/doc/classes/GraphNode.xml @@ -285,7 +285,7 @@ <member name="overlay" type="int" setter="set_overlay" getter="get_overlay" enum="GraphNode.Overlay" default="0"> Sets the overlay shown above the GraphNode. See [enum Overlay]. </member> - <member name="position_offset" type="Vector2" setter="set_position_offset" getter="get_position_offset" default="Vector2( 0, 0 )"> + <member name="position_offset" type="Vector2" setter="set_position_offset" getter="get_position_offset" default="Vector2(0, 0)"> The offset of the GraphNode, relative to the scroll offset of the [GraphEdit]. [b]Note:[/b] You cannot use position offset directly, as [GraphEdit] is a [Container]. </member> @@ -365,7 +365,7 @@ <theme_item name="close" type="Texture2D"> The icon for the close button, visible when [member show_close] is enabled. </theme_item> - <theme_item name="close_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="close_color" type="Color" default="Color(0, 0, 0, 1)"> The color modulation applied to the close button icon. </theme_item> <theme_item name="close_offset" type="int" default="18"> @@ -396,7 +396,7 @@ <theme_item name="resizer" type="Texture2D"> The icon used for resizer, visible when [member resizable] is enabled. </theme_item> - <theme_item name="resizer_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="resizer_color" type="Color" default="Color(0, 0, 0, 1)"> The color modulation applied to the resizer icon. </theme_item> <theme_item name="selectedframe" type="StyleBox"> @@ -405,7 +405,7 @@ <theme_item name="separation" type="int" default="1"> The vertical distance between ports. </theme_item> - <theme_item name="title_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="title_color" type="Color" default="Color(0, 0, 0, 1)"> Color of the title text. </theme_item> <theme_item name="title_font" type="Font"> diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml index 00d528ef8f..9fa96e5ddf 100644 --- a/doc/classes/HMACContext.xml +++ b/doc/classes/HMACContext.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="HMACContext" inherits="Reference" version="4.0"> +<class name="HMACContext" inherits="RefCounted" version="4.0"> <brief_description> Used to create an HMAC for a message using a key. </brief_description> diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml index ddfcdf7724..a08bed751f 100644 --- a/doc/classes/HTTPClient.xml +++ b/doc/classes/HTTPClient.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="HTTPClient" inherits="Reference" version="4.0"> +<class name="HTTPClient" inherits="RefCounted" version="4.0"> <brief_description> Low-level hyper-text transfer protocol client. </brief_description> @@ -158,7 +158,8 @@ <argument index="3" name="body" type="String" default=""""> </argument> <description> - Sends a request to the connected host. The URL parameter is just the part after the host, so for [code]http://somehost.com/index.php[/code], it is [code]index.php[/code]. + Sends a request to the connected host. + The URL parameter is usually just the part after the host, so for [code]http://somehost.com/index.php[/code], it is [code]/index.php[/code]. When sending requests to an HTTP proxy server, it should be an absolute URL. For [constant HTTPClient.METHOD_OPTIONS] requests, [code]*[/code] is also allowed. For [constant HTTPClient.METHOD_CONNECT] requests, it should be the authority component ([code]host:port[/code]). Headers are HTTP request headers. For available HTTP methods, see [enum Method]. To create a POST request with query strings to push to the server, do: [codeblocks] @@ -166,7 +167,7 @@ var fields = {"username" : "user", "password" : "pass"} var query_string = http_client.query_string_from_dict(fields) var headers = ["Content-Type: application/x-www-form-urlencoded", "Content-Length: " + str(query_string.length())] - var result = http_client.request(http_client.METHOD_POST, "index.php", headers, query_string) + var result = http_client.request(http_client.METHOD_POST, "/index.php", headers, query_string) [/gdscript] [csharp] var fields = new Godot.Collections.Dictionary { { "username", "user" }, { "password", "pass" } }; @@ -190,7 +191,8 @@ <argument index="3" name="body" type="PackedByteArray"> </argument> <description> - Sends a raw request to the connected host. The URL parameter is just the part after the host, so for [code]http://somehost.com/index.php[/code], it is [code]index.php[/code]. + Sends a raw request to the connected host. + The URL parameter is usually just the part after the host, so for [code]http://somehost.com/index.php[/code], it is [code]/index.php[/code]. When sending requests to an HTTP proxy server, it should be an absolute URL. For [constant HTTPClient.METHOD_OPTIONS] requests, [code]*[/code] is also allowed. For [constant HTTPClient.METHOD_CONNECT] requests, it should be the authority component ([code]host:port[/code]). Headers are HTTP request headers. For available HTTP methods, see [enum Method]. Sends the body data raw, as a byte array and does not encode it in any way. </description> diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml index 25667d8f79..908e355db3 100644 --- a/doc/classes/HTTPRequest.xml +++ b/doc/classes/HTTPRequest.xml @@ -192,7 +192,7 @@ </return> <argument index="0" name="url" type="String"> </argument> - <argument index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray()"> </argument> <argument index="2" name="ssl_validate_domain" type="bool" default="true"> </argument> @@ -211,13 +211,13 @@ </return> <argument index="0" name="url" type="String"> </argument> - <argument index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="custom_headers" type="PackedStringArray" default="PackedStringArray()"> </argument> <argument index="2" name="ssl_validate_domain" type="bool" default="true"> </argument> <argument index="3" name="method" type="int" enum="HTTPClient.Method" default="0"> </argument> - <argument index="4" name="request_data_raw" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="4" name="request_data_raw" type="PackedByteArray" default="PackedByteArray()"> </argument> <description> Creates request on the underlying [HTTPClient] using a raw array of bytes for the request body. If there is no configuration errors, it tries to connect using [method HTTPClient.connect_to_host] and passes parameters onto [method HTTPClient.request]. diff --git a/doc/classes/HashingContext.xml b/doc/classes/HashingContext.xml index e020293d76..1c7b7ca937 100644 --- a/doc/classes/HashingContext.xml +++ b/doc/classes/HashingContext.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="HashingContext" inherits="Reference" version="4.0"> +<class name="HashingContext" inherits="RefCounted" version="4.0"> <brief_description> Context to compute cryptographic hashes over multiple iterations. </brief_description> diff --git a/doc/classes/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml index f6f2a27891..9a9d3bf8f4 100644 --- a/doc/classes/HeightMapShape3D.xml +++ b/doc/classes/HeightMapShape3D.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="map_data" type="PackedFloat32Array" setter="set_map_data" getter="get_map_data" default="PackedFloat32Array( 0, 0, 0, 0 )"> + <member name="map_data" type="PackedFloat32Array" setter="set_map_data" getter="get_map_data" default="PackedFloat32Array(0, 0, 0, 0)"> Height map data, pool array must be of [member map_width] * [member map_depth] size. </member> <member name="map_depth" type="int" setter="set_map_depth" getter="get_map_depth" default="2"> diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index 91a07f66e0..167b90ea73 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -560,7 +560,7 @@ </method> </methods> <members> - <member name="data" type="Dictionary" setter="_set_data" getter="_get_data" default="{"data": PackedByteArray( ),"format": "Lum8","height": 0,"mipmaps": false,"width": 0}"> + <member name="data" type="Dictionary" setter="_set_data" getter="_get_data" default="{"data": PackedByteArray(),"format": "Lum8","height": 0,"mipmaps": false,"width": 0}"> Holds all the image's color data in a given format. See [enum Format] constants. </member> </members> diff --git a/doc/classes/ImageTexture.xml b/doc/classes/ImageTexture.xml index 5fef56e354..f89b6ad57b 100644 --- a/doc/classes/ImageTexture.xml +++ b/doc/classes/ImageTexture.xml @@ -61,10 +61,8 @@ </return> <argument index="0" name="image" type="Image"> </argument> - <argument index="1" name="immediate" type="bool" default="false"> - </argument> <description> - Replaces the texture's data with a new [Image]. If [code]immediate[/code] is [code]true[/code], it will take effect immediately after the call. + Replaces the texture's data with a new [Image]. [b]Note:[/b] The texture has to be initialized first with the [method create_from_image] method before it can be updated. The new image dimensions, format, and mipmaps configuration should match the existing texture's image configuration, otherwise it has to be re-created with the [method create_from_image] method. Use this method over [method create_from_image] if you need to update the texture frequently, which is faster than allocating additional memory for a new texture each time. </description> diff --git a/doc/classes/ImmediateGeometry3D.xml b/doc/classes/ImmediateGeometry3D.xml deleted file mode 100644 index d2d663847f..0000000000 --- a/doc/classes/ImmediateGeometry3D.xml +++ /dev/null @@ -1,113 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="ImmediateGeometry3D" inherits="GeometryInstance3D" version="4.0"> - <brief_description> - Draws simple geometry from code. - </brief_description> - <description> - Draws simple geometry from code. Uses a drawing mode similar to OpenGL 1.x. - See also [ArrayMesh], [MeshDataTool] and [SurfaceTool] for procedural geometry generation. - [b]Note:[/b] ImmediateGeometry3D is best suited to small amounts of mesh data that change every frame. It will be slow when handling large amounts of mesh data. If mesh data doesn't change often, use [ArrayMesh], [MeshDataTool] or [SurfaceTool] instead. - [b]Note:[/b] Godot uses clockwise [url=https://learnopengl.com/Advanced-OpenGL/Face-culling]winding order[/url] for front faces of triangle primitive modes. - </description> - <tutorials> - </tutorials> - <methods> - <method name="add_sphere"> - <return type="void"> - </return> - <argument index="0" name="lats" type="int"> - </argument> - <argument index="1" name="lons" type="int"> - </argument> - <argument index="2" name="radius" type="float"> - </argument> - <argument index="3" name="add_uv" type="bool" default="true"> - </argument> - <description> - Simple helper to draw an UV sphere with given latitude, longitude and radius. - </description> - </method> - <method name="add_vertex"> - <return type="void"> - </return> - <argument index="0" name="position" type="Vector3"> - </argument> - <description> - Adds a vertex in local coordinate space with the currently set color/uv/etc. - </description> - </method> - <method name="begin"> - <return type="void"> - </return> - <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType"> - </argument> - <argument index="1" name="texture" type="Texture2D" default="null"> - </argument> - <description> - Begin drawing (and optionally pass a texture override). When done call [method end]. For more information on how this works, search for [code]glBegin()[/code] and [code]glEnd()[/code] references. - For the type of primitive, see the [enum Mesh.PrimitiveType] enum. - </description> - </method> - <method name="clear"> - <return type="void"> - </return> - <description> - Clears everything that was drawn using begin/end. - </description> - </method> - <method name="end"> - <return type="void"> - </return> - <description> - Ends a drawing context and displays the results. - </description> - </method> - <method name="set_color"> - <return type="void"> - </return> - <argument index="0" name="color" type="Color"> - </argument> - <description> - The current drawing color. - </description> - </method> - <method name="set_normal"> - <return type="void"> - </return> - <argument index="0" name="normal" type="Vector3"> - </argument> - <description> - The next vertex's normal. - </description> - </method> - <method name="set_tangent"> - <return type="void"> - </return> - <argument index="0" name="tangent" type="Plane"> - </argument> - <description> - The next vertex's tangent (and binormal facing). - </description> - </method> - <method name="set_uv"> - <return type="void"> - </return> - <argument index="0" name="uv" type="Vector2"> - </argument> - <description> - The next vertex's UV. - </description> - </method> - <method name="set_uv2"> - <return type="void"> - </return> - <argument index="0" name="uv" type="Vector2"> - </argument> - <description> - The next vertex's second layer UV. - </description> - </method> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/ImmediateMesh.xml b/doc/classes/ImmediateMesh.xml new file mode 100644 index 0000000000..d2ae091cad --- /dev/null +++ b/doc/classes/ImmediateMesh.xml @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="ImmediateMesh" inherits="Mesh" version="4.0"> + <brief_description> + Mesh optimized for creating geometry manually. + </brief_description> + <description> + Mesh optimized for creating geometry manually, similar to OpenGL1.x immediate mode. + </description> + <tutorials> + </tutorials> + <methods> + <method name="clear_surfaces"> + <return type="void"> + </return> + <description> + Clear all surfaces. + </description> + </method> + <method name="surface_add_vertex"> + <return type="void"> + </return> + <argument index="0" name="vertex" type="Vector3"> + </argument> + <description> + Add a 3D vertex using the current attributes previously set. + </description> + </method> + <method name="surface_add_vertex_2d"> + <return type="void"> + </return> + <argument index="0" name="vertex" type="Vector2"> + </argument> + <description> + Add a 2D vertex using the current attributes previously set. + </description> + </method> + <method name="surface_begin"> + <return type="void"> + </return> + <argument index="0" name="primitive" type="int" enum="Mesh.PrimitiveType"> + </argument> + <argument index="1" name="material" type="Material" default="null"> + </argument> + <description> + Begin a new surface. + </description> + </method> + <method name="surface_end"> + <return type="void"> + </return> + <description> + End and commit current surface. Note that surface being created will not be visible until this function is called. + </description> + </method> + <method name="surface_set_color"> + <return type="void"> + </return> + <argument index="0" name="color" type="Color"> + </argument> + <description> + Set the color attribute that will be pushed with the next vertex. + </description> + </method> + <method name="surface_set_normal"> + <return type="void"> + </return> + <argument index="0" name="normal" type="Vector3"> + </argument> + <description> + Set the normal attribute that will be pushed with the next vertex. + </description> + </method> + <method name="surface_set_tangent"> + <return type="void"> + </return> + <argument index="0" name="tangent" type="Plane"> + </argument> + <description> + Set the tangent attribute that will be pushed with the next vertex. + </description> + </method> + <method name="surface_set_uv"> + <return type="void"> + </return> + <argument index="0" name="uv" type="Vector2"> + </argument> + <description> + Set the UV attribute that will be pushed with the next vertex. + </description> + </method> + <method name="surface_set_uv2"> + <return type="void"> + </return> + <argument index="0" name="uv2" type="Vector2"> + </argument> + <description> + Set the UV2 attribute that will be pushed with the next vertex. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml index ebfd32c5fb..b970070659 100644 --- a/doc/classes/Input.xml +++ b/doc/classes/Input.xml @@ -123,7 +123,7 @@ </return> <argument index="0" name="device" type="int"> </argument> - <argument index="1" name="axis" type="int"> + <argument index="1" name="axis" type="int" enum="JoyAxis"> </argument> <description> Returns the current value of the joypad axis at given index (see [enum JoyAxis]). @@ -252,7 +252,7 @@ </return> <argument index="0" name="device" type="int"> </argument> - <argument index="1" name="button" type="int"> + <argument index="1" name="button" type="int" enum="JoyButton"> </argument> <description> Returns [code]true[/code] if you are pressing the joypad button (see [enum JoyButton]). @@ -279,7 +279,7 @@ <method name="is_mouse_button_pressed" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="button" type="int"> + <argument index="0" name="button" type="int" enum="MouseButton"> </argument> <description> Returns [code]true[/code] if you are pressing the mouse button specified with [enum MouseButton]. @@ -341,7 +341,7 @@ </argument> <argument index="1" name="shape" type="int" enum="Input.CursorShape" default="0"> </argument> - <argument index="2" name="hotspot" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="hotspot" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Sets a custom mouse cursor image, which is only visible inside the game window. The hotspot can also be specified. Passing [code]null[/code] to the image parameter resets to the system cursor. See [enum CursorShape] for the list of shapes. diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml index 28c4773f51..c28c4c4282 100644 --- a/doc/classes/InputEvent.xml +++ b/doc/classes/InputEvent.xml @@ -90,20 +90,23 @@ Returns [code]true[/code] if this input event is an echo event (only for events of type [InputEventKey]). </description> </method> - <method name="is_pressed" qualifiers="const"> + <method name="is_match" qualifiers="const"> <return type="bool"> </return> + <argument index="0" name="event" type="InputEvent"> + </argument> + <argument index="1" name="exact_match" type="bool" default="true"> + </argument> <description> - Returns [code]true[/code] if this input event is pressed. Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. + Returns [code]true[/code] if the specified [code]event[/code] matches this event. Only valid for action events i.e key ([InputEventKey]), button ([InputEventMouseButton] or [InputEventJoypadButton]), axis [InputEventJoypadMotion] or action ([InputEventAction]) events. + If [code]exact_match[/code] is [code]false[/code], it ignores the input modifiers for [InputEventKey] and [InputEventMouseButton] events, and the direction for [InputEventJoypadMotion] events. </description> </method> - <method name="shortcut_match" qualifiers="const"> + <method name="is_pressed" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="event" type="InputEvent"> - </argument> <description> - Returns [code]true[/code] if the given input event is checking for the same key ([InputEventKey]), button ([InputEventJoypadButton]) or action ([InputEventAction]). + Returns [code]true[/code] if this input event is pressed. Not relevant for events of type [InputEventMouseMotion] or [InputEventScreenDrag]. </description> </method> <method name="xformed_by" qualifiers="const"> @@ -111,7 +114,7 @@ </return> <argument index="0" name="xform" type="Transform2D"> </argument> - <argument index="1" name="local_ofs" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="1" name="local_ofs" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Returns a copy of the given input event which has been offset by [code]local_ofs[/code] and transformed by [code]xform[/code]. Relevant for events of type [InputEventMouseButton], [InputEventMouseMotion], [InputEventScreenTouch], [InputEventScreenDrag], [InputEventMagnifyGesture] and [InputEventPanGesture]. diff --git a/doc/classes/InputEventAction.xml b/doc/classes/InputEventAction.xml index ed290fc7e2..42326f344f 100644 --- a/doc/classes/InputEventAction.xml +++ b/doc/classes/InputEventAction.xml @@ -14,7 +14,7 @@ <methods> </methods> <members> - <member name="action" type="StringName" setter="set_action" getter="get_action" default="@"""> + <member name="action" type="StringName" setter="set_action" getter="get_action" default="&"""> The action's name. Actions are accessed via this [String]. </member> <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false"> diff --git a/doc/classes/InputEventGesture.xml b/doc/classes/InputEventGesture.xml index 861ec026cd..fbde318ada 100644 --- a/doc/classes/InputEventGesture.xml +++ b/doc/classes/InputEventGesture.xml @@ -10,7 +10,7 @@ <methods> </methods> <members> - <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The local gesture position relative to the [Viewport]. If used in [method Control._gui_input], the position is relative to the current [Control] that received this gesture. </member> </members> diff --git a/doc/classes/InputEventJoypadButton.xml b/doc/classes/InputEventJoypadButton.xml index b1f4836f6e..f9afe42a7a 100644 --- a/doc/classes/InputEventJoypadButton.xml +++ b/doc/classes/InputEventJoypadButton.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0"> + <member name="button_index" type="int" setter="set_button_index" getter="get_button_index" enum="JoyButton" default="0"> Button identifier. One of the [enum JoyButton] button constants. </member> <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false"> diff --git a/doc/classes/InputEventJoypadMotion.xml b/doc/classes/InputEventJoypadMotion.xml index 39fdb14016..398b9eb6f6 100644 --- a/doc/classes/InputEventJoypadMotion.xml +++ b/doc/classes/InputEventJoypadMotion.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="axis" type="int" setter="set_axis" getter="get_axis" default="0"> + <member name="axis" type="int" setter="set_axis" getter="get_axis" enum="JoyAxis" default="0"> Axis identifier. Use one of the [enum JoyAxis] axis constants. </member> <member name="axis_value" type="float" setter="set_axis_value" getter="get_axis_value" default="0.0"> diff --git a/doc/classes/InputEventMIDI.xml b/doc/classes/InputEventMIDI.xml index 13bb9d8b85..afc9d476da 100644 --- a/doc/classes/InputEventMIDI.xml +++ b/doc/classes/InputEventMIDI.xml @@ -17,7 +17,7 @@ </member> <member name="instrument" type="int" setter="set_instrument" getter="get_instrument" default="0"> </member> - <member name="message" type="int" setter="set_message" getter="get_message" default="0"> + <member name="message" type="int" setter="set_message" getter="get_message" enum="MIDIMessage" default="0"> </member> <member name="pitch" type="int" setter="set_pitch" getter="get_pitch" default="0"> </member> diff --git a/doc/classes/InputEventMouse.xml b/doc/classes/InputEventMouse.xml index e54c3224da..b8043118b7 100644 --- a/doc/classes/InputEventMouse.xml +++ b/doc/classes/InputEventMouse.xml @@ -15,10 +15,10 @@ <member name="button_mask" type="int" setter="set_button_mask" getter="get_button_mask" default="0"> The mouse button mask identifier, one of or a bitwise combination of the [enum MouseButton] button masks. </member> - <member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position" default="Vector2( 0, 0 )"> + <member name="global_position" type="Vector2" setter="set_global_position" getter="get_global_position" default="Vector2(0, 0)"> The global mouse position relative to the current [Viewport] when used in [method Control._gui_input], otherwise is at 0,0. </member> - <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The local mouse position relative to the [Viewport]. If used in [method Control._gui_input], the position is relative to the current [Control] which is under the mouse. </member> </members> diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml index be71b42567..7a6c7410ef 100644 --- a/doc/classes/InputEventMouseButton.xml +++ b/doc/classes/InputEventMouseButton.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0"> + <member name="button_index" type="int" setter="set_button_index" getter="get_button_index" enum="MouseButton" default="0"> The mouse button identifier, one of the [enum MouseButton] button or button wheel constants. </member> <member name="double_click" type="bool" setter="set_double_click" getter="is_double_click" default="false"> diff --git a/doc/classes/InputEventMouseMotion.xml b/doc/classes/InputEventMouseMotion.xml index 0f9e71adb4..881d74ac7b 100644 --- a/doc/classes/InputEventMouseMotion.xml +++ b/doc/classes/InputEventMouseMotion.xml @@ -17,14 +17,14 @@ <member name="pressure" type="float" setter="set_pressure" getter="get_pressure" default="0.0"> Represents the pressure the user puts on the pen. Ranges from [code]0.0[/code] to [code]1.0[/code]. </member> - <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2( 0, 0 )"> + <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2(0, 0)"> The mouse position relative to the previous position (position at the last frame). [b]Note:[/b] Since [InputEventMouseMotion] is only emitted when the mouse moves, the last event won't have a relative position of [code]Vector2(0, 0)[/code] when the user stops moving the mouse. </member> - <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2( 0, 0 )"> + <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2(0, 0)"> The mouse speed in pixels per second. </member> - <member name="tilt" type="Vector2" setter="set_tilt" getter="get_tilt" default="Vector2( 0, 0 )"> + <member name="tilt" type="Vector2" setter="set_tilt" getter="get_tilt" default="Vector2(0, 0)"> Represents the angles of tilt of the pen. Positive X-coordinate value indicates a tilt to the right. Positive Y-coordinate value indicates a tilt toward the user. Ranges from [code]-1.0[/code] to [code]1.0[/code] for both axes. </member> </members> diff --git a/doc/classes/InputEventPanGesture.xml b/doc/classes/InputEventPanGesture.xml index 83161cd163..ffb1901dad 100644 --- a/doc/classes/InputEventPanGesture.xml +++ b/doc/classes/InputEventPanGesture.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="delta" type="Vector2" setter="set_delta" getter="get_delta" default="Vector2( 0, 0 )"> + <member name="delta" type="Vector2" setter="set_delta" getter="get_delta" default="Vector2(0, 0)"> </member> </members> <constants> diff --git a/doc/classes/InputEventScreenDrag.xml b/doc/classes/InputEventScreenDrag.xml index d69f175be8..079ac03f45 100644 --- a/doc/classes/InputEventScreenDrag.xml +++ b/doc/classes/InputEventScreenDrag.xml @@ -15,13 +15,13 @@ <member name="index" type="int" setter="set_index" getter="get_index" default="0"> The drag event index in the case of a multi-drag event. </member> - <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The drag position. </member> - <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2( 0, 0 )"> + <member name="relative" type="Vector2" setter="set_relative" getter="get_relative" default="Vector2(0, 0)"> The drag position relative to its start position. </member> - <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2( 0, 0 )"> + <member name="speed" type="Vector2" setter="set_speed" getter="get_speed" default="Vector2(0, 0)"> The drag speed. </member> </members> diff --git a/doc/classes/InputEventScreenTouch.xml b/doc/classes/InputEventScreenTouch.xml index f497f2fecc..7aa5f62b05 100644 --- a/doc/classes/InputEventScreenTouch.xml +++ b/doc/classes/InputEventScreenTouch.xml @@ -16,7 +16,7 @@ <member name="index" type="int" setter="set_index" getter="get_index" default="0"> The touch index in the case of a multi-touch event. One index = one finger. </member> - <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> The touch position. </member> <member name="pressed" type="bool" setter="set_pressed" getter="is_pressed" default="false"> diff --git a/doc/classes/InputMap.xml b/doc/classes/InputMap.xml index 0fb18d8e81..3948ab0208 100644 --- a/doc/classes/InputMap.xml +++ b/doc/classes/InputMap.xml @@ -41,6 +41,15 @@ Removes all events from an action. </description> </method> + <method name="action_get_deadzone"> + <return type="float"> + </return> + <argument index="0" name="action" type="StringName"> + </argument> + <description> + Returns a deadzone value for the action. + </description> + </method> <method name="action_get_events"> <return type="Array"> </return> diff --git a/doc/classes/InstancePlaceholder.xml b/doc/classes/InstancePlaceholder.xml index defd23afb1..934764b461 100644 --- a/doc/classes/InstancePlaceholder.xml +++ b/doc/classes/InstancePlaceholder.xml @@ -4,7 +4,7 @@ Placeholder for the root [Node] of a [PackedScene]. </brief_description> <description> - Turning on the option [b]Load As Placeholder[/b] for an instanced scene in the editor causes it to be replaced by an [InstancePlaceholder] when running the game. This makes it possible to delay actually loading the scene until calling [method create_instance]. This is useful to avoid loading large scenes all at once by loading parts of it selectively. + Turning on the option [b]Load As Placeholder[/b] for an instantiated scene in the editor causes it to be replaced by an [InstancePlaceholder] when running the game. This makes it possible to delay actually loading the scene until calling [method create_instance]. This is useful to avoid loading large scenes all at once by loading parts of it selectively. The [InstancePlaceholder] does not have a transform. This causes any child nodes to be positioned relatively to the [Viewport] from point (0,0), rather than their parent as displayed in the editor. Replacing the placeholder with a scene with a transform will transform children relatively to their parent again. </description> <tutorials> diff --git a/doc/classes/IntervalTweener.xml b/doc/classes/IntervalTweener.xml new file mode 100644 index 0000000000..1c59003c70 --- /dev/null +++ b/doc/classes/IntervalTweener.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="IntervalTweener" inherits="Tweener" version="4.0"> + <brief_description> + Creates an idle interval in a [Tween] animation. + </brief_description> + <description> + [IntervalTweener] is used to make delays in a tweening sequence. See [method Tween.tween_interval] for more usage information. + [b]Note:[/b] [method Tween.tween_interval] is the only correct way to create [IntervalTweener]. Any [IntervalTweener] created manually will not function correctly. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml index 0020cbf242..c639e0b88e 100644 --- a/doc/classes/ItemList.xml +++ b/doc/classes/ItemList.xml @@ -484,7 +484,7 @@ The width all columns will be adjusted to. A value of zero disables the adjustment, each item will have a width equal to the width of its content and the columns will have an uneven width. </member> - <member name="fixed_icon_size" type="Vector2" setter="set_fixed_icon_size" getter="get_fixed_icon_size" default="Vector2( 0, 0 )"> + <member name="fixed_icon_size" type="Vector2" setter="set_fixed_icon_size" getter="get_fixed_icon_size" default="Vector2(0, 0)"> The size all icons will be adjusted to. If either X or Y component is not greater than zero, icon size won't be affected. </member> @@ -593,19 +593,19 @@ <theme_item name="font" type="Font"> [Font] of the item's text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.63, 0.63, 0.63, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.63, 0.63, 0.63, 1)"> Default text [Color] of the item. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the item. </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the item is selected. </theme_item> <theme_item name="font_size" type="int"> Font size of the item's text. </theme_item> - <theme_item name="guide_color" type="Color" default="Color( 0, 0, 0, 0.1 )"> + <theme_item name="guide_color" type="Color" default="Color(0, 0, 0, 0.1)"> [Color] of the guideline. The guideline is a line drawn between each row of items. </theme_item> <theme_item name="hseparation" type="int" default="4"> diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index a9fb50c262..b95aaed143 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -1,42 +1,88 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="JSON" inherits="Object" version="4.0"> +<class name="JSON" inherits="RefCounted" version="4.0"> <brief_description> - Helper class for parsing JSON data. + Helper class for creating and parsing JSON data. </brief_description> <description> - Helper class for parsing JSON data. For usage example and other important hints, see [JSONParseResult]. + The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network. + [method stringify] is used to convert any data type into a JSON string. + [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. + [b]Example[/b] + [codeblock] + var data_to_send = ["a", "b", "c"] + var json = JSON.new() + var json_string = json.stringify(data_to_send) + # Save data + # ... + # Retrieve data + var error = json.parse(json_string) + if error == OK: + var data_received = json.get_data() + if typeof(data_received) == TYPE_ARRAY: + print(data_received) # Prints array + else: + print("Unexpected data") + else: + print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line()) + [/codeblock] </description> <tutorials> </tutorials> <methods> + <method name="get_data" qualifiers="const"> + <return type="Variant"> + </return> + <description> + Returns the [Variant] containing the data of a successful [method parse]. + [b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called. + </description> + </method> + <method name="get_error_line" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns [code]0[/code] if the last call to [method parse] was successful, or the line number where the parse failed. + </description> + </method> + <method name="get_error_message" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns an empty string if the last call to [method parse] was successful, or the error message if it failed. + </description> + </method> <method name="parse"> - <return type="JSONParseResult"> + <return type="int" enum="Error"> </return> - <argument index="0" name="json" type="String"> + <argument index="0" name="json_string" type="String"> </argument> <description> - Parses a JSON-encoded string and returns a [JSONParseResult] containing the result. + Attempts to parse the [code]json_string[/code] provided. + Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. </description> </method> - <method name="print"> + <method name="stringify"> <return type="String"> </return> - <argument index="0" name="value" type="Variant"> + <argument index="0" name="data" type="Variant"> </argument> <argument index="1" name="indent" type="String" default=""""> </argument> - <argument index="2" name="sort_keys" type="bool" default="false"> + <argument index="2" name="sort_keys" type="bool" default="true"> + </argument> + <argument index="3" name="full_precision" type="bool" default="false"> </argument> <description> Converts a [Variant] var to JSON text and returns the result. Useful for serializing data to store or send over the network. [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, converting a Variant to JSON text will convert all numerical values to [float] types. - Use [code]indent[/code] parameter to pretty print the output. + [b]Note:[/b] If [code]full_precision[/code] is true, when stringifying floats, the unreliable digits are stringified in addition to the reliable digits to guarantee exact decoding. + Use [code]indent[/code] parameter to pretty stringify the output. [b]Example output:[/b] [codeblock] - ## JSON.print(my_dictionary) + ## JSON.stringify(my_dictionary) {"name":"my_dictionary","version":"1.0.0","entities":[{"name":"entity_0","value":"value_0"},{"name":"entity_1","value":"value_1"}]} - ## JSON.print(my_dictionary, "\t") + ## JSON.stringify(my_dictionary, "\t") { "name": "my_dictionary", "version": "1.0.0", diff --git a/doc/classes/JSONParseResult.xml b/doc/classes/JSONParseResult.xml deleted file mode 100644 index bc94f74b07..0000000000 --- a/doc/classes/JSONParseResult.xml +++ /dev/null @@ -1,51 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="JSONParseResult" inherits="Reference" version="4.0"> - <brief_description> - Data class wrapper for decoded JSON. - </brief_description> - <description> - Returned by [method JSON.parse], [JSONParseResult] contains the decoded JSON or error information if the JSON source wasn't successfully parsed. You can check if the JSON source was successfully parsed with [code]if json_result.error == OK[/code]. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <members> - <member name="error" type="int" setter="set_error" getter="get_error" enum="Error"> - The error type if the JSON source was not successfully parsed. See the [enum Error] constants. - </member> - <member name="error_line" type="int" setter="set_error_line" getter="get_error_line" default="-1"> - The line number where the error occurred if the JSON source was not successfully parsed. - </member> - <member name="error_string" type="String" setter="set_error_string" getter="get_error_string" default=""""> - The error message if the JSON source was not successfully parsed. See the [enum Error] constants. - </member> - <member name="result" type="Variant" setter="set_result" getter="get_result"> - A [Variant] containing the parsed JSON. Use [method @GlobalScope.typeof] or the [code]is[/code] keyword to check if it is what you expect. For example, if the JSON source starts with curly braces ([code]{}[/code]), a [Dictionary] will be returned. If the JSON source starts with brackets ([code][][/code]), an [Array] will be returned. - [b]Note:[/b] The JSON specification does not define integer or float types, but only a [i]number[/i] type. Therefore, parsing a JSON text will convert all numerical values to [float] types. - [b]Note:[/b] JSON objects do not preserve key order like Godot dictionaries, thus, you should not rely on keys being in a certain order if a dictionary is constructed from JSON. In contrast, JSON arrays retain the order of their elements: - [codeblocks] - [gdscript] - var p = JSON.parse('["hello", "world", "!"]') - if typeof(p.result) == TYPE_ARRAY: - print(p.result[0]) # Prints "hello" - else: - push_error("Unexpected results.") - [/gdscript] - [csharp] - JSONParseResult p = JSON.Parse("[\"hello\"], \"world\", \"!\"]"); - if (p.Result is Godot.Collections.Array) - { - GD.Print((p.Result as Godot.Collections.Array)[0]); // Prints "hello" - } - else - { - GD.PushError("Unexpected results."); - } - [/csharp] - [/codeblocks] - </member> - </members> - <constants> - </constants> -</class> diff --git a/doc/classes/JSONParser.xml b/doc/classes/JSONParser.xml deleted file mode 100644 index 31ba295418..0000000000 --- a/doc/classes/JSONParser.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="JSONParser" inherits="Reference" version="4.0"> - <brief_description> - </brief_description> - <description> - </description> - <tutorials> - </tutorials> - <methods> - <method name="decode_data"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="data" type="Variant"> - </argument> - <argument index="1" name="indent" type="String" default=""""> - </argument> - <argument index="2" name="sort_keys" type="bool" default="true"> - </argument> - <description> - </description> - </method> - <method name="get_data" qualifiers="const"> - <return type="Variant"> - </return> - <description> - </description> - </method> - <method name="get_error_line" qualifiers="const"> - <return type="int"> - </return> - <description> - </description> - </method> - <method name="get_error_text" qualifiers="const"> - <return type="String"> - </return> - <description> - </description> - </method> - <method name="get_string" qualifiers="const"> - <return type="String"> - </return> - <description> - </description> - </method> - <method name="parse_string"> - <return type="int" enum="Error"> - </return> - <argument index="0" name="json_string" type="String"> - </argument> - <description> - </description> - </method> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/JavaClass.xml b/doc/classes/JavaClass.xml index 69b7a9b718..0b6a44fe14 100644 --- a/doc/classes/JavaClass.xml +++ b/doc/classes/JavaClass.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="JavaClass" inherits="Reference" version="4.0"> +<class name="JavaClass" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/JavaScriptObject.xml b/doc/classes/JavaScriptObject.xml index a9e9c77e89..087fe163b4 100644 --- a/doc/classes/JavaScriptObject.xml +++ b/doc/classes/JavaScriptObject.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="JavaScriptObject" inherits="Reference" version="4.0"> +<class name="JavaScriptObject" inherits="RefCounted" version="4.0"> <brief_description> A wrapper class for native JavaScript objects. </brief_description> diff --git a/doc/classes/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml deleted file mode 100644 index fdd4db6115..0000000000 --- a/doc/classes/KinematicBody2D.xml +++ /dev/null @@ -1,176 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="KinematicBody2D" inherits="PhysicsBody2D" version="4.0"> - <brief_description> - Kinematic body 2D node. - </brief_description> - <description> - Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses: - [b]Simulated motion:[/b] When these bodies are moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). - [b]Kinematic characters:[/b] KinematicBody2D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but don't require advanced physics. - </description> - <tutorials> - <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link> - <link title="Using KinematicBody2D">https://docs.godotengine.org/en/latest/tutorials/physics/using_kinematic_body_2d.html</link> - <link title="2D Kinematic Character Demo">https://godotengine.org/asset-library/asset/113</link> - <link title="2D Platformer Demo">https://godotengine.org/asset-library/asset/120</link> - </tutorials> - <methods> - <method name="get_floor_normal" qualifiers="const"> - <return type="Vector2"> - </return> - <description> - Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code]. - </description> - </method> - <method name="get_floor_velocity" qualifiers="const"> - <return type="Vector2"> - </return> - <description> - Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code]. - </description> - </method> - <method name="get_slide_collision"> - <return type="KinematicCollision2D"> - </return> - <argument index="0" name="slide_idx" type="int"> - </argument> - <description> - Returns a [KinematicCollision2D], which contains information about a collision that occurred during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1). - [b]Example usage:[/b] - [codeblocks] - [gdscript] - for i in get_slide_count(): - var collision = get_slide_collision(i) - print("Collided with: ", collision.collider.name) - [/gdscript] - [csharp] - for (int i = 0; i < GetSlideCount(); i++) - { - KinematicCollision2D collision = GetSlideCollision(i); - GD.Print("Collided with: ", (collision.Collider as Node).Name); - } - [/csharp] - [/codeblocks] - </description> - </method> - <method name="get_slide_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the number of times the body collided and changed direction during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. - </description> - </method> - <method name="is_on_ceiling" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the body collided with the ceiling on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code]. - </description> - </method> - <method name="is_on_floor" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code]. - </description> - </method> - <method name="is_on_wall" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code]. - </description> - </method> - <method name="move_and_collide"> - <return type="KinematicCollision2D"> - </return> - <argument index="0" name="rel_vec" type="Vector2"> - </argument> - <argument index="1" name="infinite_inertia" type="bool" default="true"> - </argument> - <argument index="2" name="exclude_raycast_shapes" type="bool" default="true"> - </argument> - <argument index="3" name="test_only" type="bool" default="false"> - </argument> - <description> - Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision. - If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given. - </description> - </method> - <method name="move_and_slide"> - <return type="Vector2"> - </return> - <argument index="0" name="linear_velocity" type="Vector2"> - </argument> - <argument index="1" name="up_direction" type="Vector2" default="Vector2( 0, 0 )"> - </argument> - <argument index="2" name="stop_on_slope" type="bool" default="false"> - </argument> - <argument index="3" name="max_slides" type="int" default="4"> - </argument> - <argument index="4" name="floor_max_angle" type="float" default="0.785398"> - </argument> - <argument index="5" name="infinite_inertia" type="bool" default="true"> - </argument> - <description> - Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody2D] or [RigidBody2D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. - This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. - [code]linear_velocity[/code] is the velocity vector in pixels per second. Unlike in [method move_and_collide], you should [i]not[/i] multiply it by [code]delta[/code] — the physics engine handles applying the velocity. - [code]up_direction[/code] is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of [code]Vector2(0, 0)[/code], everything is considered a wall. This is useful for topdown games. - If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on slopes when you include gravity in [code]linear_velocity[/code] and the body is standing still. - If the body collides, it will change direction a maximum of [code]max_slides[/code] times before it stops. - [code]floor_max_angle[/code] is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees. - If [code]infinite_inertia[/code] is [code]true[/code], body will be able to push [RigidBody2D] nodes, but it won't also detect any collisions with them. If [code]false[/code], it will interact with [RigidBody2D] nodes like with [StaticBody2D]. - Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision]. - </description> - </method> - <method name="move_and_slide_with_snap"> - <return type="Vector2"> - </return> - <argument index="0" name="linear_velocity" type="Vector2"> - </argument> - <argument index="1" name="snap" type="Vector2"> - </argument> - <argument index="2" name="up_direction" type="Vector2" default="Vector2( 0, 0 )"> - </argument> - <argument index="3" name="stop_on_slope" type="bool" default="false"> - </argument> - <argument index="4" name="max_slides" type="int" default="4"> - </argument> - <argument index="5" name="floor_max_angle" type="float" default="0.785398"> - </argument> - <argument index="6" name="infinite_inertia" type="bool" default="true"> - </argument> - <description> - Moves the body while keeping it attached to slopes. Similar to [method move_and_slide]. - As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code](0, 0)[/code] or by using [method move_and_slide] instead. - </description> - </method> - <method name="test_move"> - <return type="bool"> - </return> - <argument index="0" name="from" type="Transform2D"> - </argument> - <argument index="1" name="rel_vec" type="Vector2"> - </argument> - <argument index="2" name="infinite_inertia" type="bool" default="true"> - </argument> - <description> - Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur. - </description> - </method> - </methods> - <members> - <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.08"> - Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]). - If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. - A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. - A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies. - </member> - <member name="motion/sync_to_physics" type="bool" setter="set_sync_to_physics" getter="is_sync_to_physics_enabled" default="false"> - If [code]true[/code], the body's movement will be synchronized to the physics frame. This is useful when animating movement via [AnimationPlayer], for example on moving platforms. Do [b]not[/b] use together with [method move_and_slide] or [method move_and_collide] functions. - </member> - </members> - <constants> - </constants> -</class> diff --git a/doc/classes/KinematicBody3D.xml b/doc/classes/KinematicBody3D.xml deleted file mode 100644 index efd3f58f88..0000000000 --- a/doc/classes/KinematicBody3D.xml +++ /dev/null @@ -1,188 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="KinematicBody3D" inherits="PhysicsBody3D" version="4.0"> - <brief_description> - Kinematic body 3D node. - </brief_description> - <description> - Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all; to other types of bodies, such as a character or a rigid body, these are the same as a static body. However, they have two main uses: - [b]Simulated motion:[/b] When these bodies are moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to "physics"), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). - [b]Kinematic characters:[/b] KinematicBody3D also has an API for moving objects (the [method move_and_collide] and [method move_and_slide] methods) while performing collision tests. This makes them really useful to implement characters that collide against a world, but don't require advanced physics. - </description> - <tutorials> - <link title="Kinematic character (2D)">https://docs.godotengine.org/en/latest/tutorials/physics/kinematic_character_2d.html</link> - <link title="3D Kinematic Character Demo">https://godotengine.org/asset-library/asset/126</link> - <link title="3D Platformer Demo">https://godotengine.org/asset-library/asset/125</link> - <link title="3D Voxel Demo">https://godotengine.org/asset-library/asset/676</link> - <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> - </tutorials> - <methods> - <method name="get_axis_lock" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> - </argument> - <description> - Returns [code]true[/code] if the specified [code]axis[/code] is locked. See also [member axis_lock_motion_x], [member axis_lock_motion_y] and [member axis_lock_motion_z]. - </description> - </method> - <method name="get_floor_normal" qualifiers="const"> - <return type="Vector3"> - </return> - <description> - Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code]. - </description> - </method> - <method name="get_floor_velocity" qualifiers="const"> - <return type="Vector3"> - </return> - <description> - Returns the linear velocity of the floor at the last collision point. Only valid after calling [method move_and_slide] or [method move_and_slide_with_snap] and when [method is_on_floor] returns [code]true[/code]. - </description> - </method> - <method name="get_slide_collision"> - <return type="KinematicCollision3D"> - </return> - <argument index="0" name="slide_idx" type="int"> - </argument> - <description> - Returns a [KinematicCollision3D], which contains information about a collision that occurred during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. Since the body can collide several times in a single call to [method move_and_slide], you must specify the index of the collision in the range 0 to ([method get_slide_count] - 1). - </description> - </method> - <method name="get_slide_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the number of times the body collided and changed direction during the last call to [method move_and_slide] or [method move_and_slide_with_snap]. - </description> - </method> - <method name="is_on_ceiling" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the body collided with the ceiling on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code]. - </description> - </method> - <method name="is_on_floor" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the body collided with the floor on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code]. - </description> - </method> - <method name="is_on_wall" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the body collided with a wall on the last call of [method move_and_slide] or [method move_and_slide_with_snap]. Otherwise, returns [code]false[/code]. - </description> - </method> - <method name="move_and_collide"> - <return type="KinematicCollision3D"> - </return> - <argument index="0" name="rel_vec" type="Vector3"> - </argument> - <argument index="1" name="infinite_inertia" type="bool" default="true"> - </argument> - <argument index="2" name="exclude_raycast_shapes" type="bool" default="true"> - </argument> - <argument index="3" name="test_only" type="bool" default="false"> - </argument> - <description> - Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision. - If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given. - </description> - </method> - <method name="move_and_slide"> - <return type="Vector3"> - </return> - <argument index="0" name="linear_velocity" type="Vector3"> - </argument> - <argument index="1" name="up_direction" type="Vector3" default="Vector3( 0, 0, 0 )"> - </argument> - <argument index="2" name="stop_on_slope" type="bool" default="false"> - </argument> - <argument index="3" name="max_slides" type="int" default="4"> - </argument> - <argument index="4" name="floor_max_angle" type="float" default="0.785398"> - </argument> - <argument index="5" name="infinite_inertia" type="bool" default="true"> - </argument> - <description> - Moves the body along a vector. If the body collides with another, it will slide along the other body rather than stop immediately. If the other body is a [KinematicBody3D] or [RigidBody3D], it will also be affected by the motion of the other body. You can use this to make moving and rotating platforms, or to make nodes push other nodes. - This method should be used in [method Node._physics_process] (or in a method called by [method Node._physics_process]), as it uses the physics step's [code]delta[/code] value automatically in calculations. Otherwise, the simulation will run at an incorrect speed. - [code]linear_velocity[/code] is the velocity vector (typically meters per second). Unlike in [method move_and_collide], you should [i]not[/i] multiply it by [code]delta[/code] — the physics engine handles applying the velocity. - [code]up_direction[/code] is the up direction, used to determine what is a wall and what is a floor or a ceiling. If set to the default value of [code]Vector3(0, 0, 0)[/code], everything is considered a wall. - If [code]stop_on_slope[/code] is [code]true[/code], body will not slide on slopes when you include gravity in [code]linear_velocity[/code] and the body is standing still. - If the body collides, it will change direction a maximum of [code]max_slides[/code] times before it stops. - [code]floor_max_angle[/code] is the maximum angle (in radians) where a slope is still considered a floor (or a ceiling), rather than a wall. The default value equals 45 degrees. - If [code]infinite_inertia[/code] is [code]true[/code], body will be able to push [RigidBody3D] nodes, but it won't also detect any collisions with them. If [code]false[/code], it will interact with [RigidBody3D] nodes like with [StaticBody3D]. - Returns the [code]linear_velocity[/code] vector, rotated and/or scaled if a slide collision occurred. To get detailed information about collisions that occurred, use [method get_slide_collision]. - </description> - </method> - <method name="move_and_slide_with_snap"> - <return type="Vector3"> - </return> - <argument index="0" name="linear_velocity" type="Vector3"> - </argument> - <argument index="1" name="snap" type="Vector3"> - </argument> - <argument index="2" name="up_direction" type="Vector3" default="Vector3( 0, 0, 0 )"> - </argument> - <argument index="3" name="stop_on_slope" type="bool" default="false"> - </argument> - <argument index="4" name="max_slides" type="int" default="4"> - </argument> - <argument index="5" name="floor_max_angle" type="float" default="0.785398"> - </argument> - <argument index="6" name="infinite_inertia" type="bool" default="true"> - </argument> - <description> - Moves the body while keeping it attached to slopes. Similar to [method move_and_slide]. - As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code](0, 0, 0)[/code] or by using [method move_and_slide] instead. - </description> - </method> - <method name="set_axis_lock"> - <return type="void"> - </return> - <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> - </argument> - <argument index="1" name="lock" type="bool"> - </argument> - <description> - Locks or unlocks the specified [code]axis[/code] depending on the value of [code]lock[/code]. See also [member axis_lock_motion_x], [member axis_lock_motion_y] and [member axis_lock_motion_z]. - </description> - </method> - <method name="test_move"> - <return type="bool"> - </return> - <argument index="0" name="from" type="Transform"> - </argument> - <argument index="1" name="rel_vec" type="Vector3"> - </argument> - <argument index="2" name="infinite_inertia" type="bool" default="true"> - </argument> - <description> - Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur. - </description> - </method> - </methods> - <members> - <member name="axis_lock_motion_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's X axis movement. - </member> - <member name="axis_lock_motion_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's Y axis movement. - </member> - <member name="axis_lock_motion_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's Z axis movement. - </member> - <member name="collision/safe_margin" type="float" setter="set_safe_margin" getter="get_safe_margin" default="0.001"> - Extra margin used for collision recovery in motion functions (see [method move_and_collide], [method move_and_slide], [method move_and_slide_with_snap]). - If the body is at least this close to another body, it will consider them to be colliding and will be pushed away before performing the actual motion. - A higher value means it's more flexible for detecting collision, which helps with consistently detecting walls and floors. - A lower value forces the collision algorithm to use more exact detection, so it can be used in cases that specifically require precision, e.g at very low scale to avoid visible jittering, or for stability with a stack of kinematic bodies. - </member> - </members> - <constants> - </constants> -</class> diff --git a/doc/classes/KinematicCollision2D.xml b/doc/classes/KinematicCollision2D.xml index ec6e16e25a..d7999f1aa0 100644 --- a/doc/classes/KinematicCollision2D.xml +++ b/doc/classes/KinematicCollision2D.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="KinematicCollision2D" inherits="Reference" version="4.0"> +<class name="KinematicCollision2D" inherits="RefCounted" version="4.0"> <brief_description> - Collision data for [KinematicBody2D] collisions. + Collision data for [method PhysicsBody2D.move_and_collide] collisions. </brief_description> <description> - Contains collision data for [KinematicBody2D] collisions. When a [KinematicBody2D] is moved using [method KinematicBody2D.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a KinematicCollision2D object is returned. + Contains collision data for [method PhysicsBody2D.move_and_collide] collisions. When a [PhysicsBody2D] is moved using [method PhysicsBody2D.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a [KinematicCollision2D] object is returned. This object contains information about the collision, including the colliding object, the remaining motion, and the collision position. This information can be used to calculate a collision response. </description> <tutorials> @@ -21,28 +21,31 @@ <member name="collider_metadata" type="Variant" setter="" getter="get_collider_metadata"> The colliding body's metadata. See [Object]. </member> + <member name="collider_rid" type="RID" setter="" getter="get_collider_rid"> + The colliding body's [RID] used by the [PhysicsServer2D]. + </member> <member name="collider_shape" type="Object" setter="" getter="get_collider_shape"> The colliding body's shape. </member> <member name="collider_shape_index" type="int" setter="" getter="get_collider_shape_index" default="0"> The colliding shape's index. See [CollisionObject2D]. </member> - <member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2( 0, 0 )"> + <member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2(0, 0)"> The colliding object's velocity. </member> <member name="local_shape" type="Object" setter="" getter="get_local_shape"> The moving object's colliding shape. </member> - <member name="normal" type="Vector2" setter="" getter="get_normal" default="Vector2( 0, 0 )"> + <member name="normal" type="Vector2" setter="" getter="get_normal" default="Vector2(0, 0)"> The colliding body's shape's normal at the point of collision. </member> - <member name="position" type="Vector2" setter="" getter="get_position" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="" getter="get_position" default="Vector2(0, 0)"> The point of collision, in global coordinates. </member> - <member name="remainder" type="Vector2" setter="" getter="get_remainder" default="Vector2( 0, 0 )"> + <member name="remainder" type="Vector2" setter="" getter="get_remainder" default="Vector2(0, 0)"> The moving object's remaining movement vector. </member> - <member name="travel" type="Vector2" setter="" getter="get_travel" default="Vector2( 0, 0 )"> + <member name="travel" type="Vector2" setter="" getter="get_travel" default="Vector2(0, 0)"> The distance the moving object traveled before collision. </member> </members> diff --git a/doc/classes/KinematicCollision3D.xml b/doc/classes/KinematicCollision3D.xml index f3248a9ca1..abdb5b4f4e 100644 --- a/doc/classes/KinematicCollision3D.xml +++ b/doc/classes/KinematicCollision3D.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="KinematicCollision3D" inherits="Reference" version="4.0"> +<class name="KinematicCollision3D" inherits="RefCounted" version="4.0"> <brief_description> - Collision data for [KinematicBody3D] collisions. + Collision data for [method PhysicsBody3D.move_and_collide] collisions. </brief_description> <description> - Contains collision data for [KinematicBody3D] collisions. When a [KinematicBody3D] is moved using [method KinematicBody3D.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a KinematicCollision3D object is returned. + Contains collision data for [method PhysicsBody3D.move_and_collide] collisions. When a [PhysicsBody3D] is moved using [method PhysicsBody3D.move_and_collide], it stops if it detects a collision with another body. If a collision is detected, a [KinematicCollision3D] object is returned. This object contains information about the collision, including the colliding object, the remaining motion, and the collision position. This information can be used to calculate a collision response. </description> <tutorials> @@ -21,28 +21,31 @@ <member name="collider_metadata" type="Variant" setter="" getter="get_collider_metadata"> The colliding body's metadata. See [Object]. </member> + <member name="collider_rid" type="RID" setter="" getter="get_collider_rid"> + The colliding body's [RID] used by the [PhysicsServer3D]. + </member> <member name="collider_shape" type="Object" setter="" getter="get_collider_shape"> The colliding body's shape. </member> <member name="collider_shape_index" type="int" setter="" getter="get_collider_shape_index" default="0"> The colliding shape's index. See [CollisionObject3D]. </member> - <member name="collider_velocity" type="Vector3" setter="" getter="get_collider_velocity" default="Vector3( 0, 0, 0 )"> + <member name="collider_velocity" type="Vector3" setter="" getter="get_collider_velocity" default="Vector3(0, 0, 0)"> The colliding object's velocity. </member> <member name="local_shape" type="Object" setter="" getter="get_local_shape"> The moving object's colliding shape. </member> - <member name="normal" type="Vector3" setter="" getter="get_normal" default="Vector3( 0, 0, 0 )"> + <member name="normal" type="Vector3" setter="" getter="get_normal" default="Vector3(0, 0, 0)"> The colliding body's shape's normal at the point of collision. </member> - <member name="position" type="Vector3" setter="" getter="get_position" default="Vector3( 0, 0, 0 )"> + <member name="position" type="Vector3" setter="" getter="get_position" default="Vector3(0, 0, 0)"> The point of collision, in global coordinates. </member> - <member name="remainder" type="Vector3" setter="" getter="get_remainder" default="Vector3( 0, 0, 0 )"> + <member name="remainder" type="Vector3" setter="" getter="get_remainder" default="Vector3(0, 0, 0)"> The moving object's remaining movement vector. </member> - <member name="travel" type="Vector3" setter="" getter="get_travel" default="Vector3( 0, 0, 0 )"> + <member name="travel" type="Vector3" setter="" getter="get_travel" default="Vector3(0, 0, 0)"> The distance the moving object traveled before collision. </member> </members> diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml index 76b9686393..0789ac9010 100644 --- a/doc/classes/Label.xml +++ b/doc/classes/Label.xml @@ -79,7 +79,7 @@ If [code]true[/code], wraps the text inside the node's bounding rectangle. If you resize the node, it will change its height automatically to show all the text. </member> <member name="clip_text" type="bool" setter="set_clip_text" getter="is_clipping_text" default="false"> - If [code]true[/code], the Label only shows the text that fits inside its bounding rectangle. It also lets you scale the node down freely. + If [code]true[/code], the Label only shows the text that fits inside its bounding rectangle and will clip text horizontally. </member> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. @@ -98,7 +98,7 @@ <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0"> Set BiDi algorithm override for the structured text. </member> - <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]"> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[]"> Set additional options for BiDi override. </member> <member name="text" type="String" setter="set_text" getter="get_text" default=""""> @@ -147,13 +147,13 @@ <theme_item name="font" type="Font"> [Font] used for the [Label]'s text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_color" type="Color" default="Color(1, 1, 1, 1)"> Default text [Color] of the [Label]. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of [Font]'s outline. </theme_item> - <theme_item name="font_shadow_color" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="font_shadow_color" type="Color" default="Color(0, 0, 0, 0)"> [Color] of the text's shadow effect. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/Light2D.xml b/doc/classes/Light2D.xml index f6698352ab..0e71f29b58 100644 --- a/doc/classes/Light2D.xml +++ b/doc/classes/Light2D.xml @@ -30,7 +30,7 @@ <member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="Light2D.BlendMode" default="0"> The Light2D's blend mode. See [enum BlendMode] constants for values. </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> The Light2D's [Color]. </member> <member name="editor_only" type="bool" setter="set_editor_only" getter="is_editor_only" default="false"> @@ -57,7 +57,7 @@ <member name="range_z_min" type="int" setter="set_z_range_min" getter="get_z_range_min" default="-1024"> Minimum [code]z[/code] value of objects that are affected by the Light2D. </member> - <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 0 )"> + <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(0, 0, 0, 0)"> [Color] of shadows cast by the Light2D. </member> <member name="shadow_enabled" type="bool" setter="set_shadow_enabled" getter="is_shadow_enabled" default="false"> diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index 6bae612c9f..815d20223d 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -4,7 +4,7 @@ Provides a base class for different kinds of light nodes. </brief_description> <description> - Light3D is the [i]abstract[/i] base class for light nodes. As it can't be instanced, it shouldn't be used directly. Other types of light nodes inherit from it. Light3D contains the common variables and parameters used for lighting. + Light3D is the [i]abstract[/i] base class for light nodes. As it can't be instantiated, it shouldn't be used directly. Other types of light nodes inherit from it. Light3D contains the common variables and parameters used for lighting. </description> <tutorials> <link title="3D lights and shadows">https://docs.godotengine.org/en/latest/tutorials/3d/lights_and_shadows.html</link> @@ -42,7 +42,7 @@ <member name="light_bake_mode" type="int" setter="set_bake_mode" getter="get_bake_mode" enum="Light3D.BakeMode" default="1"> The light's bake mode. See [enum BakeMode]. </member> - <member name="light_color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="light_color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> The light's color. An [i]overbright[/i] color can be used to achieve a result equivalent to increasing the light's [member light_energy]. </member> <member name="light_cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="4294967295"> @@ -52,7 +52,7 @@ The light's strength multiplier (this is not a physical unit). For [OmniLight3D] and [SpotLight3D], changing this value will only change the light color's intensity, not the light's radius. </member> <member name="light_indirect_energy" type="float" setter="set_param" getter="get_param" default="1.0"> - Secondary multiplier used with indirect light (light bounces). Used with [GIProbe]. + Secondary multiplier used with indirect light (light bounces). Used with [VoxelGI]. </member> <member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false"> If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows. @@ -72,7 +72,7 @@ <member name="shadow_blur" type="float" setter="set_param" getter="get_param" default="1.0"> Blurs the edges of the shadow. Can be used to hide pixel artifacts in low-resolution shadow maps. A high value can impact performance, make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible. </member> - <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 1 )"> + <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(0, 0, 0, 1)"> The color of shadows cast by this light. </member> <member name="shadow_enabled" type="bool" setter="set_shadow" getter="has_shadow" default="false"> diff --git a/doc/classes/BakedLightmap.xml b/doc/classes/LightmapGI.xml index 6fd08fc4e4..d7722a83b0 100644 --- a/doc/classes/BakedLightmap.xml +++ b/doc/classes/LightmapGI.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BakedLightmap" inherits="VisualInstance3D" version="4.0"> +<class name="LightmapGI" inherits="VisualInstance3D" version="4.0"> <brief_description> </brief_description> <description> @@ -21,17 +21,17 @@ </member> <member name="environment_custom_sky" type="Sky" setter="set_environment_custom_sky" getter="get_environment_custom_sky"> </member> - <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="BakedLightmap.EnvironmentMode" default="0"> + <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="0"> </member> - <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="BakedLightmap.GenerateProbes" default="0"> + <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="0"> </member> <member name="interior" type="bool" setter="set_interior" getter="is_interior" default="false"> </member> - <member name="light_data" type="BakedLightmapData" setter="set_light_data" getter="get_light_data"> + <member name="light_data" type="LightmapGIData" setter="set_light_data" getter="get_light_data"> </member> <member name="max_texture_size" type="int" setter="set_max_texture_size" getter="get_max_texture_size" default="16384"> </member> - <member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="BakedLightmap.BakeQuality" default="1"> + <member name="quality" type="int" setter="set_bake_quality" getter="get_bake_quality" enum="LightmapGI.BakeQuality" default="1"> </member> <member name="use_denoiser" type="bool" setter="set_use_denoiser" getter="is_using_denoiser" default="true"> </member> diff --git a/doc/classes/BakedLightmapData.xml b/doc/classes/LightmapGIData.xml index 904555c48e..3a37c6dcb7 100644 --- a/doc/classes/BakedLightmapData.xml +++ b/doc/classes/LightmapGIData.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="BakedLightmapData" inherits="Resource" version="4.0"> +<class name="LightmapGIData" inherits="Resource" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/Lightmapper.xml b/doc/classes/Lightmapper.xml index e80194858a..79fae42d68 100644 --- a/doc/classes/Lightmapper.xml +++ b/doc/classes/Lightmapper.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Lightmapper" inherits="Reference" version="4.0"> +<class name="Lightmapper" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml index dec5d60cbb..587d5833b9 100644 --- a/doc/classes/Line2D.xml +++ b/doc/classes/Line2D.xml @@ -74,7 +74,7 @@ <member name="begin_cap_mode" type="int" setter="set_begin_cap_mode" getter="get_begin_cap_mode" enum="Line2D.LineCapMode" default="0"> Controls the style of the line's first point. Use [enum LineCapMode] constants. </member> - <member name="default_color" type="Color" setter="set_default_color" getter="get_default_color" default="Color( 1, 1, 1, 1 )"> + <member name="default_color" type="Color" setter="set_default_color" getter="get_default_color" default="Color(1, 1, 1, 1)"> The line's color. Will not be used if a gradient is set. </member> <member name="end_cap_mode" type="int" setter="set_end_cap_mode" getter="get_end_cap_mode" enum="Line2D.LineCapMode" default="0"> @@ -86,7 +86,7 @@ <member name="joint_mode" type="int" setter="set_joint_mode" getter="get_joint_mode" enum="Line2D.LineJointMode" default="0"> The style for the points between the start and the end. </member> - <member name="points" type="PackedVector2Array" setter="set_points" getter="get_points" default="PackedVector2Array( )"> + <member name="points" type="PackedVector2Array" setter="set_points" getter="get_points" default="PackedVector2Array()"> The points that form the lines. The line is drawn between every point set in this array. Points are interpreted as local vectors. </member> <member name="round_precision" type="int" setter="set_round_precision" getter="get_round_precision" default="8"> diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 7adf19632e..773f7b1a02 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -169,6 +169,7 @@ The caret's column position inside the [LineEdit]. When set, the text may scroll to accommodate it. </member> <member name="caret_force_displayed" type="bool" setter="set_caret_force_displayed" getter="is_caret_force_displayed" default="false"> + If [code]true[/code], the [LineEdit] will always show the caret, even if focus is lost. </member> <member name="caret_mid_grapheme" type="bool" setter="set_caret_mid_grapheme_enabled" getter="is_caret_mid_grapheme_enabled" default="false"> Allow moving caret, selecting and removing the individual composite character components. @@ -195,6 +196,28 @@ </member> <member name="max_length" type="int" setter="set_max_length" getter="get_max_length" default="0"> Maximum amount of characters that can be entered inside the [LineEdit]. If [code]0[/code], there is no limit. + When a limit is defined, characters that would exceed [member max_length] are truncated. This happens both for existing [member text] contents when setting the max length, or for new text inserted in the [LineEdit], including pasting. If any input text is truncated, the [signal text_change_rejected] signal is emitted with the truncated substring as parameter. + [b]Example:[/b] + [codeblocks] + [gdscript] + text = "Hello world" + max_length = 5 + # `text` becomes "Hello". + max_length = 10 + text += " goodbye" + # `text` becomes "Hello good". + # `text_change_rejected` is emitted with "bye" as parameter. + [/gdscript] + [csharp] + Text = "Hello world"; + MaxLength = 5; + // `Text` becomes "Hello". + MaxLength = 10; + Text += " goodbye"; + // `Text` becomes "Hello good". + // `text_change_rejected` is emitted with "bye" as parameter. + [/csharp] + [/codeblocks] </member> <member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" override="true" enum="Control.CursorShape" default="1" /> <member name="placeholder_alpha" type="float" setter="set_placeholder_alpha" getter="get_placeholder_alpha" default="0.6"> @@ -221,7 +244,7 @@ <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0"> Set BiDi algorithm override for the structured text. </member> - <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]"> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[]"> Set additional options for BiDi override. </member> <member name="text" type="String" setter="set_text" getter="get_text" default=""""> @@ -237,8 +260,10 @@ </members> <signals> <signal name="text_change_rejected"> + <argument index="0" name="rejected_substring" type="String"> + </argument> <description> - Emitted when trying to append text that would overflow the [member max_length]. + Emitted when appending text that overflows the [member max_length]. The appended text is truncated to fit [member max_length], and the part that couldn't fit is passed as the [code]rejected_substring[/code] argument. </description> </signal> <signal name="text_changed"> @@ -248,7 +273,7 @@ Emitted when the text changes. </description> </signal> - <signal name="text_entered"> + <signal name="text_submitted"> <argument index="0" name="new_text" type="String"> </argument> <description> @@ -359,16 +384,16 @@ </constant> </constants> <theme_items> - <theme_item name="caret_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="caret_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Color of the [LineEdit]'s caret (text cursor). </theme_item> <theme_item name="clear" type="Texture2D"> Texture for the clear button. See [member clear_button_enabled]. </theme_item> - <theme_item name="clear_button_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="clear_button_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Color used as default tint for the clear button. </theme_item> - <theme_item name="clear_button_color_pressed" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="clear_button_color_pressed" type="Color" default="Color(1, 1, 1, 1)"> Color used for the clear button when it's pressed. </theme_item> <theme_item name="focus" type="StyleBox"> @@ -377,19 +402,19 @@ <theme_item name="font" type="Font"> Font used for the text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Default font color. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [LineEdit]. </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(0, 0, 0, 1)"> Font color for selected text (inside the selection rectangle). </theme_item> <theme_item name="font_size" type="int"> Font size of the [LineEdit]'s text. </theme_item> - <theme_item name="font_uneditable_color" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )"> + <theme_item name="font_uneditable_color" type="Color" default="Color(0.88, 0.88, 0.88, 0.5)"> Font color when editing is disabled. </theme_item> <theme_item name="minimum_character_width" type="int" default="4"> @@ -404,7 +429,7 @@ <theme_item name="read_only" type="StyleBox"> Background used when [LineEdit] is in read-only mode ([member editable] is set to [code]false[/code]). </theme_item> - <theme_item name="selection_color" type="Color" default="Color( 0.49, 0.49, 0.49, 1 )"> + <theme_item name="selection_color" type="Color" default="Color(0.49, 0.49, 0.49, 1)"> Color of the selection rectangle. </theme_item> </theme_items> diff --git a/doc/classes/LineShape2D.xml b/doc/classes/LineShape2D.xml index 58caf1b1de..434e6fba8e 100644 --- a/doc/classes/LineShape2D.xml +++ b/doc/classes/LineShape2D.xml @@ -14,8 +14,8 @@ <member name="distance" type="float" setter="set_distance" getter="get_distance" default="0.0"> The line's distance from the origin. </member> - <member name="normal" type="Vector2" setter="set_normal" getter="get_normal" default="Vector2( 0, 1 )"> - The line's normal. + <member name="normal" type="Vector2" setter="set_normal" getter="get_normal" default="Vector2(0, -1)"> + The line's normal. Defaults to [code]Vector2.UP[/code]. </member> </members> <constants> diff --git a/doc/classes/LinkButton.xml b/doc/classes/LinkButton.xml index 6e2f4399b3..51b20cd04d 100644 --- a/doc/classes/LinkButton.xml +++ b/doc/classes/LinkButton.xml @@ -47,7 +47,7 @@ <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0"> Set BiDi algorithm override for the structured text. </member> - <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]"> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[]"> Set additional options for BiDi override. </member> <member name="text" type="String" setter="set_text" getter="get_text" default=""""> @@ -78,16 +78,16 @@ <theme_item name="font" type="Font"> [Font] of the [LinkButton]'s text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Default text [Color] of the [LinkButton]. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Text [Color] used when the [LinkButton] is being hovered. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [LinkButton]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [LinkButton] is being pressed. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/Listener3D.xml b/doc/classes/Listener3D.xml index 998ea757ff..b2fcbe534d 100644 --- a/doc/classes/Listener3D.xml +++ b/doc/classes/Listener3D.xml @@ -18,10 +18,10 @@ </description> </method> <method name="get_listener_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> - Returns the listener's global orthonormalized [Transform]. + Returns the listener's global orthonormalized [Transform3D]. </description> </method> <method name="is_current" qualifiers="const"> diff --git a/doc/classes/MenuButton.xml b/doc/classes/MenuButton.xml index 7cbf9d3dfe..3b37853d70 100644 --- a/doc/classes/MenuButton.xml +++ b/doc/classes/MenuButton.xml @@ -56,19 +56,19 @@ <theme_item name="font" type="Font"> [Font] of the [MenuButton]'s text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Default text [Color] of the [MenuButton]. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 1, 1, 1, 0.3 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(1, 1, 1, 0.3)"> Text [Color] used when the [MenuButton] is disabled. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Text [Color] used when the [MenuButton] is being hovered. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [MenuButton]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [MenuButton] is being pressed. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml index ed7c39d4d9..2cc0bd2ef9 100644 --- a/doc/classes/Mesh.xml +++ b/doc/classes/Mesh.xml @@ -16,8 +16,14 @@ <method name="create_convex_shape" qualifiers="const"> <return type="Shape3D"> </return> + <argument index="0" name="clean" type="bool" default="true"> + </argument> + <argument index="1" name="simplify" type="bool" default="false"> + </argument> <description> Calculate a [ConvexPolygonShape3D] from the mesh. + If [code]clean[/code] is [code]true[/code] (default), duplicate and interior vertices are removed automatically. You can set it to [code]false[/code] to make the process faster if not needed. + If [code]simplify[/code] is [code]true[/code], the geometry can be further simplified to reduce the amount of vertices. Disabled by default. </description> </method> <method name="create_outline" qualifiers="const"> @@ -106,7 +112,7 @@ </method> </methods> <members> - <member name="lightmap_size_hint" type="Vector2i" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint" default="Vector2i( 0, 0 )"> + <member name="lightmap_size_hint" type="Vector2i" setter="set_lightmap_size_hint" getter="get_lightmap_size_hint" default="Vector2i(0, 0)"> Sets a hint to be used for lightmap resolution. </member> </members> diff --git a/doc/classes/MeshDataTool.xml b/doc/classes/MeshDataTool.xml index 3c679047a0..c0ee1e1956 100644 --- a/doc/classes/MeshDataTool.xml +++ b/doc/classes/MeshDataTool.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MeshDataTool" inherits="Reference" version="4.0"> +<class name="MeshDataTool" inherits="RefCounted" version="4.0"> <brief_description> Helper tool to access and edit [Mesh] data. </brief_description> @@ -45,7 +45,7 @@ AddChild(mi); [/csharp] [/codeblocks] - See also [ArrayMesh], [ImmediateGeometry3D] and [SurfaceTool] for procedural geometry generation. + See also [ArrayMesh], [ImmediateMesh] and [SurfaceTool] for procedural geometry generation. [b]Note:[/b] Godot uses clockwise [url=https://learnopengl.com/Advanced-OpenGL/Face-culling]winding order[/url] for front faces of triangle primitive modes. </description> <tutorials> diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml index b5ab296bd0..930301a742 100644 --- a/doc/classes/MeshInstance3D.xml +++ b/doc/classes/MeshInstance3D.xml @@ -4,7 +4,7 @@ Node that instances meshes into a scenario. </brief_description> <description> - MeshInstance3D is a node that takes a [Mesh] resource and adds it to the current scenario by creating an instance of it. This is the class most often used render 3D geometry and can be used to instance a single [Mesh] in many places. This allows reuse of geometry which can save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance3D] instead. + MeshInstance3D is a node that takes a [Mesh] resource and adds it to the current scenario by creating an instance of it. This is the class most often used render 3D geometry and can be used to instance a single [Mesh] in many places. This allows reuse of geometry which can save on resources. When a [Mesh] has to be instantiated more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance3D] instead. </description> <tutorials> <link title="3D Material Testers Demo">https://godotengine.org/asset-library/asset/123</link> @@ -16,8 +16,14 @@ <method name="create_convex_collision"> <return type="void"> </return> + <argument index="0" name="clean" type="bool" default="true"> + </argument> + <argument index="1" name="simplify" type="bool" default="false"> + </argument> <description> This helper creates a [StaticBody3D] child node with a [ConvexPolygonShape3D] collision shape calculated from the mesh geometry. It's mainly used for testing. + If [code]clean[/code] is [code]true[/code] (default), duplicate and interior vertices are removed automatically. You can set it to [code]false[/code] to make the process faster if not needed. + If [code]simplify[/code] is [code]true[/code], the geometry can be further simplified to reduce the amount of vertices. Disabled by default. </description> </method> <method name="create_debug_tangents"> diff --git a/doc/classes/MeshLibrary.xml b/doc/classes/MeshLibrary.xml index ad8bd6991d..b33bcc89e3 100644 --- a/doc/classes/MeshLibrary.xml +++ b/doc/classes/MeshLibrary.xml @@ -72,7 +72,7 @@ </description> </method> <method name="get_item_navmesh_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="id" type="int"> </argument> @@ -96,7 +96,7 @@ </argument> <description> Returns an item's collision shapes. - The array consists of each [Shape3D] followed by its [Transform]. + The array consists of each [Shape3D] followed by its [Transform3D]. </description> </method> <method name="get_last_unused_item_id" qualifiers="const"> @@ -154,7 +154,7 @@ </return> <argument index="0" name="id" type="int"> </argument> - <argument index="1" name="navmesh" type="Transform"> + <argument index="1" name="navmesh" type="Transform3D"> </argument> <description> Sets the transform to apply to the item's navigation mesh. @@ -180,7 +180,7 @@ </argument> <description> Sets an item's collision shapes. - The array should consist of [Shape3D] objects, each followed by a [Transform] that will be applied to it. For shapes that should not have a transform, use [constant Transform.IDENTITY]. + The array should consist of [Shape3D] objects, each followed by a [Transform3D] that will be applied to it. For shapes that should not have a transform, use [constant Transform3D.IDENTITY]. </description> </method> </methods> diff --git a/doc/classes/MeshTexture.xml b/doc/classes/MeshTexture.xml index bcc9adf90f..57f2397874 100644 --- a/doc/classes/MeshTexture.xml +++ b/doc/classes/MeshTexture.xml @@ -14,7 +14,7 @@ <member name="base_texture" type="Texture2D" setter="set_base_texture" getter="get_base_texture"> Sets the base texture that the Mesh will use to draw. </member> - <member name="image_size" type="Vector2" setter="set_image_size" getter="get_image_size" default="Vector2( 0, 0 )"> + <member name="image_size" type="Vector2" setter="set_image_size" getter="get_image_size" default="Vector2(0, 0)"> Sets the size of the image, needed for reference. </member> <member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh"> diff --git a/doc/classes/MethodTweener.xml b/doc/classes/MethodTweener.xml new file mode 100644 index 0000000000..42b91abf93 --- /dev/null +++ b/doc/classes/MethodTweener.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="MethodTweener" inherits="Tweener" version="4.0"> + <brief_description> + Interpolates an abstract value and supplies it to a method called over time. + </brief_description> + <description> + [MethodTweener] is similar to a combination of [CallbackTweener] and [PropertyTweener]. It calls a method providing an interpolated value as a paramater. See [method Tween.tween_method] for more usage information. + [b]Note:[/b] [method Tween.tween_method] is the only correct way to create [MethodTweener]. Any [MethodTweener] created manually will not function correctly. + </description> + <tutorials> + </tutorials> + <methods> + <method name="set_delay"> + <return type="MethodTweener"> + </return> + <argument index="0" name="delay" type="float"> + </argument> + <description> + Sets the time in seconds after which the [MethodTweener] will start interpolating. By default there's no delay. + </description> + </method> + <method name="set_ease"> + <return type="MethodTweener"> + </return> + <argument index="0" name="ease" type="int" enum="Tween.EaseType"> + </argument> + <description> + Sets the type of used easing from [enum Tween.EaseType]. If not set, the default easing is used from the [Tween] that contains this Tweener. + </description> + </method> + <method name="set_trans"> + <return type="MethodTweener"> + </return> + <argument index="0" name="trans" type="int" enum="Tween.TransitionType"> + </argument> + <description> + Sets the type of used transition from [enum Tween.TransitionType]. If not set, the default transition is used from the [Tween] that contains this Tweener. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml index 2adebdb306..7151e58c5f 100644 --- a/doc/classes/MultiMesh.xml +++ b/doc/classes/MultiMesh.xml @@ -40,12 +40,12 @@ </description> </method> <method name="get_instance_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="instance" type="int"> </argument> <description> - Returns the [Transform] of a specific instance. + Returns the [Transform3D] of a specific instance. </description> </method> <method name="get_instance_transform_2d" qualifiers="const"> @@ -86,10 +86,10 @@ </return> <argument index="0" name="instance" type="int"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> - Sets the [Transform] for a specific instance. + Sets the [Transform3D] for a specific instance. </description> </method> <method name="set_instance_transform_2d"> @@ -105,7 +105,7 @@ </method> </methods> <members> - <member name="buffer" type="PackedFloat32Array" setter="set_buffer" getter="get_buffer" default="PackedFloat32Array( )"> + <member name="buffer" type="PackedFloat32Array" setter="set_buffer" getter="get_buffer" default="PackedFloat32Array()"> </member> <member name="color_array" type="PackedColorArray" setter="_set_color_array" getter="_get_color_array"> </member> diff --git a/doc/classes/MultiplayerAPI.xml b/doc/classes/MultiplayerAPI.xml index c168695d61..c4d8a5b1b9 100644 --- a/doc/classes/MultiplayerAPI.xml +++ b/doc/classes/MultiplayerAPI.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerAPI" inherits="Reference" version="4.0"> +<class name="MultiplayerAPI" inherits="RefCounted" version="4.0"> <brief_description> High-level multiplayer API. </brief_description> <description> - This class implements most of the logic behind the high-level multiplayer API. See also [NetworkedMultiplayerPeer]. + This class implements most of the logic behind the high-level multiplayer API. See also [MultiplayerPeer]. By default, [SceneTree] has a reference to this class that is used to provide multiplayer capabilities (i.e. RPC/RSET) across the whole scene. It is possible to override the MultiplayerAPI instance used by specific Nodes by setting the [member Node.custom_multiplayer] property, effectively allowing to run both client and server in the same scene. [b]Note:[/b] The high-level multiplayer API protocol is an implementation detail and isn't meant to be used by non-Godot servers. It may change without notice. @@ -70,10 +70,10 @@ </argument> <argument index="1" name="id" type="int" default="0"> </argument> - <argument index="2" name="mode" type="int" enum="NetworkedMultiplayerPeer.TransferMode" default="2"> + <argument index="2" name="mode" type="int" enum="MultiplayerPeer.TransferMode" default="2"> </argument> <description> - Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers. + Sends the given raw [code]bytes[/code] to a specific peer identified by [code]id[/code] (see [method MultiplayerPeer.set_target_peer]). Default ID is [code]0[/code], i.e. broadcast to all peers. </description> </method> </methods> @@ -82,7 +82,7 @@ If [code]true[/code], the MultiplayerAPI will allow encoding and decoding of object during RPCs/RSETs. [b]Warning:[/b] Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution. </member> - <member name="network_peer" type="NetworkedMultiplayerPeer" setter="set_network_peer" getter="get_network_peer"> + <member name="network_peer" type="MultiplayerPeer" setter="set_network_peer" getter="get_network_peer"> The peer object to handle the RPC system (effectively enabling networking when set). Depending on the peer itself, the MultiplayerAPI will become a network server (check with [method is_network_server]) and will set root node's network mode to master, or it will become a regular peer with root node set to puppet. All child nodes are set to inherit the network mode by default. Handling of networking-related events (connection, disconnection, new clients) is done by connecting to MultiplayerAPI's signals. </member> <member name="refuse_new_network_connections" type="bool" setter="set_refuse_new_network_connections" getter="is_refusing_new_network_connections" default="false"> @@ -135,16 +135,16 @@ </signals> <constants> <constant name="RPC_MODE_DISABLED" value="0" enum="RPCMode"> - Used with [method Node.rpc_config] or [method Node.rset_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods. + Used with [method Node.rpc_config] to disable a method or property for all RPC calls, making it unavailable. Default for all methods. </constant> <constant name="RPC_MODE_REMOTE" value="1" enum="RPCMode"> - Used with [method Node.rpc_config] or [method Node.rset_config] to set a method to be called or a property to be changed only on the remote end, not locally. Analogous to the [code]remote[/code] keyword. Calls and property changes are accepted from all remote peers, no matter if they are node's master or puppets. + Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on the remote end, not locally. Analogous to the [code]remote[/code] keyword. Calls and property changes are accepted from all remote peers, no matter if they are node's master or puppets. </constant> <constant name="RPC_MODE_MASTER" value="2" enum="RPCMode"> - Used with [method Node.rpc_config] or [method Node.rset_config] to set a method to be called or a property to be changed only on the network master for this node. Analogous to the [code]master[/code] keyword. Only accepts calls or property changes from the node's network puppets, see [method Node.set_network_master]. + Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on the network master for this node. Analogous to the [code]master[/code] keyword. Only accepts calls or property changes from the node's network puppets, see [method Node.set_network_master]. </constant> <constant name="RPC_MODE_PUPPET" value="3" enum="RPCMode"> - Used with [method Node.rpc_config] or [method Node.rset_config] to set a method to be called or a property to be changed only on puppets for this node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or property changes from the node's network master, see [method Node.set_network_master]. + Used with [method Node.rpc_config] to set a method to be called or a property to be changed only on puppets for this node. Analogous to the [code]puppet[/code] keyword. Only accepts calls or property changes from the node's network master, see [method Node.set_network_master]. </constant> <constant name="RPC_MODE_REMOTESYNC" value="4" enum="RPCMode"> Behave like [constant RPC_MODE_REMOTE] but also make the call or property change locally. Analogous to the [code]remotesync[/code] keyword. diff --git a/doc/classes/NetworkedMultiplayerPeer.xml b/doc/classes/MultiplayerPeer.xml index 06ea46f023..713cd64b82 100644 --- a/doc/classes/NetworkedMultiplayerPeer.xml +++ b/doc/classes/MultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NetworkedMultiplayerPeer" inherits="PacketPeer" version="4.0"> +<class name="MultiplayerPeer" inherits="PacketPeer" version="4.0"> <brief_description> A high-level network interface to simplify multiplayer interactions. </brief_description> @@ -13,7 +13,7 @@ </tutorials> <methods> <method name="get_connection_status" qualifiers="const"> - <return type="int" enum="NetworkedMultiplayerPeer.ConnectionStatus"> + <return type="int" enum="MultiplayerPeer.ConnectionStatus"> </return> <description> Returns the current state of the connection. See [enum ConnectionStatus]. @@ -23,14 +23,14 @@ <return type="int"> </return> <description> - Returns the ID of the [NetworkedMultiplayerPeer] who sent the most recent packet. + Returns the ID of the [MultiplayerPeer] who sent the most recent packet. </description> </method> <method name="get_unique_id" qualifiers="const"> <return type="int"> </return> <description> - Returns the ID of this [NetworkedMultiplayerPeer]. + Returns the ID of this [MultiplayerPeer]. </description> </method> <method name="poll"> @@ -53,9 +53,9 @@ </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" default="true"> - If [code]true[/code], this [NetworkedMultiplayerPeer] refuses new connections. + If [code]true[/code], this [MultiplayerPeer] refuses new connections. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="NetworkedMultiplayerPeer.TransferMode" default="0"> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" enum="MultiplayerPeer.TransferMode" default="0"> The manner in which to send packets to the [code]target_peer[/code]. See [enum TransferMode]. </member> </members> diff --git a/doc/classes/Mutex.xml b/doc/classes/Mutex.xml index f5f6308401..dfda614f8e 100644 --- a/doc/classes/Mutex.xml +++ b/doc/classes/Mutex.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Mutex" inherits="Reference" version="4.0"> +<class name="Mutex" inherits="RefCounted" version="4.0"> <brief_description> A synchronization mutex (mutual exclusion). </brief_description> diff --git a/doc/classes/NativeExtension.xml b/doc/classes/NativeExtension.xml new file mode 100644 index 0000000000..c48af7df7b --- /dev/null +++ b/doc/classes/NativeExtension.xml @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="NativeExtension" inherits="RefCounted" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="close_library"> + <return type="void"> + </return> + <description> + </description> + </method> + <method name="get_minimum_library_initialization_level" qualifiers="const"> + <return type="int" enum="NativeExtension.InitializationLevel"> + </return> + <description> + </description> + </method> + <method name="initialize_library"> + <return type="void"> + </return> + <argument index="0" name="level" type="int" enum="NativeExtension.InitializationLevel"> + </argument> + <description> + </description> + </method> + <method name="is_library_open" qualifiers="const"> + <return type="bool"> + </return> + <description> + </description> + </method> + <method name="open_library"> + <return type="int" enum="Error"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <argument index="1" name="entry_symbol" type="String"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + <constant name="INITIALIZATION_LEVEL_CORE" value="0" enum="InitializationLevel"> + </constant> + <constant name="INITIALIZATION_LEVEL_SERVERS" value="1" enum="InitializationLevel"> + </constant> + <constant name="INITIALIZATION_LEVEL_SCENE" value="2" enum="InitializationLevel"> + </constant> + <constant name="INITIALIZATION_LEVEL_EDITOR" value="3" enum="InitializationLevel"> + </constant> + </constants> +</class> diff --git a/doc/classes/NativeExtensionManager.xml b/doc/classes/NativeExtensionManager.xml new file mode 100644 index 0000000000..ba9018ff4c --- /dev/null +++ b/doc/classes/NativeExtensionManager.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="NativeExtensionManager" inherits="Object" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_extension"> + <return type="NativeExtension"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="get_loaded_extensions" qualifiers="const"> + <return type="PackedStringArray"> + </return> + <description> + </description> + </method> + <method name="load_extension"> + <return type="int" enum="NativeExtensionManager.LoadStatus"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="reload_extension"> + <return type="int" enum="NativeExtensionManager.LoadStatus"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="unload_extension"> + <return type="int" enum="NativeExtensionManager.LoadStatus"> + </return> + <argument index="0" name="path" type="String"> + </argument> + <description> + </description> + </method> + </methods> + <constants> + <constant name="LOAD_STATUS_OK" value="0" enum="LoadStatus"> + </constant> + <constant name="LOAD_STATUS_FAILED" value="1" enum="LoadStatus"> + </constant> + <constant name="LOAD_STATUS_ALREADY_LOADED" value="2" enum="LoadStatus"> + </constant> + <constant name="LOAD_STATUS_NOT_LOADED" value="3" enum="LoadStatus"> + </constant> + <constant name="LOAD_STATUS_NEEDS_RESTART" value="4" enum="LoadStatus"> + </constant> + </constants> +</class> diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index b098a7fc20..ef9efcb99c 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -413,7 +413,7 @@ </return> <argument index="0" name="region" type="RID"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> Sets the global transformation for the region. diff --git a/doc/classes/NinePatchRect.xml b/doc/classes/NinePatchRect.xml index d6de0ef4cf..5d59f994d3 100644 --- a/doc/classes/NinePatchRect.xml +++ b/doc/classes/NinePatchRect.xml @@ -53,7 +53,7 @@ <member name="patch_margin_top" type="int" setter="set_patch_margin" getter="get_patch_margin" default="0"> The height of the 9-slice's top row. A margin of 16 means the 9-slice's top corners and side will have a height of 16 pixels. You can set all 4 margin values individually to create panels with non-uniform borders. </member> - <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )"> + <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> Rectangular region of the texture to sample from. If you're working with an atlas, use this property to define the area the 9-slice should use. All other properties are relative to this one. If the rect is empty, NinePatchRect will use the whole texture. </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index 523f3a0c17..fc971effd7 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -5,16 +5,16 @@ </brief_description> <description> Nodes are Godot's building blocks. They can be assigned as the child of another node, resulting in a tree arrangement. A given node can contain any number of nodes as children with the requirement that all siblings (direct children of a node) should have unique names. - A tree of nodes is called a [i]scene[/i]. Scenes can be saved to the disk and then instanced into other scenes. This allows for very high flexibility in the architecture and data model of Godot projects. + A tree of nodes is called a [i]scene[/i]. Scenes can be saved to the disk and then instantiated into other scenes. This allows for very high flexibility in the architecture and data model of Godot projects. [b]Scene tree:[/b] The [SceneTree] contains the active tree of nodes. When a node is added to the scene tree, it receives the [constant NOTIFICATION_ENTER_TREE] notification and its [method _enter_tree] callback is triggered. Child nodes are always added [i]after[/i] their parent node, i.e. the [method _enter_tree] callback of a parent node will be triggered before its child's. Once all nodes have been added in the scene tree, they receive the [constant NOTIFICATION_READY] notification and their respective [method _ready] callbacks are triggered. For groups of nodes, the [method _ready] callback is called in reverse order, starting with the children and moving up to the parent nodes. This means that when adding a node to the scene tree, the following order will be used for the callbacks: [method _enter_tree] of the parent, [method _enter_tree] of the children, [method _ready] of the children and finally [method _ready] of the parent (recursively for the entire scene tree). [b]Processing:[/b] Nodes can override the "process" state, so that they receive a callback on each frame requesting them to process (do something). Normal processing (callback [method _process], toggled with [method set_process]) happens as fast as possible and is dependent on the frame rate, so the processing time [i]delta[/i] (in seconds) is passed as an argument. Physics processing (callback [method _physics_process], toggled with [method set_physics_process]) happens a fixed number of times per second (60 by default) and is useful for code related to the physics engine. Nodes can also process input events. When present, the [method _input] function will be called for each input that the program receives. In many cases, this can be overkill (unless used for simple projects), and the [method _unhandled_input] function might be preferred; it is called when the input event was not handled by anyone else (typically, GUI [Control] nodes), ensuring that the node only receives the events that were meant for it. - To keep track of the scene hierarchy (especially when instancing scenes into other scenes), an "owner" can be set for the node with the [member owner] property. This keeps track of who instanced what. This is mostly useful when writing editors and tools, though. + To keep track of the scene hierarchy (especially when instancing scenes into other scenes), an "owner" can be set for the node with the [member owner] property. This keeps track of who instantiated what. This is mostly useful when writing editors and tools, though. Finally, when a node is freed with [method Object.free] or [method queue_free], it will also free all its children. [b]Groups:[/b] Nodes can be added to as many groups as you want to be easy to manage, you could create groups like "enemies" or "collectables" for example, depending on your game. See [method add_to_group], [method is_in_group] and [method remove_from_group]. You can then retrieve all nodes in these groups, iterate them and even call methods on groups via the methods on [SceneTree]. - [b]Networking with nodes:[/b] After connecting to a server (or making one, see [NetworkedMultiplayerENet]), it is possible to use the built-in RPC (remote procedure call) system to communicate over the network. By calling [method rpc] with a method name, it will be called locally and in all connected peers (peers = clients and the server that accepts connections). To identify which node receives the RPC call, Godot will use its [NodePath] (make sure node names are the same on all peers). Also, take a look at the high-level networking tutorial and corresponding demos. + [b]Networking with nodes:[/b] After connecting to a server (or making one, see [ENetMultiplayerPeer]), it is possible to use the built-in RPC (remote procedure call) system to communicate over the network. By calling [method rpc] with a method name, it will be called locally and in all connected peers (peers = clients and the server that accepts connections). To identify which node receives the RPC call, Godot will use its [NodePath] (make sure node names are the same on all peers). Also, take a look at the high-level networking tutorial and corresponding demos. </description> <tutorials> <link title="Scenes and nodes">https://docs.godotengine.org/en/latest/getting_started/step_by_step/scenes_and_nodes.html</link> @@ -128,7 +128,7 @@ </argument> <description> Adds a child node. Nodes can have any number of children, but every child must have a unique name. Child nodes are automatically deleted when the parent node is deleted, so an entire scene can be removed by deleting its topmost node. - If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instanced instead of its type. + If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type. [b]Note:[/b] If the child node already has a parent, the function will fail. Use [method remove_child] first to remove the node from its current parent. For example: [codeblocks] [gdscript] @@ -159,7 +159,7 @@ </argument> <description> Adds a [code]sibling[/code] node to current's node parent, at the same level as that node, right below it. - If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instanced instead of its type. + If [code]legible_unique_name[/code] is [code]true[/code], the child node will have a human-readable name based on the name of the node being instantiated instead of its type. Use [method add_child] instead of this method if you don't need the child node to be added below a specific node in the list of children. </description> </method> @@ -182,6 +182,16 @@ Returns [code]true[/code] if the node can process while the scene tree is paused (see [member process_mode]). Always returns [code]true[/code] if the scene tree is not paused, and [code]false[/code] if the node is not in the tree. </description> </method> + <method name="create_tween"> + <return type="Tween"> + </return> + <description> + Creates a new [Tween] and binds it to this node. This is equivalent of doing: + [codeblock] + get_tree().create_tween().bind_node(self) + [/codeblock] + </description> + </method> <method name="duplicate" qualifiers="const"> <return type="Node"> </return> @@ -416,7 +426,7 @@ Returns [code]true[/code] if the [NodePath] points to a valid node and its subname points to a valid resource, e.g. [code]Area2D/CollisionShape2D:shape[/code]. Properties with a non-[Resource] type (e.g. nodes or primitive math types) are not considered resources. </description> </method> - <method name="is_a_parent_of" qualifiers="const"> + <method name="is_ancestor_of" qualifiers="const"> <return type="bool"> </return> <argument index="0" name="node" type="Node"> @@ -568,7 +578,7 @@ </return> <argument index="0" name="method" type="StringName"> </argument> - <argument index="1" name="args" type="Array" default="[ ]"> + <argument index="1" name="args" type="Array" default="[]"> </argument> <argument index="2" name="parent_first" type="bool" default="false"> </argument> @@ -649,8 +659,8 @@ <argument index="0" name="method" type="StringName"> </argument> <description> - Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. See also [method rset] and [method rset_config] for properties. Returns an empty [Variant]. - [b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [SceneTree]. You also need to keep track of the connection state, either by the [SceneTree] signals like [code]server_disconnected[/code] or by checking [code]SceneTree.network_peer.get_connection_status() == CONNECTION_CONNECTED[/code]. + Sends a remote procedure call request for the given [code]method[/code] to peers on the network (and locally), optionally sending all additional arguments as arguments to the method called by the RPC. The call request will only be received by nodes with the same [NodePath], including the exact same node name. Behaviour depends on the RPC configuration for the given method, see [method rpc_config]. Methods are not exposed to RPCs by default. Returns an empty [Variant]. + [b]Note:[/b] You can only safely use RPCs on clients after you received the [code]connected_to_server[/code] signal from the [MultiplayerAPI]. You also need to keep track of the connection state, either by the [MultiplayerAPI] signals like [code]server_disconnected[/code] or by checking [code]get_multiplayer().network_peer.get_connection_status() == CONNECTION_CONNECTED[/code]. </description> </method> <method name="rpc_config"> @@ -658,33 +668,17 @@ </return> <argument index="0" name="method" type="StringName"> </argument> - <argument index="1" name="mode" type="int" enum="MultiplayerAPI.RPCMode"> + <argument index="1" name="rpc_mode" type="int" enum="MultiplayerAPI.RPCMode"> </argument> - <description> - Changes the RPC mode for the given [code]method[/code] to the given [code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is annotating methods and properties with the corresponding keywords ([code]remote[/code], [code]master[/code], [code]puppet[/code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). By default, methods are not exposed to networking (and RPCs). See also [method rset] and [method rset_config] for properties. - </description> - </method> - <method name="rpc_id" qualifiers="vararg"> - <return type="Variant"> - </return> - <argument index="0" name="peer_id" type="int"> + <argument index="2" name="transfer_mode" type="int" enum="MultiplayerPeer.TransferMode" default="2"> </argument> - <argument index="1" name="method" type="StringName"> + <argument index="3" name="channel" type="int" default="0"> </argument> <description> - Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty [Variant]. + Changes the RPC mode for the given [code]method[/code] to the given [code]rpc_mode[/code], optionally specifying the [code]transfer_mode[/code] and [code]channel[/code] (on supported peers). See [enum MultiplayerAPI.RPCMode] and [enum MultiplayerPeer.TransferMode]. An alternative is annotating methods and properties with the corresponding keywords ([code]remote[/code], [code]master[/code], [code]puppet[/code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). By default, methods are not exposed to networking (and RPCs). </description> </method> - <method name="rpc_unreliable" qualifiers="vararg"> - <return type="Variant"> - </return> - <argument index="0" name="method" type="StringName"> - </argument> - <description> - Sends a [method rpc] using an unreliable protocol. Returns an empty [Variant]. - </description> - </method> - <method name="rpc_unreliable_id" qualifiers="vararg"> + <method name="rpc_id" qualifiers="vararg"> <return type="Variant"> </return> <argument index="0" name="peer_id" type="int"> @@ -692,66 +686,7 @@ <argument index="1" name="method" type="StringName"> </argument> <description> - Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] using an unreliable protocol (see [method NetworkedMultiplayerPeer.set_target_peer]). Returns an empty [Variant]. - </description> - </method> - <method name="rset"> - <return type="void"> - </return> - <argument index="0" name="property" type="StringName"> - </argument> - <argument index="1" name="value" type="Variant"> - </argument> - <description> - Remotely changes a property's value on other peers (and locally). Behaviour depends on the RPC configuration for the given property, see [method rset_config]. See also [method rpc] for RPCs for methods, most information applies to this method as well. - </description> - </method> - <method name="rset_config"> - <return type="int"> - </return> - <argument index="0" name="property" type="StringName"> - </argument> - <argument index="1" name="mode" type="int" enum="MultiplayerAPI.RPCMode"> - </argument> - <description> - Changes the RPC mode for the given [code]property[/code] to the given [code]mode[/code]. See [enum MultiplayerAPI.RPCMode]. An alternative is annotating methods and properties with the corresponding keywords ([code]remote[/code], [code]master[/code], [code]puppet[/code], [code]remotesync[/code], [code]mastersync[/code], [code]puppetsync[/code]). By default, properties are not exposed to networking (and RPCs). See also [method rpc] and [method rpc_config] for methods. - </description> - </method> - <method name="rset_id"> - <return type="void"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> - <argument index="1" name="property" type="StringName"> - </argument> - <argument index="2" name="value" type="Variant"> - </argument> - <description> - Remotely changes the property's value on a specific peer identified by [code]peer_id[/code] (see [method NetworkedMultiplayerPeer.set_target_peer]). - </description> - </method> - <method name="rset_unreliable"> - <return type="void"> - </return> - <argument index="0" name="property" type="StringName"> - </argument> - <argument index="1" name="value" type="Variant"> - </argument> - <description> - Remotely changes the property's value on other peers (and locally) using an unreliable protocol. - </description> - </method> - <method name="rset_unreliable_id"> - <return type="void"> - </return> - <argument index="0" name="peer_id" type="int"> - </argument> - <argument index="1" name="property" type="StringName"> - </argument> - <argument index="2" name="value" type="Variant"> - </argument> - <description> - Remotely changes property's value on a specific peer identified by [code]peer_id[/code] using an unreliable protocol (see [method NetworkedMultiplayerPeer.set_target_peer]). + Sends a [method rpc] to a specific peer identified by [code]peer_id[/code] (see [method MultiplayerPeer.set_target_peer]). Returns an empty [Variant]. </description> </method> <method name="set_display_folded"> @@ -870,7 +805,7 @@ The override to the default [MultiplayerAPI]. Set to [code]null[/code] to use the default [SceneTree] one. </member> <member name="filename" type="String" setter="set_filename" getter="get_filename"> - When a scene is instanced from a file, its topmost node contains the filename from which it was loaded. + When a scene is instantiated from a file, its topmost node contains the filename from which it was loaded. </member> <member name="multiplayer" type="MultiplayerAPI" setter="" getter="get_multiplayer"> The [MultiplayerAPI] instance associated with this node. Either the [member custom_multiplayer], or the default SceneTree one (if inside tree). @@ -949,7 +884,7 @@ Notification received when a node is unparented (parent removed it from the list of children). </constant> <constant name="NOTIFICATION_INSTANCED" value="20"> - Notification received when the node is instanced. + Notification received when the node is instantiated. </constant> <constant name="NOTIFICATION_DRAG_BEGIN" value="21"> Notification received when a drag begins. @@ -969,6 +904,18 @@ <constant name="NOTIFICATION_POST_ENTER_TREE" value="27"> Notification received when the node is ready, just before [constant NOTIFICATION_READY] is received. Unlike the latter, it's sent every time the node enters tree, instead of only once. </constant> + <constant name="NOTIFICATION_DISABLED" value="28"> + Notification received when the node is disabled. See [constant PROCESS_MODE_DISABLED]. + </constant> + <constant name="NOTIFICATION_ENABLED" value="29"> + Notification received when the node is enabled again after being disabled. See [constant PROCESS_MODE_DISABLED]. + </constant> + <constant name="NOTIFICATION_EDITOR_PRE_SAVE" value="9001"> + Notification received right before the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects. + </constant> + <constant name="NOTIFICATION_EDITOR_POST_SAVE" value="9002"> + Notification received right after the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects. + </constant> <constant name="NOTIFICATION_WM_MOUSE_ENTER" value="1002"> Notification received from the OS when the mouse enters the game window. Implemented on desktop and web platforms. diff --git a/doc/classes/Node2D.xml b/doc/classes/Node2D.xml index 988fb72267..9ffa333f17 100644 --- a/doc/classes/Node2D.xml +++ b/doc/classes/Node2D.xml @@ -122,34 +122,30 @@ <member name="global_rotation" type="float" setter="set_global_rotation" getter="get_global_rotation"> Global rotation in radians. </member> - <member name="global_rotation_degrees" type="float" setter="set_global_rotation_degrees" getter="get_global_rotation_degrees"> - Global rotation in degrees. - </member> <member name="global_scale" type="Vector2" setter="set_global_scale" getter="get_global_scale"> Global scale. </member> <member name="global_transform" type="Transform2D" setter="set_global_transform" getter="get_global_transform"> Global [Transform2D]. </member> - <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="set_position" getter="get_position" default="Vector2(0, 0)"> Position, relative to the node's parent. </member> <member name="rotation" type="float" setter="set_rotation" getter="get_rotation" default="0.0"> Rotation in radians, relative to the node's parent. </member> - <member name="rotation_degrees" type="float" setter="set_rotation_degrees" getter="get_rotation_degrees" default="0.0"> - Rotation in degrees, relative to the node's parent. - </member> - <member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2( 1, 1 )"> + <member name="scale" type="Vector2" setter="set_scale" getter="get_scale" default="Vector2(1, 1)"> The node's scale. Unscaled value: [code](1, 1)[/code]. </member> <member name="skew" type="float" setter="set_skew" getter="get_skew" default="0.0"> </member> - <member name="skew_degrees" type="float" setter="set_skew_degrees" getter="get_skew_degrees" default="0.0"> - </member> <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform"> Local [Transform2D]. </member> + <member name="y_sort_enabled" type="bool" setter="set_y_sort_enabled" getter="is_y_sort_enabled" default="false"> + If [code]true[/code], child nodes with the lowest Y position are drawn before those with a higher Y position. If [code]false[/code], Y-sorting is disabled. Y-sorting only affects children that inherit from [CanvasItem]. + You can nest nodes with Y-sorting. Child Y-sorted nodes are sorted in the same space as the parent Y-sort. This feature allows you to organize a scene better or divide it into multiple ones without changing your scene tree. + </member> <member name="z_as_relative" type="bool" setter="set_z_as_relative" getter="is_z_relative" default="true"> If [code]true[/code], the node's Z index is relative to its parent's Z index. If this node's Z index is 2 and its parent's effective Z index is 3, then this node's effective Z index will be 2 + 3 = 5. </member> diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index 5c29c0d48f..14e03a2186 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -4,7 +4,7 @@ Most basic 3D game object, parent of all 3D-related nodes. </brief_description> <description> - Most basic 3D game object, with a 3D [Transform] and visibility settings. All other 3D game objects inherit from Node3D. Use [Node3D] as a parent node to move, scale, rotate and show/hide children in a 3D project. + Most basic 3D game object, with a 3D [Transform3D] and visibility settings. All other 3D game objects inherit from Node3D. Use [Node3D] as a parent node to move, scale, rotate and show/hide children in a 3D project. Affine operations (rotate, scale, translate) happen in parent's local coordinate system, unless the [Node3D] object is set as top-level. Affine operations in this coordinate system correspond to direct affine operations on the [Node3D]'s transform. The word local below refers to this coordinate system. The coordinate system that is attached to the [Node3D] object itself is referred to as object-local coordinate system. [b]Note:[/b] Unless otherwise specified, all methods that have angle parameters must have angles specified as [i]radians[/i]. To convert degrees to radians, use [method @GlobalScope.deg2rad]. </description> @@ -20,7 +20,7 @@ Forces the transform to update. Transform changes in physics are not instant for performance reasons. Transforms are accumulated and then set. Use this if you need an up-to-date transform when doing physics operations. </description> </method> - <method name="get_parent_spatial" qualifiers="const"> + <method name="get_parent_node_3d" qualifiers="const"> <return type="Node3D"> </return> <description> @@ -103,7 +103,7 @@ </return> <argument index="0" name="target" type="Vector3"> </argument> - <argument index="1" name="up" type="Vector3" default="Vector3( 0, 1, 0 )"> + <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)"> </argument> <description> Rotates itself so that the local -Z axis points towards the [code]target[/code] position. @@ -118,7 +118,7 @@ </argument> <argument index="1" name="target" type="Vector3"> </argument> - <argument index="2" name="up" type="Vector3" default="Vector3( 0, 1, 0 )"> + <argument index="2" name="up" type="Vector3" default="Vector3(0, 1, 0)"> </argument> <description> Moves the node to the specified [code]position[/code], and then rotates itself to point toward the [code]target[/code] as per [method look_at]. Operations take place in global space. @@ -128,7 +128,7 @@ <return type="void"> </return> <description> - Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform]. + Resets this node's transformations (like scale, skew and taper) preserving its rotation and translation by performing Gram-Schmidt orthonormalization on this node's [Transform3D]. </description> </method> <method name="rotate"> @@ -202,7 +202,7 @@ <return type="void"> </return> <description> - Reset all transformations for this node (sets its [Transform] to the identity matrix). + Reset all transformations for this node (sets its [Transform3D] to the identity matrix). </description> </method> <method name="set_ignore_transform_notification"> @@ -288,27 +288,27 @@ <member name="gizmo" type="Node3DGizmo" setter="set_gizmo" getter="get_gizmo"> The [Node3DGizmo] for this node. Used for example in [EditorNode3DGizmo] as custom visualization and editing handles in Editor. </member> - <member name="global_transform" type="Transform" setter="set_global_transform" getter="get_global_transform"> - World3D space (global) [Transform] of this node. + <member name="global_transform" type="Transform3D" setter="set_global_transform" getter="get_global_transform"> + World3D space (global) [Transform3D] of this node. </member> - <member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation"> + <member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)"> + Local position or translation of this node relative to the parent. This is equivalent to [code]transform.origin[/code]. + </member> + <member name="rotation" type="Vector3" setter="set_rotation" getter="get_rotation" default="Vector3(0, 0, 0)"> Rotation part of the local transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle). [b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful. </member> - <member name="rotation_degrees" type="Vector3" setter="set_rotation_degrees" getter="get_rotation_degrees" default="Vector3( 0, 0, 0 )"> - Rotation part of the local transformation in degrees, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle). - </member> - <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3( 1, 1, 1 )"> + <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)"> Scale part of the local transformation. </member> <member name="top_level" type="bool" setter="set_as_top_level" getter="is_set_as_top_level" default="false"> If [code]true[/code], the node will not inherit its transformations from its parent. Node transformations are only in global space. </member> - <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> - Local space [Transform] of this node, with respect to the parent node. + <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> + Local space [Transform3D] of this node, with respect to the parent node. </member> - <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3( 0, 0, 0 )"> - Local translation of this node. + <member name="visibility_parent" type="NodePath" setter="set_visibility_parent" getter="get_visibility_parent" default="NodePath("")"> + Defines the visibility range parent for this node and its subtree. The visibility parent must be a GeometryInstance3D. Any visual instance will only be visible if the visibility parent (and all of its visibility ancestors) is hidden by being closer to the camera than its own [member GeometryInstance3D.visibility_range_begin]. Nodes hidden via the [member Node3D.visible] property are essentially removed from the visibility dependency tree, so dependant instances will not take the hidden node or its ancestors into account. </member> <member name="visible" type="bool" setter="set_visible" getter="is_visible" default="true"> If [code]true[/code], this node is drawn. The node is only visible if all of its antecedents are visible as well (in other words, [method is_visible_in_tree] must return [code]true[/code]). diff --git a/doc/classes/Node3DGizmo.xml b/doc/classes/Node3DGizmo.xml index 55080614fc..c561047332 100644 --- a/doc/classes/Node3DGizmo.xml +++ b/doc/classes/Node3DGizmo.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Node3DGizmo" inherits="Reference" version="4.0"> +<class name="Node3DGizmo" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/NodePath.xml b/doc/classes/NodePath.xml index 817ccd5160..0ba2e73ad4 100644 --- a/doc/classes/NodePath.xml +++ b/doc/classes/NodePath.xml @@ -20,6 +20,7 @@ @"/root/Main" # If your main scene's root node were named "Main". @"/root/MyAutoload" # If you have an autoloaded node or scene. [/codeblock] + [b]Note:[/b] In the editor, [NodePath] properties are automatically updated when moving, renaming or deleting a node in the scene tree, but they are never updated at runtime. </description> <tutorials> <link title="2D Role Playing Game Demo">https://godotengine.org/asset-library/asset/520</link> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index b8b437f78f..a9396306f4 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -94,7 +94,7 @@ </argument> <argument index="1" name="arguments" type="PackedStringArray"> </argument> - <argument index="2" name="output" type="Array" default="[ ]"> + <argument index="2" name="output" type="Array" default="[]"> </argument> <argument index="3" name="read_stderr" type="bool" default="false"> </argument> @@ -136,6 +136,14 @@ Returns the keycode of the given string (e.g. "Escape"). </description> </method> + <method name="get_cache_dir" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the [i]global[/i] cache data directory according to the operating system's standards. On desktop platforms, this path can be overridden by setting the [code]XDG_CACHE_HOME[/code] environment variable before starting the project. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_config_dir] and [method get_data_dir]. + Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path. + </description> + </method> <method name="get_cmdline_args"> <return type="PackedStringArray"> </return> @@ -167,6 +175,14 @@ [/codeblocks] </description> </method> + <method name="get_config_dir" qualifiers="const"> + <return type="String"> + </return> + <description> + Returns the [i]global[/i] user configuration directory according to the operating system's standards. On desktop platforms, this path can be overridden by setting the [code]XDG_CONFIG_HOME[/code] environment variable before starting the project. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_cache_dir] and [method get_data_dir]. + Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path. + </description> + </method> <method name="get_connected_midi_inputs"> <return type="PackedStringArray"> </return> @@ -176,32 +192,12 @@ [b]Note:[/b] This method is implemented on Linux, macOS and Windows. </description> </method> - <method name="get_date" qualifiers="const"> - <return type="Dictionary"> - </return> - <argument index="0" name="utc" type="bool" default="false"> - </argument> - <description> - Returns current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] (Daylight Savings Time). - </description> - </method> - <method name="get_datetime" qualifiers="const"> - <return type="Dictionary"> - </return> - <argument index="0" name="utc" type="bool" default="false"> - </argument> - <description> - Returns current datetime as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] (Daylight Savings Time), [code]hour[/code], [code]minute[/code], [code]second[/code]. - </description> - </method> - <method name="get_datetime_from_unix_time" qualifiers="const"> - <return type="Dictionary"> + <method name="get_data_dir" qualifiers="const"> + <return type="String"> </return> - <argument index="0" name="unix_time_val" type="int"> - </argument> <description> - Gets a dictionary of time values corresponding to the given UNIX epoch time (in seconds). - The returned Dictionary's values will be the same as [method get_datetime], with the exception of Daylight Savings Time as it cannot be determined from the epoch. + Returns the [i]global[/i] user data directory according to the operating system's standards. On desktop platforms, this path can be overridden by setting the [code]XDG_DATA_HOME[/code] environment variable before starting the project. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]File paths in Godot projects[/url] in the documentation for more information. See also [method get_cache_dir] and [method get_config_dir]. + Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path. </description> </method> <method name="get_environment" qualifiers="const"> @@ -221,6 +217,13 @@ Returns the path to the current engine executable. </description> </method> + <method name="get_external_data_dir" qualifiers="const"> + <return type="String"> + </return> + <description> + On Android, returns the absolute directory path where user data can be written to external storage if available. On all other platforms, this will return the same location as [method get_user_data_dir]. + </description> + </method> <method name="get_granted_permissions" qualifiers="const"> <return type="PackedStringArray"> </return> @@ -313,36 +316,6 @@ [b]Note:[/b] Thread IDs are not deterministic and may be reused across application restarts. </description> </method> - <method name="get_ticks_msec" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the amount of time passed in milliseconds since the engine started. - </description> - </method> - <method name="get_ticks_usec" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the amount of time passed in microseconds since the engine started. - </description> - </method> - <method name="get_time" qualifiers="const"> - <return type="Dictionary"> - </return> - <argument index="0" name="utc" type="bool" default="false"> - </argument> - <description> - Returns current time as a dictionary of keys: hour, minute, second. - </description> - </method> - <method name="get_time_zone_info" qualifiers="const"> - <return type="Dictionary"> - </return> - <description> - Returns the current time zone as a dictionary with the keys: bias and name. - </description> - </method> <method name="get_unique_id" qualifiers="const"> <return type="String"> </return> @@ -352,26 +325,6 @@ [b]Note:[/b] Returns an empty string on HTML5 and UWP, as this method isn't implemented on those platforms yet. </description> </method> - <method name="get_unix_time" qualifiers="const"> - <return type="float"> - </return> - <description> - Returns the current UNIX epoch timestamp in seconds. - [b]Important:[/b] This is the system clock that the user can manually set. [b]Never use[/b] this method for precise time calculation since its results are also subject to automatic adjustments by the operating system. [b]Always use[/b] [method get_ticks_usec] or [method get_ticks_msec] for precise time calculation instead, since they are guaranteed to be monotonic (i.e. never decrease). - </description> - </method> - <method name="get_unix_time_from_datetime" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="datetime" type="Dictionary"> - </argument> - <description> - Gets an epoch time value from a dictionary of time values. - [code]datetime[/code] must be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], [code]second[/code]. - If the dictionary is empty [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the UNIX epoch timestamp 0 (1970-01-01 at 00:00:00 UTC). - You can pass the output from [method get_datetime_from_unix_time] directly into this function. Daylight Savings Time ([code]dst[/code]), if present, is ignored. - </description> - </method> <method name="get_user_data_dir" qualifiers="const"> <return type="String"> </return> @@ -381,6 +334,7 @@ On macOS, this is [code]~/Library/Application Support/Godot/app_userdata/[project_name][/code], or [code]~/Library/Application Support/[custom_name][/code] if [code]use_custom_user_dir[/code] is set. On Windows, this is [code]%APPDATA%\Godot\app_userdata\[project_name][/code], or [code]%APPDATA%\[custom_name][/code] if [code]use_custom_user_dir[/code] is set. [code]%APPDATA%[/code] expands to [code]%USERPROFILE%\AppData\Roaming[/code]. If the project name is empty, [code]user://[/code] falls back to [code]res://[/code]. + Not to be confused with [method get_data_dir], which returns the [i]global[/i] (non-project-specific) user data directory. </description> </method> <method name="has_environment" qualifiers="const"> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 7da9c1ac38..cdf76a3a59 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -7,7 +7,7 @@ Every class which is not a built-in type inherits from this class. You can construct Objects from scripting languages, using [code]Object.new()[/code] in GDScript, [code]new Object[/code] in C#, or the "Construct Object" node in VisualScript. Objects do not manage memory. If a class inherits from Object, you will have to delete instances of it manually. To do so, call the [method free] method from your script or delete the instance from C++. - Some classes that extend Object add memory management. This is the case of [Reference], which counts references and deletes itself automatically when no longer referenced. [Node], another fundamental type, deletes all its children when freed from memory. + Some classes that extend Object add memory management. This is the case of [RefCounted], which counts references and deletes itself automatically when no longer referenced. [Node], another fundamental type, deletes all its children when freed from memory. Objects export properties, which are mainly useful for storage and editing, but not really so much in programming. Properties are exported in [method _get_property_list] and handled in [method _get] and [method _set]. However, scripting languages and C++ have simpler means to export them. Property membership can be tested directly in GDScript using [code]in[/code]: [codeblocks] @@ -26,7 +26,7 @@ [/codeblocks] The [code]in[/code] operator will evaluate to [code]true[/code] as long as the key exists, even if the value is [code]null[/code]. Objects also receive notifications. Notifications are a simple way to notify the object about different events, so they can all be handled together. See [method _notification]. - [b]Note:[/b] Unlike references to a [Reference], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [Reference] for data classes instead of [Object]. + [b]Note:[/b] Unlike references to a [RefCounted], references to an Object stored in a variable can become invalid without warning. Therefore, it's recommended to use [RefCounted] for data classes instead of [Object]. </description> <tutorials> <link title="When and how to avoid using nodes for everything">https://docs.godotengine.org/en/latest/getting_started/workflow/best_practices/node_alternatives.html</link> @@ -92,7 +92,7 @@ </return> <argument index="0" name="signal" type="String"> </argument> - <argument index="1" name="arguments" type="Array" default="[ ]"> + <argument index="1" name="arguments" type="Array" default="[]"> </argument> <description> Adds a user-defined [code]signal[/code]. Arguments are optional, but can be added as an [Array] of dictionaries, each containing [code]name: String[/code] and [code]type: int[/code] (see [enum Variant.Type]) entries. @@ -173,7 +173,7 @@ </argument> <argument index="1" name="callable" type="Callable"> </argument> - <argument index="2" name="binds" type="Array" default="[ ]"> + <argument index="2" name="binds" type="Array" default="[]"> </argument> <argument index="3" name="flags" type="int" default="0"> </argument> diff --git a/doc/classes/Occluder3D.xml b/doc/classes/Occluder3D.xml index fc676c2b49..501c4a3ccf 100644 --- a/doc/classes/Occluder3D.xml +++ b/doc/classes/Occluder3D.xml @@ -9,9 +9,9 @@ <methods> </methods> <members> - <member name="indices" type="PackedInt32Array" setter="set_indices" getter="get_indices" default="PackedInt32Array( )"> + <member name="indices" type="PackedInt32Array" setter="set_indices" getter="get_indices" default="PackedInt32Array()"> </member> - <member name="vertices" type="PackedVector3Array" setter="set_vertices" getter="get_vertices" default="PackedVector3Array( )"> + <member name="vertices" type="PackedVector3Array" setter="set_vertices" getter="get_vertices" default="PackedVector3Array()"> </member> </members> <constants> diff --git a/doc/classes/OccluderPolygon2D.xml b/doc/classes/OccluderPolygon2D.xml index 8a59ef5cb4..28d3ed433a 100644 --- a/doc/classes/OccluderPolygon2D.xml +++ b/doc/classes/OccluderPolygon2D.xml @@ -17,7 +17,7 @@ <member name="cull_mode" type="int" setter="set_cull_mode" getter="get_cull_mode" enum="OccluderPolygon2D.CullMode" default="0"> The culling mode to use. </member> - <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( )"> + <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array()"> A [Vector2] array with the index for polygon's vertices positions. [b]Note:[/b] The returned value is a copy of the underlying array, rather than a reference. </member> diff --git a/doc/classes/OptionButton.xml b/doc/classes/OptionButton.xml index 52da08c02f..4c03c59f8b 100644 --- a/doc/classes/OptionButton.xml +++ b/doc/classes/OptionButton.xml @@ -250,19 +250,19 @@ <theme_item name="font" type="Font"> [Font] of the [OptionButton]'s text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Default text [Color] of the [OptionButton]. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.2)"> Text [Color] used when the [OptionButton] is disabled. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Text [Color] used when the [OptionButton] is being hovered. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [OptionButton]. </theme_item> - <theme_item name="font_pressed_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_pressed_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the [OptionButton] is being pressed. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml index e3c78e08f1..40e8683c93 100644 --- a/doc/classes/PCKPacker.xml +++ b/doc/classes/PCKPacker.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PCKPacker" inherits="Reference" version="4.0"> +<class name="PCKPacker" inherits="RefCounted" version="4.0"> <brief_description> Creates packages that can be loaded into a running project. </brief_description> diff --git a/doc/classes/PackedDataContainer.xml b/doc/classes/PackedDataContainer.xml index 296f9d3373..f72db514f0 100644 --- a/doc/classes/PackedDataContainer.xml +++ b/doc/classes/PackedDataContainer.xml @@ -23,7 +23,7 @@ </method> </methods> <members> - <member name="__data__" type="PackedByteArray" setter="_set_data" getter="_get_data" default="PackedByteArray( )"> + <member name="__data__" type="PackedByteArray" setter="_set_data" getter="_get_data" default="PackedByteArray()"> </member> </members> <constants> diff --git a/doc/classes/PackedDataContainerRef.xml b/doc/classes/PackedDataContainerRef.xml index f0f59675de..bfd5a6f1c1 100644 --- a/doc/classes/PackedDataContainerRef.xml +++ b/doc/classes/PackedDataContainerRef.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PackedDataContainerRef" inherits="Reference" version="4.0"> +<class name="PackedDataContainerRef" inherits="RefCounted" version="4.0"> <brief_description> - Reference version of [PackedDataContainer]. + Reference-counted version of [PackedDataContainer]. </brief_description> <description> </description> diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml index 1d9be7f165..f39cae8be5 100644 --- a/doc/classes/PackedScene.xml +++ b/doc/classes/PackedScene.xml @@ -11,13 +11,13 @@ [codeblocks] [gdscript] # Use load() instead of preload() if the path isn't known at compile-time. - var scene = preload("res://scene.tscn").instance() + var scene = preload("res://scene.tscn").instantiate() # Add the node as a child of the node the script is attached to. add_child(scene) [/gdscript] [csharp] // C# has no preload, so you have to always use ResourceLoader.Load<PackedScene>(). - var scene = ResourceLoader.Load<PackedScene>("res://scene.tscn").Instance(); + var scene = ResourceLoader.Load<PackedScene>("res://scene.tscn").Instantiate(); // Add the node as a child of the node the script is attached to. AddChild(scene); [/csharp] @@ -76,7 +76,7 @@ <link title="2D Role Playing Game Demo">https://godotengine.org/asset-library/asset/520</link> </tutorials> <methods> - <method name="can_instance" qualifiers="const"> + <method name="can_instantiate" qualifiers="const"> <return type="bool"> </return> <description> @@ -90,7 +90,7 @@ Returns the [code]SceneState[/code] representing the scene file contents. </description> </method> - <method name="instance" qualifiers="const"> + <method name="instantiate" qualifiers="const"> <return type="Node"> </return> <argument index="0" name="edit_state" type="int" enum="PackedScene.GenEditState" default="0"> @@ -110,21 +110,21 @@ </method> </methods> <members> - <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" default="{"conn_count": 0,"conns": PackedInt32Array( ),"editable_instances": [ ],"names": PackedStringArray( ),"node_count": 0,"node_paths": [ ],"nodes": PackedInt32Array( ),"variants": [ ],"version": 2}"> + <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" default="{"conn_count": 0,"conns": PackedInt32Array(),"editable_instances": [],"names": PackedStringArray(),"node_count": 0,"node_paths": [],"nodes": PackedInt32Array(),"variants": [],"version": 2}"> A dictionary representation of the scene contents. Available keys include "rnames" and "variants" for resources, "node_count", "nodes", "node_paths" for nodes, "editable_instances" for base scene children overrides, "conn_count" and "conns" for signal connections, and "version" for the format style of the PackedScene. </member> </members> <constants> <constant name="GEN_EDIT_STATE_DISABLED" value="0" enum="GenEditState"> - If passed to [method instance], blocks edits to the scene state. + If passed to [method instantiate], blocks edits to the scene state. </constant> <constant name="GEN_EDIT_STATE_INSTANCE" value="1" enum="GenEditState"> - If passed to [method instance], provides local scene resources to the local scene. + If passed to [method instantiate], provides local scene resources to the local scene. [b]Note:[/b] Only available in editor builds. </constant> <constant name="GEN_EDIT_STATE_MAIN" value="2" enum="GenEditState"> - If passed to [method instance], provides local scene resources to the local scene. Only the main scene should receive the main edit state. + If passed to [method instantiate], provides local scene resources to the local scene. Only the main scene should receive the main edit state. [b]Note:[/b] Only available in editor builds. </constant> </constants> diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml index 85d41d7519..00ded39082 100644 --- a/doc/classes/PackedVector3Array.xml +++ b/doc/classes/PackedVector3Array.xml @@ -106,7 +106,7 @@ <method name="operator *" qualifiers="operator"> <return type="PackedVector3Array"> </return> - <argument index="0" name="right" type="Transform"> + <argument index="0" name="right" type="Transform3D"> </argument> <description> </description> diff --git a/doc/classes/PacketPeer.xml b/doc/classes/PacketPeer.xml index e3e2f63e14..0a758c2cd6 100644 --- a/doc/classes/PacketPeer.xml +++ b/doc/classes/PacketPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PacketPeer" inherits="Reference" version="4.0"> +<class name="PacketPeer" inherits="RefCounted" version="4.0"> <brief_description> Abstraction and base class for packet-based protocols. </brief_description> diff --git a/doc/classes/ParallaxBackground.xml b/doc/classes/ParallaxBackground.xml index 3b730fc4d4..b8097343f4 100644 --- a/doc/classes/ParallaxBackground.xml +++ b/doc/classes/ParallaxBackground.xml @@ -12,22 +12,22 @@ </methods> <members> <member name="layer" type="int" setter="set_layer" getter="get_layer" override="true" default="-100" /> - <member name="scroll_base_offset" type="Vector2" setter="set_scroll_base_offset" getter="get_scroll_base_offset" default="Vector2( 0, 0 )"> + <member name="scroll_base_offset" type="Vector2" setter="set_scroll_base_offset" getter="get_scroll_base_offset" default="Vector2(0, 0)"> The base position offset for all [ParallaxLayer] children. </member> - <member name="scroll_base_scale" type="Vector2" setter="set_scroll_base_scale" getter="get_scroll_base_scale" default="Vector2( 1, 1 )"> + <member name="scroll_base_scale" type="Vector2" setter="set_scroll_base_scale" getter="get_scroll_base_scale" default="Vector2(1, 1)"> The base motion scale for all [ParallaxLayer] children. </member> <member name="scroll_ignore_camera_zoom" type="bool" setter="set_ignore_camera_zoom" getter="is_ignore_camera_zoom" default="false"> If [code]true[/code], elements in [ParallaxLayer] child aren't affected by the zoom level of the camera. </member> - <member name="scroll_limit_begin" type="Vector2" setter="set_limit_begin" getter="get_limit_begin" default="Vector2( 0, 0 )"> + <member name="scroll_limit_begin" type="Vector2" setter="set_limit_begin" getter="get_limit_begin" default="Vector2(0, 0)"> Top-left limits for scrolling to begin. If the camera is outside of this limit, the background will stop scrolling. Must be lower than [member scroll_limit_end] to work. </member> - <member name="scroll_limit_end" type="Vector2" setter="set_limit_end" getter="get_limit_end" default="Vector2( 0, 0 )"> + <member name="scroll_limit_end" type="Vector2" setter="set_limit_end" getter="get_limit_end" default="Vector2(0, 0)"> Bottom-right limits for scrolling to end. If the camera is outside of this limit, the background will stop scrolling. Must be higher than [member scroll_limit_begin] to work. </member> - <member name="scroll_offset" type="Vector2" setter="set_scroll_offset" getter="get_scroll_offset" default="Vector2( 0, 0 )"> + <member name="scroll_offset" type="Vector2" setter="set_scroll_offset" getter="get_scroll_offset" default="Vector2(0, 0)"> The ParallaxBackground's scroll value. Calculated automatically when using a [Camera2D], but can be used to manually manage scrolling when no camera is present. </member> </members> diff --git a/doc/classes/ParallaxLayer.xml b/doc/classes/ParallaxLayer.xml index 7210bee11c..6b1e013851 100644 --- a/doc/classes/ParallaxLayer.xml +++ b/doc/classes/ParallaxLayer.xml @@ -13,13 +13,13 @@ <methods> </methods> <members> - <member name="motion_mirroring" type="Vector2" setter="set_mirroring" getter="get_mirroring" default="Vector2( 0, 0 )"> + <member name="motion_mirroring" type="Vector2" setter="set_mirroring" getter="get_mirroring" default="Vector2(0, 0)"> The ParallaxLayer's [Texture2D] mirroring. Useful for creating an infinite scrolling background. If an axis is set to [code]0[/code], the [Texture2D] will not be mirrored. </member> - <member name="motion_offset" type="Vector2" setter="set_motion_offset" getter="get_motion_offset" default="Vector2( 0, 0 )"> + <member name="motion_offset" type="Vector2" setter="set_motion_offset" getter="get_motion_offset" default="Vector2(0, 0)"> The ParallaxLayer's offset relative to the parent ParallaxBackground's [member ParallaxBackground.scroll_offset]. </member> - <member name="motion_scale" type="Vector2" setter="set_motion_scale" getter="get_motion_scale" default="Vector2( 1, 1 )"> + <member name="motion_scale" type="Vector2" setter="set_motion_scale" getter="get_motion_scale" default="Vector2(1, 1)"> Multiplies the ParallaxLayer's motion. If an axis is set to [code]0[/code], it will not scroll. </member> </members> diff --git a/doc/classes/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml index 3c364b621a..e8fde21032 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticlesMaterial.xml @@ -141,7 +141,7 @@ </member> <member name="collision_use_scale" type="bool" setter="set_collision_use_scale" getter="is_collision_using_scale" default="false"> </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> Each particle's initial color. If the [GPUParticles2D]'s [code]texture[/code] is defined, it will be multiplied by this color. To have particle display color in a [BaseMaterial3D] make sure to set [member BaseMaterial3D.vertex_color_use_as_albedo] to [code]true[/code]. </member> <member name="color_ramp" type="Texture2D" setter="set_color_ramp" getter="get_color_ramp"> @@ -156,7 +156,7 @@ <member name="damping_random" type="float" setter="set_param_randomness" getter="get_param_randomness" default="0.0"> Damping randomness ratio. </member> - <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3( 1, 0, 0 )"> + <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3(1, 0, 0)"> Unit vector specifying the particles' emission direction. </member> <member name="emission_box_extents" type="Vector3" setter="set_emission_box_extents" getter="get_emission_box_extents"> @@ -183,7 +183,7 @@ <member name="flatness" type="float" setter="set_flatness" getter="get_flatness" default="0.0"> Amount of [member spread] along the Y axis. </member> - <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3( 0, -9.8, 0 )"> + <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3(0, -9.8, 0)"> Gravity applied to every particle. </member> <member name="hue_variation" type="float" setter="set_param" getter="get_param" default="0.0"> diff --git a/doc/classes/Performance.xml b/doc/classes/Performance.xml index 9e9c5063ae..a141961df5 100644 --- a/doc/classes/Performance.xml +++ b/doc/classes/Performance.xml @@ -20,7 +20,7 @@ </argument> <argument index="1" name="callable" type="Callable"> </argument> - <argument index="2" name="arguments" type="Array" default="[ ]"> + <argument index="2" name="arguments" type="Array" default="[]"> </argument> <description> Adds a custom monitor with name same as id. You can specify the category of monitor using '/' in id. If there are more than one '/' then default category is used. Default category is "Custom". @@ -157,69 +157,53 @@ Largest amount of memory the message queue buffer has used, in bytes. The message queue is used for deferred functions calls and notifications. </constant> <constant name="OBJECT_COUNT" value="6" enum="Monitor"> - Number of objects currently instanced (including nodes). + Number of objects currently instantiated (including nodes). </constant> <constant name="OBJECT_RESOURCE_COUNT" value="7" enum="Monitor"> Number of resources currently used. </constant> <constant name="OBJECT_NODE_COUNT" value="8" enum="Monitor"> - Number of nodes currently instanced in the scene tree. This also includes the root node. + Number of nodes currently instantiated in the scene tree. This also includes the root node. </constant> <constant name="OBJECT_ORPHAN_NODE_COUNT" value="9" enum="Monitor"> Number of orphan nodes, i.e. nodes which are not parented to a node of the scene tree. </constant> - <constant name="RENDER_OBJECTS_IN_FRAME" value="10" enum="Monitor"> - 3D objects drawn per frame. + <constant name="RENDER_TOTAL_OBJECTS_IN_FRAME" value="10" enum="Monitor"> </constant> - <constant name="RENDER_VERTICES_IN_FRAME" value="11" enum="Monitor"> - Vertices drawn per frame. 3D only. + <constant name="RENDER_TOTAL_PRIMITIVES_IN_FRAME" value="11" enum="Monitor"> </constant> - <constant name="RENDER_MATERIAL_CHANGES_IN_FRAME" value="12" enum="Monitor"> - Material changes per frame. 3D only. + <constant name="RENDER_TOTAL_DRAW_CALLS_IN_FRAME" value="12" enum="Monitor"> </constant> - <constant name="RENDER_SHADER_CHANGES_IN_FRAME" value="13" enum="Monitor"> - Shader changes per frame. 3D only. - </constant> - <constant name="RENDER_SURFACE_CHANGES_IN_FRAME" value="14" enum="Monitor"> - Render surface changes per frame. 3D only. - </constant> - <constant name="RENDER_DRAW_CALLS_IN_FRAME" value="15" enum="Monitor"> - Draw calls per frame. 3D only. - </constant> - <constant name="RENDER_VIDEO_MEM_USED" value="16" enum="Monitor"> + <constant name="RENDER_VIDEO_MEM_USED" value="13" enum="Monitor"> The amount of video memory used, i.e. texture and vertex memory combined. </constant> - <constant name="RENDER_TEXTURE_MEM_USED" value="17" enum="Monitor"> + <constant name="RENDER_TEXTURE_MEM_USED" value="14" enum="Monitor"> The amount of texture memory used. </constant> - <constant name="RENDER_VERTEX_MEM_USED" value="18" enum="Monitor"> - The amount of vertex memory used. - </constant> - <constant name="RENDER_USAGE_VIDEO_MEM_TOTAL" value="19" enum="Monitor"> - Unimplemented in the GLES2 rendering backend, always returns 0. + <constant name="RENDER_BUFFER_MEM_USED" value="15" enum="Monitor"> </constant> - <constant name="PHYSICS_2D_ACTIVE_OBJECTS" value="20" enum="Monitor"> + <constant name="PHYSICS_2D_ACTIVE_OBJECTS" value="16" enum="Monitor"> Number of active [RigidBody2D] nodes in the game. </constant> - <constant name="PHYSICS_2D_COLLISION_PAIRS" value="21" enum="Monitor"> + <constant name="PHYSICS_2D_COLLISION_PAIRS" value="17" enum="Monitor"> Number of collision pairs in the 2D physics engine. </constant> - <constant name="PHYSICS_2D_ISLAND_COUNT" value="22" enum="Monitor"> + <constant name="PHYSICS_2D_ISLAND_COUNT" value="18" enum="Monitor"> Number of islands in the 2D physics engine. </constant> - <constant name="PHYSICS_3D_ACTIVE_OBJECTS" value="23" enum="Monitor"> + <constant name="PHYSICS_3D_ACTIVE_OBJECTS" value="19" enum="Monitor"> Number of active [RigidBody3D] and [VehicleBody3D] nodes in the game. </constant> - <constant name="PHYSICS_3D_COLLISION_PAIRS" value="24" enum="Monitor"> + <constant name="PHYSICS_3D_COLLISION_PAIRS" value="20" enum="Monitor"> Number of collision pairs in the 3D physics engine. </constant> - <constant name="PHYSICS_3D_ISLAND_COUNT" value="25" enum="Monitor"> + <constant name="PHYSICS_3D_ISLAND_COUNT" value="21" enum="Monitor"> Number of islands in the 3D physics engine. </constant> - <constant name="AUDIO_OUTPUT_LATENCY" value="26" enum="Monitor"> + <constant name="AUDIO_OUTPUT_LATENCY" value="22" enum="Monitor"> Output latency of the [AudioServer]. </constant> - <constant name="MONITOR_MAX" value="27" enum="Monitor"> + <constant name="MONITOR_MAX" value="23" enum="Monitor"> Represents the size of the [enum Monitor] enum. </constant> </constants> diff --git a/doc/classes/PhysicalBone2D.xml b/doc/classes/PhysicalBone2D.xml new file mode 100644 index 0000000000..cea75bad52 --- /dev/null +++ b/doc/classes/PhysicalBone2D.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PhysicalBone2D" inherits="RigidBody2D" version="4.0"> + <brief_description> + A 2D node that can be used for physically aware bones in 2D. + </brief_description> + <description> + The [code]PhysicalBone2D[/code] node is a [RigidBody2D]-based node that can be used to make [Bone2D] nodes in a [Skeleton2D] react to physics. This node is very similar to the [PhysicalBone3D] node, just for 2D instead of 3D. + [b]Note:[/b] To have the Bone2D nodes visually follow the [code]PhysicalBone2D[/code] node, use a [SkeletonModification2DPhysicalBones] modification on the [Skeleton2D] node with the [Bone2D] nodes. + [b]Note:[/b] The PhysicalBone2D node does not automatically create a [Joint2D] node to keep [code]PhysicalBone2D[/code] nodes together. You will need to create these manually. For most cases, you want to use a [PinJoint2D] node. The [code]PhysicalBone2D[/code] node can automatically configure the [Joint2D] node once it's been created as a child node. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_joint" qualifiers="const"> + <return type="Joint2D"> + </return> + <description> + Returns the first [Joint2D] child node, if one exists. This is mainly a helper function to make it easier to get the [Joint2D] that the [code]PhysicalBone2D[/code] is autoconfiguring. + </description> + </method> + <method name="is_simulating_physics" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns a boolean that indicates whether the [code]PhysicalBone2D[/code] node is running and simulating using the Godot 2D physics engine. When [code]true[/code], the PhysicalBone2D node is using physics. + </description> + </method> + </methods> + <members> + <member name="auto_configure_joint" type="bool" setter="set_auto_configure_joint" getter="get_auto_configure_joint" default="true"> + If [code]true[/code], the [code]PhysicalBone2D[/code] node will automatically configure the first [Joint2D] child node. The automatic configuration is limited to setting up the node properties and positioning the [Joint2D]. + </member> + <member name="bone2d_index" type="int" setter="set_bone2d_index" getter="get_bone2d_index" default="-1"> + The index of the [Bone2D] node that this [code]PhysicalBone2D[/code] node is supposed to be simulating. + </member> + <member name="bone2d_nodepath" type="NodePath" setter="set_bone2d_nodepath" getter="get_bone2d_nodepath" default="NodePath("")"> + The [NodePath] to the [Bone2D] node that this [code]PhysicalBone2D[/code] node is supposed to be simulating. + </member> + <member name="follow_bone_when_simulating" type="bool" setter="set_follow_bone_when_simulating" getter="get_follow_bone_when_simulating" default="false"> + If [code]true[/code], the [code]PhysicalBone2D[/code] will keep the transform of the bone it is bound to when simulating physics. + </member> + <member name="simulate_physics" type="bool" setter="set_simulate_physics" getter="get_simulate_physics" default="false"> + If [code]true[/code], the [code]PhysicalBone2D[/code] will start simulating using physics. If [code]false[/code], the [code]PhysicalBone2D[/code] will follow the transform of the [Bone2D] node. + [b]Note:[/b] To have the Bone2D nodes visually follow the [code]PhysicalBone2D[/code] node, use a [SkeletonModification2DPhysicalBones] modification on the [Skeleton2D] node with the [Bone2D] nodes. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/PhysicalBone3D.xml b/doc/classes/PhysicalBone3D.xml index 38d9f722b1..2ed862e9ce 100644 --- a/doc/classes/PhysicalBone3D.xml +++ b/doc/classes/PhysicalBone3D.xml @@ -20,15 +20,7 @@ </return> <argument index="0" name="impulse" type="Vector3"> </argument> - <argument index="1" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> - </argument> - <description> - </description> - </method> - <method name="get_axis_lock" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> + <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> </description> @@ -51,40 +43,12 @@ <description> </description> </method> - <method name="set_axis_lock"> - <return type="void"> - </return> - <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> - </argument> - <argument index="1" name="lock" type="bool"> - </argument> - <description> - </description> - </method> </methods> <members> <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="-1.0"> Damps the body's rotation if greater than [code]0[/code]. </member> - <member name="axis_lock_angular_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's rotation in the X axis. - </member> - <member name="axis_lock_angular_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's rotation in the Y axis. - </member> - <member name="axis_lock_angular_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's rotation in the Z axis. - </member> - <member name="axis_lock_linear_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's movement in the X axis. - </member> - <member name="axis_lock_linear_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's movement in the Y axis. - </member> - <member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's movement in the Z axis. - </member> - <member name="body_offset" type="Transform" setter="set_body_offset" getter="get_body_offset" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="body_offset" type="Transform3D" setter="set_body_offset" getter="get_body_offset" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> Sets the body's transform. </member> <member name="bounce" type="float" setter="set_bounce" getter="get_bounce" default="0.0"> @@ -99,15 +63,12 @@ <member name="gravity_scale" type="float" setter="set_gravity_scale" getter="get_gravity_scale" default="1.0"> This is multiplied by the global 3D gravity setting found in [b]Project > Project Settings > Physics > 3d[/b] to produce the body's gravity. For example, a value of 1 will be normal gravity, 2 will apply double gravity, and 0.5 will apply half gravity to this object. </member> - <member name="joint_offset" type="Transform" setter="set_joint_offset" getter="get_joint_offset" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="joint_offset" type="Transform3D" setter="set_joint_offset" getter="get_joint_offset" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> Sets the joint's transform. </member> - <member name="joint_rotation" type="Vector3" setter="set_joint_rotation" getter="get_joint_rotation"> + <member name="joint_rotation" type="Vector3" setter="set_joint_rotation" getter="get_joint_rotation" default="Vector3(0, 0, 0)"> Sets the joint's rotation in radians. </member> - <member name="joint_rotation_degrees" type="Vector3" setter="set_joint_rotation_degrees" getter="get_joint_rotation_degrees" default="Vector3( 0, 0, 0 )"> - Sets the joint's rotation in degrees. - </member> <member name="joint_type" type="int" setter="set_joint_type" getter="get_joint_type" enum="PhysicalBone3D.JointType" default="0"> Sets the joint type. See [enum JointType] for possible values. </member> diff --git a/doc/classes/PhysicalSkyMaterial.xml b/doc/classes/PhysicalSkyMaterial.xml index 381371b973..20ab998d35 100644 --- a/doc/classes/PhysicalSkyMaterial.xml +++ b/doc/classes/PhysicalSkyMaterial.xml @@ -19,13 +19,13 @@ <member name="exposure" type="float" setter="set_exposure" getter="get_exposure" default="0.1"> Sets the exposure of the sky. Higher exposure values make the entire sky brighter. </member> - <member name="ground_color" type="Color" setter="set_ground_color" getter="get_ground_color" default="Color( 1, 1, 1, 1 )"> + <member name="ground_color" type="Color" setter="set_ground_color" getter="get_ground_color" default="Color(1, 1, 1, 1)"> Modulates the [Color] on the bottom half of the sky to represent the ground. </member> <member name="mie_coefficient" type="float" setter="set_mie_coefficient" getter="get_mie_coefficient" default="0.005"> Controls the strength of mie scattering for the sky. Mie scattering results from light colliding with larger particles (like water). On earth, mie scattering results in a whitish color around the sun and horizon. </member> - <member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color( 0.36, 0.56, 0.82, 1 )"> + <member name="mie_color" type="Color" setter="set_mie_color" getter="get_mie_color" default="Color(0.36, 0.56, 0.82, 1)"> Controls the [Color] of the mie scattering effect. While not physically accurate, this allows for the creation of alien looking planets. </member> <member name="mie_eccentricity" type="float" setter="set_mie_eccentricity" getter="get_mie_eccentricity" default="0.8"> @@ -37,7 +37,7 @@ <member name="rayleigh_coefficient" type="float" setter="set_rayleigh_coefficient" getter="get_rayleigh_coefficient" default="2.0"> Controls the strength of the Rayleigh scattering. Rayleigh scattering results from light colliding with small particles. It is responsible for the blue color of the sky. </member> - <member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color( 0.056, 0.14, 0.3, 1 )"> + <member name="rayleigh_color" type="Color" setter="set_rayleigh_color" getter="get_rayleigh_color" default="Color(0.056, 0.14, 0.3, 1)"> Controls the [Color] of the Rayleigh scattering. While not physically accurate, this allows for the creation of alien looking planets. For example, setting this to a red [Color] results in a Mars looking atmosphere with a corresponding blue sunset. </member> <member name="sun_disk_scale" type="float" setter="set_sun_disk_scale" getter="get_sun_disk_scale" default="1.0"> diff --git a/doc/classes/PhysicsBody2D.xml b/doc/classes/PhysicsBody2D.xml index e43d3bb762..654b0fb668 100644 --- a/doc/classes/PhysicsBody2D.xml +++ b/doc/classes/PhysicsBody2D.xml @@ -26,6 +26,25 @@ Returns an array of nodes that were added as collision exceptions for this body. </description> </method> + <method name="move_and_collide"> + <return type="KinematicCollision2D"> + </return> + <argument index="0" name="rel_vec" type="Vector2"> + </argument> + <argument index="1" name="infinite_inertia" type="bool" default="true"> + </argument> + <argument index="2" name="exclude_raycast_shapes" type="bool" default="true"> + </argument> + <argument index="3" name="test_only" type="bool" default="false"> + </argument> + <argument index="4" name="safe_margin" type="float" default="0.08"> + </argument> + <description> + Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision2D], which contains information about the collision. + If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given. + [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details). + </description> + </method> <method name="remove_collision_exception_with"> <return type="void"> </return> @@ -35,6 +54,27 @@ Removes a body from the list of bodies that this body can't collide with. </description> </method> + <method name="test_move"> + <return type="bool"> + </return> + <argument index="0" name="from" type="Transform2D"> + </argument> + <argument index="1" name="rel_vec" type="Vector2"> + </argument> + <argument index="2" name="infinite_inertia" type="bool" default="true"> + </argument> + <argument index="3" name="exclude_raycast_shapes" type="bool" default="true"> + </argument> + <argument index="4" name="collision" type="KinematicCollision2D" default="null"> + </argument> + <argument index="5" name="safe_margin" type="float" default="0.08"> + </argument> + <description> + Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform2D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur. + [code]collision[/code] is an optional object of type [KinematicCollision2D], which contains additional information about the collision (should there be one). + [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody2D.collision/safe_margin] for more details). + </description> + </method> </methods> <members> <member name="input_pickable" type="bool" setter="set_pickable" getter="is_pickable" override="true" default="false" /> diff --git a/doc/classes/PhysicsBody3D.xml b/doc/classes/PhysicsBody3D.xml index b320d37d23..1ec38000be 100644 --- a/doc/classes/PhysicsBody3D.xml +++ b/doc/classes/PhysicsBody3D.xml @@ -19,6 +19,15 @@ Adds a body to the list of bodies that this body can't collide with. </description> </method> + <method name="get_axis_lock" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> + </argument> + <description> + Returns [code]true[/code] if the specified linear or rotational [code]axis[/code] is locked. + </description> + </method> <method name="get_collision_exceptions"> <return type="PhysicsBody3D[]"> </return> @@ -26,6 +35,25 @@ Returns an array of nodes that were added as collision exceptions for this body. </description> </method> + <method name="move_and_collide"> + <return type="KinematicCollision3D"> + </return> + <argument index="0" name="rel_vec" type="Vector3"> + </argument> + <argument index="1" name="infinite_inertia" type="bool" default="true"> + </argument> + <argument index="2" name="exclude_raycast_shapes" type="bool" default="true"> + </argument> + <argument index="3" name="test_only" type="bool" default="false"> + </argument> + <argument index="4" name="safe_margin" type="float" default="0.001"> + </argument> + <description> + Moves the body along the vector [code]rel_vec[/code]. The body will stop if it collides. Returns a [KinematicCollision3D], which contains information about the collision. + If [code]test_only[/code] is [code]true[/code], the body does not move but the would-be collision information is given. + [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details). + </description> + </method> <method name="remove_collision_exception_with"> <return type="void"> </return> @@ -35,7 +63,59 @@ Removes a body from the list of bodies that this body can't collide with. </description> </method> + <method name="set_axis_lock"> + <return type="void"> + </return> + <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> + </argument> + <argument index="1" name="lock" type="bool"> + </argument> + <description> + Locks or unlocks the specified linear or rotational [code]axis[/code] depending on the value of [code]lock[/code]. + </description> + </method> + <method name="test_move"> + <return type="bool"> + </return> + <argument index="0" name="from" type="Transform3D"> + </argument> + <argument index="1" name="rel_vec" type="Vector3"> + </argument> + <argument index="2" name="infinite_inertia" type="bool" default="true"> + </argument> + <argument index="3" name="exclude_raycast_shapes" type="bool" default="true"> + </argument> + <argument index="4" name="collision" type="KinematicCollision3D" default="null"> + </argument> + <argument index="5" name="safe_margin" type="float" default="0.001"> + </argument> + <description> + Checks for collisions without moving the body. Virtually sets the node's position, scale and rotation to that of the given [Transform3D], then tries to move the body along the vector [code]rel_vec[/code]. Returns [code]true[/code] if a collision would occur. + [code]collision[/code] is an optional object of type [KinematicCollision3D], which contains additional information about the collision (should there be one). + [code]safe_margin[/code] is the extra margin used for collision recovery (see [member CharacterBody3D.collision/safe_margin] for more details). + </description> + </method> </methods> + <members> + <member name="axis_lock_angular_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> + Lock the body's rotation in the X axis. + </member> + <member name="axis_lock_angular_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> + Lock the body's rotation in the Y axis. + </member> + <member name="axis_lock_angular_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> + Lock the body's rotation in the Z axis. + </member> + <member name="axis_lock_linear_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> + Lock the body's linear movement in the X axis. + </member> + <member name="axis_lock_linear_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> + Lock the body's linear movement in the Y axis. + </member> + <member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> + Lock the body's linear movement in the Z axis. + </member> + </members> <constants> </constants> </class> diff --git a/doc/classes/PhysicsDirectBodyState2D.xml b/doc/classes/PhysicsDirectBodyState2D.xml index dfc0ab909a..65cb3e7f38 100644 --- a/doc/classes/PhysicsDirectBodyState2D.xml +++ b/doc/classes/PhysicsDirectBodyState2D.xml @@ -4,7 +4,7 @@ Direct access object to a physics body in the [PhysicsServer2D]. </brief_description> <description> - Provides direct access to a physics body in the [PhysicsServer2D], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces]. + Provides direct access to a physics body in the [PhysicsServer2D], allowing safe changes to physics properties. This object is passed via the direct state callback of dynamic bodies, and is intended for changing the direct state of that body. See [method RigidBody2D._integrate_forces]. </description> <tutorials> <link title="Ray-casting">https://docs.godotengine.org/en/latest/tutorials/physics/ray-casting.html</link> @@ -24,7 +24,7 @@ </return> <argument index="0" name="force" type="Vector2"> </argument> - <argument index="1" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates. @@ -53,7 +53,7 @@ </return> <argument index="0" name="impulse" type="Vector2"> </argument> - <argument index="1" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise). The offset uses the rotation of the global coordinate system, but is centered at the object's origin. diff --git a/doc/classes/PhysicsDirectBodyState3D.xml b/doc/classes/PhysicsDirectBodyState3D.xml index eea681e696..85feeef86e 100644 --- a/doc/classes/PhysicsDirectBodyState3D.xml +++ b/doc/classes/PhysicsDirectBodyState3D.xml @@ -4,7 +4,7 @@ Direct access object to a physics body in the [PhysicsServer3D]. </brief_description> <description> - Provides direct access to a physics body in the [PhysicsServer3D], allowing safe changes to physics properties. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body. See [method RigidBody3D._integrate_forces]. + Provides direct access to a physics body in the [PhysicsServer3D], allowing safe changes to physics properties. This object is passed via the direct state callback of dynamic bodies, and is intended for changing the direct state of that body. See [method RigidBody3D._integrate_forces]. </description> <tutorials> </tutorials> @@ -12,7 +12,7 @@ <method name="add_central_force"> <return type="void"> </return> - <argument index="0" name="force" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="0" name="force" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Adds a constant directional force without affecting rotation. @@ -24,7 +24,7 @@ </return> <argument index="0" name="force" type="Vector3"> </argument> - <argument index="1" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates. @@ -42,7 +42,7 @@ <method name="apply_central_impulse"> <return type="void"> </return> - <argument index="0" name="impulse" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="0" name="impulse" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Applies a single directional impulse without affecting rotation. @@ -54,7 +54,7 @@ </return> <argument index="0" name="impulse" type="Vector3"> </argument> - <argument index="1" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts. The position uses the rotation of the global coordinate system, but is centered at the object's origin. @@ -214,7 +214,7 @@ <member name="total_linear_damp" type="float" setter="" getter="get_total_linear_damp"> The rate at which the body stops moving, if there are not any other forces moving it. </member> - <member name="transform" type="Transform" setter="set_transform" getter="get_transform"> + <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform"> The body's transformation matrix. </member> </members> diff --git a/doc/classes/PhysicsDirectSpaceState2D.xml b/doc/classes/PhysicsDirectSpaceState2D.xml index b6f95305ed..6c8c957e5d 100644 --- a/doc/classes/PhysicsDirectSpaceState2D.xml +++ b/doc/classes/PhysicsDirectSpaceState2D.xml @@ -56,7 +56,7 @@ </argument> <argument index="1" name="max_results" type="int" default="32"> </argument> - <argument index="2" name="exclude" type="Array" default="[ ]"> + <argument index="2" name="exclude" type="Array" default="[]"> </argument> <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> @@ -84,7 +84,7 @@ </argument> <argument index="2" name="max_results" type="int" default="32"> </argument> - <argument index="3" name="exclude" type="Array" default="[ ]"> + <argument index="3" name="exclude" type="Array" default="[]"> </argument> <argument index="4" name="collision_layer" type="int" default="2147483647"> </argument> @@ -102,7 +102,7 @@ </argument> <argument index="1" name="to" type="Vector2"> </argument> - <argument index="2" name="exclude" type="Array" default="[ ]"> + <argument index="2" name="exclude" type="Array" default="[]"> </argument> <argument index="3" name="collision_layer" type="int" default="2147483647"> </argument> diff --git a/doc/classes/PhysicsDirectSpaceState3D.xml b/doc/classes/PhysicsDirectSpaceState3D.xml index 243d071c56..a69b6f07fd 100644 --- a/doc/classes/PhysicsDirectSpaceState3D.xml +++ b/doc/classes/PhysicsDirectSpaceState3D.xml @@ -57,7 +57,7 @@ </argument> <argument index="1" name="to" type="Vector3"> </argument> - <argument index="2" name="exclude" type="Array" default="[ ]"> + <argument index="2" name="exclude" type="Array" default="[]"> </argument> <argument index="3" name="collision_mask" type="int" default="2147483647"> </argument> diff --git a/doc/classes/PhysicsServer2D.xml b/doc/classes/PhysicsServer2D.xml index cfa4215fd4..33cd61eb9c 100644 --- a/doc/classes/PhysicsServer2D.xml +++ b/doc/classes/PhysicsServer2D.xml @@ -16,7 +16,7 @@ </argument> <argument index="1" name="shape" type="RID"> </argument> - <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )"> + <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)"> </argument> <argument index="3" name="disabled" type="bool" default="false"> </argument> @@ -333,7 +333,7 @@ </argument> <argument index="1" name="force" type="Vector2"> </argument> - <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Adds a positioned force to the applied force and torque. As with [method body_apply_impulse], both the force and the offset from the body origin are in global coordinates. A force differs from an impulse in that, while the two are forces, the impulse clears itself after being applied. @@ -346,7 +346,7 @@ </argument> <argument index="1" name="shape" type="RID"> </argument> - <argument index="2" name="transform" type="Transform2D" default="Transform2D( 1, 0, 0, 1, 0, 0 )"> + <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)"> </argument> <argument index="3" name="disabled" type="bool" default="false"> </argument> @@ -381,7 +381,7 @@ </argument> <argument index="1" name="impulse" type="Vector2"> </argument> - <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Adds a positioned impulse to the applied force and torque. Both the force and the offset from the body origin are in global coordinates. @@ -1207,16 +1207,16 @@ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one. </constant> <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode"> - Constant for static bodies. + Constant for static bodies. In this mode, a body can be only moved by user code. </constant> <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode"> - Constant for kinematic bodies. + Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path. </constant> - <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode"> - Constant for rigid bodies. + <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode"> + Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied. </constant> - <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode"> - Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics. + <constant name="BODY_MODE_DYNAMIC_LOCKED" value="3" enum="BodyMode"> + Constant for locked dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces. </constant> <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter"> Constant to set/get a body's bounce factor. diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 46de9e5282..88ce222324 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -16,7 +16,7 @@ </argument> <argument index="1" name="shape" type="RID"> </argument> - <argument index="2" name="transform" type="Transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <argument index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> </argument> <argument index="3" name="disabled" type="bool" default="false"> </argument> @@ -92,7 +92,7 @@ </description> </method> <method name="area_get_shape_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="area" type="RID"> </argument> @@ -121,7 +121,7 @@ </description> </method> <method name="area_get_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="area" type="RID"> </argument> @@ -258,7 +258,7 @@ </argument> <argument index="1" name="shape_idx" type="int"> </argument> - <argument index="2" name="transform" type="Transform"> + <argument index="2" name="transform" type="Transform3D"> </argument> <description> Sets the transform matrix for an area shape. @@ -291,7 +291,7 @@ </return> <argument index="0" name="area" type="RID"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> Sets the transform matrix for an area. @@ -325,7 +325,7 @@ </argument> <argument index="1" name="force" type="Vector3"> </argument> - <argument index="2" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> </description> @@ -337,7 +337,7 @@ </argument> <argument index="1" name="shape" type="RID"> </argument> - <argument index="2" name="transform" type="Transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <argument index="2" name="transform" type="Transform3D" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> </argument> <argument index="3" name="disabled" type="bool" default="false"> </argument> @@ -372,7 +372,7 @@ </argument> <argument index="1" name="impulse" type="Vector3"> </argument> - <argument index="2" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="2" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Gives the body a push at a [code]position[/code] in the direction of the [code]impulse[/code]. @@ -443,14 +443,6 @@ Returns the [PhysicsDirectBodyState3D] of the body. </description> </method> - <method name="body_get_kinematic_safe_margin" qualifiers="const"> - <return type="float"> - </return> - <argument index="0" name="body" type="RID"> - </argument> - <description> - </description> - </method> <method name="body_get_max_contacts_reported" qualifiers="const"> <return type="int"> </return> @@ -510,7 +502,7 @@ </description> </method> <method name="body_get_shape_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="body" type="RID"> </argument> @@ -661,16 +653,6 @@ Sets the function used to calculate physics for an object, if that object allows it (see [method body_set_omit_force_integration]). </description> </method> - <method name="body_set_kinematic_safe_margin"> - <return type="void"> - </return> - <argument index="0" name="body" type="RID"> - </argument> - <argument index="1" name="margin" type="float"> - </argument> - <description> - </description> - </method> <method name="body_set_max_contacts_reported"> <return type="void"> </return> @@ -760,7 +742,7 @@ </argument> <argument index="1" name="shape_idx" type="int"> </argument> - <argument index="2" name="transform" type="Transform"> + <argument index="2" name="transform" type="Transform3D"> </argument> <description> Sets the transform matrix for a body shape. @@ -790,6 +772,25 @@ Sets a body state (see [enum BodyState] constants). </description> </method> + <method name="body_test_motion"> + <return type="bool"> + </return> + <argument index="0" name="body" type="RID"> + </argument> + <argument index="1" name="from" type="Transform3D"> + </argument> + <argument index="2" name="motion" type="Vector3"> + </argument> + <argument index="3" name="infinite_inertia" type="bool"> + </argument> + <argument index="4" name="margin" type="float" default="0.001"> + </argument> + <argument index="5" name="result" type="PhysicsTestMotionResult3D" default="null"> + </argument> + <description> + Returns [code]true[/code] if a collision would result from moving in the given direction from a given point in space. Margin increases the size of the shapes involved in the collision detection. [PhysicsTestMotionResult3D] can be passed to return additional information in. + </description> + </method> <method name="box_shape_create"> <return type="RID"> </return> @@ -1017,11 +1018,11 @@ </argument> <argument index="1" name="body_A" type="RID"> </argument> - <argument index="2" name="local_ref_A" type="Transform"> + <argument index="2" name="local_ref_A" type="Transform3D"> </argument> <argument index="3" name="body_B" type="RID"> </argument> - <argument index="4" name="local_ref_B" type="Transform"> + <argument index="4" name="local_ref_B" type="Transform3D"> </argument> <description> </description> @@ -1033,11 +1034,11 @@ </argument> <argument index="1" name="body_A" type="RID"> </argument> - <argument index="2" name="local_ref_A" type="Transform"> + <argument index="2" name="local_ref_A" type="Transform3D"> </argument> <argument index="3" name="body_B" type="RID"> </argument> - <argument index="4" name="local_ref_B" type="Transform"> + <argument index="4" name="local_ref_B" type="Transform3D"> </argument> <description> </description> @@ -1049,11 +1050,11 @@ </argument> <argument index="1" name="body_A" type="RID"> </argument> - <argument index="2" name="hinge_A" type="Transform"> + <argument index="2" name="hinge_A" type="Transform3D"> </argument> <argument index="3" name="body_B" type="RID"> </argument> - <argument index="4" name="hinge_B" type="Transform"> + <argument index="4" name="hinge_B" type="Transform3D"> </argument> <description> </description> @@ -1081,11 +1082,11 @@ </argument> <argument index="1" name="body_A" type="RID"> </argument> - <argument index="2" name="local_ref_A" type="Transform"> + <argument index="2" name="local_ref_A" type="Transform3D"> </argument> <argument index="3" name="body_B" type="RID"> </argument> - <argument index="4" name="local_ref_B" type="Transform"> + <argument index="4" name="local_ref_B" type="Transform3D"> </argument> <description> </description> @@ -1595,16 +1596,16 @@ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one. </constant> <constant name="BODY_MODE_STATIC" value="0" enum="BodyMode"> - Constant for static bodies. + Constant for static bodies. In this mode, a body can be only moved by user code. </constant> <constant name="BODY_MODE_KINEMATIC" value="1" enum="BodyMode"> - Constant for kinematic bodies. + Constant for kinematic bodies. In this mode, a body can be only moved by user code and collides with other bodies along its path. </constant> - <constant name="BODY_MODE_RIGID" value="2" enum="BodyMode"> - Constant for rigid bodies. + <constant name="BODY_MODE_DYNAMIC" value="2" enum="BodyMode"> + Constant for dynamic bodies. In this mode, a body can be pushed by other bodies and has forces applied. </constant> - <constant name="BODY_MODE_CHARACTER" value="3" enum="BodyMode"> - Constant for rigid bodies in character mode. In this mode, a body can not rotate, and only its linear velocity is affected by physics. + <constant name="BODY_MODE_DYNAMIC_LOCKED" value="3" enum="BodyMode"> + Constant for locked dynamic bodies. In this mode, a body is dynamic but can not rotate, and only its linear velocity is affected by external forces. </constant> <constant name="BODY_PARAM_BOUNCE" value="0" enum="BodyParameter"> Constant to set/get a body's bounce factor. diff --git a/doc/classes/PhysicsShapeQueryParameters2D.xml b/doc/classes/PhysicsShapeQueryParameters2D.xml index 4d7fc61517..229a40638a 100644 --- a/doc/classes/PhysicsShapeQueryParameters2D.xml +++ b/doc/classes/PhysicsShapeQueryParameters2D.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PhysicsShapeQueryParameters2D" inherits="Reference" version="4.0"> +<class name="PhysicsShapeQueryParameters2D" inherits="RefCounted" version="4.0"> <brief_description> Parameters to be sent to a 2D shape physics query. </brief_description> <description> - This class contains the shape and other parameters for 2D intersection/collision queries. See also [PhysicsShapeQueryResult2D]. + This class contains the shape and other parameters for 2D intersection/collision queries. </description> <tutorials> </tutorials> @@ -20,13 +20,13 @@ <member name="collision_layer" type="int" setter="set_collision_layer" getter="get_collision_layer" default="2147483647"> The physics layer(s) the query will take into account (as a bitmask). See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]"> + <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> The list of objects or object [RID]s that will be excluded from collisions. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> The collision margin for the shape. </member> - <member name="motion" type="Vector2" setter="set_motion" getter="get_motion" default="Vector2( 0, 0 )"> + <member name="motion" type="Vector2" setter="set_motion" getter="get_motion" default="Vector2(0, 0)"> The motion of the shape being queried for. </member> <member name="shape" type="Resource" setter="set_shape" getter="get_shape"> @@ -63,7 +63,7 @@ [/csharp] [/codeblocks] </member> - <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D( 1, 0, 0, 1, 0, 0 )"> + <member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D(1, 0, 0, 1, 0, 0)"> The queried shape's transform matrix. </member> </members> diff --git a/doc/classes/PhysicsShapeQueryParameters3D.xml b/doc/classes/PhysicsShapeQueryParameters3D.xml index 4b43ea66fc..9ca892acb3 100644 --- a/doc/classes/PhysicsShapeQueryParameters3D.xml +++ b/doc/classes/PhysicsShapeQueryParameters3D.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PhysicsShapeQueryParameters3D" inherits="Reference" version="4.0"> +<class name="PhysicsShapeQueryParameters3D" inherits="RefCounted" version="4.0"> <brief_description> Parameters to be sent to a 3D shape physics query. </brief_description> <description> - This class contains the shape and other parameters for 3D intersection/collision queries. See also [PhysicsShapeQueryResult3D]. + This class contains the shape and other parameters for 3D intersection/collision queries. </description> <tutorials> </tutorials> @@ -20,7 +20,7 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="2147483647"> The physics layer(s) the query will take into account (as a bitmask). See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[ ]"> + <member name="exclude" type="Array" setter="set_exclude" getter="get_exclude" default="[]"> The list of objects or object [RID]s that will be excluded from collisions. </member> <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0"> @@ -60,7 +60,7 @@ [/csharp] [/codeblocks] </member> - <member name="transform" type="Transform" setter="set_transform" getter="get_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> The queried shape's transform matrix. </member> </members> diff --git a/doc/classes/PhysicsShapeQueryResult2D.xml b/doc/classes/PhysicsShapeQueryResult2D.xml deleted file mode 100644 index 227683cc33..0000000000 --- a/doc/classes/PhysicsShapeQueryResult2D.xml +++ /dev/null @@ -1,58 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="PhysicsShapeQueryResult2D" inherits="Reference" version="4.0"> - <brief_description> - Result of a 2D shape query in [PhysicsServer2D]. - </brief_description> - <description> - The result of a 2D shape query in [PhysicsServer2D]. See also [PhysicsShapeQueryParameters2D]. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_result_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the number of objects that intersected with the shape. - </description> - </method> - <method name="get_result_object" qualifiers="const"> - <return type="Object"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the [Object] that intersected with the shape at index [code]idx[/code]. - </description> - </method> - <method name="get_result_object_id" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the instance ID of the [Object] that intersected with the shape at index [code]idx[/code]. - </description> - </method> - <method name="get_result_object_shape" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the child index of the object's [Shape2D] that intersected with the shape at index [code]idx[/code]. - </description> - </method> - <method name="get_result_rid" qualifiers="const"> - <return type="RID"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the [RID] of the object that intersected with the shape at index [code]idx[/code]. - </description> - </method> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/PhysicsShapeQueryResult3D.xml b/doc/classes/PhysicsShapeQueryResult3D.xml deleted file mode 100644 index 4555c4e242..0000000000 --- a/doc/classes/PhysicsShapeQueryResult3D.xml +++ /dev/null @@ -1,58 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="PhysicsShapeQueryResult3D" inherits="Reference" version="4.0"> - <brief_description> - Result of a 3D shape query in [PhysicsServer3D]. - </brief_description> - <description> - The result of a 3D shape query in [PhysicsServer3D]. See also [PhysicsShapeQueryParameters3D]. - </description> - <tutorials> - </tutorials> - <methods> - <method name="get_result_count" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the number of objects that intersected with the shape. - </description> - </method> - <method name="get_result_object" qualifiers="const"> - <return type="Object"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the [Object] that intersected with the shape at index [code]idx[/code]. - </description> - </method> - <method name="get_result_object_id" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the instance ID of the [Object] that intersected with the shape at index [code]idx[/code]. - </description> - </method> - <method name="get_result_object_shape" qualifiers="const"> - <return type="int"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the child index of the object's [Shape3D] that intersected with the shape at index [code]idx[/code]. - </description> - </method> - <method name="get_result_rid" qualifiers="const"> - <return type="RID"> - </return> - <argument index="0" name="idx" type="int"> - </argument> - <description> - Returns the [RID] of the object that intersected with the shape at index [code]idx[/code]. - </description> - </method> - </methods> - <constants> - </constants> -</class> diff --git a/doc/classes/PhysicsTestMotionResult2D.xml b/doc/classes/PhysicsTestMotionResult2D.xml index 301cff2885..bf3497386e 100644 --- a/doc/classes/PhysicsTestMotionResult2D.xml +++ b/doc/classes/PhysicsTestMotionResult2D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="PhysicsTestMotionResult2D" inherits="Reference" version="4.0"> +<class name="PhysicsTestMotionResult2D" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> @@ -17,15 +17,21 @@ </member> <member name="collider_shape" type="int" setter="" getter="get_collider_shape" default="0"> </member> - <member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2( 0, 0 )"> + <member name="collider_velocity" type="Vector2" setter="" getter="get_collider_velocity" default="Vector2(0, 0)"> </member> - <member name="collision_normal" type="Vector2" setter="" getter="get_collision_normal" default="Vector2( 0, 0 )"> + <member name="collision_depth" type="float" setter="" getter="get_collision_depth" default="0.0"> </member> - <member name="collision_point" type="Vector2" setter="" getter="get_collision_point" default="Vector2( 0, 0 )"> + <member name="collision_normal" type="Vector2" setter="" getter="get_collision_normal" default="Vector2(0, 0)"> </member> - <member name="motion" type="Vector2" setter="" getter="get_motion" default="Vector2( 0, 0 )"> + <member name="collision_point" type="Vector2" setter="" getter="get_collision_point" default="Vector2(0, 0)"> </member> - <member name="motion_remainder" type="Vector2" setter="" getter="get_motion_remainder" default="Vector2( 0, 0 )"> + <member name="collision_safe_fraction" type="float" setter="" getter="get_collision_safe_fraction" default="0.0"> + </member> + <member name="collision_unsafe_fraction" type="float" setter="" getter="get_collision_unsafe_fraction" default="0.0"> + </member> + <member name="motion" type="Vector2" setter="" getter="get_motion" default="Vector2(0, 0)"> + </member> + <member name="motion_remainder" type="Vector2" setter="" getter="get_motion_remainder" default="Vector2(0, 0)"> </member> </members> <constants> diff --git a/doc/classes/PhysicsTestMotionResult3D.xml b/doc/classes/PhysicsTestMotionResult3D.xml new file mode 100644 index 0000000000..08c72ba965 --- /dev/null +++ b/doc/classes/PhysicsTestMotionResult3D.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PhysicsTestMotionResult3D" inherits="RefCounted" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="collider" type="Object" setter="" getter="get_collider"> + </member> + <member name="collider_id" type="int" setter="" getter="get_collider_id" default="0"> + </member> + <member name="collider_rid" type="RID" setter="" getter="get_collider_rid"> + </member> + <member name="collider_shape" type="int" setter="" getter="get_collider_shape" default="0"> + </member> + <member name="collider_velocity" type="Vector3" setter="" getter="get_collider_velocity" default="Vector3(0, 0, 0)"> + </member> + <member name="collision_depth" type="float" setter="" getter="get_collision_depth" default="0.0"> + </member> + <member name="collision_normal" type="Vector3" setter="" getter="get_collision_normal" default="Vector3(0, 0, 0)"> + </member> + <member name="collision_point" type="Vector3" setter="" getter="get_collision_point" default="Vector3(0, 0, 0)"> + </member> + <member name="collision_safe_fraction" type="float" setter="" getter="get_collision_safe_fraction" default="0.0"> + </member> + <member name="collision_unsafe_fraction" type="float" setter="" getter="get_collision_unsafe_fraction" default="0.0"> + </member> + <member name="motion" type="Vector3" setter="" getter="get_motion" default="Vector3(0, 0, 0)"> + </member> + <member name="motion_remainder" type="Vector3" setter="" getter="get_motion_remainder" default="Vector3(0, 0, 0)"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/PinJoint2D.xml b/doc/classes/PinJoint2D.xml index 42155a7f25..ed45149cdf 100644 --- a/doc/classes/PinJoint2D.xml +++ b/doc/classes/PinJoint2D.xml @@ -4,7 +4,7 @@ Pin joint for 2D shapes. </brief_description> <description> - Pin joint for 2D rigid bodies. It pins two bodies (rigid or static) together. + Pin joint for 2D rigid bodies. It pins two bodies (dynamic or static) together. </description> <tutorials> </tutorials> diff --git a/doc/classes/PinJoint3D.xml b/doc/classes/PinJoint3D.xml index 267ea38873..37a85e497f 100644 --- a/doc/classes/PinJoint3D.xml +++ b/doc/classes/PinJoint3D.xml @@ -4,7 +4,7 @@ Pin joint for 3D PhysicsBodies. </brief_description> <description> - Pin joint for 3D rigid bodies. It pins 2 bodies (rigid or static) together. See also [Generic6DOFJoint3D]. + Pin joint for 3D rigid bodies. It pins 2 bodies (dynamic or static) together. See also [Generic6DOFJoint3D]. </description> <tutorials> </tutorials> diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml index 2342f00631..12869061c4 100644 --- a/doc/classes/Plane.xml +++ b/doc/classes/Plane.xml @@ -169,23 +169,23 @@ <description> </description> </method> - <method name="operator +" qualifiers="operator"> - <return type="Plane"> + <method name="operator ==" qualifiers="operator"> + <return type="bool"> </return> + <argument index="0" name="right" type="Plane"> + </argument> <description> </description> </method> - <method name="operator -" qualifiers="operator"> + <method name="operator unary+" qualifiers="operator"> <return type="Plane"> </return> <description> </description> </method> - <method name="operator ==" qualifiers="operator"> - <return type="bool"> + <method name="operator unary-" qualifiers="operator"> + <return type="Plane"> </return> - <argument index="0" name="right" type="Plane"> - </argument> <description> </description> </method> @@ -204,7 +204,7 @@ The distance from the origin to the plane, in the direction of [member normal]. This value is typically non-negative. In the scalar equation of the plane [code]ax + by + cz = d[/code], this is [code]d[/code], while the [code](a, b, c)[/code] coordinates are represented by the [member normal] property. </member> - <member name="normal" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> + <member name="normal" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)"> The normal of the plane, which must be normalized. In the scalar equation of the plane [code]ax + by + cz = d[/code], this is the vector [code](a, b, c)[/code], where [code]d[/code] is the [member d] property. </member> @@ -219,13 +219,13 @@ </member> </members> <constants> - <constant name="PLANE_YZ" value="Plane( 1, 0, 0, 0 )"> + <constant name="PLANE_YZ" value="Plane(1, 0, 0, 0)"> A plane that extends in the Y and Z axes (normal vector points +X). </constant> - <constant name="PLANE_XZ" value="Plane( 0, 1, 0, 0 )"> + <constant name="PLANE_XZ" value="Plane(0, 1, 0, 0)"> A plane that extends in the X and Z axes (normal vector points +Y). </constant> - <constant name="PLANE_XY" value="Plane( 0, 0, 1, 0 )"> + <constant name="PLANE_XY" value="Plane(0, 0, 1, 0)"> A plane that extends in the X and Y axes (normal vector points +Z). </constant> </constants> diff --git a/doc/classes/PlaneMesh.xml b/doc/classes/PlaneMesh.xml index 333d687e91..56bf98772b 100644 --- a/doc/classes/PlaneMesh.xml +++ b/doc/classes/PlaneMesh.xml @@ -12,7 +12,10 @@ <methods> </methods> <members> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 2, 2 )"> + <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)"> + Offset of the generated plane. Useful for particles. + </member> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(2, 2)"> Size of the generated plane. </member> <member name="subdivide_depth" type="int" setter="set_subdivide_depth" getter="get_subdivide_depth" default="0"> diff --git a/doc/classes/PointLight2D.xml b/doc/classes/PointLight2D.xml index 9337bc8351..a7207a3c80 100644 --- a/doc/classes/PointLight2D.xml +++ b/doc/classes/PointLight2D.xml @@ -12,7 +12,7 @@ <member name="height" type="float" setter="set_height" getter="get_height" default="0.0"> The height of the light. Used with 2D normal mapping. </member> - <member name="offset" type="Vector2" setter="set_texture_offset" getter="get_texture_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_texture_offset" getter="get_texture_offset" default="Vector2(0, 0)"> The offset of the light's [member texture]. </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> diff --git a/doc/classes/Polygon2D.xml b/doc/classes/Polygon2D.xml index 3aca83658d..5a53063148 100644 --- a/doc/classes/Polygon2D.xml +++ b/doc/classes/Polygon2D.xml @@ -88,9 +88,9 @@ <member name="antialiased" type="bool" setter="set_antialiased" getter="get_antialiased" default="false"> If [code]true[/code], polygon edges will be anti-aliased. </member> - <member name="bones" type="Array" setter="_set_bones" getter="_get_bones" default="[ ]"> + <member name="bones" type="Array" setter="_set_bones" getter="_get_bones" default="[]"> </member> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 1, 1, 1, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)"> The polygon's fill color. If [code]texture[/code] is defined, it will be multiplied by this color. It will also be the default color for vertices not set in [code]vertex_colors[/code]. </member> <member name="internal_vertex_count" type="int" setter="set_internal_vertex_count" getter="get_internal_vertex_count" default="0"> @@ -101,36 +101,33 @@ <member name="invert_enable" type="bool" setter="set_invert" getter="get_invert" default="false"> If [code]true[/code], polygon will be inverted, containing the area outside the defined points and extending to the [code]invert_border[/code]. </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The offset applied to each vertex. </member> - <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( )"> + <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array()"> The polygon's list of vertices. The final point will be connected to the first. [b]Note:[/b] This returns a copy of the [PackedVector2Array] rather than a reference. </member> - <member name="polygons" type="Array" setter="set_polygons" getter="get_polygons" default="[ ]"> + <member name="polygons" type="Array" setter="set_polygons" getter="get_polygons" default="[]"> </member> <member name="skeleton" type="NodePath" setter="set_skeleton" getter="get_skeleton" default="NodePath("")"> </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> The polygon's fill texture. Use [code]uv[/code] to set texture coordinates. </member> - <member name="texture_offset" type="Vector2" setter="set_texture_offset" getter="get_texture_offset" default="Vector2( 0, 0 )"> + <member name="texture_offset" type="Vector2" setter="set_texture_offset" getter="get_texture_offset" default="Vector2(0, 0)"> Amount to offset the polygon's [code]texture[/code]. If [code](0, 0)[/code] the texture's origin (its top-left corner) will be placed at the polygon's [code]position[/code]. </member> - <member name="texture_rotation" type="float" setter="set_texture_rotation" getter="get_texture_rotation"> + <member name="texture_rotation" type="float" setter="set_texture_rotation" getter="get_texture_rotation" default="0.0"> The texture's rotation in radians. </member> - <member name="texture_rotation_degrees" type="float" setter="set_texture_rotation_degrees" getter="get_texture_rotation_degrees" default="0.0"> - The texture's rotation in degrees. - </member> - <member name="texture_scale" type="Vector2" setter="set_texture_scale" getter="get_texture_scale" default="Vector2( 1, 1 )"> + <member name="texture_scale" type="Vector2" setter="set_texture_scale" getter="get_texture_scale" default="Vector2(1, 1)"> Amount to multiply the [code]uv[/code] coordinates when using a [code]texture[/code]. Larger values make the texture smaller, and vice versa. </member> - <member name="uv" type="PackedVector2Array" setter="set_uv" getter="get_uv" default="PackedVector2Array( )"> + <member name="uv" type="PackedVector2Array" setter="set_uv" getter="get_uv" default="PackedVector2Array()"> Texture coordinates for each vertex of the polygon. There should be one [code]uv[/code] per polygon vertex. If there are fewer, undefined vertices will use [code](0, 0)[/code]. </member> - <member name="vertex_colors" type="PackedColorArray" setter="set_vertex_colors" getter="get_vertex_colors" default="PackedColorArray( )"> + <member name="vertex_colors" type="PackedColorArray" setter="set_vertex_colors" getter="get_vertex_colors" default="PackedColorArray()"> Color for each vertex. Colors are interpolated between vertices, resulting in smooth gradients. There should be one per polygon vertex. If there are fewer, undefined vertices will use [code]color[/code]. </member> </members> diff --git a/doc/classes/Popup.xml b/doc/classes/Popup.xml index b8d8a55412..89695989c8 100644 --- a/doc/classes/Popup.xml +++ b/doc/classes/Popup.xml @@ -13,6 +13,7 @@ <members> <member name="borderless" type="bool" setter="set_flag" getter="get_flag" override="true" default="true" /> <member name="close_on_parent_focus" type="bool" setter="set_close_on_parent_focus" getter="get_close_on_parent_focus" default="true"> + If [code]true[/code], the [Popup] will close when its parent is focused. </member> <member name="transient" type="bool" setter="set_transient" getter="is_transient" override="true" default="true" /> <member name="unresizable" type="bool" setter="set_flag" getter="get_flag" override="true" default="true" /> diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml index 418785222e..3489c5435a 100644 --- a/doc/classes/PopupMenu.xml +++ b/doc/classes/PopupMenu.xml @@ -260,6 +260,7 @@ <return type="int"> </return> <description> + Returns the index of the currently focused item. Returns [code]-1[/code] if no item is focused. </description> </method> <method name="get_item_accelerator" qualifiers="const"> @@ -717,22 +718,22 @@ <theme_item name="font" type="Font"> [Font] used for the menu items. </theme_item> - <theme_item name="font_accelerator_color" type="Color" default="Color( 0.7, 0.7, 0.7, 0.8 )"> + <theme_item name="font_accelerator_color" type="Color" default="Color(0.7, 0.7, 0.7, 0.8)"> The text [Color] used for shortcuts and accelerators that show next to the menu item name when defined. See [method get_item_accelerator] for more info on accelerators. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> The default text [Color] for menu items' names. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.4, 0.4, 0.4, 0.8 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.4, 0.4, 0.4, 0.8)"> [Color] used for disabled menu items' text. </theme_item> - <theme_item name="font_hover_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_hover_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> [Color] used for the hovered text. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the menu item. </theme_item> - <theme_item name="font_separator_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_separator_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> [Color] used for labeled separators' text. See [method add_separator]. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/PrimitiveMesh.xml b/doc/classes/PrimitiveMesh.xml index 8b73bcb9c1..ca41c367c8 100644 --- a/doc/classes/PrimitiveMesh.xml +++ b/doc/classes/PrimitiveMesh.xml @@ -30,8 +30,8 @@ </method> </methods> <members> - <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB( 0, 0, 0, 0, 0, 0 )"> - Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices. + <member name="custom_aabb" type="AABB" setter="set_custom_aabb" getter="get_custom_aabb" default="AABB(0, 0, 0, 0, 0, 0)"> + Overrides the [AABB] with one defined by user for use with frustum culling. Especially useful to avoid unexpected culling when using a shader to offset vertices. </member> <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false"> If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn. diff --git a/doc/classes/PrismMesh.xml b/doc/classes/PrismMesh.xml index b2e1fdd3f0..0e66281fd1 100644 --- a/doc/classes/PrismMesh.xml +++ b/doc/classes/PrismMesh.xml @@ -14,7 +14,7 @@ <member name="left_to_right" type="float" setter="set_left_to_right" getter="get_left_to_right" default="0.5"> Displacement of the upper edge along the X axis. 0.0 positions edge straight above the bottom-left edge. </member> - <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> + <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)"> Size of the prism. </member> <member name="subdivide_depth" type="int" setter="set_subdivide_depth" getter="get_subdivide_depth" default="0"> diff --git a/doc/classes/ProceduralSkyMaterial.xml b/doc/classes/ProceduralSkyMaterial.xml index d3e1dbca27..c598a2c266 100644 --- a/doc/classes/ProceduralSkyMaterial.xml +++ b/doc/classes/ProceduralSkyMaterial.xml @@ -13,7 +13,7 @@ <methods> </methods> <members> - <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color" default="Color( 0.12, 0.12, 0.13, 1 )"> + <member name="ground_bottom_color" type="Color" setter="set_ground_bottom_color" getter="get_ground_bottom_color" default="Color(0.12, 0.12, 0.13, 1)"> Color of the ground at the bottom. Blends with [member ground_horizon_color]. </member> <member name="ground_curve" type="float" setter="set_ground_curve" getter="get_ground_curve" default="0.02"> @@ -22,7 +22,7 @@ <member name="ground_energy" type="float" setter="set_ground_energy" getter="get_ground_energy" default="1.0"> Amount of energy contribution from the ground. </member> - <member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color" default="Color( 0.37, 0.33, 0.31, 1 )"> + <member name="ground_horizon_color" type="Color" setter="set_ground_horizon_color" getter="get_ground_horizon_color" default="Color(0.37, 0.33, 0.31, 1)"> Color of the ground at the horizon. Blends with [member ground_bottom_color]. </member> <member name="sky_curve" type="float" setter="set_sky_curve" getter="get_sky_curve" default="0.09"> @@ -31,10 +31,10 @@ <member name="sky_energy" type="float" setter="set_sky_energy" getter="get_sky_energy" default="1.0"> Amount of energy contribution from the sky. </member> - <member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color" default="Color( 0.55, 0.69, 0.81, 1 )"> + <member name="sky_horizon_color" type="Color" setter="set_sky_horizon_color" getter="get_sky_horizon_color" default="Color(0.55, 0.69, 0.81, 1)"> Color of the sky at the horizon. Blends with [member sky_top_color]. </member> - <member name="sky_top_color" type="Color" setter="set_sky_top_color" getter="get_sky_top_color" default="Color( 0.35, 0.46, 0.71, 1 )"> + <member name="sky_top_color" type="Color" setter="set_sky_top_color" getter="get_sky_top_color" default="Color(0.35, 0.46, 0.71, 1)"> Color of the sky at the top. Blends with [member sky_horizon_color]. </member> <member name="sun_angle_max" type="float" setter="set_sun_angle_max" getter="get_sun_angle_max" default="100.0"> diff --git a/doc/classes/ProgressBar.xml b/doc/classes/ProgressBar.xml index 160b61c720..c33f6f636d 100644 --- a/doc/classes/ProgressBar.xml +++ b/doc/classes/ProgressBar.xml @@ -29,13 +29,13 @@ <theme_item name="font" type="Font"> Font used to draw the fill percentage if [member percent_visible] is [code]true[/code]. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> The color of the text. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [ProgressBar]. </theme_item> - <theme_item name="font_shadow_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="font_shadow_color" type="Color" default="Color(0, 0, 0, 1)"> The color of the text's shadow. </theme_item> <theme_item name="font_size" type="int"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index a200858a3c..fbd257cdba 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -226,7 +226,7 @@ </method> </methods> <members> - <member name="application/boot_splash/bg_color" type="Color" setter="" getter="" default="Color( 0.14, 0.14, 0.14, 1 )"> + <member name="application/boot_splash/bg_color" type="Color" setter="" getter="" default="Color(0.14, 0.14, 0.14, 1)"> Background color for the boot splash. </member> <member name="application/boot_splash/fullsize" type="bool" setter="" getter="" default="true"> @@ -266,10 +266,12 @@ Icon set in [code].ico[/code] format used on Windows to set the game's icon. This is done automatically on start by calling [method DisplayServer.set_native_icon]. </member> <member name="application/run/disable_stderr" type="bool" setter="" getter="" default="false"> - If [code]true[/code], disables printing to standard error in an exported build. + If [code]true[/code], disables printing to standard error. If [code]true[/code], this also hides error and warning messages printed by [method @GlobalScope.push_error] and [method @GlobalScope.push_warning]. See also [member application/run/disable_stdout]. + Changes to this setting will only be applied upon restarting the application. </member> <member name="application/run/disable_stdout" type="bool" setter="" getter="" default="false"> - If [code]true[/code], disables printing to standard output in an exported build. + If [code]true[/code], disables printing to standard output. This is equivalent to starting the editor or project with the [code]--quiet[/code] command line argument. See also [member application/run/disable_stderr]. + Changes to this setting will only be applied upon restarting the application. </member> <member name="application/run/flush_stdout_on_print" type="bool" setter="" getter="" default="false"> If [code]true[/code], flushes the standard output stream every time a line is printed. This affects both terminal logging and file logging. @@ -309,7 +311,7 @@ If [code]true[/code], microphone input will be allowed. This requires appropriate permissions to be set when exporting to Android or iOS. </member> <member name="audio/driver/mix_rate" type="int" setter="" getter="" default="44100"> - Mixing rate used for audio. In general, it's better to not touch this and leave it to the host operating system. + The mixing rate used for audio (in Hz). In general, it's better to not touch this and leave it to the host operating system. </member> <member name="audio/driver/output_latency" type="int" setter="" getter="" default="15"> Output latency in milliseconds for audio. Lower values will result in lower audio latency at the cost of increased CPU usage. Low values may result in audible cracking on slower hardware. @@ -443,7 +445,7 @@ </member> <member name="debug/settings/fps/force_fps" type="int" setter="" getter="" default="0"> Maximum number of frames per second allowed. The actual number of frames per second may still be below this value if the game is lagging. - If [member display/window/vsync/use_vsync] is enabled, it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate. + If [member display/window/vsync/vsync_mode] is set to [code]Enabled[/code] or [code]Adaptive[/code], it takes precedence and the forced FPS number cannot exceed the monitor's refresh rate. This setting is therefore mostly relevant for lowering the maximum FPS below VSync, e.g. to perform non-real-time rendering of static frames, or test the project under lag conditions. </member> <member name="debug/settings/gdscript/max_call_stack" type="int" setter="" getter="" default="1024"> @@ -461,7 +463,7 @@ <member name="debug/settings/visual_script/max_call_stack" type="int" setter="" getter="" default="1024"> Maximum call stack in visual scripting, to avoid infinite recursion. </member> - <member name="debug/shapes/collision/contact_color" type="Color" setter="" getter="" default="Color( 1, 0.2, 0.1, 0.8 )"> + <member name="debug/shapes/collision/contact_color" type="Color" setter="" getter="" default="Color(1, 0.2, 0.1, 0.8)"> Color of the contact points between collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu. </member> <member name="debug/shapes/collision/draw_2d_outlines" type="bool" setter="" getter="" default="true"> @@ -470,22 +472,22 @@ <member name="debug/shapes/collision/max_contacts_displayed" type="int" setter="" getter="" default="10000"> Maximum number of contact points between collision shapes to display when "Visible Collision Shapes" is enabled in the Debug menu. </member> - <member name="debug/shapes/collision/shape_color" type="Color" setter="" getter="" default="Color( 0, 0.6, 0.7, 0.42 )"> + <member name="debug/shapes/collision/shape_color" type="Color" setter="" getter="" default="Color(0, 0.6, 0.7, 0.42)"> Color of the collision shapes, visible when "Visible Collision Shapes" is enabled in the Debug menu. </member> - <member name="debug/shapes/navigation/disabled_geometry_color" type="Color" setter="" getter="" default="Color( 1, 0.7, 0.1, 0.4 )"> + <member name="debug/shapes/navigation/disabled_geometry_color" type="Color" setter="" getter="" default="Color(1, 0.7, 0.1, 0.4)"> Color of the disabled navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. </member> - <member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color( 0.1, 1, 0.7, 0.4 )"> + <member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)"> Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu. </member> <member name="display/mouse_cursor/custom_image" type="String" setter="" getter="" default=""""> Custom image for the mouse cursor (limited to 256×256). </member> - <member name="display/mouse_cursor/custom_image_hotspot" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> + <member name="display/mouse_cursor/custom_image_hotspot" type="Vector2" setter="" getter="" default="Vector2(0, 0)"> Hotspot for the custom mouse cursor image. </member> - <member name="display/mouse_cursor/tooltip_position_offset" type="Vector2" setter="" getter="" default="Vector2( 10, 10 )"> + <member name="display/mouse_cursor/tooltip_position_offset" type="Vector2" setter="" getter="" default="Vector2(10, 10)"> Position offset for tooltips, relative to the mouse cursor's hotspot. </member> <member name="display/window/dpi/allow_hidpi" type="bool" setter="" getter="" default="false"> @@ -530,12 +532,10 @@ <member name="display/window/size/width" type="int" setter="" getter="" default="1024"> Sets the game's main viewport width. On desktop platforms, this is the default window size. Stretch mode settings also use this as a reference when enabled. </member> - <member name="display/window/vsync/use_vsync" type="bool" setter="" getter="" default="true"> - If [code]true[/code], enables vertical synchronization. This eliminates tearing that may appear in moving scenes, at the cost of higher input latency and stuttering at lower framerates. If [code]false[/code], vertical synchronization will be disabled, however, many platforms will enforce it regardless (such as mobile platforms and HTML5). - </member> - <member name="display/window/vsync/vsync_via_compositor" type="bool" setter="" getter="" default="false"> - If [code]Use Vsync[/code] is enabled and this setting is [code]true[/code], enables vertical synchronization via the operating system's window compositor when in windowed mode and the compositor is enabled. This will prevent stutter in certain situations. (Windows only.) - [b]Note:[/b] This option is experimental and meant to alleviate stutter experienced by some users. However, some users have experienced a Vsync framerate halving (e.g. from 60 FPS to 30 FPS) when using it. + <member name="display/window/vsync/vsync_mode" type="int" setter="" getter="" default="1"> + Sets the VSync mode for the main game window. + See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application. + Depending on the platform and used renderer, the engine will fall back to [code]Enabled[/code], if the desired mode is not supported. </member> <member name="editor/node_naming/name_casing" type="int" setter="" getter="" default="0"> When creating node names automatically, set the type of casing in this project. This is mostly an editor setting. @@ -551,7 +551,7 @@ prime-run %command% [/codeblock] </member> - <member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray( "gd", "shader" )"> + <member name="editor/script/search_in_file_extensions" type="PackedStringArray" setter="" getter="" default="PackedStringArray("gd", "gdshader")"> Text-based file extensions to include in the script editor's "Find in Files" feature. You can add e.g. [code]tscn[/code] if you wish to also parse your scene files, especially if you use built-in scripts which are serialized in the scene files. </member> <member name="editor/script/templates_search_path" type="String" setter="" getter="" default=""res://script_templates""> @@ -739,6 +739,8 @@ If no selection is currently active, selects the word currently under the caret in text fields. If a selection is currently active, deselects the current selection. [b]Note:[/b] Currently, this is only implemented in [TextEdit], not [LineEdit]. </member> + <member name="input/ui_text_submit" type="Dictionary" setter="" getter=""> + </member> <member name="input/ui_text_toggle_insert_mode" type="Dictionary" setter="" getter=""> </member> <member name="input/ui_undo" type="Dictionary" setter="" getter=""> @@ -1139,8 +1141,6 @@ <member name="layer_names/3d_render/layer_9" type="String" setter="" getter="" default=""""> Optional name for the 3D render layer 9. If left empty, the layer will display as "Layer 9". </member> - <member name="memory/limits/command_queue/multithreading_queue_size_kb" type="int" setter="" getter="" default="256"> - </member> <member name="memory/limits/message_queue/max_size_kb" type="int" setter="" getter="" default="4096"> Godot uses a message queue to defer some function calls. If you run out of space on it (you will see an error), you can increase the size here. </member> @@ -1222,7 +1222,7 @@ [/csharp] [/codeblocks] </member> - <member name="physics/2d/default_gravity_vector" type="Vector2" setter="" getter="" default="Vector2( 0, 1 )"> + <member name="physics/2d/default_gravity_vector" type="Vector2" setter="" getter="" default="Vector2(0, 1)"> The default gravity direction in 2D. [b]Note:[/b] This property is only read when the project starts. To change the default gravity vector at runtime, use the following code sample: [codeblocks] @@ -1274,7 +1274,7 @@ [/csharp] [/codeblocks] </member> - <member name="physics/3d/default_gravity_vector" type="Vector3" setter="" getter="" default="Vector3( 0, -1, 0 )"> + <member name="physics/3d/default_gravity_vector" type="Vector3" setter="" getter="" default="Vector3(0, -1, 0)"> The default gravity direction in 3D. [b]Note:[/b] This property is only read when the project starts. To change the default gravity vector at runtime, use the following code sample: [codeblocks] @@ -1313,7 +1313,8 @@ [b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.iterations_per_second] instead. </member> <member name="physics/common/physics_jitter_fix" type="float" setter="" getter="" default="0.5"> - Fix to improve physics jitter, specially on monitors where refresh rate is different than the physics FPS. + Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be fine for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. + [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0[/code]. [b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_jitter_fix] instead. </member> <member name="rendering/2d/sdf/oversize" type="int" setter="" getter="" default="1"> @@ -1365,7 +1366,7 @@ <member name="rendering/driver/threads/thread_model" type="int" setter="" getter="" default="1"> Thread model for rendering. Rendering on a thread can vastly improve performance, but synchronizing to the main thread can cause a bit more jitter. </member> - <member name="rendering/environment/defaults/default_clear_color" type="Color" setter="" getter="" default="Color( 0.3, 0.3, 0.3, 1 )"> + <member name="rendering/environment/defaults/default_clear_color" type="Color" setter="" getter="" default="Color(0.3, 0.3, 0.3, 1)"> Default background clear color. Overridable per [Viewport] using its [Environment]. See [member Environment.background_mode] and [member Environment.background_color] in particular. To change this default color programmatically, use [method RenderingServer.set_default_clear_color]. </member> <member name="rendering/environment/defaults/default_environment" type="String" setter="" getter="" default=""""> @@ -1421,18 +1422,14 @@ </member> <member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false"> </member> - <member name="rendering/global_illumination/gi_probes/anisotropic" type="bool" setter="" getter="" default="false"> - If [code]true[/code], take additional samples when rendering objects affected by a [GIProbe] to reduce artifacts from only sampling in one direction. - </member> - <member name="rendering/global_illumination/gi_probes/quality" type="int" setter="" getter="" default="1"> - Sets the number of cone samples taken when rendering objects affected by [GIProbe]s. - </member> <member name="rendering/global_illumination/sdfgi/frames_to_converge" type="int" setter="" getter="" default="4"> </member> <member name="rendering/global_illumination/sdfgi/frames_to_update_lights" type="int" setter="" getter="" default="2"> </member> <member name="rendering/global_illumination/sdfgi/probe_ray_count" type="int" setter="" getter="" default="1"> </member> + <member name="rendering/global_illumination/voxel_gi/quality" type="int" setter="" getter="" default="1"> + </member> <member name="rendering/lightmapping/bake_performance/max_rays_per_pass" type="int" setter="" getter="" default="32"> </member> <member name="rendering/lightmapping/bake_performance/max_rays_per_probe_pass" type="int" setter="" getter="" default="64"> @@ -1578,20 +1575,31 @@ <member name="rendering/textures/default_filters/use_nearest_mipmap_filter" type="bool" setter="" getter="" default="false"> If [code]true[/code], uses nearest-neighbor mipmap filtering when using mipmaps (also called "bilinear filtering"), which will result in visible seams appearing between mipmap stages. This may increase performance in mobile as less memory bandwidth is used. If [code]false[/code], linear mipmap filtering (also called "trilinear filtering") is used. </member> + <member name="rendering/textures/lossless_compression/force_png" type="bool" setter="" getter="" default="false"> + If [code]true[/code], the texture importer will import lossless textures using the PNG format. Otherwise, it will default to using WebP. + </member> + <member name="rendering/textures/lossless_compression/webp_compression_level" type="int" setter="" getter="" default="2"> + The default compression level for lossless WebP. Higher levels result in smaller files at the cost of compression speed. Decompression speed is mostly unaffected by the compression level. Supported values are 0 to 9. Note that compression levels above 6 are very slow and offer very little savings. + </member> <member name="rendering/textures/vram_compression/import_bptc" type="bool" setter="" getter="" default="false"> If [code]true[/code], the texture importer will import VRAM-compressed textures using the BPTC algorithm. This texture compression algorithm is only supported on desktop platforms, and only when using the Vulkan renderer. + [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor. </member> <member name="rendering/textures/vram_compression/import_etc" type="bool" setter="" getter="" default="false"> If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression algorithm. This algorithm doesn't support alpha channels in textures. + [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor. </member> <member name="rendering/textures/vram_compression/import_etc2" type="bool" setter="" getter="" default="true"> If [code]true[/code], the texture importer will import VRAM-compressed textures using the Ericsson Texture Compression 2 algorithm. This texture compression algorithm is only supported when using the Vulkan renderer. + [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor. </member> <member name="rendering/textures/vram_compression/import_pvrtc" type="bool" setter="" getter="" default="false"> If [code]true[/code], the texture importer will import VRAM-compressed textures using the PowerVR Texture Compression algorithm. This texture compression algorithm is only supported on iOS. + [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor. </member> <member name="rendering/textures/vram_compression/import_s3tc" type="bool" setter="" getter="" default="true"> If [code]true[/code], the texture importer will import VRAM-compressed textures using the S3 Texture Compression algorithm. This algorithm is only supported on desktop platforms and consoles. + [b]Note:[/b] Changing this setting does [i]not[/i] impact textures that were already imported before. To make this setting apply to textures that were already imported, exit the editor, remove the [code].godot/imported/[/code] folder located inside the project folder then restart the editor. </member> <member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64"> </member> @@ -1605,8 +1613,8 @@ </member> <member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64"> </member> - <member name="world/2d/cell_size" type="int" setter="" getter="" default="100"> - Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels). + <member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false"> + If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled. </member> </members> <constants> diff --git a/doc/classes/PropertyTweener.xml b/doc/classes/PropertyTweener.xml new file mode 100644 index 0000000000..1e77bb33c6 --- /dev/null +++ b/doc/classes/PropertyTweener.xml @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="PropertyTweener" inherits="Tweener" version="4.0"> + <brief_description> + Interpolates an [Object]'s property over time. + </brief_description> + <description> + [PropertyTweener] is used to interpolate a property in an object. See [method Tween.tween_property] for more usage information. + [b]Note:[/b] [method Tween.tween_property] is the only correct way to create [PropertyTweener]. Any [PropertyTweener] created manually will not function correctly. + </description> + <tutorials> + </tutorials> + <methods> + <method name="as_relative"> + <return type="PropertyTweener"> + </return> + <description> + When called, the final value will be used as a relative value instead. Example: + [codeblock] + var tween = get_tree().create_tween() + tween.tween_property(self, "position", Vector2.RIGHT * 100, 1).as_relative() #the node will move by 100 pixels to the right + [/codeblock] + </description> + </method> + <method name="from"> + <return type="PropertyTweener"> + </return> + <argument index="0" name="value" type="Variant"> + </argument> + <description> + Sets a custom initial value to the [PropertyTweener]. Example: + [codeblock] + var tween = get_tree().create_tween() + tween.tween_property(self, "position", Vector2(200, 100), 1).from(Vector2(100, 100) #this will move the node from position (100, 100) to (200, 100) + [/codeblock] + </description> + </method> + <method name="from_current"> + <return type="PropertyTweener"> + </return> + <description> + Makes the [PropertyTweener] use the current property value (i.e. at the time of creating this [PropertyTweener]) as a starting point. This is equivalent of using [method from] with the current value. These two calls will do the same: + [codeblock] + tween.tween_property(self, "position", Vector2(200, 100), 1).from(position) + tween.tween_property(self, "position", Vector2(200, 100), 1).from_current() + [/codeblock] + </description> + </method> + <method name="set_delay"> + <return type="PropertyTweener"> + </return> + <argument index="0" name="delay" type="float"> + </argument> + <description> + Sets the time in seconds after which the [PropertyTweener] will start interpolating. By default there's no delay. + </description> + </method> + <method name="set_ease"> + <return type="PropertyTweener"> + </return> + <argument index="0" name="ease" type="int" enum="Tween.EaseType"> + </argument> + <description> + Sets the type of used easing from [enum Tween.EaseType]. If not set, the default easing is used from the [Tween] that contains this Tweener. + </description> + </method> + <method name="set_trans"> + <return type="PropertyTweener"> + </return> + <argument index="0" name="trans" type="int" enum="Tween.TransitionType"> + </argument> + <description> + Sets the type of used transition from [enum Tween.TransitionType]. If not set, the default transition is used from the [Tween] that contains this Tweener. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/ProximityGroup3D.xml b/doc/classes/ProximityGroup3D.xml index 512d55c9a0..22e397b832 100644 --- a/doc/classes/ProximityGroup3D.xml +++ b/doc/classes/ProximityGroup3D.xml @@ -23,7 +23,7 @@ <members> <member name="dispatch_mode" type="int" setter="set_dispatch_mode" getter="get_dispatch_mode" enum="ProximityGroup3D.DispatchMode" default="0"> </member> - <member name="grid_radius" type="Vector3" setter="set_grid_radius" getter="get_grid_radius" default="Vector3( 1, 1, 1 )"> + <member name="grid_radius" type="Vector3" setter="set_grid_radius" getter="get_grid_radius" default="Vector3(1, 1, 1)"> </member> <member name="group_name" type="String" setter="set_group_name" getter="get_group_name" default=""""> </member> diff --git a/doc/classes/QuadMesh.xml b/doc/classes/QuadMesh.xml index 24a3d76ee2..4209e3db14 100644 --- a/doc/classes/QuadMesh.xml +++ b/doc/classes/QuadMesh.xml @@ -13,7 +13,10 @@ <methods> </methods> <members> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 1, 1 )"> + <member name="center_offset" type="Vector3" setter="set_center_offset" getter="get_center_offset" default="Vector3(0, 0, 0)"> + Offset of the generated Quad. Useful for particles. + </member> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(1, 1)"> Size on the X and Y axes. </member> </members> diff --git a/doc/classes/Quat.xml b/doc/classes/Quaternion.xml index 1c0a3e37c0..06434ab268 100644 --- a/doc/classes/Quat.xml +++ b/doc/classes/Quaternion.xml @@ -1,11 +1,11 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Quat" version="4.0"> +<class name="Quaternion" version="4.0"> <brief_description> Quaternion. </brief_description> <description> A unit quaternion used for representing 3D rotations. Quaternions need to be normalized to be used for rotation. - It is similar to Basis, which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. Basis stores rotation, scale, and shearing, while Quat only stores rotation. + It is similar to Basis, which implements matrix representation of rotations, and can be parametrized using both an axis-angle pair or Euler angles. Basis stores rotation, scale, and shearing, while Quaternion only stores rotation. Due to its compactness and the way it is stored in memory, certain operations (obtaining axis-angle and performing SLERP, in particular) are more efficient and robust against floating-point errors. </description> <tutorials> @@ -13,24 +13,24 @@ <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> </tutorials> <methods> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> <description> Constructs a default-initialized quaternion with all components set to [code]0[/code]. </description> </method> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> - <argument index="0" name="from" type="Quat"> + <argument index="0" name="from" type="Quaternion"> </argument> <description> - Constructs a [Quat] as a copy of the given [Quat]. + Constructs a [Quaternion] as a copy of the given [Quaternion]. </description> </method> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> <argument index="0" name="arc_from" type="Vector3"> </argument> @@ -39,8 +39,8 @@ <description> </description> </method> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> <argument index="0" name="axis" type="Vector3"> </argument> @@ -50,8 +50,8 @@ Constructs a quaternion that will rotate around the given axis by the specified angle. The axis must be a normalized vector. </description> </method> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> <argument index="0" name="euler" type="Vector3"> </argument> @@ -59,8 +59,8 @@ Constructs a quaternion that will perform a rotation specified by Euler angles (in the YXZ convention: when decomposing, first Z, then X, and Y last), given in the vector format as (X angle, Y angle, Z angle). </description> </method> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> <argument index="0" name="from" type="Basis"> </argument> @@ -68,8 +68,8 @@ Constructs a quaternion from the given [Basis]. </description> </method> - <method name="Quat" qualifiers="constructor"> - <return type="Quat"> + <method name="Quaternion" qualifiers="constructor"> + <return type="Quaternion"> </return> <argument index="0" name="x" type="float"> </argument> @@ -83,14 +83,24 @@ Constructs a quaternion defined by the given values. </description> </method> + <method name="angle_to" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="to" type="Quaternion"> + </argument> + <description> + Returns the angle between this quaternion and [code]to[/code]. This is the magnitude of the angle you would need to rotate by to get from one to the other. + [b]Note:[/b] This method has an abnormally high amount of floating-point error, so methods such as [code]is_zero_approx[/code] will not work reliably. + </description> + </method> <method name="cubic_slerp" qualifiers="const"> - <return type="Quat"> + <return type="Quaternion"> </return> - <argument index="0" name="b" type="Quat"> + <argument index="0" name="b" type="Quaternion"> </argument> - <argument index="1" name="pre_a" type="Quat"> + <argument index="1" name="pre_a" type="Quaternion"> </argument> - <argument index="2" name="post_b" type="Quat"> + <argument index="2" name="post_b" type="Quaternion"> </argument> <argument index="3" name="weight" type="float"> </argument> @@ -101,7 +111,7 @@ <method name="dot" qualifiers="const"> <return type="float"> </return> - <argument index="0" name="with" type="Quat"> + <argument index="0" name="with" type="Quaternion"> </argument> <description> Returns the dot product of two quaternions. @@ -115,7 +125,7 @@ </description> </method> <method name="inverse" qualifiers="const"> - <return type="Quat"> + <return type="Quaternion"> </return> <description> Returns the inverse of the quaternion. @@ -124,7 +134,7 @@ <method name="is_equal_approx" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="to" type="Quat"> + <argument index="0" name="to" type="Quaternion"> </argument> <description> Returns [code]true[/code] if this quaternion and [code]quat[/code] are approximately equal, by running [method @GlobalScope.is_equal_approx] on each component. @@ -152,7 +162,7 @@ </description> </method> <method name="normalized" qualifiers="const"> - <return type="Quat"> + <return type="Quaternion"> </return> <description> Returns a copy of the quaternion, normalized to unit length. @@ -161,29 +171,29 @@ <method name="operator !=" qualifiers="operator"> <return type="bool"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Quat"> + <return type="Vector3"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Vector3"> </argument> <description> </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Vector3"> + <return type="Quaternion"> </return> - <argument index="0" name="right" type="Vector3"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> <argument index="0" name="right" type="float"> </argument> @@ -191,7 +201,7 @@ </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> <argument index="0" name="right" type="int"> </argument> @@ -199,35 +209,23 @@ </description> </method> <method name="operator +" qualifiers="operator"> - <return type="Quat"> - </return> - <description> - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> </description> </method> <method name="operator -" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> - <description> - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="Quat"> - </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> </description> </method> <method name="operator /" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> <argument index="0" name="right" type="float"> </argument> @@ -235,7 +233,7 @@ </description> </method> <method name="operator /" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> <argument index="0" name="right" type="int"> </argument> @@ -245,7 +243,7 @@ <method name="operator ==" qualifiers="operator"> <return type="bool"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> </description> @@ -258,10 +256,22 @@ <description> </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="Quaternion"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="Quaternion"> + </return> + <description> + </description> + </method> <method name="slerp" qualifiers="const"> - <return type="Quat"> + <return type="Quaternion"> </return> - <argument index="0" name="to" type="Quat"> + <argument index="0" name="to" type="Quaternion"> </argument> <argument index="1" name="weight" type="float"> </argument> @@ -271,9 +281,9 @@ </description> </method> <method name="slerpni" qualifiers="const"> - <return type="Quat"> + <return type="Quaternion"> </return> - <argument index="0" name="to" type="Quat"> + <argument index="0" name="to" type="Quaternion"> </argument> <argument index="1" name="weight" type="float"> </argument> @@ -301,7 +311,7 @@ </member> </members> <constants> - <constant name="IDENTITY" value="Quat( 0, 0, 0, 1 )"> + <constant name="IDENTITY" value="Quaternion(0, 0, 0, 1)"> The identity quaternion, representing no rotation. Equivalent to an identity [Basis] matrix. If a vector is transformed by an identity quaternion, it will not change. </constant> </constants> diff --git a/doc/classes/RDAttachmentFormat.xml b/doc/classes/RDAttachmentFormat.xml index 4ee7b9b28e..b73377bf77 100644 --- a/doc/classes/RDAttachmentFormat.xml +++ b/doc/classes/RDAttachmentFormat.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDAttachmentFormat" inherits="Reference" version="4.0"> +<class name="RDAttachmentFormat" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDFramebufferPass.xml b/doc/classes/RDFramebufferPass.xml new file mode 100644 index 0000000000..c26c41f93f --- /dev/null +++ b/doc/classes/RDFramebufferPass.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="RDFramebufferPass" inherits="RefCounted" version="4.0"> + <brief_description> + Framebuffer pass attachment description. + </brief_description> + <description> + This class contains the list of attachment descriptions for a framebuffer pass. Each points with an index to a previously supplied list of texture attachments. + Multipass framebuffers can optimize some configurations in mobile, on desktop they provide little to no advantage. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="color_attachments" type="PackedInt32Array" setter="set_color_attachments" getter="get_color_attachments" default="PackedInt32Array()"> + Color attachments in order starting from 0. If this attachment is not used by the shader, pass ATTACHMENT_UNUSED to skip. + </member> + <member name="depth_attachment" type="int" setter="set_depth_attachment" getter="get_depth_attachment" default="-1"> + Depth attachment. ATTACHMENT_UNUSED should be used if no depth buffer is required for this pass. + </member> + <member name="input_attachments" type="PackedInt32Array" setter="set_input_attachments" getter="get_input_attachments" default="PackedInt32Array()"> + Used for multipass framebuffers (more than one render pass). Converts an attachment to an input. Make sure to also supply it properly in the [RDUniform] for the uniform set. + </member> + <member name="preserve_attachments" type="PackedInt32Array" setter="set_preserve_attachments" getter="get_preserve_attachments" default="PackedInt32Array()"> + Attachments to preserve in this pass (otherwise they are erased). + </member> + <member name="resolve_attachments" type="PackedInt32Array" setter="set_resolve_attachments" getter="get_resolve_attachments" default="PackedInt32Array()"> + If the color attachments are multisampled, non-multisampled resolve attachments can be provided. + </member> + </members> + <constants> + <constant name="ATTACHMENT_UNUSED" value="-1"> + </constant> + </constants> +</class> diff --git a/doc/classes/RDPipelineColorBlendState.xml b/doc/classes/RDPipelineColorBlendState.xml index adc6f1f6a3..b672a053c7 100644 --- a/doc/classes/RDPipelineColorBlendState.xml +++ b/doc/classes/RDPipelineColorBlendState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDPipelineColorBlendState" inherits="Reference" version="4.0"> +<class name="RDPipelineColorBlendState" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> @@ -9,9 +9,9 @@ <methods> </methods> <members> - <member name="attachments" type="RDPipelineColorBlendStateAttachment[]" setter="set_attachments" getter="get_attachments" default="[ ]"> + <member name="attachments" type="RDPipelineColorBlendStateAttachment[]" setter="set_attachments" getter="get_attachments" default="[]"> </member> - <member name="blend_constant" type="Color" setter="set_blend_constant" getter="get_blend_constant" default="Color( 0, 0, 0, 1 )"> + <member name="blend_constant" type="Color" setter="set_blend_constant" getter="get_blend_constant" default="Color(0, 0, 0, 1)"> </member> <member name="enable_logic_op" type="bool" setter="set_enable_logic_op" getter="get_enable_logic_op" default="false"> </member> diff --git a/doc/classes/RDPipelineColorBlendStateAttachment.xml b/doc/classes/RDPipelineColorBlendStateAttachment.xml index 7f118b5f0b..a6a1900cb5 100644 --- a/doc/classes/RDPipelineColorBlendStateAttachment.xml +++ b/doc/classes/RDPipelineColorBlendStateAttachment.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDPipelineColorBlendStateAttachment" inherits="Reference" version="4.0"> +<class name="RDPipelineColorBlendStateAttachment" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDPipelineDepthStencilState.xml b/doc/classes/RDPipelineDepthStencilState.xml index 562ff52819..76e0506bca 100644 --- a/doc/classes/RDPipelineDepthStencilState.xml +++ b/doc/classes/RDPipelineDepthStencilState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDPipelineDepthStencilState" inherits="Reference" version="4.0"> +<class name="RDPipelineDepthStencilState" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDPipelineMultisampleState.xml b/doc/classes/RDPipelineMultisampleState.xml index 4658c7d9ba..b4345f1f8b 100644 --- a/doc/classes/RDPipelineMultisampleState.xml +++ b/doc/classes/RDPipelineMultisampleState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDPipelineMultisampleState" inherits="Reference" version="4.0"> +<class name="RDPipelineMultisampleState" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> @@ -19,7 +19,7 @@ </member> <member name="sample_count" type="int" setter="set_sample_count" getter="get_sample_count" enum="RenderingDevice.TextureSamples" default="0"> </member> - <member name="sample_masks" type="int[]" setter="set_sample_masks" getter="get_sample_masks" default="[ ]"> + <member name="sample_masks" type="int[]" setter="set_sample_masks" getter="get_sample_masks" default="[]"> </member> </members> <constants> diff --git a/doc/classes/RDPipelineRasterizationState.xml b/doc/classes/RDPipelineRasterizationState.xml index 5064dd6deb..3f8c50cf42 100644 --- a/doc/classes/RDPipelineRasterizationState.xml +++ b/doc/classes/RDPipelineRasterizationState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDPipelineRasterizationState" inherits="Reference" version="4.0"> +<class name="RDPipelineRasterizationState" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDPipelineSpecializationConstant.xml b/doc/classes/RDPipelineSpecializationConstant.xml new file mode 100644 index 0000000000..4d9481b846 --- /dev/null +++ b/doc/classes/RDPipelineSpecializationConstant.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="RDPipelineSpecializationConstant" inherits="RefCounted" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="constant_id" type="int" setter="set_constant_id" getter="get_constant_id" default="0"> + </member> + <member name="value" type="Variant" setter="set_value" getter="get_value"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/RDSamplerState.xml b/doc/classes/RDSamplerState.xml index ab31960b7c..9a9d55948c 100644 --- a/doc/classes/RDSamplerState.xml +++ b/doc/classes/RDSamplerState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDSamplerState" inherits="Reference" version="4.0"> +<class name="RDSamplerState" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDShaderBytecode.xml b/doc/classes/RDShaderBytecode.xml index 7a3501004e..20bf9bdd72 100644 --- a/doc/classes/RDShaderBytecode.xml +++ b/doc/classes/RDShaderBytecode.xml @@ -45,15 +45,15 @@ </method> </methods> <members> - <member name="bytecode_compute" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray( )"> + <member name="bytecode_compute" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()"> </member> - <member name="bytecode_fragment" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray( )"> + <member name="bytecode_fragment" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()"> </member> - <member name="bytecode_tesselation_control" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray( )"> + <member name="bytecode_tesselation_control" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()"> </member> - <member name="bytecode_tesselation_evaluation" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray( )"> + <member name="bytecode_tesselation_evaluation" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()"> </member> - <member name="bytecode_vertex" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray( )"> + <member name="bytecode_vertex" type="PackedByteArray" setter="set_stage_bytecode" getter="get_stage_bytecode" default="PackedByteArray()"> </member> <member name="compile_error_compute" type="String" setter="set_stage_compile_error" getter="get_stage_compile_error" default=""""> </member> diff --git a/doc/classes/RDShaderFile.xml b/doc/classes/RDShaderFile.xml index 14e70d53ea..346a97a1c0 100644 --- a/doc/classes/RDShaderFile.xml +++ b/doc/classes/RDShaderFile.xml @@ -10,7 +10,7 @@ <method name="get_bytecode" qualifiers="const"> <return type="RDShaderBytecode"> </return> - <argument index="0" name="version" type="StringName" default="@"""> + <argument index="0" name="version" type="StringName" default="&"""> </argument> <description> </description> @@ -26,7 +26,7 @@ </return> <argument index="0" name="bytecode" type="RDShaderBytecode"> </argument> - <argument index="1" name="version" type="StringName" default="@"""> + <argument index="1" name="version" type="StringName" default="&"""> </argument> <description> </description> diff --git a/doc/classes/RDShaderSource.xml b/doc/classes/RDShaderSource.xml index c1cfd34bb7..68fc43d8ef 100644 --- a/doc/classes/RDShaderSource.xml +++ b/doc/classes/RDShaderSource.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDShaderSource" inherits="Reference" version="4.0"> +<class name="RDShaderSource" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDTextureFormat.xml b/doc/classes/RDTextureFormat.xml index e41ddff368..ccfa6d1b95 100644 --- a/doc/classes/RDTextureFormat.xml +++ b/doc/classes/RDTextureFormat.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDTextureFormat" inherits="Reference" version="4.0"> +<class name="RDTextureFormat" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDTextureView.xml b/doc/classes/RDTextureView.xml index 73b2a7ae4a..db140ae775 100644 --- a/doc/classes/RDTextureView.xml +++ b/doc/classes/RDTextureView.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDTextureView" inherits="Reference" version="4.0"> +<class name="RDTextureView" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDUniform.xml b/doc/classes/RDUniform.xml index bc8a21e985..666935d663 100644 --- a/doc/classes/RDUniform.xml +++ b/doc/classes/RDUniform.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDUniform" inherits="Reference" version="4.0"> +<class name="RDUniform" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RDVertexAttribute.xml b/doc/classes/RDVertexAttribute.xml index 56fe40b51d..3499918cc8 100644 --- a/doc/classes/RDVertexAttribute.xml +++ b/doc/classes/RDVertexAttribute.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RDVertexAttribute" inherits="Reference" version="4.0"> +<class name="RDVertexAttribute" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/RandomNumberGenerator.xml b/doc/classes/RandomNumberGenerator.xml index 6312cd18aa..9c84cdd03e 100644 --- a/doc/classes/RandomNumberGenerator.xml +++ b/doc/classes/RandomNumberGenerator.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RandomNumberGenerator" inherits="Reference" version="4.0"> +<class name="RandomNumberGenerator" inherits="RefCounted" version="4.0"> <brief_description> A class for generating pseudo-random numbers. </brief_description> @@ -23,7 +23,7 @@ <return type="float"> </return> <description> - Generates a pseudo-random float between [code]0.0[/code] and [code]1.0[/code] (inclusive). + Returns a pseudo-random float between [code]0.0[/code] and [code]1.0[/code] (inclusive). </description> </method> <method name="randf_range"> @@ -34,7 +34,7 @@ <argument index="1" name="to" type="float"> </argument> <description> - Generates a pseudo-random float between [code]from[/code] and [code]to[/code] (inclusive). + Returns a pseudo-random float between [code]from[/code] and [code]to[/code] (inclusive). </description> </method> <method name="randfn"> @@ -45,14 +45,14 @@ <argument index="1" name="deviation" type="float" default="1.0"> </argument> <description> - Generates a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-distributed[/url] pseudo-random number, using Box-Muller transform with the specified [code]mean[/code] and a standard [code]deviation[/code]. This is also called Gaussian distribution. + Returns a [url=https://en.wikipedia.org/wiki/Normal_distribution]normally-distributed[/url] pseudo-random number, using Box-Muller transform with the specified [code]mean[/code] and a standard [code]deviation[/code]. This is also called Gaussian distribution. </description> </method> <method name="randi"> <return type="int"> </return> <description> - Generates a pseudo-random 32-bit unsigned integer between [code]0[/code] and [code]4294967295[/code] (inclusive). + Returns a pseudo-random 32-bit unsigned integer between [code]0[/code] and [code]4294967295[/code] (inclusive). </description> </method> <method name="randi_range"> @@ -63,14 +63,14 @@ <argument index="1" name="to" type="int"> </argument> <description> - Generates a pseudo-random 32-bit signed integer between [code]from[/code] and [code]to[/code] (inclusive). + Returns a pseudo-random 32-bit signed integer between [code]from[/code] and [code]to[/code] (inclusive). </description> </method> <method name="randomize"> <return type="void"> </return> <description> - Setups a time-based seed to generator. + Setups a time-based seed to for this [RandomNumberGenerator] instance. Unlike the [@GlobalScope] random number generation functions, different [RandomNumberGenerator] instances can use different seeds. </description> </method> </methods> diff --git a/doc/classes/RayCast2D.xml b/doc/classes/RayCast2D.xml index e30d7df63f..14b67b46df 100644 --- a/doc/classes/RayCast2D.xml +++ b/doc/classes/RayCast2D.xml @@ -138,7 +138,7 @@ <member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true"> If [code]true[/code], the parent node will be excluded from collision detection. </member> - <member name="target_position" type="Vector2" setter="set_target_position" getter="get_target_position" default="Vector2( 0, 50 )"> + <member name="target_position" type="Vector2" setter="set_target_position" getter="get_target_position" default="Vector2(0, 50)"> The ray's destination point, relative to the RayCast's [code]position[/code]. </member> </members> diff --git a/doc/classes/RayCast3D.xml b/doc/classes/RayCast3D.xml index 443890438f..98c8c96403 100644 --- a/doc/classes/RayCast3D.xml +++ b/doc/classes/RayCast3D.xml @@ -136,7 +136,7 @@ <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1"> The ray's collision mask. Only objects in at least one collision layer enabled in the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information. </member> - <member name="debug_shape_custom_color" type="Color" setter="set_debug_shape_custom_color" getter="get_debug_shape_custom_color" default="Color( 0, 0, 0, 1 )"> + <member name="debug_shape_custom_color" type="Color" setter="set_debug_shape_custom_color" getter="get_debug_shape_custom_color" default="Color(0, 0, 0, 1)"> The custom color to use to draw the shape in the editor and at run-time if [b]Visible Collision Shapes[/b] is enabled in the [b]Debug[/b] menu. This color will be highlighted at run-time if the [RayCast3D] is colliding with something. If set to [code]Color(0.0, 0.0, 0.0)[/code] (by default), the color set in [member ProjectSettings.debug/shapes/collision/shape_color] is used. </member> @@ -149,7 +149,7 @@ <member name="exclude_parent" type="bool" setter="set_exclude_parent_body" getter="get_exclude_parent_body" default="true"> If [code]true[/code], collisions will be ignored for this RayCast3D's immediate parent. </member> - <member name="target_position" type="Vector3" setter="set_target_position" getter="get_target_position" default="Vector3( 0, -1, 0 )"> + <member name="target_position" type="Vector3" setter="set_target_position" getter="get_target_position" default="Vector3(0, -1, 0)"> The ray's destination point, relative to the RayCast's [code]position[/code]. </member> </members> diff --git a/doc/classes/Rect2.xml b/doc/classes/Rect2.xml index 352a18e326..627c488b01 100644 --- a/doc/classes/Rect2.xml +++ b/doc/classes/Rect2.xml @@ -214,13 +214,13 @@ </method> </methods> <members> - <member name="end" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> + <member name="end" type="Vector2" setter="" getter="" default="Vector2(0, 0)"> Ending corner. This is calculated as [code]position + size[/code]. Setting this value will change the size. </member> - <member name="position" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> + <member name="position" type="Vector2" setter="" getter="" default="Vector2(0, 0)"> Beginning corner. Typically has values lower than [member end]. </member> - <member name="size" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> + <member name="size" type="Vector2" setter="" getter="" default="Vector2(0, 0)"> Size from [member position] to [member end]. Typically, all components are positive. If the size is negative, you can use [method abs] to fix it. </member> diff --git a/doc/classes/Rect2i.xml b/doc/classes/Rect2i.xml index 84bef9b406..67d148084f 100644 --- a/doc/classes/Rect2i.xml +++ b/doc/classes/Rect2i.xml @@ -193,13 +193,13 @@ </method> </methods> <members> - <member name="end" type="Vector2i" setter="" getter="" default="Vector2i( 0, 0 )"> + <member name="end" type="Vector2i" setter="" getter="" default="Vector2i(0, 0)"> Ending corner. This is calculated as [code]position + size[/code]. Setting this value will change the size. </member> - <member name="position" type="Vector2i" setter="" getter="" default="Vector2i( 0, 0 )"> + <member name="position" type="Vector2i" setter="" getter="" default="Vector2i(0, 0)"> Beginning corner. Typically has values lower than [member end]. </member> - <member name="size" type="Vector2i" setter="" getter="" default="Vector2i( 0, 0 )"> + <member name="size" type="Vector2i" setter="" getter="" default="Vector2i(0, 0)"> Size from [member position] to [member end]. Typically, all components are positive. If the size is negative, you can use [method abs] to fix it. </member> diff --git a/doc/classes/RectangleShape2D.xml b/doc/classes/RectangleShape2D.xml index 8e37fbad6f..f2795ae4a1 100644 --- a/doc/classes/RectangleShape2D.xml +++ b/doc/classes/RectangleShape2D.xml @@ -13,7 +13,7 @@ <methods> </methods> <members> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 20, 20 )"> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(20, 20)"> The rectangle's width and height. </member> </members> diff --git a/doc/classes/Reference.xml b/doc/classes/RefCounted.xml index 724d2db924..cf96514203 100644 --- a/doc/classes/Reference.xml +++ b/doc/classes/RefCounted.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Reference" inherits="Object" version="4.0"> +<class name="RefCounted" inherits="Object" version="4.0"> <brief_description> Base class for reference-counted objects. </brief_description> <description> Base class for any object that keeps a reference count. [Resource] and many other helper objects inherit this class. Unlike other [Object] types, References keep an internal reference counter so that they are automatically released when no longer in use, and only then. References therefore do not need to be freed manually with [method Object.free]. - In the vast majority of use cases, instantiating and using [Reference]-derived types is all you need to do. The methods provided in this class are only for advanced users, and can cause issues if misused. + In the vast majority of use cases, instantiating and using [RefCounted]-derived types is all you need to do. The methods provided in this class are only for advanced users, and can cause issues if misused. [b]Note:[/b] In C#, references will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free references that are no longer in use. This means that unused references will linger on for a while before being removed. </description> <tutorials> diff --git a/doc/classes/ReferenceRect.xml b/doc/classes/ReferenceRect.xml index 1a3fbbdfc5..df9a6f0a46 100644 --- a/doc/classes/ReferenceRect.xml +++ b/doc/classes/ReferenceRect.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="border_color" type="Color" setter="set_border_color" getter="get_border_color" default="Color( 1, 0, 0, 1 )"> + <member name="border_color" type="Color" setter="set_border_color" getter="get_border_color" default="Color(1, 0, 0, 1)"> Sets the border [Color] of the [ReferenceRect]. </member> <member name="border_width" type="float" setter="set_border_width" getter="get_border_width" default="1.0"> diff --git a/doc/classes/ReflectionProbe.xml b/doc/classes/ReflectionProbe.xml index cd08778c89..db01faced8 100644 --- a/doc/classes/ReflectionProbe.xml +++ b/doc/classes/ReflectionProbe.xml @@ -5,7 +5,7 @@ </brief_description> <description> Captures its surroundings as a cubemap, and stores versions of it with increasing levels of blur to simulate different material roughnesses. - The [ReflectionProbe] is used to create high-quality reflections at the cost of performance. It can be combined with [GIProbe]s and Screen Space Reflections to achieve high quality reflections. [ReflectionProbe]s render all objects within their [member cull_mask], so updating them can be quite expensive. It is best to update them once with the important static objects and then leave them. + The [ReflectionProbe] is used to create high-quality reflections at the cost of performance. It can be combined with [VoxelGI]s and Screen Space Reflections to achieve high quality reflections. [ReflectionProbe]s render all objects within their [member cull_mask], so updating them can be quite expensive. It is best to update them once with the important static objects and then leave them. </description> <tutorials> <link title="Reflection probes">https://docs.godotengine.org/en/latest/tutorials/3d/reflection_probes.html</link> @@ -13,7 +13,7 @@ <methods> </methods> <members> - <member name="ambient_color" type="Color" setter="set_ambient_color" getter="get_ambient_color" default="Color( 0, 0, 0, 1 )"> + <member name="ambient_color" type="Color" setter="set_ambient_color" getter="get_ambient_color" default="Color(0, 0, 0, 1)"> </member> <member name="ambient_color_energy" type="float" setter="set_ambient_color_energy" getter="get_ambient_color_energy" default="1.0"> </member> @@ -28,8 +28,8 @@ <member name="enable_shadows" type="bool" setter="set_enable_shadows" getter="are_shadows_enabled" default="false"> If [code]true[/code], computes shadows in the reflection probe. This makes the reflection probe slower to render; you may want to disable this if using the [constant UPDATE_ALWAYS] [member update_mode]. </member> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 1, 1, 1 )"> - The size of the reflection probe. The larger the extents the more space covered by the probe which will lower the perceived resolution. It is best to keep the extents only as large as you need them. + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(10, 10, 10)"> + The size of the reflection probe. The larger the extents, the more space covered by the probe, which will lower the perceived resolution. It is best to keep the extents only as large as you need them. </member> <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="1.0"> Defines the reflection intensity. Intensity modulates the strength of the reflection. @@ -42,7 +42,7 @@ <member name="max_distance" type="float" setter="set_max_distance" getter="get_max_distance" default="0.0"> Sets the max distance away from the probe an object can be before it is culled. </member> - <member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3( 0, 0, 0 )"> + <member name="origin_offset" type="Vector3" setter="set_origin_offset" getter="get_origin_offset" default="Vector3(0, 0, 0)"> Sets the origin offset to be used when this reflection probe is in box project mode. </member> <member name="update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="ReflectionProbe.UpdateMode" default="0"> diff --git a/doc/classes/RemoteTransform3D.xml b/doc/classes/RemoteTransform3D.xml index bd3da2aea9..453177496f 100644 --- a/doc/classes/RemoteTransform3D.xml +++ b/doc/classes/RemoteTransform3D.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="RemoteTransform3D" inherits="Node3D" version="4.0"> <brief_description> - RemoteTransform3D pushes its own [Transform] to another [Node3D] derived Node in the scene. + RemoteTransform3D pushes its own [Transform3D] to another [Node3D] derived Node in the scene. </brief_description> <description> - RemoteTransform3D pushes its own [Transform] to another [Node3D] derived Node (called the remote node) in the scene. + RemoteTransform3D pushes its own [Transform3D] to another [Node3D] derived Node (called the remote node) in the scene. It can be set to update another Node's position, rotation and/or scale. It can use either global or local coordinates. </description> <tutorials> diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index 841d2bde72..901a985961 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -140,6 +140,8 @@ </return> <argument index="0" name="shader" type="RID"> </argument> + <argument index="1" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]"> + </argument> <description> </description> </method> @@ -196,15 +198,15 @@ </argument> <argument index="4" name="final_depth_action" type="int" enum="RenderingDevice.FinalAction"> </argument> - <argument index="5" name="clear_color_values" type="PackedColorArray" default="PackedColorArray( )"> + <argument index="5" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()"> </argument> <argument index="6" name="clear_depth" type="float" default="1.0"> </argument> <argument index="7" name="clear_stencil" type="int" default="0"> </argument> - <argument index="8" name="region" type="Rect2" default="Rect2i( 0, 0, 0, 0 )"> + <argument index="8" name="region" type="Rect2" default="Rect2i(0, 0, 0, 0)"> </argument> - <argument index="9" name="storage_textures" type="Array" default="[ ]"> + <argument index="9" name="storage_textures" type="Array" default="[]"> </argument> <description> </description> @@ -214,7 +216,7 @@ </return> <argument index="0" name="screen" type="int" default="0"> </argument> - <argument index="1" name="clear_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <argument index="1" name="clear_color" type="Color" default="Color(0, 0, 0, 1)"> </argument> <description> </description> @@ -234,15 +236,15 @@ </argument> <argument index="5" name="final_depth_action" type="int" enum="RenderingDevice.FinalAction"> </argument> - <argument index="6" name="clear_color_values" type="PackedColorArray" default="PackedColorArray( )"> + <argument index="6" name="clear_color_values" type="PackedColorArray" default="PackedColorArray()"> </argument> <argument index="7" name="clear_depth" type="float" default="1.0"> </argument> <argument index="8" name="clear_stencil" type="int" default="0"> </argument> - <argument index="9" name="region" type="Rect2" default="Rect2i( 0, 0, 0, 0 )"> + <argument index="9" name="region" type="Rect2" default="Rect2i(0, 0, 0, 0)"> </argument> - <argument index="10" name="storage_textures" type="RID[]" default="[ ]"> + <argument index="10" name="storage_textures" type="RID[]" default="[]"> </argument> <description> </description> @@ -316,7 +318,7 @@ </return> <argument index="0" name="draw_list" type="int"> </argument> - <argument index="1" name="rect" type="Rect2" default="Rect2i( 0, 0, 0, 0 )"> + <argument index="1" name="rect" type="Rect2" default="Rect2i(0, 0, 0, 0)"> </argument> <description> </description> @@ -341,13 +343,29 @@ <description> </description> </method> + <method name="draw_list_switch_to_next_pass"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="draw_list_switch_to_next_pass_split"> + <return type="PackedInt64Array"> + </return> + <argument index="0" name="splits" type="int"> + </argument> + <description> + </description> + </method> <method name="framebuffer_create"> <return type="RID"> </return> - <argument index="0" name="textures" type="Array"> + <argument index="0" name="textures" type="RID[]"> </argument> <argument index="1" name="validate_with_format" type="int" default="-1"> </argument> + <argument index="2" name="view_count" type="int" default="1"> + </argument> <description> </description> </method> @@ -363,11 +381,27 @@ <description> </description> </method> + <method name="framebuffer_create_multipass"> + <return type="RID"> + </return> + <argument index="0" name="textures" type="RID[]"> + </argument> + <argument index="1" name="passes" type="RDFramebufferPass[]"> + </argument> + <argument index="2" name="validate_with_format" type="int" default="-1"> + </argument> + <argument index="3" name="view_count" type="int" default="1"> + </argument> + <description> + </description> + </method> <method name="framebuffer_format_create"> <return type="int"> </return> <argument index="0" name="attachments" type="RDAttachmentFormat[]"> </argument> + <argument index="1" name="view_count" type="int" default="1"> + </argument> <description> </description> </method> @@ -379,11 +413,25 @@ <description> </description> </method> + <method name="framebuffer_format_create_multipass"> + <return type="int"> + </return> + <argument index="0" name="attachments" type="RDAttachmentFormat[]"> + </argument> + <argument index="1" name="passes" type="RDFramebufferPass[]"> + </argument> + <argument index="2" name="view_count" type="int" default="1"> + </argument> + <description> + </description> + </method> <method name="framebuffer_format_get_texture_samples"> <return type="int" enum="RenderingDevice.TextureSamples"> </return> <argument index="0" name="format" type="int"> </argument> + <argument index="1" name="render_pass" type="int" default="0"> + </argument> <description> </description> </method> @@ -469,6 +517,14 @@ <description> </description> </method> + <method name="get_memory_usage" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="arg0" type="int" enum="RenderingDevice.MemoryType"> + </argument> + <description> + </description> + </method> <method name="index_array_create"> <return type="RID"> </return> @@ -488,7 +544,7 @@ </argument> <argument index="1" name="format" type="int" enum="RenderingDevice.IndexBufferFormat"> </argument> - <argument index="2" name="data" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="2" name="data" type="PackedByteArray" default="PackedByteArray()"> </argument> <argument index="3" name="use_restart_indices" type="bool" default="false"> </argument> @@ -524,6 +580,10 @@ </argument> <argument index="8" name="dynamic_state_flags" type="int" default="0"> </argument> + <argument index="9" name="for_render_pass" type="int" default="0"> + </argument> + <argument index="10" name="specialization_constants" type="RDPipelineSpecializationConstant[]" default="[]"> + </argument> <description> </description> </method> @@ -606,7 +666,7 @@ </return> <argument index="0" name="size_bytes" type="int"> </argument> - <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()"> </argument> <argument index="2" name="usage" type="int" default="0"> </argument> @@ -632,7 +692,7 @@ </argument> <argument index="1" name="format" type="int" enum="RenderingDevice.DataFormat"> </argument> - <argument index="2" name="data" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="2" name="data" type="PackedByteArray" default="PackedByteArray()"> </argument> <description> </description> @@ -690,7 +750,7 @@ </argument> <argument index="1" name="view" type="RDTextureView"> </argument> - <argument index="2" name="data" type="PackedByteArray[]" default="[ ]"> + <argument index="2" name="data" type="PackedByteArray[]" default="[]"> </argument> <description> </description> @@ -788,7 +848,7 @@ </return> <argument index="0" name="size_bytes" type="int"> </argument> - <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()"> </argument> <description> </description> @@ -818,7 +878,7 @@ </return> <argument index="0" name="size_bytes" type="int"> </argument> - <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray( )"> + <argument index="1" name="data" type="PackedByteArray" default="PackedByteArray()"> </argument> <argument index="2" name="use_as_storage" type="bool" default="false"> </argument> @@ -1653,6 +1713,12 @@ </constant> <constant name="SHADER_LANGUAGE_HLSL" value="1" enum="ShaderLanguage"> </constant> + <constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL" value="0" enum="PipelineSpecializationConstantType"> + </constant> + <constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT" value="1" enum="PipelineSpecializationConstantType"> + </constant> + <constant name="PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT" value="2" enum="PipelineSpecializationConstantType"> + </constant> <constant name="LIMIT_MAX_BOUND_UNIFORM_SETS" value="0" enum="Limit"> </constant> <constant name="LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS" value="1" enum="Limit"> @@ -1723,6 +1789,12 @@ </constant> <constant name="LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z" value="34" enum="Limit"> </constant> + <constant name="MEMORY_TEXTURES" value="0" enum="MemoryType"> + </constant> + <constant name="MEMORY_BUFFERS" value="1" enum="MemoryType"> + </constant> + <constant name="MEMORY_TOTAL" value="2" enum="MemoryType"> + </constant> <constant name="INVALID_ID" value="-1"> </constant> <constant name="INVALID_FORMAT_ID" value="-1"> diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 7a345f726d..6b45653bf2 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -18,42 +18,92 @@ <link title="Optimization using Servers">https://docs.godotengine.org/en/latest/tutorials/optimization/using_servers.html</link> </tutorials> <methods> - <method name="black_bars_set_images"> - <return type="void"> + <method name="bake_render_uv2"> + <return type="Image[]"> </return> - <argument index="0" name="left" type="RID"> + <argument index="0" name="base" type="RID"> + </argument> + <argument index="1" name="material_overrides" type="Array"> + </argument> + <argument index="2" name="image_size" type="Vector2i"> </argument> - <argument index="1" name="top" type="RID"> + <description> + </description> + </method> + <method name="camera_create"> + <return type="RID"> + </return> + <description> + Creates a camera and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_*[/code] RenderingServer functions. + Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. + </description> + </method> + <method name="camera_effects_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="camera_effects_set_custom_exposure"> + <return type="void"> + </return> + <argument index="0" name="camera_effects" type="RID"> </argument> - <argument index="2" name="right" type="RID"> + <argument index="1" name="enable" type="bool"> </argument> - <argument index="3" name="bottom" type="RID"> + <argument index="2" name="exposure" type="float"> </argument> <description> - Sets images to be rendered in the window margin. </description> </method> - <method name="black_bars_set_margins"> + <method name="camera_effects_set_dof_blur"> <return type="void"> </return> - <argument index="0" name="left" type="int"> + <argument index="0" name="camera_effects" type="RID"> + </argument> + <argument index="1" name="far_enable" type="bool"> + </argument> + <argument index="2" name="far_distance" type="float"> </argument> - <argument index="1" name="top" type="int"> + <argument index="3" name="far_transition" type="float"> </argument> - <argument index="2" name="right" type="int"> + <argument index="4" name="near_enable" type="bool"> </argument> - <argument index="3" name="bottom" type="int"> + <argument index="5" name="near_distance" type="float"> + </argument> + <argument index="6" name="near_transition" type="float"> + </argument> + <argument index="7" name="amount" type="float"> </argument> <description> - Sets margin size, where black bars (or images, if [method black_bars_set_images] was used) are rendered. </description> </method> - <method name="camera_create"> - <return type="RID"> + <method name="camera_effects_set_dof_blur_bokeh_shape"> + <return type="void"> </return> + <argument index="0" name="shape" type="int" enum="RenderingServer.DOFBokehShape"> + </argument> + <description> + </description> + </method> + <method name="camera_effects_set_dof_blur_quality"> + <return type="void"> + </return> + <argument index="0" name="quality" type="int" enum="RenderingServer.DOFBlurQuality"> + </argument> + <argument index="1" name="use_jitter" type="bool"> + </argument> + <description> + </description> + </method> + <method name="camera_set_camera_effects"> + <return type="void"> + </return> + <argument index="0" name="camera" type="RID"> + </argument> + <argument index="1" name="effects" type="RID"> + </argument> <description> - Creates a camera and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]camera_*[/code] RenderingServer functions. - Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. </description> </method> <method name="camera_set_cull_mask"> @@ -130,10 +180,10 @@ </return> <argument index="0" name="camera" type="RID"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> - Sets [Transform] of camera. + Sets [Transform3D] of camera. </description> </method> <method name="camera_set_use_vertical_aspect"> @@ -155,6 +205,246 @@ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. </description> </method> + <method name="canvas_item_add_circle"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="pos" type="Vector2"> + </argument> + <argument index="2" name="radius" type="float"> + </argument> + <argument index="3" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_clip_ignore"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="ignore" type="bool"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_line"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="from" type="Vector2"> + </argument> + <argument index="2" name="to" type="Vector2"> + </argument> + <argument index="3" name="color" type="Color"> + </argument> + <argument index="4" name="width" type="float" default="1.0"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_mesh"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="mesh" type="RID"> + </argument> + <argument index="2" name="transform" type="Transform2D" default="Transform2D(1, 0, 0, 1, 0, 0)"> + </argument> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> + </argument> + <argument index="4" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_multimesh"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="mesh" type="RID"> + </argument> + <argument index="2" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_nine_patch"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="rect" type="Rect2"> + </argument> + <argument index="2" name="source" type="Rect2"> + </argument> + <argument index="3" name="texture" type="RID"> + </argument> + <argument index="4" name="topleft" type="Vector2"> + </argument> + <argument index="5" name="bottomright" type="Vector2"> + </argument> + <argument index="6" name="x_axis_mode" type="int" enum="RenderingServer.NinePatchAxisMode" default="0"> + </argument> + <argument index="7" name="y_axis_mode" type="int" enum="RenderingServer.NinePatchAxisMode" default="0"> + </argument> + <argument index="8" name="draw_center" type="bool" default="true"> + </argument> + <argument index="9" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_particles"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="particles" type="RID"> + </argument> + <argument index="2" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_polygon"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="points" type="PackedVector2Array"> + </argument> + <argument index="2" name="colors" type="PackedColorArray"> + </argument> + <argument index="3" name="uvs" type="PackedVector2Array" default="PackedVector2Array()"> + </argument> + <argument index="4" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_polyline"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="points" type="PackedVector2Array"> + </argument> + <argument index="2" name="colors" type="PackedColorArray"> + </argument> + <argument index="3" name="width" type="float" default="1.0"> + </argument> + <argument index="4" name="antialiased" type="bool" default="false"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_primitive"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="points" type="PackedVector2Array"> + </argument> + <argument index="2" name="colors" type="PackedColorArray"> + </argument> + <argument index="3" name="uvs" type="PackedVector2Array"> + </argument> + <argument index="4" name="texture" type="RID"> + </argument> + <argument index="5" name="width" type="float" default="1.0"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_rect"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="rect" type="Rect2"> + </argument> + <argument index="2" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_set_transform"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="transform" type="Transform2D"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_texture_rect"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="rect" type="Rect2"> + </argument> + <argument index="2" name="texture" type="RID"> + </argument> + <argument index="3" name="tile" type="bool" default="false"> + </argument> + <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> + </argument> + <argument index="5" name="transpose" type="bool" default="false"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_texture_rect_region"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="rect" type="Rect2"> + </argument> + <argument index="2" name="texture" type="RID"> + </argument> + <argument index="3" name="src_rect" type="Rect2"> + </argument> + <argument index="4" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> + </argument> + <argument index="5" name="transpose" type="bool" default="false"> + </argument> + <argument index="6" name="clip_uv" type="bool" default="true"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_add_triangle_array"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="indices" type="PackedInt32Array"> + </argument> + <argument index="2" name="points" type="PackedVector2Array"> + </argument> + <argument index="3" name="colors" type="PackedColorArray"> + </argument> + <argument index="4" name="uvs" type="PackedVector2Array" default="PackedVector2Array()"> + </argument> + <argument index="5" name="bones" type="PackedInt32Array" default="PackedInt32Array()"> + </argument> + <argument index="6" name="weights" type="PackedFloat32Array" default="PackedFloat32Array()"> + </argument> + <argument index="7" name="texture" type="RID"> + </argument> + <argument index="8" name="count" type="int" default="-1"> + </argument> + <description> + </description> + </method> <method name="canvas_item_clear"> <return type="void"> </return> @@ -164,6 +454,40 @@ Clears the [CanvasItem] and removes all commands in it. </description> </method> + <method name="canvas_item_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="canvas_item_set_canvas_group_mode"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="mode" type="int" enum="RenderingServer.CanvasGroupMode"> + </argument> + <argument index="2" name="clear_margin" type="float" default="5.0"> + </argument> + <argument index="3" name="fit_empty" type="bool" default="false"> + </argument> + <argument index="4" name="fit_margin" type="float" default="0.0"> + </argument> + <argument index="5" name="blur_mipmaps" type="bool" default="false"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_clip"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="clip" type="bool"> + </argument> + <description> + </description> + </method> <method name="canvas_item_set_copy_to_backbuffer"> <return type="void"> </return> @@ -177,6 +501,58 @@ Sets the [CanvasItem] to copy a rect to the backbuffer. </description> </method> + <method name="canvas_item_set_custom_rect"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="use_custom_rect" type="bool"> + </argument> + <argument index="2" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_default_texture_filter"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_default_texture_repeat"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_distance_field_mode"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_draw_behind_parent"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> <method name="canvas_item_set_draw_index"> <return type="void"> </return> @@ -188,6 +564,16 @@ Sets the index for the [CanvasItem]. </description> </method> + <method name="canvas_item_set_light_mask"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="mask" type="int"> + </argument> + <description> + </description> + </method> <method name="canvas_item_set_material"> <return type="void"> </return> @@ -199,6 +585,56 @@ Sets a new material to the [CanvasItem]. </description> </method> + <method name="canvas_item_set_modulate"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_parent"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="parent" type="RID"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_self_modulate"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_sort_children_by_y"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_transform"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="transform" type="Transform2D"> + </argument> + <description> + </description> + </method> <method name="canvas_item_set_use_parent_material"> <return type="void"> </return> @@ -210,6 +646,32 @@ Sets if the [CanvasItem] uses its parent's material. </description> </method> + <method name="canvas_item_set_visibility_notifier"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <argument index="2" name="area" type="Rect2"> + </argument> + <argument index="3" name="enter_callable" type="Callable"> + </argument> + <argument index="4" name="exit_callable" type="Callable"> + </argument> + <description> + </description> + </method> + <method name="canvas_item_set_visible"> + <return type="void"> + </return> + <argument index="0" name="item" type="RID"> + </argument> + <argument index="1" name="visible" type="bool"> + </argument> + <description> + </description> + </method> <method name="canvas_item_set_z_as_relative_to_parent"> <return type="void"> </return> @@ -270,6 +732,16 @@ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. </description> </method> + <method name="canvas_light_occluder_set_as_sdf_collision"> + <return type="void"> + </return> + <argument index="0" name="occluder" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> <method name="canvas_light_occluder_set_enabled"> <return type="void"> </return> @@ -537,6 +1009,14 @@ Sets the shape of the occluder polygon. </description> </method> + <method name="canvas_set_disable_scale"> + <return type="void"> + </return> + <argument index="0" name="disable" type="bool"> + </argument> + <description> + </description> + </method> <method name="canvas_set_item_mirroring"> <return type="void"> </return> @@ -561,12 +1041,174 @@ Modulates all colors in the given canvas. </description> </method> + <method name="canvas_set_shadow_texture_size"> + <return type="void"> + </return> + <argument index="0" name="size" type="int"> + </argument> + <description> + </description> + </method> + <method name="canvas_texture_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="canvas_texture_set_channel"> + <return type="void"> + </return> + <argument index="0" name="canvas_texture" type="RID"> + </argument> + <argument index="1" name="channel" type="int" enum="RenderingServer.CanvasTextureChannel"> + </argument> + <argument index="2" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="canvas_texture_set_shading_parameters"> + <return type="void"> + </return> + <argument index="0" name="canvas_texture" type="RID"> + </argument> + <argument index="1" name="base_color" type="Color"> + </argument> + <argument index="2" name="shininess" type="float"> + </argument> + <description> + </description> + </method> + <method name="canvas_texture_set_texture_filter"> + <return type="void"> + </return> + <argument index="0" name="canvas_texture" type="RID"> + </argument> + <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter"> + </argument> + <description> + </description> + </method> + <method name="canvas_texture_set_texture_repeat"> + <return type="void"> + </return> + <argument index="0" name="canvas_texture" type="RID"> + </argument> + <argument index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat"> + </argument> + <description> + </description> + </method> <method name="create_local_rendering_device" qualifiers="const"> <return type="RenderingDevice"> </return> <description> </description> </method> + <method name="decal_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="decal_set_albedo_mix"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="albedo_mix" type="float"> + </argument> + <description> + </description> + </method> + <method name="decal_set_cull_mask"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="mask" type="int"> + </argument> + <description> + </description> + </method> + <method name="decal_set_distance_fade"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <argument index="2" name="begin" type="float"> + </argument> + <argument index="3" name="length" type="float"> + </argument> + <description> + </description> + </method> + <method name="decal_set_emission_energy"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="energy" type="float"> + </argument> + <description> + </description> + </method> + <method name="decal_set_extents"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="extents" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="decal_set_fade"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="above" type="float"> + </argument> + <argument index="2" name="below" type="float"> + </argument> + <description> + </description> + </method> + <method name="decal_set_modulate"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="color" type="Color"> + </argument> + <description> + </description> + </method> + <method name="decal_set_normal_fade"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="fade" type="float"> + </argument> + <description> + </description> + </method> + <method name="decal_set_texture"> + <return type="void"> + </return> + <argument index="0" name="decal" type="RID"> + </argument> + <argument index="1" name="type" type="int" enum="RenderingServer.DecalTexture"> + </argument> + <argument index="2" name="texture" type="RID"> + </argument> + <description> + </description> + </method> <method name="directional_light_create"> <return type="RID"> </return> @@ -576,6 +1218,36 @@ To place in a scene, attach this directional light to an instance using [method instance_set_base] using the returned RID. </description> </method> + <method name="directional_shadow_atlas_set_size"> + <return type="void"> + </return> + <argument index="0" name="size" type="int"> + </argument> + <argument index="1" name="is_16bits" type="bool"> + </argument> + <description> + </description> + </method> + <method name="directional_shadow_quality_set"> + <return type="void"> + </return> + <argument index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality"> + </argument> + <description> + </description> + </method> + <method name="environment_bake_panorama"> + <return type="Image"> + </return> + <argument index="0" name="environment" type="RID"> + </argument> + <argument index="1" name="bake_irradiance" type="bool"> + </argument> + <argument index="2" name="size" type="Vector2i"> + </argument> + <description> + </description> + </method> <method name="environment_create"> <return type="RID"> </return> @@ -584,6 +1256,22 @@ Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. </description> </method> + <method name="environment_glow_set_use_bicubic_upscale"> + <return type="void"> + </return> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="environment_glow_set_use_high_quality"> + <return type="void"> + </return> + <argument index="0" name="enable" type="bool"> + </argument> + <description> + </description> + </method> <method name="environment_set_adjustment"> <return type="void"> </return> @@ -620,7 +1308,7 @@ </argument> <argument index="5" name="reflection_source" type="int" enum="RenderingServer.EnvironmentReflectionSource" default="0"> </argument> - <argument index="6" name="ao_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <argument index="6" name="ao_color" type="Color" default="Color(0, 0, 0, 1)"> </argument> <description> </description> @@ -721,6 +1409,58 @@ <description> </description> </method> + <method name="environment_set_sdfgi"> + <return type="void"> + </return> + <argument index="0" name="env" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <argument index="2" name="cascades" type="int" enum="RenderingServer.EnvironmentSDFGICascades"> + </argument> + <argument index="3" name="min_cell_size" type="float"> + </argument> + <argument index="4" name="y_scale" type="int" enum="RenderingServer.EnvironmentSDFGIYScale"> + </argument> + <argument index="5" name="use_occlusion" type="bool"> + </argument> + <argument index="6" name="bounce_feedback" type="float"> + </argument> + <argument index="7" name="read_sky" type="bool"> + </argument> + <argument index="8" name="energy" type="float"> + </argument> + <argument index="9" name="normal_bias" type="float"> + </argument> + <argument index="10" name="probe_bias" type="float"> + </argument> + <description> + </description> + </method> + <method name="environment_set_sdfgi_frames_to_converge"> + <return type="void"> + </return> + <argument index="0" name="frames" type="int" enum="RenderingServer.EnvironmentSDFGIFramesToConverge"> + </argument> + <description> + </description> + </method> + <method name="environment_set_sdfgi_frames_to_update_light"> + <return type="void"> + </return> + <argument index="0" name="frames" type="int" enum="RenderingServer.EnvironmentSDFGIFramesToUpdateLight"> + </argument> + <description> + </description> + </method> + <method name="environment_set_sdfgi_ray_count"> + <return type="void"> + </return> + <argument index="0" name="ray_count" type="int" enum="RenderingServer.EnvironmentSDFGIRayCount"> + </argument> + <description> + </description> + </method> <method name="environment_set_sky"> <return type="void"> </return> @@ -781,6 +1521,24 @@ Sets the variables to be used with the "screen space ambient occlusion" post-process effect. See [Environment] for more details. </description> </method> + <method name="environment_set_ssao_quality"> + <return type="void"> + </return> + <argument index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSAOQuality"> + </argument> + <argument index="1" name="half_size" type="bool"> + </argument> + <argument index="2" name="adaptive_target" type="float"> + </argument> + <argument index="3" name="blur_passes" type="int"> + </argument> + <argument index="4" name="fadeout_from" type="float"> + </argument> + <argument index="5" name="fadeout_to" type="float"> + </argument> + <description> + </description> + </method> <method name="environment_set_ssr"> <return type="void"> </return> @@ -800,6 +1558,14 @@ Sets the variables to be used with the "screen space reflections" post-process effect. See [Environment] for more details. </description> </method> + <method name="environment_set_ssr_roughness_quality"> + <return type="void"> + </return> + <argument index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSRRoughnessQuality"> + </argument> + <description> + </description> + </method> <method name="environment_set_tonemap"> <return type="void"> </return> @@ -825,11 +1591,48 @@ Sets the variables to be used with the "tonemap" post-process effect. See [Environment] for more details. </description> </method> - <method name="finish"> + <method name="environment_set_volumetric_fog"> <return type="void"> </return> + <argument index="0" name="env" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <argument index="2" name="density" type="float"> + </argument> + <argument index="3" name="light" type="Color"> + </argument> + <argument index="4" name="light_energy" type="float"> + </argument> + <argument index="5" name="length" type="float"> + </argument> + <argument index="6" name="p_detail_spread" type="float"> + </argument> + <argument index="7" name="gi_inject" type="float"> + </argument> + <argument index="8" name="temporal_reprojection" type="bool"> + </argument> + <argument index="9" name="temporal_reprojection_amount" type="float"> + </argument> + <description> + </description> + </method> + <method name="environment_set_volumetric_fog_filter_active"> + <return type="void"> + </return> + <argument index="0" name="active" type="bool"> + </argument> + <description> + </description> + </method> + <method name="environment_set_volumetric_fog_volume_size"> + <return type="void"> + </return> + <argument index="0" name="size" type="int"> + </argument> + <argument index="1" name="depth" type="int"> + </argument> <description> - Removes buffers and clears testcubes. </description> </method> <method name="force_draw"> @@ -840,14 +1643,12 @@ <argument index="1" name="frame_step" type="float" default="0.0"> </argument> <description> - Forces a frame to be drawn when the function is called. Drawing a frame updates all [Viewport]s that are set to update. Use with extreme caution. </description> </method> <method name="force_sync"> <return type="void"> </return> <description> - Synchronizes threads. </description> </method> <method name="free_rid"> @@ -865,13 +1666,12 @@ <description> </description> </method> - <method name="get_render_info"> + <method name="get_rendering_info"> <return type="int"> </return> - <argument index="0" name="info" type="int" enum="RenderingServer.RenderInfo"> + <argument index="0" name="info" type="int" enum="RenderingServer.RenderingInfo"> </argument> <description> - Returns a certain information, see [enum RenderInfo] for options. </description> </method> <method name="get_test_cube"> @@ -963,6 +1763,16 @@ <description> </description> </method> + <method name="global_variable_set_override"> + <return type="void"> + </return> + <argument index="0" name="name" type="StringName"> + </argument> + <argument index="1" name="value" type="Variant"> + </argument> + <description> + </description> + </method> <method name="has_changed" qualifiers="const"> <return type="bool"> </return> @@ -988,216 +1798,149 @@ Returns [code]true[/code] if the OS supports a certain feature. Features might be [code]s3tc[/code], [code]etc[/code], [code]etc2[/code] and [code]pvrtc[/code]. </description> </method> - <method name="immediate_begin"> + <method name="instance_attach_object_instance_id"> <return type="void"> </return> - <argument index="0" name="immediate" type="RID"> - </argument> - <argument index="1" name="primitive" type="int" enum="RenderingServer.PrimitiveType"> - </argument> - <argument index="2" name="texture" type="RID"> + <argument index="0" name="instance" type="RID"> </argument> - <description> - Sets up [ImmediateGeometry3D] internals to prepare for drawing. Equivalent to [method ImmediateGeometry3D.begin]. - </description> - </method> - <method name="immediate_clear"> - <return type="void"> - </return> - <argument index="0" name="immediate" type="RID"> + <argument index="1" name="id" type="int"> </argument> <description> - Clears everything that was set up between [method immediate_begin] and [method immediate_end]. Equivalent to [method ImmediateGeometry3D.clear]. + Attaches a unique Object ID to instance. Object ID must be attached to instance for proper culling with [method instances_cull_aabb], [method instances_cull_convex], and [method instances_cull_ray]. </description> </method> - <method name="immediate_color"> + <method name="instance_attach_skeleton"> <return type="void"> </return> - <argument index="0" name="immediate" type="RID"> + <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="color" type="Color"> + <argument index="1" name="skeleton" type="RID"> </argument> <description> - Sets the color to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_color]. + Attaches a skeleton to an instance. Removes the previous skeleton from the instance. </description> </method> - <method name="immediate_create"> + <method name="instance_create"> <return type="RID"> </return> <description> - Creates an immediate geometry and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]immediate_*[/code] RenderingServer functions. + Creates a visual instance and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions. Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. - To place in a scene, attach this immediate geometry to an instance using [method instance_set_base] using the returned RID. - </description> - </method> - <method name="immediate_end"> - <return type="void"> - </return> - <argument index="0" name="immediate" type="RID"> - </argument> - <description> - Ends drawing the [ImmediateGeometry3D] and displays it. Equivalent to [method ImmediateGeometry3D.end]. + An instance is a way of placing a 3D object in the scenario. Objects like particles, meshes, and reflection probes need to be associated with an instance to be visible in the scenario using [method instance_set_base]. </description> </method> - <method name="immediate_get_material" qualifiers="const"> + <method name="instance_create2"> <return type="RID"> </return> - <argument index="0" name="immediate" type="RID"> - </argument> - <description> - Returns the material assigned to the [ImmediateGeometry3D]. - </description> - </method> - <method name="immediate_normal"> - <return type="void"> - </return> - <argument index="0" name="immediate" type="RID"> + <argument index="0" name="base" type="RID"> </argument> - <argument index="1" name="normal" type="Vector3"> + <argument index="1" name="scenario" type="RID"> </argument> <description> - Sets the normal to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_normal]. + Creates a visual instance, adds it to the RenderingServer, and sets both base and scenario. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions. + Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. </description> </method> - <method name="immediate_set_material"> - <return type="void"> + <method name="instance_geometry_get_shader_parameter" qualifiers="const"> + <return type="Variant"> </return> - <argument index="0" name="immediate" type="RID"> + <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="material" type="RID"> + <argument index="1" name="parameter" type="StringName"> </argument> <description> - Sets the material to be used to draw the [ImmediateGeometry3D]. </description> </method> - <method name="immediate_tangent"> - <return type="void"> + <method name="instance_geometry_get_shader_parameter_default_value" qualifiers="const"> + <return type="Variant"> </return> - <argument index="0" name="immediate" type="RID"> + <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="tangent" type="Plane"> + <argument index="1" name="parameter" type="StringName"> </argument> <description> - Sets the tangent to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_tangent]. </description> </method> - <method name="immediate_uv"> - <return type="void"> + <method name="instance_geometry_get_shader_parameter_list" qualifiers="const"> + <return type="Array"> </return> - <argument index="0" name="immediate" type="RID"> - </argument> - <argument index="1" name="tex_uv" type="Vector2"> + <argument index="0" name="instance" type="RID"> </argument> <description> - Sets the UV to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_uv]. </description> </method> - <method name="immediate_uv2"> + <method name="instance_geometry_set_cast_shadows_setting"> <return type="void"> </return> - <argument index="0" name="immediate" type="RID"> + <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="tex_uv" type="Vector2"> + <argument index="1" name="shadow_casting_setting" type="int" enum="RenderingServer.ShadowCastingSetting"> </argument> <description> - Sets the UV2 to be used with next vertex. Equivalent to [method ImmediateGeometry3D.set_uv2]. + Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance3D.cast_shadow]. </description> </method> - <method name="immediate_vertex"> + <method name="instance_geometry_set_flag"> <return type="void"> </return> - <argument index="0" name="immediate" type="RID"> - </argument> - <argument index="1" name="vertex" type="Vector3"> + <argument index="0" name="instance" type="RID"> </argument> - <description> - Adds the next vertex using the information provided in advance. Equivalent to [method ImmediateGeometry3D.add_vertex]. - </description> - </method> - <method name="immediate_vertex_2d"> - <return type="void"> - </return> - <argument index="0" name="immediate" type="RID"> + <argument index="1" name="flag" type="int" enum="RenderingServer.InstanceFlags"> </argument> - <argument index="1" name="vertex" type="Vector2"> + <argument index="2" name="enabled" type="bool"> </argument> <description> - Adds the next vertex using the information provided in advance. This is a helper class that calls [method immediate_vertex] under the hood. Equivalent to [method ImmediateGeometry3D.add_vertex]. - </description> - </method> - <method name="init"> - <return type="void"> - </return> - <description> - Initializes the rendering server. This function is called internally by platform-dependent code during engine initialization. If called from a running game, it will not do anything. + Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details. </description> </method> - <method name="instance_attach_object_instance_id"> + <method name="instance_geometry_set_lightmap"> <return type="void"> </return> <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="id" type="int"> + <argument index="1" name="lightmap" type="RID"> </argument> - <description> - Attaches a unique Object ID to instance. Object ID must be attached to instance for proper culling with [method instances_cull_aabb], [method instances_cull_convex], and [method instances_cull_ray]. - </description> - </method> - <method name="instance_attach_skeleton"> - <return type="void"> - </return> - <argument index="0" name="instance" type="RID"> + <argument index="2" name="lightmap_uv_scale" type="Rect2"> </argument> - <argument index="1" name="skeleton" type="RID"> + <argument index="3" name="lightmap_slice" type="int"> </argument> <description> - Attaches a skeleton to an instance. Removes the previous skeleton from the instance. - </description> - </method> - <method name="instance_create"> - <return type="RID"> - </return> - <description> - Creates a visual instance and adds it to the RenderingServer. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions. - Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. - An instance is a way of placing a 3D object in the scenario. Objects like particles, meshes, and reflection probes need to be associated with an instance to be visible in the scenario using [method instance_set_base]. </description> </method> - <method name="instance_create2"> - <return type="RID"> + <method name="instance_geometry_set_lod_bias"> + <return type="void"> </return> - <argument index="0" name="base" type="RID"> + <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="scenario" type="RID"> + <argument index="1" name="lod_bias" type="float"> </argument> <description> - Creates a visual instance, adds it to the RenderingServer, and sets both base and scenario. It can be accessed with the RID that is returned. This RID will be used in all [code]instance_*[/code] RenderingServer functions. - Once finished with your RID, you will want to free the RID using the RenderingServer's [method free_rid] static method. </description> </method> - <method name="instance_geometry_set_as_instance_lod"> + <method name="instance_geometry_set_material_override"> <return type="void"> </return> <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="as_lod_of_instance" type="RID"> + <argument index="1" name="material" type="RID"> </argument> <description> - Not implemented in Godot 3.x. + Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_override]. </description> </method> - <method name="instance_geometry_set_cast_shadows_setting"> + <method name="instance_geometry_set_shader_parameter"> <return type="void"> </return> <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="shadow_casting_setting" type="int" enum="RenderingServer.ShadowCastingSetting"> + <argument index="1" name="parameter" type="StringName"> + </argument> + <argument index="2" name="value" type="Variant"> </argument> <description> - Sets the shadow casting setting to one of [enum ShadowCastingSetting]. Equivalent to [member GeometryInstance3D.cast_shadow]. </description> </method> - <method name="instance_geometry_set_draw_range"> + <method name="instance_geometry_set_visibility_range"> <return type="void"> </return> <argument index="0" name="instance" type="RID"> @@ -1211,31 +1954,7 @@ <argument index="4" name="max_margin" type="float"> </argument> <description> - Not implemented in Godot 3.x. - </description> - </method> - <method name="instance_geometry_set_flag"> - <return type="void"> - </return> - <argument index="0" name="instance" type="RID"> - </argument> - <argument index="1" name="flag" type="int" enum="RenderingServer.InstanceFlags"> - </argument> - <argument index="2" name="enabled" type="bool"> - </argument> - <description> - Sets the flag for a given [enum InstanceFlags]. See [enum InstanceFlags] for more details. - </description> - </method> - <method name="instance_geometry_set_material_override"> - <return type="void"> - </return> - <argument index="0" name="instance" type="RID"> - </argument> - <argument index="1" name="material" type="RID"> - </argument> - <description> - Sets a material that will override the material for all surfaces on the mesh associated with this instance. Equivalent to [member GeometryInstance3D.material_override]. + Sets the visibility range values for the given geometry instance. Equivalent to [member GeometryInstance3D.visibility_range_begin] and related properties. </description> </method> <method name="instance_set_base"> @@ -1273,17 +1992,6 @@ Sets a custom AABB to use when culling objects from the view frustum. Equivalent to [method GeometryInstance3D.set_custom_aabb]. </description> </method> - <method name="instance_set_exterior"> - <return type="void"> - </return> - <argument index="0" name="instance" type="RID"> - </argument> - <argument index="1" name="enabled" type="bool"> - </argument> - <description> - Function not implemented in Godot 3.x. - </description> - </method> <method name="instance_set_extra_visibility_margin"> <return type="void"> </return> @@ -1335,12 +2043,23 @@ </return> <argument index="0" name="instance" type="RID"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> Sets the world space transform of the instance. Equivalent to [member Node3D.transform]. </description> </method> + <method name="instance_set_visibility_parent"> + <return type="void"> + </return> + <argument index="0" name="instance" type="RID"> + </argument> + <argument index="1" name="parent" type="RID"> + </argument> + <description> + Sets the visibility parent for the given instance. Equivalent to [member Node3D.visibility_parent]. + </description> + </method> <method name="instance_set_visible"> <return type="void"> </return> @@ -1401,17 +2120,6 @@ If [code]true[/code], this directional light will blend between shadow map splits resulting in a smoother transition between them. Equivalent to [member DirectionalLight3D.directional_shadow_blend_splits]. </description> </method> - <method name="light_directional_set_shadow_depth_range_mode"> - <return type="void"> - </return> - <argument index="0" name="light" type="RID"> - </argument> - <argument index="1" name="range_mode" type="int" enum="RenderingServer.LightDirectionalShadowDepthRangeMode"> - </argument> - <description> - Sets the shadow depth range mode for this directional light. Equivalent to [member DirectionalLight3D.directional_shadow_depth_range]. See [enum LightDirectionalShadowDepthRangeMode] for options. - </description> - </method> <method name="light_directional_set_shadow_mode"> <return type="void"> </return> @@ -1477,6 +2185,16 @@ Sets the cull mask for this Light3D. Lights only affect objects in the selected layers. Equivalent to [member Light3D.light_cull_mask]. </description> </method> + <method name="light_set_max_sdfgi_cascade"> + <return type="void"> + </return> + <argument index="0" name="light" type="RID"> + </argument> + <argument index="1" name="cascade" type="int"> + </argument> + <description> + </description> + </method> <method name="light_set_negative"> <return type="void"> </return> @@ -1545,6 +2263,100 @@ Sets the color of the shadow cast by the light. Equivalent to [member Light3D.shadow_color]. </description> </method> + <method name="lightmap_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="lightmap_get_probe_capture_bsp_tree" qualifiers="const"> + <return type="PackedInt32Array"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <description> + </description> + </method> + <method name="lightmap_get_probe_capture_points" qualifiers="const"> + <return type="PackedVector3Array"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <description> + </description> + </method> + <method name="lightmap_get_probe_capture_sh" qualifiers="const"> + <return type="PackedColorArray"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <description> + </description> + </method> + <method name="lightmap_get_probe_capture_tetrahedra" qualifiers="const"> + <return type="PackedInt32Array"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <description> + </description> + </method> + <method name="lightmap_set_probe_bounds"> + <return type="void"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <argument index="1" name="bounds" type="AABB"> + </argument> + <description> + </description> + </method> + <method name="lightmap_set_probe_capture_data"> + <return type="void"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <argument index="1" name="points" type="PackedVector3Array"> + </argument> + <argument index="2" name="point_sh" type="PackedColorArray"> + </argument> + <argument index="3" name="tetrahedra" type="PackedInt32Array"> + </argument> + <argument index="4" name="bsp_tree" type="PackedInt32Array"> + </argument> + <description> + </description> + </method> + <method name="lightmap_set_probe_capture_update_speed"> + <return type="void"> + </return> + <argument index="0" name="speed" type="float"> + </argument> + <description> + </description> + </method> + <method name="lightmap_set_probe_interior"> + <return type="void"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <argument index="1" name="interior" type="bool"> + </argument> + <description> + </description> + </method> + <method name="lightmap_set_textures"> + <return type="void"> + </return> + <argument index="0" name="lightmap" type="RID"> + </argument> + <argument index="1" name="light" type="RID"> + </argument> + <argument index="2" name="uses_sh" type="bool"> + </argument> + <description> + </description> + </method> <method name="make_sphere_mesh"> <return type="RID"> </return> @@ -1623,6 +2435,35 @@ Sets a shader material's shader. </description> </method> + <method name="mesh_add_surface"> + <return type="void"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="surface" type="Dictionary"> + </argument> + <description> + </description> + </method> + <method name="mesh_add_surface_from_arrays"> + <return type="void"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="primitive" type="int" enum="RenderingServer.PrimitiveType"> + </argument> + <argument index="2" name="arrays" type="Array"> + </argument> + <argument index="3" name="blend_shapes" type="Array" default="[]"> + </argument> + <argument index="4" name="lods" type="Dictionary" default="{ +}"> + </argument> + <argument index="5" name="compress_format" type="int" default="0"> + </argument> + <description> + </description> + </method> <method name="mesh_clear"> <return type="void"> </return> @@ -1641,6 +2482,16 @@ To place in a scene, attach this mesh to an instance using [method instance_set_base] using the returned RID. </description> </method> + <method name="mesh_create_from_surfaces"> + <return type="RID"> + </return> + <argument index="0" name="surfaces" type="Dictionary[]"> + </argument> + <argument index="1" name="blend_shape_count" type="int" default="0"> + </argument> + <description> + </description> + </method> <method name="mesh_get_blend_shape_count" qualifiers="const"> <return type="int"> </return> @@ -1668,6 +2519,16 @@ Returns a mesh's custom aabb. </description> </method> + <method name="mesh_get_surface"> + <return type="Dictionary"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="surface" type="int"> + </argument> + <description> + </description> + </method> <method name="mesh_get_surface_count" qualifiers="const"> <return type="int"> </return> @@ -1699,6 +2560,16 @@ Sets a mesh's custom aabb. </description> </method> + <method name="mesh_set_shadow_mesh"> + <return type="void"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="shadow_mesh" type="RID"> + </argument> + <description> + </description> + </method> <method name="mesh_surface_get_arrays" qualifiers="const"> <return type="Array"> </return> @@ -1787,7 +2658,35 @@ Sets a mesh's surface's material. </description> </method> - <method name="mesh_surface_update_region"> + <method name="mesh_surface_update_attribute_region"> + <return type="void"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="surface" type="int"> + </argument> + <argument index="2" name="offset" type="int"> + </argument> + <argument index="3" name="data" type="PackedByteArray"> + </argument> + <description> + </description> + </method> + <method name="mesh_surface_update_skin_region"> + <return type="void"> + </return> + <argument index="0" name="mesh" type="RID"> + </argument> + <argument index="1" name="surface" type="int"> + </argument> + <argument index="2" name="offset" type="int"> + </argument> + <argument index="3" name="data" type="PackedByteArray"> + </argument> + <description> + </description> + </method> + <method name="mesh_surface_update_vertex_region"> <return type="void"> </return> <argument index="0" name="mesh" type="RID"> @@ -1799,7 +2698,6 @@ <argument index="3" name="data" type="PackedByteArray"> </argument> <description> - Updates a specific region of a vertex buffer for the specified surface. Warning: this function alters the vertex buffer directly with no safety mechanisms, you can easily corrupt your mesh. </description> </method> <method name="multimesh_allocate_data"> @@ -1894,14 +2792,14 @@ </description> </method> <method name="multimesh_instance_get_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="multimesh" type="RID"> </argument> <argument index="1" name="index" type="int"> </argument> <description> - Returns the [Transform] of the specified instance. + Returns the [Transform3D] of the specified instance. </description> </method> <method name="multimesh_instance_get_transform_2d" qualifiers="const"> @@ -1948,10 +2846,10 @@ </argument> <argument index="1" name="index" type="int"> </argument> - <argument index="2" name="transform" type="Transform"> + <argument index="2" name="transform" type="Transform3D"> </argument> <description> - Sets the [Transform] for this instance. Equivalent to [method MultiMesh.set_instance_transform]. + Sets the [Transform3D] for this instance. Equivalent to [method MultiMesh.set_instance_transform]. </description> </method> <method name="multimesh_instance_set_transform_2d"> @@ -2008,11 +2906,11 @@ <method name="occluder_set_mesh"> <return type="void"> </return> - <argument index="0" name="arg0" type="RID"> + <argument index="0" name="occluder" type="RID"> </argument> - <argument index="1" name="arg1" type="PackedVector3Array"> + <argument index="1" name="vertices" type="PackedVector3Array"> </argument> - <argument index="2" name="arg2" type="PackedInt32Array"> + <argument index="2" name="indices" type="PackedInt32Array"> </argument> <description> </description> @@ -2026,6 +2924,110 @@ To place in a scene, attach this omni light to an instance using [method instance_set_base] using the returned RID. </description> </method> + <method name="particles_collision_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="particles_collision_height_field_update"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_attractor_attenuation"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="curve" type="float"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_attractor_directionality"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="amount" type="float"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_attractor_strength"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="setrngth" type="float"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_box_extents"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="extents" type="Vector3"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_collision_type"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="type" type="int" enum="RenderingServer.ParticlesCollisionType"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_cull_mask"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="mask" type="int"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_field_texture"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_height_field_resolution"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="resolution" type="int" enum="RenderingServer.ParticlesCollisionHeightfieldResolution"> + </argument> + <description> + </description> + </method> + <method name="particles_collision_set_sphere_radius"> + <return type="void"> + </return> + <argument index="0" name="particles_collision" type="RID"> + </argument> + <argument index="1" name="radius" type="float"> + </argument> + <description> + </description> + </method> <method name="particles_create"> <return type="RID"> </return> @@ -2035,6 +3037,24 @@ To place in a scene, attach these particles to an instance using [method instance_set_base] using the returned RID. </description> </method> + <method name="particles_emit"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="transform" type="Transform3D"> + </argument> + <argument index="2" name="velocity" type="Vector3"> + </argument> + <argument index="3" name="color" type="Color"> + </argument> + <argument index="4" name="custom" type="Color"> + </argument> + <argument index="5" name="emit_flags" type="int"> + </argument> + <description> + </description> + </method> <method name="particles_get_current_aabb"> <return type="AABB"> </return> @@ -2091,6 +3111,16 @@ Sets the number of particles to be drawn and allocates the memory for them. Equivalent to [member GPUParticles3D.amount]. </description> </method> + <method name="particles_set_collision_base_size"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="size" type="float"> + </argument> + <description> + </description> + </method> <method name="particles_set_custom_aabb"> <return type="void"> </return> @@ -2142,10 +3172,10 @@ </return> <argument index="0" name="particles" type="RID"> </argument> - <argument index="1" name="transform" type="Transform"> + <argument index="1" name="transform" type="Transform3D"> </argument> <description> - Sets the [Transform] that will be used by the particles when they first emit. + Sets the [Transform3D] that will be used by the particles when they first emit. </description> </method> <method name="particles_set_emitting"> @@ -2192,6 +3222,16 @@ If [code]true[/code], uses fractional delta which smooths the movement of the particles. Equivalent to [member GPUParticles3D.fract_delta]. </description> </method> + <method name="particles_set_interpolate"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> <method name="particles_set_lifetime"> <return type="void"> </return> @@ -2203,6 +3243,16 @@ Sets the lifetime of each particle in the system. Equivalent to [member GPUParticles3D.lifetime]. </description> </method> + <method name="particles_set_mode"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="mode" type="int" enum="RenderingServer.ParticlesMode"> + </argument> + <description> + </description> + </method> <method name="particles_set_one_shot"> <return type="void"> </return> @@ -2258,6 +3308,48 @@ Sets the speed scale of the particle system. Equivalent to [member GPUParticles3D.speed_scale]. </description> </method> + <method name="particles_set_subemitter"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="subemitter_particles" type="RID"> + </argument> + <description> + </description> + </method> + <method name="particles_set_trail_bind_poses"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="bind_poses" type="Transform3D[]"> + </argument> + <description> + </description> + </method> + <method name="particles_set_trails"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <argument index="2" name="length_sec" type="float"> + </argument> + <description> + </description> + </method> + <method name="particles_set_transform_align"> + <return type="void"> + </return> + <argument index="0" name="particles" type="RID"> + </argument> + <argument index="1" name="align" type="int" enum="RenderingServer.ParticlesTransformAlign"> + </argument> + <description> + </description> + </method> <method name="particles_set_use_local_coordinates"> <return type="void"> </return> @@ -2374,6 +3466,16 @@ Sets the intensity of the reflection probe. Intensity modulates the strength of the reflection. Equivalent to [member ReflectionProbe.intensity]. </description> </method> + <method name="reflection_probe_set_lod_threshold"> + <return type="void"> + </return> + <argument index="0" name="probe" type="RID"> + </argument> + <argument index="1" name="pixels" type="float"> + </argument> + <description> + </description> + </method> <method name="reflection_probe_set_max_distance"> <return type="void"> </return> @@ -2396,6 +3498,16 @@ Sets the origin offset to be used when this reflection probe is in box project mode. Equivalent to [member ReflectionProbe.origin_offset]. </description> </method> + <method name="reflection_probe_set_resolution"> + <return type="void"> + </return> + <argument index="0" name="probe" type="RID"> + </argument> + <argument index="1" name="resolution" type="int"> + </argument> + <description> + </description> + </method> <method name="reflection_probe_set_update_mode"> <return type="void"> </return> @@ -2440,18 +3552,18 @@ <description> </description> </method> - <method name="scenario_set_debug"> + <method name="scenario_set_environment"> <return type="void"> </return> <argument index="0" name="scenario" type="RID"> </argument> - <argument index="1" name="debug_mode" type="int" enum="RenderingServer.ScenarioDebugMode"> + <argument index="1" name="environment" type="RID"> </argument> <description> - Sets the [enum ScenarioDebugMode] for this scenario. See [enum ScenarioDebugMode] for options. + Sets the environment that will be used with this scenario. </description> </method> - <method name="scenario_set_environment"> + <method name="scenario_set_fallback_environment"> <return type="void"> </return> <argument index="0" name="scenario" type="RID"> @@ -2459,18 +3571,19 @@ <argument index="1" name="environment" type="RID"> </argument> <description> - Sets the environment that will be used with this scenario. + Sets the fallback environment to be used by this scenario. The fallback environment is used if no environment is set. Internally, this is used by the editor to provide a default environment. </description> </method> - <method name="scenario_set_fallback_environment"> + <method name="screen_space_roughness_limiter_set_active"> <return type="void"> </return> - <argument index="0" name="scenario" type="RID"> + <argument index="0" name="enable" type="bool"> </argument> - <argument index="1" name="environment" type="RID"> + <argument index="1" name="amount" type="float"> + </argument> + <argument index="2" name="limit" type="float"> </argument> <description> - Sets the fallback environment to be used by this scenario. The fallback environment is used if no environment is set. Internally, this is used by the editor to provide a default environment. </description> </method> <method name="set_boot_image"> @@ -2528,7 +3641,7 @@ </return> <argument index="0" name="shader" type="RID"> </argument> - <argument index="1" name="name" type="StringName"> + <argument index="1" name="param" type="StringName"> </argument> <description> Returns a default texture from a shader searched by name. @@ -2537,15 +3650,15 @@ <method name="shader_get_param_default" qualifiers="const"> <return type="Variant"> </return> - <argument index="0" name="material" type="RID"> + <argument index="0" name="shader" type="RID"> </argument> - <argument index="1" name="parameter" type="StringName"> + <argument index="1" name="param" type="StringName"> </argument> <description> </description> </method> <method name="shader_get_param_list" qualifiers="const"> - <return type="Array"> + <return type="Dictionary[]"> </return> <argument index="0" name="shader" type="RID"> </argument> @@ -2553,28 +3666,25 @@ Returns the parameters of a shader. </description> </method> - <method name="shader_set_code"> + <method name="shader_set_default_texture_param"> <return type="void"> </return> <argument index="0" name="shader" type="RID"> </argument> - <argument index="1" name="code" type="String"> + <argument index="1" name="param" type="StringName"> + </argument> + <argument index="2" name="texture" type="RID"> </argument> <description> - Sets a shader's code. + Sets a shader's default texture. Overwrites the texture given by name. </description> </method> - <method name="shader_set_default_texture_param"> + <method name="shadows_quality_set"> <return type="void"> </return> - <argument index="0" name="shader" type="RID"> - </argument> - <argument index="1" name="name" type="StringName"> - </argument> - <argument index="2" name="texture" type="RID"> + <argument index="0" name="quality" type="int" enum="RenderingServer.ShadowQuality"> </argument> <description> - Sets a shader's default texture. Overwrites the texture given by name. </description> </method> <method name="skeleton_allocate_data"> @@ -2590,14 +3700,14 @@ </description> </method> <method name="skeleton_bone_get_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="skeleton" type="RID"> </argument> <argument index="1" name="bone" type="int"> </argument> <description> - Returns the [Transform] set for a specific bone of this skeleton. + Returns the [Transform3D] set for a specific bone of this skeleton. </description> </method> <method name="skeleton_bone_get_transform_2d" qualifiers="const"> @@ -2618,10 +3728,10 @@ </argument> <argument index="1" name="bone" type="int"> </argument> - <argument index="2" name="transform" type="Transform"> + <argument index="2" name="transform" type="Transform3D"> </argument> <description> - Sets the [Transform] for a specific bone of this skeleton. + Sets the [Transform3D] for a specific bone of this skeleton. </description> </method> <method name="skeleton_bone_set_transform_2d"> @@ -2654,6 +3764,30 @@ Returns the number of bones allocated for this skeleton. </description> </method> + <method name="skeleton_set_base_transform_2d"> + <return type="void"> + </return> + <argument index="0" name="skeleton" type="RID"> + </argument> + <argument index="1" name="base_transform" type="Transform2D"> + </argument> + <description> + </description> + </method> + <method name="sky_bake_panorama"> + <return type="Image"> + </return> + <argument index="0" name="sky" type="RID"> + </argument> + <argument index="1" name="energy" type="float"> + </argument> + <argument index="2" name="bake_irradiance" type="bool"> + </argument> + <argument index="3" name="size" type="Vector2i"> + </argument> + <description> + </description> + </method> <method name="sky_create"> <return type="RID"> </return> @@ -2673,6 +3807,26 @@ Sets the material that the sky uses to render the background and reflection maps. </description> </method> + <method name="sky_set_mode"> + <return type="void"> + </return> + <argument index="0" name="sky" type="RID"> + </argument> + <argument index="1" name="mode" type="int" enum="RenderingServer.SkyMode"> + </argument> + <description> + </description> + </method> + <method name="sky_set_radiance_size"> + <return type="void"> + </return> + <argument index="0" name="sky" type="RID"> + </argument> + <argument index="1" name="radiance_size" type="int"> + </argument> + <description> + </description> + </method> <method name="spot_light_create"> <return type="RID"> </return> @@ -2682,6 +3836,24 @@ To place in a scene, attach this spot light to an instance using [method instance_set_base] using the returned RID. </description> </method> + <method name="sub_surface_scattering_set_quality"> + <return type="void"> + </return> + <argument index="0" name="quality" type="int" enum="RenderingServer.SubSurfaceScatteringQuality"> + </argument> + <description> + </description> + </method> + <method name="sub_surface_scattering_set_scale"> + <return type="void"> + </return> + <argument index="0" name="scale" type="float"> + </argument> + <argument index="1" name="depth_scale" type="float"> + </argument> + <description> + </description> + </method> <method name="texture_2d_create"> <return type="RID"> </return> @@ -2698,6 +3870,162 @@ <description> </description> </method> + <method name="texture_2d_layer_get" qualifiers="const"> + <return type="Image"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="layer" type="int"> + </argument> + <description> + </description> + </method> + <method name="texture_2d_layered_create"> + <return type="RID"> + </return> + <argument index="0" name="layers" type="Image[]"> + </argument> + <argument index="1" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType"> + </argument> + <description> + </description> + </method> + <method name="texture_2d_layered_placeholder_create"> + <return type="RID"> + </return> + <argument index="0" name="layered_type" type="int" enum="RenderingServer.TextureLayeredType"> + </argument> + <description> + </description> + </method> + <method name="texture_2d_placeholder_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="texture_2d_update"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="image" type="Image"> + </argument> + <argument index="2" name="layer" type="int"> + </argument> + <description> + </description> + </method> + <method name="texture_3d_create"> + <return type="RID"> + </return> + <argument index="0" name="format" type="int" enum="Image.Format"> + </argument> + <argument index="1" name="width" type="int"> + </argument> + <argument index="2" name="height" type="int"> + </argument> + <argument index="3" name="depth" type="int"> + </argument> + <argument index="4" name="mipmaps" type="bool"> + </argument> + <argument index="5" name="data" type="Image[]"> + </argument> + <description> + </description> + </method> + <method name="texture_3d_get" qualifiers="const"> + <return type="Image[]"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="texture_3d_placeholder_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="texture_3d_update"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="data" type="Image[]"> + </argument> + <description> + </description> + </method> + <method name="texture_get_path" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="texture_proxy_create"> + <return type="RID"> + </return> + <argument index="0" name="base" type="RID"> + </argument> + <description> + </description> + </method> + <method name="texture_proxy_update"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="proxy_to" type="RID"> + </argument> + <description> + </description> + </method> + <method name="texture_replace"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="by_texture" type="RID"> + </argument> + <description> + </description> + </method> + <method name="texture_set_force_redraw_if_visible"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="texture_set_path"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="path" type="String"> + </argument> + <description> + </description> + </method> + <method name="texture_set_size_override"> + <return type="void"> + </return> + <argument index="0" name="texture" type="RID"> + </argument> + <argument index="1" name="width" type="int"> + </argument> + <argument index="2" name="height" type="int"> + </argument> + <description> + </description> + </method> <method name="viewport_attach_camera"> <return type="void"> </return> @@ -2725,7 +4053,7 @@ </return> <argument index="0" name="viewport" type="RID"> </argument> - <argument index="1" name="rect" type="Rect2" default="Rect2( 0, 0, 0, 0 )"> + <argument index="1" name="rect" type="Rect2" default="Rect2(0, 0, 0, 0)"> </argument> <argument index="2" name="screen" type="int" default="0"> </argument> @@ -2772,10 +4100,11 @@ </return> <argument index="0" name="viewport" type="RID"> </argument> - <argument index="1" name="info" type="int" enum="RenderingServer.ViewportRenderInfo"> + <argument index="1" name="type" type="int" enum="RenderingServer.ViewportRenderInfoType"> + </argument> + <argument index="2" name="info" type="int" enum="RenderingServer.ViewportRenderInfo"> </argument> <description> - Returns a viewport's render information. For options, see the [enum ViewportRenderInfo] constants. </description> </method> <method name="viewport_get_texture" qualifiers="const"> @@ -2860,48 +4189,67 @@ Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for options. </description> </method> - <method name="viewport_set_disable_environment"> + <method name="viewport_set_default_canvas_item_texture_filter"> <return type="void"> </return> <argument index="0" name="viewport" type="RID"> </argument> - <argument index="1" name="disabled" type="bool"> + <argument index="1" name="filter" type="int" enum="RenderingServer.CanvasItemTextureFilter"> </argument> <description> - If [code]true[/code], rendering of a viewport's environment is disabled. </description> </method> - <method name="viewport_set_global_canvas_transform"> + <method name="viewport_set_default_canvas_item_texture_repeat"> <return type="void"> </return> <argument index="0" name="viewport" type="RID"> </argument> - <argument index="1" name="transform" type="Transform2D"> + <argument index="1" name="repeat" type="int" enum="RenderingServer.CanvasItemTextureRepeat"> </argument> <description> - Sets the viewport's global transformation matrix. </description> </method> - <method name="viewport_set_hide_canvas"> + <method name="viewport_set_disable_2d"> <return type="void"> </return> <argument index="0" name="viewport" type="RID"> </argument> - <argument index="1" name="hidden" type="bool"> + <argument index="1" name="disable" type="bool"> </argument> <description> If [code]true[/code], the viewport's canvas is not rendered. </description> </method> - <method name="viewport_set_hide_scenario"> + <method name="viewport_set_disable_3d"> <return type="void"> </return> <argument index="0" name="viewport" type="RID"> </argument> - <argument index="1" name="hidden" type="bool"> + <argument index="1" name="disable" type="bool"> </argument> <description> - Currently unimplemented in Godot 3.x. + </description> + </method> + <method name="viewport_set_disable_environment"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="disabled" type="bool"> + </argument> + <description> + If [code]true[/code], rendering of a viewport's environment is disabled. + </description> + </method> + <method name="viewport_set_global_canvas_transform"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="transform" type="Transform2D"> + </argument> + <description> + Sets the viewport's global transformation matrix. </description> </method> <method name="viewport_set_measure_render_time"> @@ -2972,7 +4320,29 @@ </argument> <description> Sets a viewport's scenario. - The scenario contains information about the [enum ScenarioDebugMode], environment information, reflection atlas etc. + The scenario contains information about environment information, reflection atlas etc. + </description> + </method> + <method name="viewport_set_screen_space_aa"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="mode" type="int" enum="RenderingServer.ViewportScreenSpaceAA"> + </argument> + <description> + </description> + </method> + <method name="viewport_set_sdf_oversize_and_scale"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="oversize" type="int" enum="RenderingServer.ViewportSDFOversize"> + </argument> + <argument index="2" name="scale" type="int" enum="RenderingServer.ViewportSDFScale"> + </argument> + <description> </description> </method> <method name="viewport_set_shadow_atlas_quadrant_subdivision"> @@ -3014,6 +4384,26 @@ Sets the viewport's width and height. </description> </method> + <method name="viewport_set_snap_2d_transforms_to_pixel"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> + <method name="viewport_set_snap_2d_vertices_to_pixel"> + <return type="void"> + </return> + <argument index="0" name="viewport" type="RID"> + </argument> + <argument index="1" name="enabled" type="bool"> + </argument> + <description> + </description> + </method> <method name="viewport_set_transparent_background"> <return type="void"> </return> @@ -3067,6 +4457,188 @@ If [code]true[/code], the viewport uses augmented or virtual reality technologies. See [XRInterface]. </description> </method> + <method name="visibility_notifier_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="visibility_notifier_set_aabb"> + <return type="void"> + </return> + <argument index="0" name="notifier" type="RID"> + </argument> + <argument index="1" name="aabb" type="AABB"> + </argument> + <description> + </description> + </method> + <method name="visibility_notifier_set_callbacks"> + <return type="void"> + </return> + <argument index="0" name="notifier" type="RID"> + </argument> + <argument index="1" name="enter_callable" type="Callable"> + </argument> + <argument index="2" name="exit_callable" type="Callable"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_allocate_data"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="to_cell_xform" type="Transform3D"> + </argument> + <argument index="2" name="aabb" type="AABB"> + </argument> + <argument index="3" name="octree_size" type="Vector3i"> + </argument> + <argument index="4" name="octree_cells" type="PackedByteArray"> + </argument> + <argument index="5" name="data_cells" type="PackedByteArray"> + </argument> + <argument index="6" name="distance_field" type="PackedByteArray"> + </argument> + <argument index="7" name="level_counts" type="PackedInt32Array"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_create"> + <return type="RID"> + </return> + <description> + </description> + </method> + <method name="voxel_gi_get_data_cells" qualifiers="const"> + <return type="PackedByteArray"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_get_distance_field" qualifiers="const"> + <return type="PackedByteArray"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_get_level_counts" qualifiers="const"> + <return type="PackedInt32Array"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_get_octree_cells" qualifiers="const"> + <return type="PackedByteArray"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_get_octree_size" qualifiers="const"> + <return type="Vector3i"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_get_to_cell_xform" qualifiers="const"> + <return type="Transform3D"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_bias"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="bias" type="float"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_dynamic_range"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="range" type="float"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_energy"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="energy" type="float"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_interior"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_normal_bias"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="bias" type="float"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_propagation"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="amount" type="float"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_quality"> + <return type="void"> + </return> + <argument index="0" name="quality" type="int" enum="RenderingServer.VoxelGIQuality"> + </argument> + <description> + </description> + </method> + <method name="voxel_gi_set_use_two_bounces"> + <return type="void"> + </return> + <argument index="0" name="voxel_gi" type="RID"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> </methods> <members> <member name="render_loop_enabled" type="bool" setter="set_render_loop_enabled" getter="is_render_loop_enabled"> @@ -3104,6 +4676,8 @@ <constant name="MAX_CURSORS" value="8"> Unused enum in Godot 3.x. </constant> + <constant name="MAX_2D_DIRECTIONAL_LIGHTS" value="8"> + </constant> <constant name="TEXTURE_LAYERED_2D_ARRAY" value="0" enum="TextureLayeredType"> </constant> <constant name="TEXTURE_LAYERED_CUBEMAP" value="1" enum="TextureLayeredType"> @@ -3181,6 +4755,26 @@ <constant name="ARRAY_MAX" value="13" enum="ArrayType"> Represents the size of the [enum ArrayType] enum. </constant> + <constant name="ARRAY_CUSTOM_COUNT" value="4"> + </constant> + <constant name="ARRAY_CUSTOM_RGBA8_UNORM" value="0" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_RGBA8_SNORM" value="1" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_RG_HALF" value="2" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_RGBA_HALF" value="3" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_R_FLOAT" value="4" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_RG_FLOAT" value="5" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_RGB_FLOAT" value="6" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_RGBA_FLOAT" value="7" enum="ArrayCustomFormat"> + </constant> + <constant name="ARRAY_CUSTOM_MAX" value="8" enum="ArrayCustomFormat"> + </constant> <constant name="ARRAY_FORMAT_VERTEX" value="1" enum="ArrayFormat"> Flag used to mark a vertex array. </constant> @@ -3220,6 +4814,8 @@ </constant> <constant name="ARRAY_FORMAT_CUSTOM_BASE" value="13" enum="ArrayFormat"> </constant> + <constant name="ARRAY_FORMAT_CUSTOM_BITS" value="3" enum="ArrayFormat"> + </constant> <constant name="ARRAY_FORMAT_CUSTOM0_SHIFT" value="13" enum="ArrayFormat"> </constant> <constant name="ARRAY_FORMAT_CUSTOM1_SHIFT" value="16" enum="ArrayFormat"> @@ -3267,7 +4863,7 @@ Use [Transform2D] to store MultiMesh transform. </constant> <constant name="MULTIMESH_TRANSFORM_3D" value="1" enum="MultimeshTransformFormat"> - Use [Transform] to store MultiMesh transform. + Use [Transform3D] to store MultiMesh transform. </constant> <constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType"> Is a directional (sun) light. @@ -3328,6 +4924,8 @@ <constant name="LIGHT_PARAM_SHADOW_BLUR" value="16" enum="LightParam"> Blurs the edges of the shadow. Can be used to hide pixel artifacts in low resolution shadow maps. A high value can make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible. </constant> + <constant name="LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE" value="17" enum="LightParam"> + </constant> <constant name="LIGHT_PARAM_TRANSMITTANCE_BIAS" value="18" enum="LightParam"> </constant> <constant name="LIGHT_PARAM_MAX" value="19" enum="LightParam"> @@ -3354,11 +4952,17 @@ <constant name="LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS" value="2" enum="LightDirectionalShadowMode"> Use 4 splits for shadow projection when using directional light. </constant> - <constant name="LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE" value="0" enum="LightDirectionalShadowDepthRangeMode"> - Keeps shadows stable as camera moves but has lower effective resolution. + <constant name="SHADOW_QUALITY_HARD" value="0" enum="ShadowQuality"> </constant> - <constant name="LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED" value="1" enum="LightDirectionalShadowDepthRangeMode"> - Optimize use of shadow maps, increasing the effective resolution. But may result in shadows moving or flickering slightly. + <constant name="SHADOW_QUALITY_SOFT_LOW" value="1" enum="ShadowQuality"> + </constant> + <constant name="SHADOW_QUALITY_SOFT_MEDIUM" value="2" enum="ShadowQuality"> + </constant> + <constant name="SHADOW_QUALITY_SOFT_HIGH" value="3" enum="ShadowQuality"> + </constant> + <constant name="SHADOW_QUALITY_SOFT_ULTRA" value="4" enum="ShadowQuality"> + </constant> + <constant name="SHADOW_QUALITY_MAX" value="5" enum="ShadowQuality"> </constant> <constant name="REFLECTION_PROBE_UPDATE_ONCE" value="0" enum="ReflectionProbeUpdateMode"> Reflection probe will update reflections once and then stop. @@ -3382,15 +4986,71 @@ </constant> <constant name="DECAL_TEXTURE_MAX" value="4" enum="DecalTexture"> </constant> + <constant name="VOXEL_GI_QUALITY_LOW" value="0" enum="VoxelGIQuality"> + </constant> + <constant name="VOXEL_GI_QUALITY_HIGH" value="1" enum="VoxelGIQuality"> + </constant> + <constant name="PARTICLES_MODE_2D" value="0" enum="ParticlesMode"> + </constant> + <constant name="PARTICLES_MODE_3D" value="1" enum="ParticlesMode"> + </constant> + <constant name="PARTICLES_TRANSFORM_ALIGN_DISABLED" value="0" enum="ParticlesTransformAlign"> + </constant> + <constant name="PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD" value="1" enum="ParticlesTransformAlign"> + </constant> + <constant name="PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY" value="2" enum="ParticlesTransformAlign"> + </constant> + <constant name="PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY" value="3" enum="ParticlesTransformAlign"> + </constant> + <constant name="PARTICLES_EMIT_FLAG_POSITION" value="1"> + </constant> + <constant name="PARTICLES_EMIT_FLAG_ROTATION_SCALE" value="2"> + </constant> + <constant name="PARTICLES_EMIT_FLAG_VELOCITY" value="4"> + </constant> + <constant name="PARTICLES_EMIT_FLAG_COLOR" value="8"> + </constant> + <constant name="PARTICLES_EMIT_FLAG_CUSTOM" value="16"> + </constant> <constant name="PARTICLES_DRAW_ORDER_INDEX" value="0" enum="ParticlesDrawOrder"> Draw particles in the order that they appear in the particles array. </constant> <constant name="PARTICLES_DRAW_ORDER_LIFETIME" value="1" enum="ParticlesDrawOrder"> Sort particles based on their lifetime. </constant> + <constant name="PARTICLES_DRAW_ORDER_REVERSE_LIFETIME" value="2" enum="ParticlesDrawOrder"> + </constant> <constant name="PARTICLES_DRAW_ORDER_VIEW_DEPTH" value="3" enum="ParticlesDrawOrder"> Sort particles based on their distance to the camera. </constant> + <constant name="PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT" value="0" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_TYPE_BOX_ATTRACT" value="1" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT" value="2" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE" value="3" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_TYPE_BOX_COLLIDE" value="4" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_TYPE_SDF_COLLIDE" value="5" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE" value="6" enum="ParticlesCollisionType"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_256" value="0" enum="ParticlesCollisionHeightfieldResolution"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_512" value="1" enum="ParticlesCollisionHeightfieldResolution"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024" value="2" enum="ParticlesCollisionHeightfieldResolution"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_2048" value="3" enum="ParticlesCollisionHeightfieldResolution"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_4096" value="4" enum="ParticlesCollisionHeightfieldResolution"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_8192" value="5" enum="ParticlesCollisionHeightfieldResolution"> + </constant> + <constant name="PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX" value="6" enum="ParticlesCollisionHeightfieldResolution"> + </constant> <constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode"> Do not update the viewport. </constant> @@ -3414,6 +5074,24 @@ <constant name="VIEWPORT_CLEAR_ONLY_NEXT_FRAME" value="2" enum="ViewportClearMode"> The viewport is cleared once, then the clear mode is set to [constant VIEWPORT_CLEAR_NEVER]. </constant> + <constant name="VIEWPORT_SDF_OVERSIZE_100_PERCENT" value="0" enum="ViewportSDFOversize"> + </constant> + <constant name="VIEWPORT_SDF_OVERSIZE_120_PERCENT" value="1" enum="ViewportSDFOversize"> + </constant> + <constant name="VIEWPORT_SDF_OVERSIZE_150_PERCENT" value="2" enum="ViewportSDFOversize"> + </constant> + <constant name="VIEWPORT_SDF_OVERSIZE_200_PERCENT" value="3" enum="ViewportSDFOversize"> + </constant> + <constant name="VIEWPORT_SDF_OVERSIZE_MAX" value="4" enum="ViewportSDFOversize"> + </constant> + <constant name="VIEWPORT_SDF_SCALE_100_PERCENT" value="0" enum="ViewportSDFScale"> + </constant> + <constant name="VIEWPORT_SDF_SCALE_50_PERCENT" value="1" enum="ViewportSDFScale"> + </constant> + <constant name="VIEWPORT_SDF_SCALE_25_PERCENT" value="2" enum="ViewportSDFScale"> + </constant> + <constant name="VIEWPORT_SDF_SCALE_MAX" value="3" enum="ViewportSDFScale"> + </constant> <constant name="VIEWPORT_MSAA_DISABLED" value="0" enum="ViewportMSAA"> Multisample antialiasing is disabled. </constant> @@ -3437,26 +5115,29 @@ </constant> <constant name="VIEWPORT_SCREEN_SPACE_AA_MAX" value="2" enum="ViewportScreenSpaceAA"> </constant> + <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW" value="0" enum="ViewportOcclusionCullingBuildQuality"> + </constant> + <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM" value="1" enum="ViewportOcclusionCullingBuildQuality"> + </constant> + <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH" value="2" enum="ViewportOcclusionCullingBuildQuality"> + </constant> <constant name="VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME" value="0" enum="ViewportRenderInfo"> Number of objects drawn in a single frame. </constant> - <constant name="VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME" value="1" enum="ViewportRenderInfo"> + <constant name="VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME" value="1" enum="ViewportRenderInfo"> Number of vertices drawn in a single frame. </constant> - <constant name="VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="ViewportRenderInfo"> - Number of material changes during this frame. + <constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="2" enum="ViewportRenderInfo"> + Number of draw calls during this frame. </constant> - <constant name="VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="ViewportRenderInfo"> - Number of shader changes during this frame. + <constant name="VIEWPORT_RENDER_INFO_MAX" value="3" enum="ViewportRenderInfo"> + Represents the size of the [enum ViewportRenderInfo] enum. </constant> - <constant name="VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="ViewportRenderInfo"> - Number of surface changes during this frame. + <constant name="VIEWPORT_RENDER_INFO_TYPE_VISIBLE" value="0" enum="ViewportRenderInfoType"> </constant> - <constant name="VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME" value="5" enum="ViewportRenderInfo"> - Number of draw calls during this frame. + <constant name="VIEWPORT_RENDER_INFO_TYPE_SHADOW" value="1" enum="ViewportRenderInfoType"> </constant> - <constant name="VIEWPORT_RENDER_INFO_MAX" value="6" enum="ViewportRenderInfo"> - Represents the size of the [enum ViewportRenderInfo] enum. + <constant name="VIEWPORT_RENDER_INFO_TYPE_MAX" value="2" enum="ViewportRenderInfoType"> </constant> <constant name="VIEWPORT_DEBUG_DRAW_DISABLED" value="0" enum="ViewportDebugDraw"> Debug draw is disabled. Default setting. @@ -3477,14 +5158,14 @@ <constant name="VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="ViewportDebugDraw"> Normal buffer is drawn instead of regular scene so you can see the per-pixel normals that will be used by post-processing effects. </constant> - <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO" value="6" enum="ViewportDebugDraw"> - Objects are displayed with only the albedo value from [GIProbe]s. + <constant name="VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO" value="6" enum="ViewportDebugDraw"> + Objects are displayed with only the albedo value from [VoxelGI]s. </constant> - <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING" value="7" enum="ViewportDebugDraw"> - Objects are displayed with only the lighting value from [GIProbe]s. + <constant name="VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING" value="7" enum="ViewportDebugDraw"> + Objects are displayed with only the lighting value from [VoxelGI]s. </constant> - <constant name="VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION" value="8" enum="ViewportDebugDraw"> - Objects are displayed with only the emission color from [GIProbe]s. + <constant name="VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION" value="8" enum="ViewportDebugDraw"> + Objects are displayed with only the emission color from [VoxelGI]s. </constant> <constant name="VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS" value="9" enum="ViewportDebugDraw"> Draws the shadow atlas that stores shadows from [OmniLight3D]s and [SpotLight3D]s in the upper left quadrant of the [Viewport]. @@ -3508,11 +5189,25 @@ </constant> <constant name="VIEWPORT_DEBUG_DRAW_GI_BUFFER" value="17" enum="ViewportDebugDraw"> </constant> + <constant name="VIEWPORT_DEBUG_DRAW_DISABLE_LOD" value="18" enum="ViewportDebugDraw"> + </constant> + <constant name="VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS" value="19" enum="ViewportDebugDraw"> + </constant> + <constant name="VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS" value="20" enum="ViewportDebugDraw"> + </constant> + <constant name="VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS" value="21" enum="ViewportDebugDraw"> + </constant> + <constant name="VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES" value="22" enum="ViewportDebugDraw"> + </constant> <constant name="VIEWPORT_DEBUG_DRAW_OCCLUDERS" value="23" enum="ViewportDebugDraw"> </constant> + <constant name="SKY_MODE_AUTOMATIC" value="0" enum="SkyMode"> + </constant> <constant name="SKY_MODE_QUALITY" value="1" enum="SkyMode"> Uses high quality importance sampling to process the radiance map. In general, this results in much higher quality than [constant Sky.PROCESS_MODE_REALTIME] but takes much longer to generate. This should not be used if you plan on changing the sky at runtime. If you are finding that the reflection is not blurry enough and is showing sparkles or fireflies, try increasing [member ProjectSettings.rendering/reflections/sky_reflections/ggx_samples]. </constant> + <constant name="SKY_MODE_INCREMENTAL" value="2" enum="SkyMode"> + </constant> <constant name="SKY_MODE_REALTIME" value="3" enum="SkyMode"> Uses the fast filtering algorithm to process the radiance map. In general this results in lower quality, but substantially faster run times. [b]Note:[/b] The fast filtering algorithm is limited to 256x256 cubemaps, so [member Sky.radiance_size] must be set to [constant Sky.RADIANCE_SIZE_256]. @@ -3609,64 +5304,88 @@ <constant name="ENV_SSAO_QUALITY_ULTRA" value="4" enum="EnvironmentSSAOQuality"> Highest quality screen space ambient occlusion. Uses the adaptive setting which can be dynamically adjusted to smoothly balance performance and visual quality. </constant> - <constant name="SUB_SURFACE_SCATTERING_QUALITY_DISABLED" value="0" enum="SubSurfaceScatteringQuality"> + <constant name="ENV_SDFGI_CASCADES_4" value="0" enum="EnvironmentSDFGICascades"> </constant> - <constant name="SUB_SURFACE_SCATTERING_QUALITY_LOW" value="1" enum="SubSurfaceScatteringQuality"> + <constant name="ENV_SDFGI_CASCADES_6" value="1" enum="EnvironmentSDFGICascades"> </constant> - <constant name="SUB_SURFACE_SCATTERING_QUALITY_MEDIUM" value="2" enum="SubSurfaceScatteringQuality"> + <constant name="ENV_SDFGI_CASCADES_8" value="2" enum="EnvironmentSDFGICascades"> </constant> - <constant name="SUB_SURFACE_SCATTERING_QUALITY_HIGH" value="3" enum="SubSurfaceScatteringQuality"> + <constant name="ENV_SDFGI_Y_SCALE_DISABLED" value="0" enum="EnvironmentSDFGIYScale"> </constant> - <constant name="DOF_BLUR_QUALITY_VERY_LOW" value="0" enum="DOFBlurQuality"> - Lowest quality DOF blur. This is the fastest setting, but you may be able to see filtering artifacts. + <constant name="ENV_SDFGI_Y_SCALE_75_PERCENT" value="1" enum="EnvironmentSDFGIYScale"> </constant> - <constant name="DOF_BLUR_QUALITY_LOW" value="1" enum="DOFBlurQuality"> - Low quality DOF blur. + <constant name="ENV_SDFGI_Y_SCALE_50_PERCENT" value="2" enum="EnvironmentSDFGIYScale"> </constant> - <constant name="DOF_BLUR_QUALITY_MEDIUM" value="2" enum="DOFBlurQuality"> - Medium quality DOF blur. + <constant name="ENV_SDFGI_RAY_COUNT_4" value="0" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="DOF_BLUR_QUALITY_HIGH" value="3" enum="DOFBlurQuality"> - Highest quality DOF blur. Results in the smoothest looking blur by taking the most samples, but is also significantly slower. + <constant name="ENV_SDFGI_RAY_COUNT_8" value="1" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="DOF_BOKEH_BOX" value="0" enum="DOFBokehShape"> - Calculate the DOF blur using a box filter. The fastest option, but results in obvious lines in blur pattern. + <constant name="ENV_SDFGI_RAY_COUNT_16" value="2" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="DOF_BOKEH_HEXAGON" value="1" enum="DOFBokehShape"> - Calculates DOF blur using a hexagon shaped filter. + <constant name="ENV_SDFGI_RAY_COUNT_32" value="3" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="DOF_BOKEH_CIRCLE" value="2" enum="DOFBokehShape"> - Calculates DOF blur using a circle shaped filter. Best quality and most realistic, but slowest. Use only for areas where a lot of performance can be dedicated to post-processing (e.g. cutscenes). + <constant name="ENV_SDFGI_RAY_COUNT_64" value="4" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="SHADOW_QUALITY_HARD" value="0" enum="ShadowQuality"> + <constant name="ENV_SDFGI_RAY_COUNT_96" value="5" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="SHADOW_QUALITY_SOFT_LOW" value="1" enum="ShadowQuality"> + <constant name="ENV_SDFGI_RAY_COUNT_128" value="6" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="SHADOW_QUALITY_SOFT_MEDIUM" value="2" enum="ShadowQuality"> + <constant name="ENV_SDFGI_RAY_COUNT_MAX" value="7" enum="EnvironmentSDFGIRayCount"> </constant> - <constant name="SHADOW_QUALITY_SOFT_HIGH" value="3" enum="ShadowQuality"> + <constant name="ENV_SDFGI_CONVERGE_IN_5_FRAMES" value="0" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="SHADOW_QUALITY_SOFT_ULTRA" value="4" enum="ShadowQuality"> + <constant name="ENV_SDFGI_CONVERGE_IN_10_FRAMES" value="1" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="SHADOW_QUALITY_MAX" value="5" enum="ShadowQuality"> + <constant name="ENV_SDFGI_CONVERGE_IN_15_FRAMES" value="2" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="SCENARIO_DEBUG_DISABLED" value="0" enum="ScenarioDebugMode"> - Do not use a debug mode. + <constant name="ENV_SDFGI_CONVERGE_IN_20_FRAMES" value="3" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="SCENARIO_DEBUG_WIREFRAME" value="1" enum="ScenarioDebugMode"> - Draw all objects as wireframe models. + <constant name="ENV_SDFGI_CONVERGE_IN_25_FRAMES" value="4" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="SCENARIO_DEBUG_OVERDRAW" value="2" enum="ScenarioDebugMode"> - Draw all objects in a way that displays how much overdraw is occurring. Overdraw occurs when a section of pixels is drawn and shaded and then another object covers it up. To optimize a scene, you should reduce overdraw. + <constant name="ENV_SDFGI_CONVERGE_IN_30_FRAMES" value="5" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="SCENARIO_DEBUG_SHADELESS" value="3" enum="ScenarioDebugMode"> - Draw all objects without shading. Equivalent to setting all objects shaders to [code]unshaded[/code]. + <constant name="ENV_SDFGI_CONVERGE_MAX" value="6" enum="EnvironmentSDFGIFramesToConverge"> </constant> - <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW" value="0" enum="ViewportOcclusionCullingBuildQuality"> + <constant name="ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME" value="0" enum="EnvironmentSDFGIFramesToUpdateLight"> </constant> - <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM" value="1" enum="ViewportOcclusionCullingBuildQuality"> + <constant name="ENV_SDFGI_UPDATE_LIGHT_IN_2_FRAMES" value="1" enum="EnvironmentSDFGIFramesToUpdateLight"> </constant> - <constant name="VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH" value="2" enum="ViewportOcclusionCullingBuildQuality"> + <constant name="ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES" value="2" enum="EnvironmentSDFGIFramesToUpdateLight"> + </constant> + <constant name="ENV_SDFGI_UPDATE_LIGHT_IN_8_FRAMES" value="3" enum="EnvironmentSDFGIFramesToUpdateLight"> + </constant> + <constant name="ENV_SDFGI_UPDATE_LIGHT_IN_16_FRAMES" value="4" enum="EnvironmentSDFGIFramesToUpdateLight"> + </constant> + <constant name="ENV_SDFGI_UPDATE_LIGHT_MAX" value="5" enum="EnvironmentSDFGIFramesToUpdateLight"> + </constant> + <constant name="SUB_SURFACE_SCATTERING_QUALITY_DISABLED" value="0" enum="SubSurfaceScatteringQuality"> + </constant> + <constant name="SUB_SURFACE_SCATTERING_QUALITY_LOW" value="1" enum="SubSurfaceScatteringQuality"> + </constant> + <constant name="SUB_SURFACE_SCATTERING_QUALITY_MEDIUM" value="2" enum="SubSurfaceScatteringQuality"> + </constant> + <constant name="SUB_SURFACE_SCATTERING_QUALITY_HIGH" value="3" enum="SubSurfaceScatteringQuality"> + </constant> + <constant name="DOF_BOKEH_BOX" value="0" enum="DOFBokehShape"> + Calculate the DOF blur using a box filter. The fastest option, but results in obvious lines in blur pattern. + </constant> + <constant name="DOF_BOKEH_HEXAGON" value="1" enum="DOFBokehShape"> + Calculates DOF blur using a hexagon shaped filter. + </constant> + <constant name="DOF_BOKEH_CIRCLE" value="2" enum="DOFBokehShape"> + Calculates DOF blur using a circle shaped filter. Best quality and most realistic, but slowest. Use only for areas where a lot of performance can be dedicated to post-processing (e.g. cutscenes). + </constant> + <constant name="DOF_BLUR_QUALITY_VERY_LOW" value="0" enum="DOFBlurQuality"> + Lowest quality DOF blur. This is the fastest setting, but you may be able to see filtering artifacts. + </constant> + <constant name="DOF_BLUR_QUALITY_LOW" value="1" enum="DOFBlurQuality"> + Low quality DOF blur. + </constant> + <constant name="DOF_BLUR_QUALITY_MEDIUM" value="2" enum="DOFBlurQuality"> + Medium quality DOF blur. + </constant> + <constant name="DOF_BLUR_QUALITY_HIGH" value="3" enum="DOFBlurQuality"> + Highest quality DOF blur. Results in the smoothest looking blur by taking the most samples, but is also significantly slower. </constant> <constant name="INSTANCE_NONE" value="0" enum="InstanceType"> The instance does not have a type. @@ -3677,35 +5396,34 @@ <constant name="INSTANCE_MULTIMESH" value="2" enum="InstanceType"> The instance is a multimesh. </constant> - <constant name="INSTANCE_IMMEDIATE" value="3" enum="InstanceType"> - The instance is an immediate geometry. - </constant> - <constant name="INSTANCE_PARTICLES" value="4" enum="InstanceType"> + <constant name="INSTANCE_PARTICLES" value="3" enum="InstanceType"> The instance is a particle emitter. </constant> - <constant name="INSTANCE_PARTICLES_COLLISION" value="5" enum="InstanceType"> + <constant name="INSTANCE_PARTICLES_COLLISION" value="4" enum="InstanceType"> </constant> - <constant name="INSTANCE_LIGHT" value="6" enum="InstanceType"> + <constant name="INSTANCE_LIGHT" value="5" enum="InstanceType"> The instance is a light. </constant> - <constant name="INSTANCE_REFLECTION_PROBE" value="7" enum="InstanceType"> + <constant name="INSTANCE_REFLECTION_PROBE" value="6" enum="InstanceType"> The instance is a reflection probe. </constant> - <constant name="INSTANCE_DECAL" value="8" enum="InstanceType"> + <constant name="INSTANCE_DECAL" value="7" enum="InstanceType"> The instance is a decal. </constant> - <constant name="INSTANCE_GI_PROBE" value="9" enum="InstanceType"> - The instance is a GI probe. + <constant name="INSTANCE_VOXEL_GI" value="8" enum="InstanceType"> + The instance is a VoxelGI. </constant> - <constant name="INSTANCE_LIGHTMAP" value="10" enum="InstanceType"> + <constant name="INSTANCE_LIGHTMAP" value="9" enum="InstanceType"> The instance is a lightmap. </constant> - <constant name="INSTANCE_OCCLUDER" value="11" enum="InstanceType"> + <constant name="INSTANCE_OCCLUDER" value="10" enum="InstanceType"> + </constant> + <constant name="INSTANCE_VISIBLITY_NOTIFIER" value="11" enum="InstanceType"> </constant> <constant name="INSTANCE_MAX" value="12" enum="InstanceType"> Represents the size of the [enum InstanceType] enum. </constant> - <constant name="INSTANCE_GEOMETRY_MASK" value="30" enum="InstanceType"> + <constant name="INSTANCE_GEOMETRY_MASK" value="14" enum="InstanceType"> A combination of the flags of geometry instances (mesh, multimesh, immediate and particles). </constant> <constant name="INSTANCE_FLAG_USE_BAKED_LIGHT" value="0" enum="InstanceFlags"> @@ -3734,6 +5452,20 @@ <constant name="SHADOW_CASTING_SETTING_SHADOWS_ONLY" value="3" enum="ShadowCastingSetting"> Only render the shadows from the object. The object itself will not be drawn. </constant> + <constant name="BAKE_CHANNEL_ALBEDO_ALPHA" value="0" enum="BakeChannels"> + </constant> + <constant name="BAKE_CHANNEL_NORMAL" value="1" enum="BakeChannels"> + </constant> + <constant name="BAKE_CHANNEL_ORM" value="2" enum="BakeChannels"> + </constant> + <constant name="BAKE_CHANNEL_EMISSION" value="3" enum="BakeChannels"> + </constant> + <constant name="CANVAS_TEXTURE_CHANNEL_DIFFUSE" value="0" enum="CanvasTextureChannel"> + </constant> + <constant name="CANVAS_TEXTURE_CHANNEL_NORMAL" value="1" enum="CanvasTextureChannel"> + </constant> + <constant name="CANVAS_TEXTURE_CHANNEL_SPECULAR" value="2" enum="CanvasTextureChannel"> + </constant> <constant name="NINE_PATCH_STRETCH" value="0" enum="NinePatchAxisMode"> The nine patch gets stretched where needed. </constant> @@ -3880,35 +5612,17 @@ </constant> <constant name="GLOBAL_VAR_TYPE_MAX" value="28" enum="GlobalVariableType"> </constant> - <constant name="INFO_OBJECTS_IN_FRAME" value="0" enum="RenderInfo"> - The amount of objects in the frame. - </constant> - <constant name="INFO_VERTICES_IN_FRAME" value="1" enum="RenderInfo"> - The amount of vertices in the frame. - </constant> - <constant name="INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="RenderInfo"> - The amount of modified materials in the frame. - </constant> - <constant name="INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="RenderInfo"> - The amount of shader rebinds in the frame. - </constant> - <constant name="INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="RenderInfo"> - The amount of surface changes in the frame. + <constant name="RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME" value="0" enum="RenderingInfo"> </constant> - <constant name="INFO_DRAW_CALLS_IN_FRAME" value="5" enum="RenderInfo"> - The amount of draw calls in frame. + <constant name="RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME" value="1" enum="RenderingInfo"> </constant> - <constant name="INFO_USAGE_VIDEO_MEM_TOTAL" value="6" enum="RenderInfo"> - Unimplemented in the GLES2 rendering backend, always returns 0. + <constant name="RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME" value="2" enum="RenderingInfo"> </constant> - <constant name="INFO_VIDEO_MEM_USED" value="7" enum="RenderInfo"> - The amount of video memory used, i.e. texture and vertex memory combined. + <constant name="RENDERING_INFO_TEXTURE_MEM_USED" value="3" enum="RenderingInfo"> </constant> - <constant name="INFO_TEXTURE_MEM_USED" value="8" enum="RenderInfo"> - The amount of texture memory used. + <constant name="RENDERING_INFO_BUFFER_MEM_USED" value="4" enum="RenderingInfo"> </constant> - <constant name="INFO_VERTEX_MEM_USED" value="9" enum="RenderInfo"> - The amount of vertex memory used. + <constant name="RENDERING_INFO_VIDEO_MEM_USED" value="5" enum="RenderingInfo"> </constant> <constant name="FEATURE_SHADERS" value="0" enum="Features"> Hardware supports shaders. This enum is currently unused in Godot 3.x. diff --git a/doc/classes/Resource.xml b/doc/classes/Resource.xml index 75736798fd..c8800a3c25 100644 --- a/doc/classes/Resource.xml +++ b/doc/classes/Resource.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Resource" inherits="Reference" version="4.0"> +<class name="Resource" inherits="RefCounted" version="4.0"> <brief_description> Base class for all resources. </brief_description> <description> - Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [Reference], resources are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instanced from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource. + Resource is the base class for all Godot-specific resource types, serving primarily as data containers. Since they inherit from [RefCounted], resources are reference-counted and freed when no longer in use. They are also cached once loaded from disk, so that any further attempts to load a resource from a given path will return the same reference (all this in contrast to a [Node], which is not reference-counted and can be instantiated from disk as many times as desired). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource. [b]Note:[/b] In C#, resources will not be freed instantly after they are no longer in use. Instead, garbage collection will run periodically and will free resources that are no longer in use. This means that unused resources will linger on for a while before being removed. </description> <tutorials> diff --git a/doc/classes/ResourceFormatLoader.xml b/doc/classes/ResourceFormatLoader.xml index 9943f644cf..6abe5c813b 100644 --- a/doc/classes/ResourceFormatLoader.xml +++ b/doc/classes/ResourceFormatLoader.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ResourceFormatLoader" inherits="Reference" version="4.0"> +<class name="ResourceFormatLoader" inherits="RefCounted" version="4.0"> <brief_description> Loads a specific resource type from a file. </brief_description> @@ -11,7 +11,7 @@ <tutorials> </tutorials> <methods> - <method name="get_dependencies" qualifiers="virtual"> + <method name="_get_dependencies" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="path" type="String"> @@ -23,14 +23,14 @@ [b]Note:[/b] Custom resource types defined by scripts aren't known by the [ClassDB], so you might just return [code]"Resource"[/code] for them. </description> </method> - <method name="get_recognized_extensions" qualifiers="virtual"> + <method name="_get_recognized_extensions" qualifiers="virtual"> <return type="PackedStringArray"> </return> <description> Gets the list of extensions for files this loader is able to read. </description> </method> - <method name="get_resource_type" qualifiers="virtual"> + <method name="_get_resource_type" qualifiers="virtual"> <return type="String"> </return> <argument index="0" name="path" type="String"> @@ -40,7 +40,7 @@ [b]Note:[/b] Custom resource types defined by scripts aren't known by the [ClassDB], so you might just return [code]"Resource"[/code] for them. </description> </method> - <method name="handles_type" qualifiers="virtual"> + <method name="_handles_type" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="typename" type="StringName"> @@ -50,7 +50,7 @@ [b]Note:[/b] Custom resource types defined by scripts aren't known by the [ClassDB], so you might just handle [code]"Resource"[/code] for them. </description> </method> - <method name="load" qualifiers="virtual"> + <method name="_load" qualifiers="virtual"> <return type="Variant"> </return> <argument index="0" name="path" type="String"> @@ -66,7 +66,7 @@ The [code]cache_mode[/code] property defines whether and how the cache should be used or updated when loading the resource. See [enum CacheMode] for details. </description> </method> - <method name="rename_dependencies" qualifiers="virtual"> + <method name="_rename_dependencies" qualifiers="virtual"> <return type="int"> </return> <argument index="0" name="path" type="String"> diff --git a/doc/classes/ResourceFormatSaver.xml b/doc/classes/ResourceFormatSaver.xml index 69f8b43898..df71e05d02 100644 --- a/doc/classes/ResourceFormatSaver.xml +++ b/doc/classes/ResourceFormatSaver.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ResourceFormatSaver" inherits="Reference" version="4.0"> +<class name="ResourceFormatSaver" inherits="RefCounted" version="4.0"> <brief_description> Saves a specific resource type to a file. </brief_description> @@ -10,16 +10,16 @@ <tutorials> </tutorials> <methods> - <method name="get_recognized_extensions" qualifiers="virtual"> + <method name="_get_recognized_extensions" qualifiers="virtual"> <return type="PackedStringArray"> </return> <argument index="0" name="resource" type="Resource"> </argument> <description> - Returns the list of extensions available for saving the resource object, provided it is recognized (see [method recognize]). + Returns the list of extensions available for saving the resource object, provided it is recognized (see [method _recognize]). </description> </method> - <method name="recognize" qualifiers="virtual"> + <method name="_recognize" qualifiers="virtual"> <return type="bool"> </return> <argument index="0" name="resource" type="Resource"> @@ -28,7 +28,7 @@ Returns whether the given resource object can be saved by this saver. </description> </method> - <method name="save" qualifiers="virtual"> + <method name="_save" qualifiers="virtual"> <return type="int"> </return> <argument index="0" name="path" type="String"> diff --git a/doc/classes/ResourceImporter.xml b/doc/classes/ResourceImporter.xml index 0475d2c94d..59900b1b73 100644 --- a/doc/classes/ResourceImporter.xml +++ b/doc/classes/ResourceImporter.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="ResourceImporter" inherits="Reference" version="4.0"> +<class name="ResourceImporter" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index c81b21333f..682d7b97f3 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -84,7 +84,7 @@ </return> <argument index="0" name="path" type="String"> </argument> - <argument index="1" name="progress" type="Array" default="[ ]"> + <argument index="1" name="progress" type="Array" default="[]"> </argument> <description> Returns the status of a threaded loading operation started with [method load_threaded_request] for the resource at [code]path[/code]. See [enum ThreadLoadStatus] for possible return values. diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml index 7ca70f5a7a..38884a027f 100644 --- a/doc/classes/RichTextLabel.xml +++ b/doc/classes/RichTextLabel.xml @@ -24,7 +24,7 @@ </argument> <argument index="2" name="height" type="int" default="0"> </argument> - <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="4" name="inline_align" type="int" enum="VAlign" default="0"> </argument> @@ -170,6 +170,15 @@ Terminates the current tag. Use after [code]push_*[/code] methods to close BBCodes manually. Does not need to follow [code]add_*[/code] methods. </description> </method> + <method name="push_bgcolor"> + <return type="void"> + </return> + <argument index="0" name="bgcolor" type="Color"> + </argument> + <description> + Adds a [code][bgcolor][/code] tag to the tag stack. + </description> + </method> <method name="push_bold"> <return type="void"> </return> @@ -209,18 +218,27 @@ </argument> <argument index="2" name="size" type="int"> </argument> - <argument index="3" name="dropcap_margins" type="Rect2" default="Rect2( 0, 0, 0, 0 )"> + <argument index="3" name="dropcap_margins" type="Rect2" default="Rect2(0, 0, 0, 0)"> </argument> - <argument index="4" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="4" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="5" name="outline_size" type="int" default="0"> </argument> - <argument index="6" name="outline_color" type="Color" default="Color( 0, 0, 0, 0 )"> + <argument index="6" name="outline_color" type="Color" default="Color(0, 0, 0, 0)"> </argument> <description> Adds a [code][dropcap][/code] tag to the tag stack. Drop cap (dropped capital) is a decorative element at the beginning of a paragraph that is larger than the rest of the text. </description> </method> + <method name="push_fgcolor"> + <return type="void"> + </return> + <argument index="0" name="fgcolor" type="Color"> + </argument> + <description> + Adds a [code][fgcolor][/code] tag to the tag stack. + </description> + </method> <method name="push_font"> <return type="void"> </return> @@ -450,7 +468,7 @@ The label's text in BBCode format. Is not representative of manual modifications to the internal tag stack. Erases changes made by other methods when edited. [b]Note:[/b] It is unadvised to use the [code]+=[/code] operator with [code]bbcode_text[/code] (e.g. [code]bbcode_text += "some string"[/code]) as it replaces the whole text and can cause slowdowns. Use [method append_bbcode] for adding text instead, unless you absolutely need to close a tag that was opened in an earlier method call. </member> - <member name="custom_effects" type="Array" setter="set_effects" getter="get_effects" default="[ ]"> + <member name="custom_effects" type="Array" setter="set_effects" getter="get_effects" default="[]"> The currently installed custom effects. This is an array of [RichTextEffect]s. To add a custom effect, it's more convenient to use [method install_effect]. </member> @@ -484,7 +502,7 @@ <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0"> Set BiDi algorithm override for the structured text. </member> - <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]"> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[]"> Set additional options for BiDi override. </member> <member name="tab_size" type="int" setter="set_tab_size" getter="get_tab_size" default="4"> @@ -592,11 +610,15 @@ </constant> <constant name="ITEM_RAINBOW" value="20" enum="ItemType"> </constant> - <constant name="ITEM_META" value="21" enum="ItemType"> + <constant name="ITEM_BGCOLOR" value="21" enum="ItemType"> + </constant> + <constant name="ITEM_FGCOLOR" value="22" enum="ItemType"> + </constant> + <constant name="ITEM_META" value="23" enum="ItemType"> </constant> - <constant name="ITEM_DROPCAP" value="22" enum="ItemType"> + <constant name="ITEM_DROPCAP" value="24" enum="ItemType"> </constant> - <constant name="ITEM_CUSTOMFX" value="23" enum="ItemType"> + <constant name="ITEM_CUSTOMFX" value="25" enum="ItemType"> </constant> </constants> <theme_items> @@ -612,19 +634,19 @@ <theme_item name="bold_italics_font_size" type="int"> The font size used for bold italics text. </theme_item> - <theme_item name="default_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="default_color" type="Color" default="Color(1, 1, 1, 1)"> The default text color. </theme_item> <theme_item name="focus" type="StyleBox"> The background The background used when the [RichTextLabel] is focused. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The default tint of text outline. </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(0, 0, 0, 1)"> The color of selected text, used when [member selection_enabled] is [code]true[/code]. </theme_item> - <theme_item name="font_shadow_color" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="font_shadow_color" type="Color" default="Color(0, 0, 0, 0)"> The color of the font's shadow. </theme_item> <theme_item name="italics_font" type="Font"> @@ -654,7 +676,7 @@ <theme_item name="outline_size" type="int" default="0"> The size of the text outline. </theme_item> - <theme_item name="selection_color" type="Color" default="Color( 0.1, 0.1, 1, 0.8 )"> + <theme_item name="selection_color" type="Color" default="Color(0.1, 0.1, 1, 0.8)"> The color of the selection box. </theme_item> <theme_item name="shadow_as_outline" type="int" default="0"> @@ -666,16 +688,16 @@ <theme_item name="shadow_offset_y" type="int" default="1"> The vertical offset of the font's shadow. </theme_item> - <theme_item name="table_border" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="table_border" type="Color" default="Color(0, 0, 0, 0)"> The default cell border color. </theme_item> - <theme_item name="table_even_row_bg" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="table_even_row_bg" type="Color" default="Color(0, 0, 0, 0)"> The default background color for even rows. </theme_item> <theme_item name="table_hseparation" type="int" default="3"> The horizontal separation of elements in a table. </theme_item> - <theme_item name="table_odd_row_bg" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="table_odd_row_bg" type="Color" default="Color(0, 0, 0, 0)"> The default background color for odd rows. </theme_item> <theme_item name="table_vseparation" type="int" default="3"> diff --git a/doc/classes/RigidBody2D.xml b/doc/classes/RigidBody2D.xml index a37ebb2dd5..64573b7282 100644 --- a/doc/classes/RigidBody2D.xml +++ b/doc/classes/RigidBody2D.xml @@ -5,7 +5,7 @@ </brief_description> <description> This node implements simulated 2D physics. You do not control a RigidBody2D directly. Instead, you apply forces to it (gravity, impulses, etc.) and the physics simulation calculates the resulting movement based on its mass, friction, and other physical properties. - A RigidBody2D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic. + A RigidBody2D has 4 behavior [member mode]s: Dynamic, Static, DynamicLocked, and Kinematic. [b]Note:[/b] You should not change a RigidBody2D's [code]position[/code] or [code]linear_velocity[/code] every frame or even very often. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state. Please also keep in mind that physics bodies manage their own transform which overwrites the ones you set. So any direct or indirect transformation (including scaling of the node or its parent) will be visible in the editor only, and immediately reset at runtime. If you need to override the default physics behavior or add a transformation at runtime, you can write a custom force integration. See [member custom_integrator]. @@ -39,7 +39,7 @@ </return> <argument index="0" name="force" type="Vector2"> </argument> - <argument index="1" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Adds a positioned force to the body. Both the force and the offset from the body origin are in global coordinates. @@ -57,7 +57,7 @@ <method name="apply_central_impulse"> <return type="void"> </return> - <argument index="0" name="impulse" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="0" name="impulse" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Applies a directional impulse without affecting rotation. @@ -68,7 +68,7 @@ </return> <argument index="0" name="impulse" type="Vector2"> </argument> - <argument index="1" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="1" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Applies a positioned impulse to the body. An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts (use the "_force" functions otherwise). The position uses the rotation of the global coordinate system, but is centered at the object's origin. @@ -100,21 +100,6 @@ Sets the body's velocity on the given axis. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior. </description> </method> - <method name="test_motion"> - <return type="bool"> - </return> - <argument index="0" name="motion" type="Vector2"> - </argument> - <argument index="1" name="infinite_inertia" type="bool" default="true"> - </argument> - <argument index="2" name="margin" type="float" default="0.08"> - </argument> - <argument index="3" name="result" type="PhysicsTestMotionResult2D" default="null"> - </argument> - <description> - Returns [code]true[/code] if a collision would result from moving in the given vector. [code]margin[/code] increases the size of the shapes involved in the collision detection, and [code]result[/code] is an object of type [PhysicsTestMotionResult2D], which contains additional information about the collision (should there be one). - </description> - </method> </methods> <members> <member name="angular_damp" type="float" setter="set_angular_damp" getter="get_angular_damp" default="-1.0"> @@ -124,7 +109,7 @@ <member name="angular_velocity" type="float" setter="set_angular_velocity" getter="get_angular_velocity" default="0.0"> The body's rotational velocity. </member> - <member name="applied_force" type="Vector2" setter="set_applied_force" getter="get_applied_force" default="Vector2( 0, 0 )"> + <member name="applied_force" type="Vector2" setter="set_applied_force" getter="get_applied_force" default="Vector2(0, 0)"> The body's total applied force. </member> <member name="applied_torque" type="float" setter="set_applied_torque" getter="get_applied_torque" default="0.0"> @@ -132,7 +117,6 @@ </member> <member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true"> If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping]. - [b]Note:[/b] A RigidBody2D will never enter sleep mode automatically if its [member mode] is [constant MODE_CHARACTER]. It can still be put to sleep manually by setting its [member sleeping] property to [code]true[/code]. </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> If [code]true[/code], the body will emit signals when it collides with another RigidBody2D. See also [member contacts_reported]. @@ -158,7 +142,7 @@ Damps the body's [member linear_velocity]. If [code]-1[/code], the body will use the [b]Default Linear Damp[/b] in [b]Project > Project Settings > Physics > 2d[/b]. See [member ProjectSettings.physics/2d/default_linear_damp] for more details about damping. </member> - <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2( 0, 0 )"> + <member name="linear_velocity" type="Vector2" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector2(0, 0)"> The body's linear velocity. </member> <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0"> @@ -234,17 +218,17 @@ </signal> </signals> <constants> - <constant name="MODE_RIGID" value="0" enum="Mode"> - Rigid mode. The body behaves as a physical object. It collides with other bodies and responds to forces applied to it. This is the default mode. + <constant name="MODE_DYNAMIC" value="0" enum="Mode"> + Dynamic body mode. This is the default mode of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code. </constant> <constant name="MODE_STATIC" value="1" enum="Mode"> - Static mode. The body behaves like a [StaticBody2D] and does not move. + Static body mode. The body behaves like a [StaticBody2D], and must be moved by code. </constant> - <constant name="MODE_CHARACTER" value="2" enum="Mode"> - Character mode. Similar to [constant MODE_RIGID], but the body can not rotate. + <constant name="MODE_DYNAMIC_LOCKED" value="2" enum="Mode"> + Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate. </constant> <constant name="MODE_KINEMATIC" value="3" enum="Mode"> - Kinematic mode. The body behaves like a [KinematicBody2D], and must be moved by code. + Kinematic body mode. The body behaves like a [StaticBody2D] with [member StaticBody2D.kinematic_motion] enabled, and must be moved by user code. </constant> <constant name="CCD_MODE_DISABLED" value="0" enum="CCDMode"> Continuous collision detection disabled. This is the fastest way to detect body collisions, but can miss small, fast-moving objects. diff --git a/doc/classes/RigidBody3D.xml b/doc/classes/RigidBody3D.xml index 2ee8e2697c..fb2b9690a3 100644 --- a/doc/classes/RigidBody3D.xml +++ b/doc/classes/RigidBody3D.xml @@ -5,7 +5,7 @@ </brief_description> <description> This is the node that implements full 3D physics. This means that you do not control a RigidBody3D directly. Instead, you can apply forces to it (gravity, impulses, etc.), and the physics simulation will calculate the resulting movement, collision, bouncing, rotating, etc. - A RigidBody3D has 4 behavior [member mode]s: Rigid, Static, Character, and Kinematic. + A RigidBody3D has 4 behavior [member mode]s: Dynamic, Static, DynamicLocked, and Kinematic. [b]Note:[/b] Don't change a RigidBody3D's position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed Hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop may result in strange behavior. If you need to directly affect the body's state, use [method _integrate_forces], which allows you to directly access the physics state. If you need to override the default physics behavior, you can write a custom force integration function. See [member custom_integrator]. With Bullet physics (the default), the center of mass is the RigidBody3D center. With GodotPhysics, the center of mass is the average of the [CollisionShape3D] centers. @@ -40,7 +40,7 @@ </return> <argument index="0" name="force" type="Vector3"> </argument> - <argument index="1" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Adds a constant directional force (i.e. acceleration). @@ -71,7 +71,7 @@ </return> <argument index="0" name="impulse" type="Vector3"> </argument> - <argument index="1" name="position" type="Vector3" default="Vector3( 0, 0, 0 )"> + <argument index="1" name="position" type="Vector3" default="Vector3(0, 0, 0)"> </argument> <description> Applies a positioned impulse to the body. An impulse is time independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason it should only be used when simulating one-time impacts. The position uses the rotation of the global coordinate system, but is centered at the object's origin. @@ -86,15 +86,6 @@ Applies a torque impulse which will be affected by the body mass and shape. This will rotate the body around the [code]impulse[/code] vector passed. </description> </method> - <method name="get_axis_lock" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> - </argument> - <description> - Returns [code]true[/code] if the specified linear or rotational axis is locked. - </description> - </method> <method name="get_colliding_bodies" qualifiers="const"> <return type="Array"> </return> @@ -110,17 +101,6 @@ Returns the inverse inertia tensor basis. This is used to calculate the angular acceleration resulting from a torque applied to the [RigidBody3D]. </description> </method> - <method name="set_axis_lock"> - <return type="void"> - </return> - <argument index="0" name="axis" type="int" enum="PhysicsServer3D.BodyAxis"> - </argument> - <argument index="1" name="lock" type="bool"> - </argument> - <description> - Locks the specified linear or rotational axis. - </description> - </method> <method name="set_axis_velocity"> <return type="void"> </return> @@ -136,30 +116,11 @@ Damps RigidBody3D's rotational forces. See [member ProjectSettings.physics/3d/default_angular_damp] for more details about damping. </member> - <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity" default="Vector3( 0, 0, 0 )"> + <member name="angular_velocity" type="Vector3" setter="set_angular_velocity" getter="get_angular_velocity" default="Vector3(0, 0, 0)"> RigidBody3D's rotational velocity. </member> - <member name="axis_lock_angular_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's rotation in the X axis. - </member> - <member name="axis_lock_angular_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's rotation in the Y axis. - </member> - <member name="axis_lock_angular_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's rotation in the Z axis. - </member> - <member name="axis_lock_linear_x" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's movement in the X axis. - </member> - <member name="axis_lock_linear_y" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's movement in the Y axis. - </member> - <member name="axis_lock_linear_z" type="bool" setter="set_axis_lock" getter="get_axis_lock" default="false"> - Lock the body's movement in the Z axis. - </member> <member name="can_sleep" type="bool" setter="set_can_sleep" getter="is_able_to_sleep" default="true"> If [code]true[/code], the body can enter sleep mode when there is no movement. See [member sleeping]. - [b]Note:[/b] A RigidBody3D will never enter sleep mode automatically if its [member mode] is [constant MODE_CHARACTER]. It can still be put to sleep manually by setting its [member sleeping] property to [code]true[/code]. </member> <member name="contact_monitor" type="bool" setter="set_contact_monitor" getter="is_contact_monitor_enabled" default="false"> If [code]true[/code], the RigidBody3D will emit signals when it collides with another RigidBody3D. See also [member contacts_reported]. @@ -182,7 +143,7 @@ The body's linear damp. Cannot be less than -1.0. If this value is different from -1.0, any linear damp derived from the world or areas will be overridden. See [member ProjectSettings.physics/3d/default_linear_damp] for more details about damping. </member> - <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3( 0, 0, 0 )"> + <member name="linear_velocity" type="Vector3" setter="set_linear_velocity" getter="get_linear_velocity" default="Vector3(0, 0, 0)"> The body's linear velocity. Can be used sporadically, but [b]don't set this every frame[/b], because physics may run in another thread and runs at a different granularity. Use [method _integrate_forces] as your process loop for precise control of the body state. </member> <member name="mass" type="float" setter="set_mass" getter="get_mass" default="1.0"> @@ -260,17 +221,17 @@ </signal> </signals> <constants> - <constant name="MODE_RIGID" value="0" enum="Mode"> - Rigid body mode. This is the "natural" state of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code. + <constant name="MODE_DYNAMIC" value="0" enum="Mode"> + Dynamic body mode. This is the default mode of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code. </constant> <constant name="MODE_STATIC" value="1" enum="Mode"> - Static mode. The body behaves like a [StaticBody3D], and can only move by user code. + Static body mode. The body behaves like a [StaticBody3D], and can only move by user code. </constant> - <constant name="MODE_CHARACTER" value="2" enum="Mode"> - Character body mode. This behaves like a rigid body, but can not rotate. + <constant name="MODE_DYNAMIC_LOCKED" value="2" enum="Mode"> + Locked dynamic body mode. Similar to [constant MODE_DYNAMIC], but the body can not rotate. </constant> <constant name="MODE_KINEMATIC" value="3" enum="Mode"> - Kinematic body mode. The body behaves like a [KinematicBody3D], and can only move by user code. + Kinematic body mode. The body behaves like a [StaticBody3D] with [member StaticBody3D.kinematic_motion] enabled, and can only move by user code. </constant> </constants> </class> diff --git a/doc/classes/SceneState.xml b/doc/classes/SceneState.xml index abc429d5fe..6d804cc697 100644 --- a/doc/classes/SceneState.xml +++ b/doc/classes/SceneState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="SceneState" inherits="Reference" version="4.0"> +<class name="SceneState" inherits="RefCounted" version="4.0"> <brief_description> A script interface to a scene file's data. </brief_description> @@ -95,7 +95,7 @@ <argument index="0" name="idx" type="int"> </argument> <description> - Returns the node's index, which is its position relative to its siblings. This is only relevant and saved in scenes for cases where new nodes are added to an instanced or inherited scene among siblings from the base scene. Despite the name, this index is not related to the [code]idx[/code] argument used here and in other methods. + Returns the node's index, which is its position relative to its siblings. This is only relevant and saved in scenes for cases where new nodes are added to an instantiated or inherited scene among siblings from the base scene. Despite the name, this index is not related to the [code]idx[/code] argument used here and in other methods. </description> </method> <method name="get_node_instance" qualifiers="const"> @@ -199,14 +199,14 @@ </methods> <constants> <constant name="GEN_EDIT_STATE_DISABLED" value="0" enum="GenEditState"> - If passed to [method PackedScene.instance], blocks edits to the scene state. + If passed to [method PackedScene.instantiate], blocks edits to the scene state. </constant> <constant name="GEN_EDIT_STATE_INSTANCE" value="1" enum="GenEditState"> - If passed to [method PackedScene.instance], provides inherited scene resources to the local scene. + If passed to [method PackedScene.instantiate], provides inherited scene resources to the local scene. [b]Note:[/b] Only available in editor builds. </constant> <constant name="GEN_EDIT_STATE_MAIN" value="2" enum="GenEditState"> - If passed to [method PackedScene.instance], provides local scene resources to the local scene. Only the main scene should receive the main edit state. + If passed to [method PackedScene.instantiate], provides local scene resources to the local scene. Only the main scene should receive the main edit state. [b]Note:[/b] Only available in editor builds. </constant> </constants> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index 06800082cb..bf51b4dfa7 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -90,6 +90,13 @@ The timer will be automatically freed after its time elapses. </description> </method> + <method name="create_tween"> + <return type="Tween"> + </return> + <description> + Creates and returns a new [Tween]. + </description> + </method> <method name="get_first_node_in_group"> <return type="Node"> </return> @@ -105,20 +112,6 @@ Returns the current frame number, i.e. the total frame count since the application started. </description> </method> - <method name="get_network_connected_peers" qualifiers="const"> - <return type="PackedInt32Array"> - </return> - <description> - Returns the peer IDs of all connected peers of this [SceneTree]'s [member network_peer]. - </description> - </method> - <method name="get_network_unique_id" qualifiers="const"> - <return type="int"> - </return> - <description> - Returns the unique peer ID of this [SceneTree]'s [member network_peer]. - </description> - </method> <method name="get_node_count" qualifiers="const"> <return type="int"> </return> @@ -135,11 +128,11 @@ Returns a list of all nodes assigned to the given group. </description> </method> - <method name="get_rpc_sender_id" qualifiers="const"> - <return type="int"> + <method name="get_processed_tweens"> + <return type="Array"> </return> <description> - Returns the sender's peer ID for the most recently received RPC call. + Returns an array of currently exising [Tween]s in the [SceneTree] (both running and paused). </description> </method> <method name="has_group" qualifiers="const"> @@ -151,20 +144,6 @@ Returns [code]true[/code] if the given group exists. </description> </method> - <method name="has_network_peer" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if there is a [member network_peer] set. - </description> - </method> - <method name="is_network_server" qualifiers="const"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if this [SceneTree]'s [member network_peer] is in server mode (listening for connections). - </description> - </method> <method name="notify_group"> <return type="void"> </return> @@ -207,6 +186,7 @@ Quits the application at the end of the current iteration. Argument [code]exit_code[/code] can optionally be given (defaulting to 0) to customize the exit status code. By convention, an exit code of [code]0[/code] indicates success whereas a non-zero exit code indicates an error. For portability reasons, the exit code should be set between 0 and 125 (inclusive). + [b]Note:[/b] On iOS this method doesn't work. Instead, as recommended by the iOS Human Interface Guidelines, the user is expected to close apps via the Home button. </description> </method> <method name="reload_current_scene"> @@ -286,32 +266,16 @@ If [code]true[/code] (default value), enables automatic polling of the [MultiplayerAPI] for this SceneTree during [signal process_frame]. If [code]false[/code], you need to manually call [method MultiplayerAPI.poll] to process network packets and deliver RPCs/RSETs. This allows running RPCs/RSETs in a different loop (e.g. physics, thread, specific time step) and for manual [Mutex] protection when accessing the [MultiplayerAPI] from threads. </member> - <member name="network_peer" type="NetworkedMultiplayerPeer" setter="set_network_peer" getter="get_network_peer"> - The peer object to handle the RPC system (effectively enabling networking when set). Depending on the peer itself, the [SceneTree] will become a network server (check with [method is_network_server]) and will set the root node's network mode to master, or it will become a regular peer with the root node set to puppet. All child nodes are set to inherit the network mode by default. Handling of networking-related events (connection, disconnection, new clients) is done by connecting to [SceneTree]'s signals. - </member> <member name="paused" type="bool" setter="set_pause" getter="is_paused" default="false"> If [code]true[/code], the [SceneTree] is paused. Doing so will have the following behavior: - 2D and 3D physics will be stopped. - [method Node._process], [method Node._physics_process] and [method Node._input] will not be called anymore in nodes. </member> - <member name="refuse_new_network_connections" type="bool" setter="set_refuse_new_network_connections" getter="is_refusing_new_network_connections" default="false"> - If [code]true[/code], the [SceneTree]'s [member network_peer] refuses new incoming connections. - </member> <member name="root" type="Window" setter="" getter="get_root"> The [SceneTree]'s root [Window]. </member> </members> <signals> - <signal name="connected_to_server"> - <description> - Emitted whenever this [SceneTree]'s [member network_peer] successfully connected to a server. Only emitted on clients. - </description> - </signal> - <signal name="connection_failed"> - <description> - Emitted whenever this [SceneTree]'s [member network_peer] fails to establish a connection to a server. Only emitted on clients. - </description> - </signal> <signal name="files_dropped"> <argument index="0" name="files" type="PackedStringArray"> </argument> @@ -321,20 +285,6 @@ Emitted when files are dragged from the OS file manager and dropped in the game window. The arguments are a list of file paths and the identifier of the screen where the drag originated. </description> </signal> - <signal name="network_peer_connected"> - <argument index="0" name="id" type="int"> - </argument> - <description> - Emitted whenever this [SceneTree]'s [member network_peer] connects with a new peer. ID is the peer ID of the new peer. Clients get notified when other clients connect to the same server. Upon connecting to a server, a client also receives this signal for the server (with ID being 1). - </description> - </signal> - <signal name="network_peer_disconnected"> - <argument index="0" name="id" type="int"> - </argument> - <description> - Emitted whenever this [SceneTree]'s [member network_peer] disconnects from a peer. Clients get notified when other clients disconnect from the same server. - </description> - </signal> <signal name="node_added"> <argument index="0" name="node" type="Node"> </argument> @@ -373,11 +323,6 @@ Emitted immediately before [method Node._process] is called on every node in the [SceneTree]. </description> </signal> - <signal name="server_disconnected"> - <description> - Emitted whenever this [SceneTree]'s [member network_peer] disconnected from server. Only emitted on clients. - </description> - </signal> <signal name="tree_changed"> <description> Emitted whenever the [SceneTree] hierarchy changed (children being moved or renamed, etc.). diff --git a/doc/classes/SceneTreeTimer.xml b/doc/classes/SceneTreeTimer.xml index b223bf6821..4eef754345 100644 --- a/doc/classes/SceneTreeTimer.xml +++ b/doc/classes/SceneTreeTimer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="SceneTreeTimer" inherits="Reference" version="4.0"> +<class name="SceneTreeTimer" inherits="RefCounted" version="4.0"> <brief_description> One-shot timer. </brief_description> diff --git a/doc/classes/Script.xml b/doc/classes/Script.xml index 56272760bd..e7527d73e2 100644 --- a/doc/classes/Script.xml +++ b/doc/classes/Script.xml @@ -11,11 +11,11 @@ <link title="Scripting">https://docs.godotengine.org/en/latest/getting_started/step_by_step/scripting.html</link> </tutorials> <methods> - <method name="can_instance" qualifiers="const"> + <method name="can_instantiate" qualifiers="const"> <return type="bool"> </return> <description> - Returns [code]true[/code] if the script can be instanced. + Returns [code]true[/code] if the script can be instantiated. </description> </method> <method name="get_base_script" qualifiers="const"> diff --git a/doc/classes/ScriptEditor.xml b/doc/classes/ScriptEditor.xml index 28620bd29b..31dbf7453f 100644 --- a/doc/classes/ScriptEditor.xml +++ b/doc/classes/ScriptEditor.xml @@ -9,30 +9,6 @@ <tutorials> </tutorials> <methods> - <method name="can_drop_data_fw" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="point" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <argument index="2" name="from" type="Control"> - </argument> - <description> - </description> - </method> - <method name="drop_data_fw"> - <return type="void"> - </return> - <argument index="0" name="point" type="Vector2"> - </argument> - <argument index="1" name="data" type="Variant"> - </argument> - <argument index="2" name="from" type="Control"> - </argument> - <description> - </description> - </method> <method name="get_current_editor" qualifiers="const"> <return type="ScriptEditorBase"> </return> @@ -47,16 +23,6 @@ Returns a [Script] that is currently active in editor. </description> </method> - <method name="get_drag_data_fw"> - <return type="Variant"> - </return> - <argument index="0" name="point" type="Vector2"> - </argument> - <argument index="1" name="from" type="Control"> - </argument> - <description> - </description> - </method> <method name="get_open_script_editors" qualifiers="const"> <return type="Array"> </return> diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml index e5c4c32450..a135062bd8 100644 --- a/doc/classes/ScriptEditorBase.xml +++ b/doc/classes/ScriptEditorBase.xml @@ -9,7 +9,7 @@ <tutorials> </tutorials> <methods> - <method name="add_syntax_highlighter" qualifiers="virtual"> + <method name="_add_syntax_highlighter" qualifiers="virtual"> <return type="void"> </return> <argument index="0" name="highlighter" type="Object"> diff --git a/doc/classes/SegmentShape2D.xml b/doc/classes/SegmentShape2D.xml index 31c0f7f1f3..341c5e9d20 100644 --- a/doc/classes/SegmentShape2D.xml +++ b/doc/classes/SegmentShape2D.xml @@ -11,10 +11,10 @@ <methods> </methods> <members> - <member name="a" type="Vector2" setter="set_a" getter="get_a" default="Vector2( 0, 0 )"> + <member name="a" type="Vector2" setter="set_a" getter="get_a" default="Vector2(0, 0)"> The segment's first point position. </member> - <member name="b" type="Vector2" setter="set_b" getter="get_b" default="Vector2( 0, 10 )"> + <member name="b" type="Vector2" setter="set_b" getter="get_b" default="Vector2(0, 10)"> The segment's second point position. </member> </members> diff --git a/doc/classes/Semaphore.xml b/doc/classes/Semaphore.xml index f311e1c72f..e8b405e52a 100644 --- a/doc/classes/Semaphore.xml +++ b/doc/classes/Semaphore.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Semaphore" inherits="Reference" version="4.0"> +<class name="Semaphore" inherits="RefCounted" version="4.0"> <brief_description> A synchronization semaphore. </brief_description> diff --git a/doc/classes/Signal.xml b/doc/classes/Signal.xml index 84efc974c0..1fd70a43fd 100644 --- a/doc/classes/Signal.xml +++ b/doc/classes/Signal.xml @@ -40,7 +40,7 @@ </return> <argument index="0" name="callable" type="Callable"> </argument> - <argument index="1" name="binds" type="Array" default="[ ]"> + <argument index="1" name="binds" type="Array" default="[]"> </argument> <argument index="2" name="flags" type="int" default="0"> </argument> diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml index 0ddbac9ba4..6665a4a9f6 100644 --- a/doc/classes/Skeleton2D.xml +++ b/doc/classes/Skeleton2D.xml @@ -10,6 +10,17 @@ <link title="2D skeletons">https://docs.godotengine.org/en/latest/tutorials/animation/2d_skeletons.html</link> </tutorials> <methods> + <method name="execute_modifications"> + <return type="void"> + </return> + <argument index="0" name="delta" type="float"> + </argument> + <argument index="1" name="execution_mode" type="int"> + </argument> + <description> + Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton3D has one assigned. + </description> + </method> <method name="get_bone"> <return type="Bone2D"> </return> @@ -26,6 +37,22 @@ Returns the number of [Bone2D] nodes in the node hierarchy parented by Skeleton2D. </description> </method> + <method name="get_bone_local_pose_override"> + <return type="Transform2D"> + </return> + <argument index="0" name="bone_idx" type="int"> + </argument> + <description> + Returns the local pose override transform for [code]bone_idx[/code]. + </description> + </method> + <method name="get_modification_stack" qualifiers="const"> + <return type="SkeletonModificationStack2D"> + </return> + <description> + Returns the [SkeletonModificationStack2D] attached to this skeleton, if one exists. + </description> + </method> <method name="get_skeleton" qualifiers="const"> <return type="RID"> </return> @@ -33,10 +60,37 @@ Returns the [RID] of a Skeleton2D instance. </description> </method> + <method name="set_bone_local_pose_override"> + <return type="void"> + </return> + <argument index="0" name="bone_idx" type="int"> + </argument> + <argument index="1" name="override_pose" type="Transform2D"> + </argument> + <argument index="2" name="strength" type="float"> + </argument> + <argument index="3" name="persistent" type="bool"> + </argument> + <description> + Sets the local pose transform, [code]pose[/code], for the bone at [code]bone_idx[/code]. + [code]amount[/code] is the interpolation strengh that will be used when applying the pose, and [code]persistent[/code] determines if the applied pose will remain. + [b]Note:[/b] The pose transform needs to be a local transform relative to the [Bone2D] node at [code]bone_idx[/code]! + </description> + </method> + <method name="set_modification_stack"> + <return type="void"> + </return> + <argument index="0" name="modification_stack" type="SkeletonModificationStack2D"> + </argument> + <description> + Sets the [SkeletonModificationStack2D] attached to this skeleton. + </description> + </method> </methods> <signals> <signal name="bone_setup_changed"> <description> + Emitted when the [Bone2D] setup attached to this skeletons changes. This is primarily used internally within the skeleton. </description> </signal> </signals> diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml index 44ad460459..136f2f0a63 100644 --- a/doc/classes/Skeleton3D.xml +++ b/doc/classes/Skeleton3D.xml @@ -23,9 +23,9 @@ </description> </method> <method name="bone_transform_to_world_transform"> - <return type="Transform"> + <return type="Transform3D"> </return> - <argument index="0" name="bone_transform" type="Transform"> + <argument index="0" name="bone_transform" type="Transform3D"> </argument> <description> Takes the given bone pose/transform and converts it to a world transform, relative to the [Skeleton3D] node. @@ -63,7 +63,7 @@ </description> </method> <method name="get_bone_custom_pose" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="bone_idx" type="int"> </argument> @@ -72,7 +72,7 @@ </description> </method> <method name="get_bone_global_pose" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="bone_idx" type="int"> </argument> @@ -81,7 +81,7 @@ </description> </method> <method name="get_bone_global_pose_no_override" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="bone_idx" type="int"> </argument> @@ -109,7 +109,7 @@ </description> </method> <method name="get_bone_pose" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="bone_idx" type="int"> </argument> @@ -124,7 +124,7 @@ </description> </method> <method name="get_bone_rest" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="bone_idx" type="int"> </argument> @@ -171,7 +171,7 @@ <method name="physical_bones_start_simulation"> <return type="void"> </return> - <argument index="0" name="bones" type="StringName[]" default="[ ]"> + <argument index="0" name="bones" type="StringName[]" default="[]"> </argument> <description> Tells the [PhysicalBone3D] nodes in the Skeleton to start simulating and reacting to the physics world. @@ -199,7 +199,7 @@ </return> <argument index="0" name="bone_idx" type="int"> </argument> - <argument index="1" name="custom_pose" type="Transform"> + <argument index="1" name="custom_pose" type="Transform3D"> </argument> <description> Sets the custom pose transform, [code]custom_pose[/code], for the bone at [code]bone_idx[/code]. This pose is an addition to the bone rest pose. @@ -222,7 +222,7 @@ </return> <argument index="0" name="bone_idx" type="int"> </argument> - <argument index="1" name="pose" type="Transform"> + <argument index="1" name="pose" type="Transform3D"> </argument> <argument index="2" name="amount" type="float"> </argument> @@ -261,7 +261,7 @@ </return> <argument index="0" name="bone_idx" type="int"> </argument> - <argument index="1" name="pose" type="Transform"> + <argument index="1" name="pose" type="Transform3D"> </argument> <description> Sets the pose transform for bone [code]bone_idx[/code]. @@ -273,7 +273,7 @@ </return> <argument index="0" name="bone_idx" type="int"> </argument> - <argument index="1" name="rest" type="Transform"> + <argument index="1" name="rest" type="Transform3D"> </argument> <description> Sets the rest transform for bone [code]bone_idx[/code]. @@ -289,9 +289,9 @@ </description> </method> <method name="world_transform_to_bone_transform"> - <return type="Transform"> + <return type="Transform3D"> </return> - <argument index="0" name="world_transform" type="Transform"> + <argument index="0" name="world_transform" type="Transform3D"> </argument> <description> Takes the given world transform, relative to the [Skeleton3D], and converts it to a bone pose/transform. diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml index 5193109447..138ebe4411 100644 --- a/doc/classes/SkeletonIK3D.xml +++ b/doc/classes/SkeletonIK3D.xml @@ -38,7 +38,7 @@ <members> <member name="interpolation" type="float" setter="set_interpolation" getter="get_interpolation" default="1.0"> </member> - <member name="magnet" type="Vector3" setter="set_magnet_position" getter="get_magnet_position" default="Vector3( 0, 0, 0 )"> + <member name="magnet" type="Vector3" setter="set_magnet_position" getter="get_magnet_position" default="Vector3(0, 0, 0)"> </member> <member name="max_iterations" type="int" setter="set_max_iterations" getter="get_max_iterations" default="10"> </member> @@ -46,13 +46,13 @@ </member> <member name="override_tip_basis" type="bool" setter="set_override_tip_basis" getter="is_override_tip_basis" default="true"> </member> - <member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="@"""> + <member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&"""> </member> - <member name="target" type="Transform" setter="set_target_transform" getter="get_target_transform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="target" type="Transform3D" setter="set_target_transform" getter="get_target_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> </member> <member name="target_node" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> </member> - <member name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="@"""> + <member name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="&"""> </member> <member name="use_magnet" type="bool" setter="set_use_magnet" getter="is_using_magnet" default="false"> </member> diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml new file mode 100644 index 0000000000..8596dac76e --- /dev/null +++ b/doc/classes/SkeletonModification2D.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2D" inherits="Resource" version="4.0"> + <brief_description> + A resource that operates on [Bone2D] nodes in a [Skeleton2D]. + </brief_description> + <description> + This resource provides an interface that can be expanded so code that operates on [Bone2D] nodes in a [Skeleton2D] can be mixed and matched together to create complex interactions. + This is used to provide Godot with a flexible and powerful Inverse Kinematics solution that can be adapted for many different uses. + </description> + <tutorials> + </tutorials> + <methods> + <method name="_draw_editor_gizmo" qualifiers="virtual"> + <return type="void"> + </return> + <description> + Used for drawing [b]editor-only[/b] modification gizmos. This function will only be called in the Godot editor and can be overriden to draw custom gizmos. + [b]Note:[/b] You will need to use the Skeleton2D from [method SkeletonModificationStack2D.get_skeleton] and it's draw functions, as the [SkeletonModification2D] resource cannot draw on its own. + </description> + </method> + <method name="_execute" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="delta" type="float"> + </argument> + <description> + Executes the given modification. This is where the modification performs whatever function it is designed to do. + </description> + </method> + <method name="_setup_modification" qualifiers="virtual"> + <return type="void"> + </return> + <argument index="0" name="modification_stack" type="SkeletonModificationStack2D"> + </argument> + <description> + Called when the modification is setup. This is where the modification performs initialization. + </description> + </method> + <method name="clamp_angle"> + <return type="float"> + </return> + <argument index="0" name="angle" type="float"> + </argument> + <argument index="1" name="min" type="float"> + </argument> + <argument index="2" name="max" type="float"> + </argument> + <argument index="3" name="invert" type="bool"> + </argument> + <description> + Takes a angle and clamps it so it is within the passed-in [code]min[/code] and [code]max[/code] range. [code]invert[/code] will inversely clamp the angle, clamping it to the range outside of the given bounds. + </description> + </method> + <method name="get_editor_draw_gizmo" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether this modification will call [method _draw_editor_gizmo] in the Godot editor to draw modification-specific gizmos. + </description> + </method> + <method name="get_is_setup" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether this modification has been successfully setup or not. + </description> + </method> + <method name="get_modification_stack"> + <return type="SkeletonModificationStack2D"> + </return> + <description> + Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on. + </description> + </method> + <method name="set_editor_draw_gizmo"> + <return type="void"> + </return> + <argument index="0" name="draw_gizmo" type="bool"> + </argument> + <description> + Sets whether this modification will call [method _draw_editor_gizmo] in the Godot editor to draw modification-specific gizmos. + </description> + </method> + <method name="set_is_setup"> + <return type="void"> + </return> + <argument index="0" name="is_setup" type="bool"> + </argument> + <description> + Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack2D] the modification is bound to should handle setting the modification up. + </description> + </method> + </methods> + <members> + <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="true"> + If [code]true[/code], the modification's [method _execute] function will be called by the [SkeletonModificationStack2D]. + </member> + <member name="execution_mode" type="int" setter="set_execution_mode" getter="get_execution_mode" default="0"> + The execution mode for the modification. This tells the modification stack when to execute the modification. Some modifications have settings that are only availible in certain execution modes. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DCCDIK.xml b/doc/classes/SkeletonModification2DCCDIK.xml new file mode 100644 index 0000000000..014d366a42 --- /dev/null +++ b/doc/classes/SkeletonModification2DCCDIK.xml @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that uses CCDIK to manipulate a series of bones to reach a target in 2D. + </brief_description> + <description> + This [SkeletonModification2D] uses an algorithm called [b]C[/b]yclic [b]C[/b]oordinate [b]D[/b]escent [b]I[/b]nverse [b]K[/b]inematics, or CCDIK, to maniuplate a chain of bones in a [Skeleton2D] so it reaches a defined target. + CCDIK works by rotating a set of bones, typically called a "bone chain", on a single axis. Each bone is rotated to face the target from the tip (by default), which over a chain of bones allow it to rotate properly to reach the target. Because the bones only rotate on a single axis, CCDIK [i]can[/i] look more robotic than other IK solvers. + [b]Note:[/b] The CCDIK modifier has [code]ccdik_joints[/code], which are the data objects that hold the data for each joint in the CCDIK chain. This is different from a bone! CCDIK joints hold the data needed for each bone in the bone chain used by CCDIK. + CCDIK also fully supports angle constraints, allowing for more control over how a solution is met. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_ccdik_joint_bone2d_node" qualifiers="const"> + <return type="NodePath"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_ccdik_joint_bone_index" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the index of the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_ccdik_joint_constraint_angle_invert" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_angle_invert] for details. + </description> + </method> + <method name="get_ccdik_joint_constraint_angle_max" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the maximum angle constraint for the joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_ccdik_joint_constraint_angle_min" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the minimum angle constraint for the joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_ccdik_joint_enable_constraint" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns whether angle constraints on the CCDIK joint at [code]joint_idx[/code] are enabled. + </description> + </method> + <method name="get_ccdik_joint_rotate_from_joint" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns whether the joint at [code]joint_idx[/code] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code]. The default is to rotate from the tip. + </description> + </method> + <method name="set_ccdik_joint_bone2d_node"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="bone2d_nodepath" type="NodePath"> + </argument> + <description> + Sets the [Bone2D] node assigned to the CCDIK joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_ccdik_joint_bone_index"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="bone_idx" type="int"> + </argument> + <description> + Sets the bone index, [code]bone_index[/code], of the CCDIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the CCDIK joint based on data provided by the linked skeleton. + </description> + </method> + <method name="set_ccdik_joint_constraint_angle_invert"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="invert" type="bool"> + </argument> + <description> + Sets whether the CCDIK joint at [code]joint_idx[/code] uses an inverted joint constraint. + An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values. + </description> + </method> + <method name="set_ccdik_joint_constraint_angle_max"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="angle_max" type="float"> + </argument> + <description> + Sets the maximum angle constraint for the joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_ccdik_joint_constraint_angle_min"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="angle_min" type="float"> + </argument> + <description> + Sets the minimum angle constraint for the joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_ccdik_joint_enable_constraint"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="enable_constraint" type="bool"> + </argument> + <description> + Determines whether angle constraints on the CCDIK joint at [code]joint_idx[/code] are enabled. When [code]true[/code], constraints will be enabled and taken into account when solving. + </description> + </method> + <method name="set_ccdik_joint_rotate_from_joint"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="rotate_from_joint" type="bool"> + </argument> + <description> + Sets whether the joint at [code]joint_idx[/code] is set to rotate from the joint, [code]true[/code], or to rotate from the tip, [code]false[/code]. + </description> + </method> + </methods> + <members> + <member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0"> + The amount of CCDIK joints in the CCDIK modification. + </member> + <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> + The NodePath to the node that is the target for the CCDIK modification. This node is what the CCDIK chain will attempt to rotate the bone chain to. + </member> + <member name="tip_nodepath" type="NodePath" setter="set_tip_node" getter="get_tip_node" default="NodePath("")"> + The end position of the CCDIK chain. Typically, this should be a child of a [Bone2D] node attached to the final [Bone2D] in the CCDIK chain. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DFABRIK.xml b/doc/classes/SkeletonModification2DFABRIK.xml new file mode 100644 index 0000000000..62ab34b06f --- /dev/null +++ b/doc/classes/SkeletonModification2DFABRIK.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that uses FABRIK to manipulate a series of [Bone2D] nodes to reach a target. + </brief_description> + <description> + This [SkeletonModification2D] uses an algorithm called [b]F[/b]orward [b]A[/b]nd [b]B[/b]ackward [b]R[/b]eaching [b]I[/b]nverse [b]K[/b]inematics, or FABRIK, to rotate a bone chain so that it reaches a target. + FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other. + Because of how FABRIK works, it often gives more natural results than those seen in [SkeletonModification2DCCDIK]. FABRIK also supports angle constraints, which are fully taken into account when solving. + [b]Note:[/b] The FABRIK modifier has [code]fabrik_joints[/code], which are the data objects that hold the data for each joint in the FABRIK chain. This is different from [Bone2D] nodes! FABRIK joints hold the data needed for each [Bone2D] in the bone chain used by FABRIK. + To help control how the FABRIK joints move, a magnet vector can be passed, which can nudge the bones in a certain direction prior to solving, giving a level of control over the final result. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_fabrik_joint_bone2d_node" qualifiers="const"> + <return type="NodePath"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_fabrik_joint_bone_index" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the index of the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_fabrik_joint_magnet_position" qualifiers="const"> + <return type="Vector2"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the magnet position vector for the joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_fabrik_joint_use_target_rotation" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns whether the joint is using the target's rotation rather than allowing FABRIK to rotate the joint. This option only applies to the tip/final joint in the chain. + </description> + </method> + <method name="set_fabrik_joint_bone2d_node"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="bone2d_nodepath" type="NodePath"> + </argument> + <description> + Sets the [Bone2D] node assigned to the FABRIK joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_fabrik_joint_bone_index"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="bone_idx" type="int"> + </argument> + <description> + Sets the bone index, [code]bone_index[/code], of the FABRIK joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the FABRIK joint based on data provided by the linked skeleton. + </description> + </method> + <method name="set_fabrik_joint_magnet_position"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="magnet_position" type="Vector2"> + </argument> + <description> + Sets the magnet position vector for the joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_fabrik_joint_use_target_rotation"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="use_target_rotation" type="bool"> + </argument> + <description> + Sets whether the joint at [code]joint_idx[/code] will use the target node's rotation rather than letting FABRIK rotate the node. + [b]Note:[/b] This option only works for the tip/final joint in the chain. For all other nodes, this option will be ignored. + </description> + </method> + </methods> + <members> + <member name="fabrik_data_chain_length" type="int" setter="set_fabrik_data_chain_length" getter="get_fabrik_data_chain_length" default="0"> + The amount of FABRIK joints in the FABRIK modification. + </member> + <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> + The NodePath to the node that is the target for the FABRIK modification. This node is what the FABRIK chain will attempt to rotate the bone chain to. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DJiggle.xml b/doc/classes/SkeletonModification2DJiggle.xml new file mode 100644 index 0000000000..ae46acd0d0 --- /dev/null +++ b/doc/classes/SkeletonModification2DJiggle.xml @@ -0,0 +1,232 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that jiggles [Bone2D] nodes as they move towards a target. + </brief_description> + <description> + This modification moves a series of bones, typically called a bone chain, towards a target. What makes this modification special is that it calculates the velocity and acceleration for each bone in the bone chain, and runs a very light physics-like calculation using the inputted values. This allows the bones to overshoot the target and "jiggle" around. It can be configured to act more like a spring, or sway around like cloth might. + This modification is useful for adding additional motion to things like hair, the edges of clothing, and more. It has several settings to that allow control over how the joint moves when the target moves. + [b]Note:[/b] The Jiggle modifier has [code]jiggle_joints[/code], which are the data objects that hold the data for each joint in the Jiggle chain. This is different from than [Bone2D] nodes! Jiggle joints hold the data needed for each [Bone2D] in the bone chain used by the Jiggle modification. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_collision_mask" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the collision mask used by the Jiggle modifier when collisions are enabled. + </description> + </method> + <method name="get_jiggle_joint_bone2d_node" qualifiers="const"> + <return type="NodePath"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_jiggle_joint_bone_index" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the index of the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_jiggle_joint_damping" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the amount of damping of the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_jiggle_joint_gravity" qualifiers="const"> + <return type="Vector2"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns a [Vector2] representing the amount of gravity the Jiggle joint at [code]joint_idx[/code] is influenced by. + </description> + </method> + <method name="get_jiggle_joint_mass" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the amount of mass of the jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_jiggle_joint_override" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns a boolean that indiciates whether the joint at [code]joint_idx[/code] is overriding the default Jiggle joint data defined in the modification. + </description> + </method> + <method name="get_jiggle_joint_stiffness" qualifiers="const"> + <return type="float"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the stiffness of the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="get_jiggle_joint_use_gravity" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns a boolean that indiciates whether the joint at [code]joint_idx[/code] is using gravity or not. + </description> + </method> + <method name="get_use_colliders" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether the jiggle modifier is taking physics colliders into account when solving. + </description> + </method> + <method name="set_collision_mask"> + <return type="void"> + </return> + <argument index="0" name="collision_mask" type="int"> + </argument> + <description> + Sets the collision mask that the Jiggle modifier will use when reacting to colliders, if the Jiggle modifier is set to take colliders into account. + </description> + </method> + <method name="set_jiggle_joint_bone2d_node"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="bone2d_node" type="NodePath"> + </argument> + <description> + Sets the [Bone2D] node assigned to the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_jiggle_joint_bone_index"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="bone_idx" type="int"> + </argument> + <description> + Sets the bone index, [code]bone_index[/code], of the Jiggle joint at [code]joint_idx[/code]. When possible, this will also update the [code]bone2d_node[/code] of the Jiggle joint based on data provided by the linked skeleton. + </description> + </method> + <method name="set_jiggle_joint_damping"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="damping" type="float"> + </argument> + <description> + Sets the amount of dampening of the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_jiggle_joint_gravity"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="gravity" type="Vector2"> + </argument> + <description> + Sets the gravity vector of the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_jiggle_joint_mass"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="mass" type="float"> + </argument> + <description> + Sets the of mass of the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_jiggle_joint_override"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="override" type="bool"> + </argument> + <description> + Sets whether the Jiggle joint at [code]joint_idx[/code] should override the default Jiggle joint settings. Setting this to [code]true[/code] will make the joint use its own settings rather than the default ones attached to the modification. + </description> + </method> + <method name="set_jiggle_joint_stiffness"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="stiffness" type="float"> + </argument> + <description> + Sets the of stiffness of the Jiggle joint at [code]joint_idx[/code]. + </description> + </method> + <method name="set_jiggle_joint_use_gravity"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="use_gravity" type="bool"> + </argument> + <description> + Sets whether the Jiggle joint at [code]joint_idx[/code] should use gravity. + </description> + </method> + <method name="set_use_colliders"> + <return type="void"> + </return> + <argument index="0" name="use_colliders" type="bool"> + </argument> + <description> + If [code]true[/code], the Jiggle modifier will take colliders into account, keeping them from entering into these collision objects. + </description> + </method> + </methods> + <members> + <member name="damping" type="float" setter="set_damping" getter="get_damping" default="0.75"> + The default amount of dampening applied to the Jiggle joints, if they are not overriden. Higher values lead to more of the calculated velocity being applied. + </member> + <member name="gravity" type="Vector2" setter="set_gravity" getter="get_gravity" default="Vector2(0, 6)"> + The default amount of gravity applied to the Jiggle joints, if they are not overriden. + </member> + <member name="jiggle_data_chain_length" type="int" setter="set_jiggle_data_chain_length" getter="get_jiggle_data_chain_length" default="0"> + The amount of Jiggle joints in the Jiggle modification. + </member> + <member name="mass" type="float" setter="set_mass" getter="get_mass" default="0.75"> + The default amount of mass assigned to the Jiggle joints, if they are not overriden. Higher values lead to faster movements and more overshooting. + </member> + <member name="stiffness" type="float" setter="set_stiffness" getter="get_stiffness" default="3.0"> + The default amount of stiffness assigned to the Jiggle joints, if they are not overriden. Higher values act more like springs, quickly moving into the correct position. + </member> + <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> + The NodePath to the node that is the target for the Jiggle modification. This node is what the Jiggle chain will attempt to rotate the bone chain to. + </member> + <member name="use_gravity" type="bool" setter="set_use_gravity" getter="get_use_gravity" default="false"> + Whether the gravity vector, [member gravity], should be applied to the Jiggle joints, assuming they are not overriding the default settings. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DLookAt.xml b/doc/classes/SkeletonModification2DLookAt.xml new file mode 100644 index 0000000000..b0fa0e5a01 --- /dev/null +++ b/doc/classes/SkeletonModification2DLookAt.xml @@ -0,0 +1,107 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that rotates a [Bone2D] node to look at a target. + </brief_description> + <description> + This [SkeletonModification2D] rotates a bone to look a target. This is extremely helpful for moving character's head to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_additional_rotation" qualifiers="const"> + <return type="float"> + </return> + <description> + Returns the amount of additional rotation that is applied after the LookAt modification executes. + </description> + </method> + <method name="get_constraint_angle_invert" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns whether the constraints to this modification are inverted or not. + </description> + </method> + <method name="get_constraint_angle_max" qualifiers="const"> + <return type="float"> + </return> + <description> + Returns the constraint's maximum allowed angle. + </description> + </method> + <method name="get_constraint_angle_min" qualifiers="const"> + <return type="float"> + </return> + <description> + Returns the constraint's minimum allowed angle. + </description> + </method> + <method name="get_enable_constraint" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns [code]true[/code] if the LookAt modification is using constraints. + </description> + </method> + <method name="set_additional_rotation"> + <return type="void"> + </return> + <argument index="0" name="rotation" type="float"> + </argument> + <description> + Sets the amount of additional rotation that is to be applied after executing the modification. This allows for offsetting the results by the inputted rotation amount. + </description> + </method> + <method name="set_constraint_angle_invert"> + <return type="void"> + </return> + <argument index="0" name="invert" type="bool"> + </argument> + <description> + When [code]true[/code], the modification will use an inverted joint constraint. + An inverted joint constraint only constraints the [Bone2D] to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values. + </description> + </method> + <method name="set_constraint_angle_max"> + <return type="void"> + </return> + <argument index="0" name="angle_max" type="float"> + </argument> + <description> + Sets the constraint's maximum allowed angle. + </description> + </method> + <method name="set_constraint_angle_min"> + <return type="void"> + </return> + <argument index="0" name="angle_min" type="float"> + </argument> + <description> + Sets the constraint's minimum allowed angle. + </description> + </method> + <method name="set_enable_constraint"> + <return type="void"> + </return> + <argument index="0" name="enable_constraint" type="bool"> + </argument> + <description> + Sets whether this modification will use constraints or not. When [code]true[/code], constraints will be applied when solving the LookAt modification. + </description> + </method> + </methods> + <members> + <member name="bone2d_node" type="NodePath" setter="set_bone2d_node" getter="get_bone2d_node" default="NodePath("")"> + The [Bone2D] node that the modification will operate on. + </member> + <member name="bone_index" type="int" setter="set_bone_index" getter="get_bone_index" default="-1"> + The index of the [Bone2D] node that the modification will oeprate on. + </member> + <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> + The NodePath to the node that is the target for the LookAt modification. This node is what the modification will rotate the [Bone2D] to. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DPhysicalBones.xml b/doc/classes/SkeletonModification2DPhysicalBones.xml new file mode 100644 index 0000000000..2547727097 --- /dev/null +++ b/doc/classes/SkeletonModification2DPhysicalBones.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that applies the transforms of [PhysicalBone2D] nodes to [Bone2D] nodes. + </brief_description> + <description> + This modification takes the transforms of [PhysicalBone2D] nodes and applies them to [Bone2D] nodes. This allows the [Bone2D] nodes to react to physics thanks to the linked [PhysicalBone2D] nodes. + </description> + <tutorials> + </tutorials> + <methods> + <method name="fetch_physical_bones"> + <return type="void"> + </return> + <description> + Empties the list of [PhysicalBone2D] nodes and populates it will all [PhysicalBone2D] nodes that are children of the [Skeleton2D]. + </description> + </method> + <method name="get_physical_bone_node" qualifiers="const"> + <return type="NodePath"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <description> + Returns the [PhysicalBone2D] node at [code]joint_idx[/code]. + </description> + </method> + <method name="set_physical_bone_node"> + <return type="void"> + </return> + <argument index="0" name="joint_idx" type="int"> + </argument> + <argument index="1" name="physicalbone2d_node" type="NodePath"> + </argument> + <description> + Sets the [PhysicalBone2D] node at [code]joint_idx[/code]. + [b]Note:[/b] This is just the index used for this modification, not the bone index used in the [Skeleton2D]. + </description> + </method> + <method name="start_simulation"> + <return type="void"> + </return> + <argument index="0" name="bones" type="StringName[]" default="[]"> + </argument> + <description> + Tell the [PhysicalBone2D] nodes to start simulating and interacting with the physics world. + Optionally, an array of bone names can be passed to this function, and that will cause only [PhysicalBone2D] nodes with those names to start simulating. + </description> + </method> + <method name="stop_simulation"> + <return type="void"> + </return> + <argument index="0" name="bones" type="StringName[]" default="[]"> + </argument> + <description> + Tell the [PhysicalBone2D] nodes to stop simulating and interacting with the physics world. + Optionally, an array of bone names can be passed to this function, and that will cause only [PhysicalBone2D] nodes with those names to stop simulating. + </description> + </method> + </methods> + <members> + <member name="physical_bone_chain_length" type="int" setter="set_physical_bone_chain_length" getter="get_physical_bone_chain_length" default="0"> + The amount of [PhysicalBone2D] nodes linked in this modification. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DStackHolder.xml b/doc/classes/SkeletonModification2DStackHolder.xml new file mode 100644 index 0000000000..313cf81482 --- /dev/null +++ b/doc/classes/SkeletonModification2DStackHolder.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that holds and executes a [SkeletonModificationStack2D]. + </brief_description> + <description> + This [SkeletonModification2D] holds a reference to a [SkeletonModificationStack2D], allowing you to use multiple modification stacks on a single [Skeleton2D]. + [b]Note:[/b] The modifications in the held [SkeletonModificationStack2D] will only be executed if their execution mode matches the execution mode of the SkeletonModification2DStackHolder. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_held_modification_stack" qualifiers="const"> + <return type="SkeletonModificationStack2D"> + </return> + <description> + Returns the [SkeletonModificationStack2D] that this modification is holding. + </description> + </method> + <method name="set_held_modification_stack"> + <return type="void"> + </return> + <argument index="0" name="held_modification_stack" type="SkeletonModificationStack2D"> + </argument> + <description> + Sets the [SkeletonModificationStack2D] that this modification is holding. This modification stack will then be executed when this modification is executed. + </description> + </method> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml new file mode 100644 index 0000000000..554515556b --- /dev/null +++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" version="4.0"> + <brief_description> + A modification that rotates two bones using the law of cosigns to reach the target. + </brief_description> + <description> + This [SkeletonModification2D] uses an algorithm typically called TwoBoneIK. This algorithm works by leveraging the law of cosigns and the lengths of the bones to figure out what rotation the bones currently have, and what rotation they need to make a complete triangle, where the first bone, the second bone, and the target form the three verticies of the triangle. Because the algorithm works by making a triangle, it can only opperate on two bones. + TwoBoneIK is great for arms, legs, and really any joints that can be represented by just two bones that bend to reach a target. This solver is more lightweight than [SkeletonModification2DFABRIK], but gives similar, natural looking results. + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_joint_one_bone2d_node" qualifiers="const"> + <return type="NodePath"> + </return> + <description> + Returns the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification. + </description> + </method> + <method name="get_joint_one_bone_idx" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the index of the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification. + </description> + </method> + <method name="get_joint_two_bone2d_node" qualifiers="const"> + <return type="NodePath"> + </return> + <description> + Returns the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification. + </description> + </method> + <method name="get_joint_two_bone_idx" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the index of the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification. + </description> + </method> + <method name="set_joint_one_bone2d_node"> + <return type="void"> + </return> + <argument index="0" name="bone2d_node" type="NodePath"> + </argument> + <description> + Sets the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification. + </description> + </method> + <method name="set_joint_one_bone_idx"> + <return type="void"> + </return> + <argument index="0" name="bone_idx" type="int"> + </argument> + <description> + Sets the index of the [Bone2D] node that is being used as the first bone in the TwoBoneIK modification. + </description> + </method> + <method name="set_joint_two_bone2d_node"> + <return type="void"> + </return> + <argument index="0" name="bone2d_node" type="NodePath"> + </argument> + <description> + Sets the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification. + </description> + </method> + <method name="set_joint_two_bone_idx"> + <return type="void"> + </return> + <argument index="0" name="bone_idx" type="int"> + </argument> + <description> + Sets the index of the [Bone2D] node that is being used as the second bone in the TwoBoneIK modification. + </description> + </method> + </methods> + <members> + <member name="flip_bend_direction" type="bool" setter="set_flip_bend_direction" getter="get_flip_bend_direction" default="false"> + If [code]true[/code], the bones in the modification will blend outward as opposed to inwards when contracting. If [code]false[/code], the bones will bend inwards when contracting. + </member> + <member name="target_maximum_distance" type="float" setter="set_target_maximum_distance" getter="get_target_maximum_distance" default="0.0"> + The maximum distance the target can be at. If the target is farther than this distance, the modification will solve as if it's at this maximum distance. When set to [code]0[/code], the modification will solve without distance constraints. + </member> + <member name="target_minimum_distance" type="float" setter="set_target_minimum_distance" getter="get_target_minimum_distance" default="0.0"> + The minimum distance the target can be at. If the target is closer than this distance, the modification will solve as if it's at this minimum distance. When set to [code]0[/code], the modification will solve without distance constraints. + </member> + <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath("")"> + The NodePath to the node that is the target for the TwoBoneIK modification. This node is what the modification will use when bending the [Bone2D] nodes. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/SkeletonModificationStack2D.xml b/doc/classes/SkeletonModificationStack2D.xml new file mode 100644 index 0000000000..35b899fe08 --- /dev/null +++ b/doc/classes/SkeletonModificationStack2D.xml @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="SkeletonModificationStack2D" inherits="Resource" version="4.0"> + <brief_description> + A resource that holds a stack of [SkeletonModification2D]s. + </brief_description> + <description> + This resource is used by the Skeleton and holds a stack of [SkeletonModification2D]s. + This controls the order of the modifications and how they are applied. Modification order is especially important for full-body IK setups, as you need to execute the modifications in the correct order to get the desired results. For example, you want to execute a modification on the spine [i]before[/i] the arms on a humanoid skeleton. + This resource also controls how strongly all of the modifications are applied to the [Skeleton2D]. + </description> + <tutorials> + </tutorials> + <methods> + <method name="add_modification"> + <return type="void"> + </return> + <argument index="0" name="modification" type="SkeletonModification2D"> + </argument> + <description> + Adds the passed-in [SkeletonModification2D] to the stack. + </description> + </method> + <method name="delete_modification"> + <return type="void"> + </return> + <argument index="0" name="mod_idx" type="int"> + </argument> + <description> + Deletes the [SkeletonModification2D] at the index position [code]mod_idx[/code], if it exists. + </description> + </method> + <method name="enable_all_modifications"> + <return type="void"> + </return> + <argument index="0" name="enabled" type="bool"> + </argument> + <description> + Enables all [SkeletonModification2D]s in the stack. + </description> + </method> + <method name="execute"> + <return type="void"> + </return> + <argument index="0" name="delta" type="float"> + </argument> + <argument index="1" name="execution_mode" type="int"> + </argument> + <description> + Executes all of the [SkeletonModification2D]s in the stack that use the same execution mode as the passed-in [code]execution_mode[/code], starting from index [code]0[/code] to [member modification_count]. + [b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results. + </description> + </method> + <method name="get_is_setup" qualifiers="const"> + <return type="bool"> + </return> + <description> + Returns a boolean that indiciates whether the modification stack is setup and can execute. + </description> + </method> + <method name="get_modification" qualifiers="const"> + <return type="SkeletonModification2D"> + </return> + <argument index="0" name="mod_idx" type="int"> + </argument> + <description> + Returns the [SkeletonModification2D] at the passed-in index, [code]mod_idx[/code]. + </description> + </method> + <method name="get_skeleton" qualifiers="const"> + <return type="Skeleton2D"> + </return> + <description> + Returns the [Skeleton2D] node that the SkeletonModificationStack2D is bound to. + </description> + </method> + <method name="set_modification"> + <return type="void"> + </return> + <argument index="0" name="mod_idx" type="int"> + </argument> + <argument index="1" name="modification" type="SkeletonModification2D"> + </argument> + <description> + Sets the modification at [code]mod_idx[/code] to the passed-in modification, [code]modification[/code]. + </description> + </method> + <method name="setup"> + <return type="void"> + </return> + <description> + Sets up the modification stack so it can execute. This function should be called by [Skeleton2D] and shouldn't be manually called unless you know what you are doing. + </description> + </method> + </methods> + <members> + <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="false"> + If [code]true[/code], the modification's in the stack will be called. This is handled automatically through the [Skeleton2D] node. + </member> + <member name="modification_count" type="int" setter="set_modification_count" getter="get_modification_count" default="0"> + The number of modifications in the stack. + </member> + <member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0"> + The interpolation strength of the modifications in stack. A value of [code]0[/code] will make it where the modifications are not applied, a strength of [code]0.5[/code] will be half applied, and a strength of [code]1[/code] will allow the modifications to be fully applied and override the [Skeleton2D] [Bone2D] poses. + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/Skin.xml b/doc/classes/Skin.xml index e22feb42f0..f409b6c80c 100644 --- a/doc/classes/Skin.xml +++ b/doc/classes/Skin.xml @@ -12,7 +12,7 @@ </return> <argument index="0" name="bone" type="int"> </argument> - <argument index="1" name="pose" type="Transform"> + <argument index="1" name="pose" type="Transform3D"> </argument> <description> </description> @@ -46,7 +46,7 @@ </description> </method> <method name="get_bind_pose" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="bind_index" type="int"> </argument> @@ -86,7 +86,7 @@ </return> <argument index="0" name="bind_index" type="int"> </argument> - <argument index="1" name="pose" type="Transform"> + <argument index="1" name="pose" type="Transform3D"> </argument> <description> </description> diff --git a/doc/classes/SkinReference.xml b/doc/classes/SkinReference.xml index 8fc163f88d..3f8bc3be82 100644 --- a/doc/classes/SkinReference.xml +++ b/doc/classes/SkinReference.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="SkinReference" inherits="Reference" version="4.0"> +<class name="SkinReference" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml index 7999ad774d..b143c60d9d 100644 --- a/doc/classes/SoftBody3D.xml +++ b/doc/classes/SoftBody3D.xml @@ -93,6 +93,9 @@ </member> <member name="damping_coefficient" type="float" setter="set_damping_coefficient" getter="get_damping_coefficient" default="0.01"> </member> + <member name="disable_mode" type="int" setter="set_disable_mode" getter="get_disable_mode" enum="SoftBody3D.DisableMode" default="0"> + Defines the behavior in physics when [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED]. See [enum DisableMode] for more details about the different modes. + </member> <member name="drag_coefficient" type="float" setter="set_drag_coefficient" getter="get_drag_coefficient" default="0.0"> </member> <member name="linear_stiffness" type="float" setter="set_linear_stiffness" getter="get_linear_stiffness" default="0.5"> @@ -113,5 +116,12 @@ </member> </members> <constants> + <constant name="DISABLE_MODE_REMOVE" value="0" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], remove from the physics simulation to stop all physics interactions with this [SoftBody3D]. + Automatically re-added to the physics simulation when the [Node] is processed again. + </constant> + <constant name="DISABLE_MODE_KEEP_ACTIVE" value="1" enum="DisableMode"> + When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], do not affect the physics simulation. + </constant> </constants> </class> diff --git a/doc/classes/Sprite2D.xml b/doc/classes/Sprite2D.xml index c320adb1be..b419b003bf 100644 --- a/doc/classes/Sprite2D.xml +++ b/doc/classes/Sprite2D.xml @@ -64,13 +64,13 @@ <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0"> Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1. </member> - <member name="frame_coords" type="Vector2i" setter="set_frame_coords" getter="get_frame_coords" default="Vector2i( 0, 0 )"> + <member name="frame_coords" type="Vector2i" setter="set_frame_coords" getter="get_frame_coords" default="Vector2i(0, 0)"> Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1. </member> <member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1"> The number of columns in the sprite sheet. </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The texture's drawing offset. </member> <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false"> @@ -79,7 +79,7 @@ <member name="region_filter_clip_enabled" type="bool" setter="set_region_filter_clip_enabled" getter="is_region_filter_clip_enabled" default="false"> If [code]true[/code], the outermost pixels get blurred out. [member region_enabled] must be [code]true[/code]. </member> - <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )"> + <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> The region of the atlas texture to display. [member region_enabled] must be [code]true[/code]. </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> diff --git a/doc/classes/Sprite3D.xml b/doc/classes/Sprite3D.xml index a7d61a6bab..ddb9d543e8 100644 --- a/doc/classes/Sprite3D.xml +++ b/doc/classes/Sprite3D.xml @@ -14,16 +14,15 @@ <member name="frame" type="int" setter="set_frame" getter="get_frame" default="0"> Current frame to display from sprite sheet. [member hframes] or [member vframes] must be greater than 1. </member> - <member name="frame_coords" type="Vector2i" setter="set_frame_coords" getter="get_frame_coords" default="Vector2i( 0, 0 )"> + <member name="frame_coords" type="Vector2i" setter="set_frame_coords" getter="get_frame_coords" default="Vector2i(0, 0)"> Coordinates of the frame to display from sprite sheet. This is as an alias for the [member frame] property. [member hframes] or [member vframes] must be greater than 1. </member> <member name="hframes" type="int" setter="set_hframes" getter="get_hframes" default="1"> The number of columns in the sprite sheet. </member> <member name="region_enabled" type="bool" setter="set_region_enabled" getter="is_region_enabled" default="false"> - If [code]true[/code], texture will be cut from a larger atlas texture. See [member region_rect]. </member> - <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )"> + <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> The region of the atlas texture to display. [member region_enabled] must be [code]true[/code]. </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> diff --git a/doc/classes/SpriteBase3D.xml b/doc/classes/SpriteBase3D.xml index 06b9c2b042..3168e2d848 100644 --- a/doc/classes/SpriteBase3D.xml +++ b/doc/classes/SpriteBase3D.xml @@ -66,10 +66,10 @@ <member name="flip_v" type="bool" setter="set_flip_v" getter="is_flipped_v" default="false"> If [code]true[/code], texture is flipped vertically. </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color( 1, 1, 1, 1 )"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> A color value that gets multiplied on, could be used for mood-coloring or to simulate the color of light. </member> - <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2( 0, 0 )"> + <member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)"> The texture's drawing offset. </member> <member name="opacity" type="float" setter="set_opacity" getter="get_opacity" default="1.0"> diff --git a/doc/classes/StaticBody2D.xml b/doc/classes/StaticBody2D.xml index 2a5c1ea6f4..85915a53fe 100644 --- a/doc/classes/StaticBody2D.xml +++ b/doc/classes/StaticBody2D.xml @@ -4,8 +4,11 @@ Static body for 2D physics. </brief_description> <description> - Static body for 2D physics. A StaticBody2D is a body that is not intended to move. It is ideal for implementing objects in the environment, such as walls or platforms. - Additionally, a constant linear or angular velocity can be set for the static body, which will affect colliding bodies as if it were moving (for example, a conveyor belt). + Static body for 2D physics. A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody2D], they don't consume any CPU resources as long as they don't move. + They however have extra functionalities to move and affect other bodies: + [b]Constant velocity:[/b] [member constant_linear_velocity] and [member constant_angular_velocity] can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels). + [b]Transform change:[/b] Static bodies can be also moved by code. Unless [member kinematic_motion] is enabled, they are just teleported in this case and don't affect other bodies on their path. + [b]Kinematic motion:[/b] Static bodies can have [member kinematic_motion] enabled to make them kinematic bodies that can be moved by code and push other bodies on their path. </description> <tutorials> </tutorials> @@ -13,10 +16,14 @@ </methods> <members> <member name="constant_angular_velocity" type="float" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="0.0"> - The body's constant angular velocity. This does not rotate the body, but affects colliding bodies, as if it were rotating. + The body's constant angular velocity. This does not rotate the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were rotating. </member> - <member name="constant_linear_velocity" type="Vector2" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector2( 0, 0 )"> - The body's constant linear velocity. This does not move the body, but affects colliding bodies, as if it were moving. + <member name="constant_linear_velocity" type="Vector2" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector2(0, 0)"> + The body's constant linear velocity. This does not move the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were moving. + </member> + <member name="kinematic_motion" type="bool" setter="set_kinematic_motion_enabled" getter="is_kinematic_motion_enabled" default="false"> + If [code]true[/code], the body will act the same as a [RigidBody2D] in [constant RigidBody2D.MODE_KINEMATIC] mode. + When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. diff --git a/doc/classes/StaticBody3D.xml b/doc/classes/StaticBody3D.xml index 63a15cbe1d..f83d440f10 100644 --- a/doc/classes/StaticBody3D.xml +++ b/doc/classes/StaticBody3D.xml @@ -4,8 +4,11 @@ Static body for 3D physics. </brief_description> <description> - Static body for 3D physics. A static body is a simple body that is not intended to move. In contrast to [RigidBody3D], they don't consume any CPU resources as long as they don't move. - Additionally, a constant linear or angular velocity can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels). + Static body for 3D physics. A static body is a simple body that can't be moved by external forces or contacts. It is ideal for implementing objects in the environment, such as walls or platforms. In contrast to [RigidBody3D], they don't consume any CPU resources as long as they don't move. + They however have extra functionalities to move and affect other bodies: + [b]Constant velocity:[/b] [member constant_linear_velocity] and [member constant_angular_velocity] can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels). + [b]Transform change:[/b] Static bodies can be also moved by code. Unless [member kinematic_motion] is enabled, they are just teleported in this case and don't affect other bodies on their path. + [b]Kinematic motion:[/b] Static bodies can have [member kinematic_motion] enabled to make them kinematic bodies that can be moved by code and push other bodies on their path. </description> <tutorials> <link title="3D Physics Tests Demo">https://godotengine.org/asset-library/asset/675</link> @@ -15,11 +18,15 @@ <methods> </methods> <members> - <member name="constant_angular_velocity" type="Vector3" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="Vector3( 0, 0, 0 )"> - The body's constant angular velocity. This does not rotate the body, but affects other bodies that touch it, as if it was in a state of rotation. + <member name="constant_angular_velocity" type="Vector3" setter="set_constant_angular_velocity" getter="get_constant_angular_velocity" default="Vector3(0, 0, 0)"> + The body's constant angular velocity. This does not rotate the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were rotating. </member> - <member name="constant_linear_velocity" type="Vector3" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector3( 0, 0, 0 )"> - The body's constant linear velocity. This does not move the body, but affects other bodies that touch it, as if it was in a state of movement. + <member name="constant_linear_velocity" type="Vector3" setter="set_constant_linear_velocity" getter="get_constant_linear_velocity" default="Vector3(0, 0, 0)"> + The body's constant linear velocity. This does not move the body (unless [member kinematic_motion] is enabled), but affects other bodies that touch it, as if it were moving. + </member> + <member name="kinematic_motion" type="bool" setter="set_kinematic_motion_enabled" getter="is_kinematic_motion_enabled" default="false"> + If [code]true[/code], the body will act the same as a [RigidBody3D] in [constant RigidBody3D.MODE_KINEMATIC] mode. + When the body is moved manually, either from code or from an [AnimationPlayer] (with [member AnimationPlayer.playback_process_mode] set to [code]physics[/code]), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc). </member> <member name="physics_material_override" type="PhysicsMaterial" setter="set_physics_material_override" getter="get_physics_material_override"> The physics material override for the body. diff --git a/doc/classes/StreamPeer.xml b/doc/classes/StreamPeer.xml index f120103916..5367a572f1 100644 --- a/doc/classes/StreamPeer.xml +++ b/doc/classes/StreamPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="StreamPeer" inherits="Reference" version="4.0"> +<class name="StreamPeer" inherits="RefCounted" version="4.0"> <brief_description> Abstraction and base class for stream-based protocols. </brief_description> diff --git a/doc/classes/StreamPeerBuffer.xml b/doc/classes/StreamPeerBuffer.xml index 41cef9fb55..03a150b90f 100644 --- a/doc/classes/StreamPeerBuffer.xml +++ b/doc/classes/StreamPeerBuffer.xml @@ -49,7 +49,7 @@ </method> </methods> <members> - <member name="data_array" type="PackedByteArray" setter="set_data_array" getter="get_data_array" default="PackedByteArray( )"> + <member name="data_array" type="PackedByteArray" setter="set_data_array" getter="get_data_array" default="PackedByteArray()"> </member> </members> <constants> diff --git a/doc/classes/String.xml b/doc/classes/String.xml index a81defa16c..3bf05e7c92 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -275,7 +275,7 @@ Returns a copy of the string with the substring [code]what[/code] inserted at the given position. </description> </method> - <method name="is_abs_path" qualifiers="const"> + <method name="is_absolute_path" qualifiers="const"> <return type="bool"> </return> <description> @@ -352,7 +352,7 @@ Returns [code]true[/code] if this string is a valid identifier. A valid identifier may contain only letters, digits and underscores ([code]_[/code]) and the first character may not be a digit. </description> </method> - <method name="is_valid_integer" qualifiers="const"> + <method name="is_valid_int" qualifiers="const"> <return type="bool"> </return> <description> diff --git a/doc/classes/StyleBoxFlat.xml b/doc/classes/StyleBoxFlat.xml index d66ae210ec..9e02fb57c3 100644 --- a/doc/classes/StyleBoxFlat.xml +++ b/doc/classes/StyleBoxFlat.xml @@ -156,13 +156,13 @@ <member name="anti_aliasing_size" type="int" setter="set_aa_size" getter="get_aa_size" default="1"> This changes the size of the faded ring. Higher values can be used to achieve a "blurry" effect. </member> - <member name="bg_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color( 0.6, 0.6, 0.6, 1 )"> + <member name="bg_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color(0.6, 0.6, 0.6, 1)"> The background color of the stylebox. </member> <member name="border_blend" type="bool" setter="set_border_blend" getter="get_border_blend" default="false"> If [code]true[/code], the border will fade into the background color. </member> - <member name="border_color" type="Color" setter="set_border_color" getter="get_border_color" default="Color( 0.8, 0.8, 0.8, 1 )"> + <member name="border_color" type="Color" setter="set_border_color" getter="get_border_color" default="Color(0.8, 0.8, 0.8, 1)"> Sets the color of the border. </member> <member name="border_width_bottom" type="int" setter="set_border_width" getter="get_border_width" default="0"> @@ -209,10 +209,10 @@ <member name="expand_margin_top" type="float" setter="set_expand_margin" getter="get_expand_margin" default="0.0"> Expands the stylebox outside of the control rect on the top edge. Useful in combination with [member border_width_top] to draw a border outside the control rect. </member> - <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color( 0, 0, 0, 0.6 )"> + <member name="shadow_color" type="Color" setter="set_shadow_color" getter="get_shadow_color" default="Color(0, 0, 0, 0.6)"> The color of the shadow. This has no effect if [member shadow_size] is lower than 1. </member> - <member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset" default="Vector2( 0, 0 )"> + <member name="shadow_offset" type="Vector2" setter="set_shadow_offset" getter="get_shadow_offset" default="Vector2(0, 0)"> The shadow offset in pixels. Adjusts the position of the shadow relatively to the stylebox. </member> <member name="shadow_size" type="int" setter="set_shadow_size" getter="get_shadow_size" default="0"> diff --git a/doc/classes/StyleBoxLine.xml b/doc/classes/StyleBoxLine.xml index 4a2dbf60e4..850c656720 100644 --- a/doc/classes/StyleBoxLine.xml +++ b/doc/classes/StyleBoxLine.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> The line's color. </member> <member name="grow_begin" type="float" setter="set_grow_begin" getter="get_grow_begin" default="1.0"> diff --git a/doc/classes/StyleBoxTexture.xml b/doc/classes/StyleBoxTexture.xml index 895d0c357d..be14048126 100644 --- a/doc/classes/StyleBoxTexture.xml +++ b/doc/classes/StyleBoxTexture.xml @@ -116,10 +116,10 @@ A higher value means more of the source texture is considered to be part of the top border of the 3×3 box. This is also the value used as fallback for [member StyleBox.content_margin_top] if it is negative. </member> - <member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate" default="Color( 1, 1, 1, 1 )"> + <member name="modulate_color" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> Modulates the color of the texture when this style box is drawn. </member> - <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2( 0, 0, 0, 0 )"> + <member name="region_rect" type="Rect2" setter="set_region_rect" getter="get_region_rect" default="Rect2(0, 0, 0, 0)"> Species a sub-region of the texture to use. This is equivalent to first wrapping the texture in an [AtlasTexture] with the same region. </member> @@ -127,13 +127,6 @@ The texture to use when drawing this style box. </member> </members> - <signals> - <signal name="texture_changed"> - <description> - Emitted when the stylebox's texture is changed. - </description> - </signal> - </signals> <constants> <constant name="AXIS_STRETCH_MODE_STRETCH" value="0" enum="AxisStretchMode"> Stretch the stylebox's texture. This results in visible distortion unless the texture size matches the stylebox's size perfectly. diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml index f54f22d6fa..9c5610e2c7 100644 --- a/doc/classes/SubViewport.xml +++ b/doc/classes/SubViewport.xml @@ -25,10 +25,10 @@ <member name="render_target_update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="SubViewport.UpdateMode" default="2"> The update mode when the sub-viewport is used as a render target. </member> - <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i( 512, 512 )"> + <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(512, 512)"> The width and height of the sub-viewport. </member> - <member name="size_2d_override" type="Vector2i" setter="set_size_2d_override" getter="get_size_2d_override" default="Vector2i( 0, 0 )"> + <member name="size_2d_override" type="Vector2i" setter="set_size_2d_override" getter="get_size_2d_override" default="Vector2i(0, 0)"> The 2D size override of the sub-viewport. If either the width or height is [code]0[/code], the override is disabled. </member> <member name="size_2d_override_stretch" type="bool" setter="set_size_2d_override_stretch" getter="is_size_2d_override_stretch_enabled" default="false"> diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml index 1195e4aa2b..a8b836ff0c 100644 --- a/doc/classes/SurfaceTool.xml +++ b/doc/classes/SurfaceTool.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="SurfaceTool" inherits="Reference" version="4.0"> +<class name="SurfaceTool" inherits="RefCounted" version="4.0"> <brief_description> Helper tool to create geometry. </brief_description> @@ -24,7 +24,7 @@ The above [SurfaceTool] now contains one vertex of a triangle which has a UV coordinate and a specified [Color]. If another vertex were added without calling [method set_uv] or [method set_color], then the last values would be used. Vertex attributes must be passed [b]before[/b] calling [method add_vertex]. Failure to do so will result in an error when committing the vertex information to a mesh. Additionally, the attributes used before the first vertex is added determine the format of the mesh. For example, if you only add UVs to the first vertex, you cannot add color to any of the subsequent vertices. - See also [ArrayMesh], [ImmediateGeometry3D] and [MeshDataTool] for procedural geometry generation. + See also [ArrayMesh], [ImmediateMesh] and [MeshDataTool] for procedural geometry generation. [b]Note:[/b] Godot uses clockwise [url=https://learnopengl.com/Advanced-OpenGL/Face-culling]winding order[/url] for front faces of triangle primitive modes. </description> <tutorials> @@ -45,15 +45,15 @@ </return> <argument index="0" name="vertices" type="PackedVector3Array"> </argument> - <argument index="1" name="uvs" type="PackedVector2Array" default="PackedVector2Array( )"> + <argument index="1" name="uvs" type="PackedVector2Array" default="PackedVector2Array()"> </argument> - <argument index="2" name="colors" type="PackedColorArray" default="PackedColorArray( )"> + <argument index="2" name="colors" type="PackedColorArray" default="PackedColorArray()"> </argument> - <argument index="3" name="uv2s" type="PackedVector2Array" default="PackedVector2Array( )"> + <argument index="3" name="uv2s" type="PackedVector2Array" default="PackedVector2Array()"> </argument> - <argument index="4" name="normals" type="PackedVector3Array" default="PackedVector3Array( )"> + <argument index="4" name="normals" type="PackedVector3Array" default="PackedVector3Array()"> </argument> - <argument index="5" name="tangents" type="Array" default="[ ]"> + <argument index="5" name="tangents" type="Array" default="[]"> </argument> <description> Inserts a triangle fan made of array data into [Mesh] being constructed. @@ -76,10 +76,10 @@ </argument> <argument index="1" name="surface" type="int"> </argument> - <argument index="2" name="transform" type="Transform"> + <argument index="2" name="transform" type="Transform3D"> </argument> <description> - Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform]. + Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform3D]. </description> </method> <method name="begin"> diff --git a/doc/classes/TCPServer.xml b/doc/classes/TCPServer.xml index 28f06ad3ae..7160055c6d 100644 --- a/doc/classes/TCPServer.xml +++ b/doc/classes/TCPServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TCPServer" inherits="Reference" version="4.0"> +<class name="TCPServer" inherits="RefCounted" version="4.0"> <brief_description> A TCP server. </brief_description> diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml index ddf6b465a4..3f24509ec7 100644 --- a/doc/classes/TabContainer.xml +++ b/doc/classes/TabContainer.xml @@ -198,19 +198,19 @@ <theme_item name="font" type="Font"> The font used to draw tab names. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.2)"> Font color of disabled tabs. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the tab name. </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Font color of the currently selected tab. </theme_item> <theme_item name="font_size" type="int"> Font size of the tab names. </theme_item> - <theme_item name="font_unselected_color" type="Color" default="Color( 0.69, 0.69, 0.69, 1 )"> + <theme_item name="font_unselected_color" type="Color" default="Color(0.69, 0.69, 0.69, 1)"> Font color of the other, unselected tabs. </theme_item> <theme_item name="icon_separation" type="int" default="4"> diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml index d784585e20..aff104c922 100644 --- a/doc/classes/Tabs.xml +++ b/doc/classes/Tabs.xml @@ -362,19 +362,19 @@ <theme_item name="font" type="Font"> The font used to draw tab names. </theme_item> - <theme_item name="font_disabled_color" type="Color" default="Color( 0.9, 0.9, 0.9, 0.2 )"> + <theme_item name="font_disabled_color" type="Color" default="Color(0.9, 0.9, 0.9, 0.2)"> Font color of disabled tabs. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the tab name. </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Font color of the currently selected tab. </theme_item> <theme_item name="font_size" type="int"> Font size of the tab names. </theme_item> - <theme_item name="font_unselected_color" type="Color" default="Color( 0.69, 0.69, 0.69, 1 )"> + <theme_item name="font_unselected_color" type="Color" default="Color(0.69, 0.69, 0.69, 1)"> Font color of the other, unselected tabs. </theme_item> <theme_item name="hseparation" type="int" default="4"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 74811318dc..5de6c059c3 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -10,6 +10,13 @@ <tutorials> </tutorials> <methods> + <method name="_backspace" qualifiers="virtual"> + <return type="void"> + </return> + <description> + A virtual method that is called whenever backspace is triggered. + </description> + </method> <method name="add_gutter"> <return type="void"> </return> @@ -18,13 +25,11 @@ <description> </description> </method> - <method name="can_fold" qualifiers="const"> - <return type="bool"> + <method name="backspace"> + <return type="void"> </return> - <argument index="0" name="line" type="int"> - </argument> <description> - Returns if the given line is foldable, that is, it has indented lines right below it. + Causes the [TextEdit] to perform a backspace. </description> </method> <method name="center_viewport_to_cursor"> @@ -95,7 +100,7 @@ <description> Moves the cursor at the specified [code]line[/code] index. If [code]adjust_viewport[/code] is set to [code]true[/code], the viewport will center at the cursor position after the move occurs. - If [code]can_be_hidden[/code] is set to [code]true[/code], the specified [code]line[/code] can be hidden using [method set_line_as_hidden]. + If [code]can_be_hidden[/code] is set to [code]true[/code], the specified [code]line[/code] can be hidden. </description> </method> <method name="cut"> @@ -105,34 +110,32 @@ Cut's the current selection. </description> </method> - <method name="deselect"> + <method name="delete_selection"> <return type="void"> </return> <description> - Deselects the current selection. </description> </method> - <method name="fold_all_lines"> + <method name="deselect"> <return type="void"> </return> <description> - Folds all lines that are possible to be folded (see [method can_fold]). + Deselects the current selection. </description> </method> - <method name="fold_line"> - <return type="void"> + <method name="get_caret_draw_pos" qualifiers="const"> + <return type="Vector2"> </return> - <argument index="0" name="line" type="int"> - </argument> <description> - Folds the given line, if possible (see [method can_fold]). + Gets the caret pixel draw poistion. </description> </method> - <method name="get_caret_draw_pos" qualifiers="const"> - <return type="Vector2"> + <method name="get_first_non_whitespace_column" qualifiers="const"> + <return type="int"> </return> + <argument index="0" name="line" type="int"> + </argument> <description> - Gets the caret pixel draw poistion. </description> </method> <method name="get_gutter_count" qualifiers="const"> @@ -165,6 +168,15 @@ <description> </description> </method> + <method name="get_indent_level" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="line" type="int"> + </argument> + <description> + Returns the indent level of a specific line. + </description> + </method> <method name="get_line" qualifiers="const"> <return type="String"> </return> @@ -299,6 +311,13 @@ Returns the selection end line. </description> </method> + <method name="get_tab_size" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the [TextEdit]'s' tab size. + </description> + </method> <method name="get_visible_line_count" qualifiers="const"> <return type="int"> </return> @@ -329,15 +348,6 @@ Returns [code]true[/code] if the caret is visible on the screen. </description> </method> - <method name="is_folded" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="line" type="int"> - </argument> - <description> - Returns whether the line at the specified index is folded or not. - </description> - </method> <method name="is_gutter_clickable" qualifiers="const"> <return type="bool"> </return> @@ -372,15 +382,6 @@ <description> </description> </method> - <method name="is_line_hidden" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="line" type="int"> - </argument> - <description> - Returns whether the line at the specified index is hidden or not. - </description> - </method> <method name="is_selection_active" qualifiers="const"> <return type="bool"> </return> @@ -397,6 +398,16 @@ Triggers a right-click menu action by the specified index. See [enum MenuItems] for a list of available indexes. </description> </method> + <method name="merge_gutters"> + <return type="void"> + </return> + <argument index="0" name="from_line" type="int"> + </argument> + <argument index="1" name="to_line" type="int"> + </argument> + <description> + </description> + </method> <method name="paste"> <return type="void"> </return> @@ -560,17 +571,6 @@ Sets the text for a specific line. </description> </method> - <method name="set_line_as_hidden"> - <return type="void"> - </return> - <argument index="0" name="line" type="int"> - </argument> - <argument index="1" name="enable" type="bool"> - </argument> - <description> - If [code]true[/code], hides the line of the specified index. - </description> - </method> <method name="set_line_background_color"> <return type="void"> </return> @@ -665,13 +665,13 @@ <description> </description> </method> - <method name="toggle_fold_line"> + <method name="set_tab_size"> <return type="void"> </return> - <argument index="0" name="line" type="int"> + <argument index="0" name="size" type="int"> </argument> <description> - Toggle the folding of the code block at the given line. + Sets the tab size for the [TextEdit] to use. </description> </method> <method name="undo"> @@ -681,22 +681,6 @@ Perform undo operation. </description> </method> - <method name="unfold_line"> - <return type="void"> - </return> - <argument index="0" name="line" type="int"> - </argument> - <description> - Unfolds the given line, if folded. - </description> - </method> - <method name="unhide_all_lines"> - <return type="void"> - </return> - <description> - Unhide all lines that were previously set to hidden by [method set_line_as_hidden]. - </description> - </method> </methods> <members> <member name="caret_blink" type="bool" setter="cursor_set_blink_enabled" getter="cursor_get_blink_enabled" default="false"> @@ -730,9 +714,6 @@ If [code]true[/code], the "tab" character will have a visible representation. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" /> - <member name="hiding_enabled" type="bool" setter="set_hiding_enabled" getter="is_hiding_enabled" default="false"> - If [code]true[/code], all lines that have been set to hidden by [method set_line_as_hidden], will not be visible. - </member> <member name="highlight_all_occurrences" type="bool" setter="set_highlight_all_occurrences" getter="is_highlight_all_occurrences_enabled" default="false"> If [code]true[/code], all occurrences of the selected text will be highlighted. </member> @@ -774,7 +755,7 @@ <member name="structured_text_bidi_override" type="int" setter="set_structured_text_bidi_override" getter="get_structured_text_bidi_override" enum="Control.StructuredTextParser" default="0"> Set BiDi algorithm override for the structured text. </member> - <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[ ]"> + <member name="structured_text_bidi_override_options" type="Array" setter="set_structured_text_bidi_override_options" getter="get_structured_text_bidi_override_options" default="[]"> Set additional options for BiDi override. </member> <member name="syntax_highlighter" type="SyntaxHighlighter" setter="set_syntax_highlighter" getter="get_syntax_highlighter"> @@ -963,18 +944,16 @@ </constant> </constants> <theme_items> - <theme_item name="background_color" type="Color" default="Color( 0, 0, 0, 0 )"> + <theme_item name="background_color" type="Color" default="Color(0, 0, 0, 0)"> Sets the background [Color] of this [TextEdit]. </theme_item> - <theme_item name="brace_mismatch_color" type="Color" default="Color( 1, 0.2, 0.2, 1 )"> - </theme_item> - <theme_item name="caret_background_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="brace_mismatch_color" type="Color" default="Color(1, 0.2, 0.2, 1)"> </theme_item> - <theme_item name="caret_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="caret_background_color" type="Color" default="Color(0, 0, 0, 1)"> </theme_item> - <theme_item name="code_folding_color" type="Color" default="Color( 0.8, 0.8, 0.8, 0.8 )"> + <theme_item name="caret_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> </theme_item> - <theme_item name="current_line_color" type="Color" default="Color( 0.25, 0.25, 0.26, 0.8 )"> + <theme_item name="current_line_color" type="Color" default="Color(0.25, 0.25, 0.26, 0.8)"> Sets the [Color] of the breakpoints. [member breakpoint_gutter] has to be enabled. </theme_item> <theme_item name="focus" type="StyleBox"> @@ -982,15 +961,15 @@ <theme_item name="font" type="Font"> Sets the default [Font]. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Sets the font [Color]. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the [TextEdit]. </theme_item> - <theme_item name="font_readonly_color" type="Color" default="Color( 0.88, 0.88, 0.88, 0.5 )"> + <theme_item name="font_readonly_color" type="Color" default="Color(0.88, 0.88, 0.88, 0.5)"> </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(0, 0, 0, 1)"> Sets the [Color] of the selected text. [member override_selected_font_color] has to be enabled. </theme_item> <theme_item name="font_size" type="int"> @@ -1008,7 +987,7 @@ <theme_item name="read_only" type="StyleBox"> Sets the [StyleBox] of this [TextEdit] when [member readonly] is enabled. </theme_item> - <theme_item name="selection_color" type="Color" default="Color( 0.49, 0.49, 0.49, 1 )"> + <theme_item name="selection_color" type="Color" default="Color(0.49, 0.49, 0.49, 1)"> Sets the highlight [Color] of text selections. </theme_item> <theme_item name="space" type="Texture2D"> @@ -1017,7 +996,7 @@ <theme_item name="tab" type="Texture2D"> Sets a custom [Texture2D] for tab text characters. </theme_item> - <theme_item name="word_highlighted_color" type="Color" default="Color( 0.8, 0.9, 0.9, 0.15 )"> + <theme_item name="word_highlighted_color" type="Color" default="Color(0.8, 0.9, 0.9, 0.15)"> Sets the highlight [Color] of multiple occurrences. [member highlight_all_occurrences] has to be enabled. </theme_item> </theme_items> diff --git a/doc/classes/TextLine.xml b/doc/classes/TextLine.xml index c21da09edb..318c3be794 100644 --- a/doc/classes/TextLine.xml +++ b/doc/classes/TextLine.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TextLine" inherits="Reference" version="4.0"> +<class name="TextLine" inherits="RefCounted" version="4.0"> <brief_description> Holds a line of text. </brief_description> @@ -56,7 +56,7 @@ </argument> <argument index="1" name="pos" type="Vector2"> </argument> - <argument index="2" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="2" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -71,7 +71,7 @@ </argument> <argument index="2" name="outline_size" type="int" default="1"> </argument> - <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. diff --git a/doc/classes/TextParagraph.xml b/doc/classes/TextParagraph.xml index 8df53b8423..d67a9bcb85 100644 --- a/doc/classes/TextParagraph.xml +++ b/doc/classes/TextParagraph.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TextParagraph" inherits="Reference" version="4.0"> +<class name="TextParagraph" inherits="RefCounted" version="4.0"> <brief_description> Holds a paragraph of text. </brief_description> @@ -63,9 +63,9 @@ </argument> <argument index="1" name="pos" type="Vector2"> </argument> - <argument index="2" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="2" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> - <argument index="3" name="dc_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="dc_color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -78,7 +78,7 @@ </argument> <argument index="1" name="pos" type="Vector2"> </argument> - <argument index="2" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="2" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -93,7 +93,7 @@ </argument> <argument index="2" name="outline_size" type="int" default="1"> </argument> - <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw drop cap outline into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -108,7 +108,7 @@ </argument> <argument index="2" name="line" type="int"> </argument> - <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw single line of text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -125,7 +125,7 @@ </argument> <argument index="3" name="outline_size" type="int" default="1"> </argument> - <argument index="4" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="4" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw outline of the single line of text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -140,9 +140,9 @@ </argument> <argument index="2" name="outline_size" type="int" default="1"> </argument> - <argument index="3" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> - <argument index="4" name="dc_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="4" name="dc_color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw outlines of all lines of the text and drop cap into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the top left corner of the bounding box. @@ -344,7 +344,7 @@ </argument> <argument index="2" name="size" type="int"> </argument> - <argument index="3" name="dropcap_margins" type="Rect2" default="Rect2( 0, 0, 0, 0 )"> + <argument index="3" name="dropcap_margins" type="Rect2" default="Rect2(0, 0, 0, 0)"> </argument> <argument index="4" name="opentype_features" type="Dictionary" default="{ }"> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index fe63e434c9..c943946ab3 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -149,7 +149,7 @@ </argument> <argument index="4" name="index" type="int"> </argument> - <argument index="5" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="5" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draws single glyph into a canvas item at the position, using [code]font[/code] at the size [code]size[/code]. @@ -171,7 +171,7 @@ </argument> <argument index="5" name="index" type="int"> </argument> - <argument index="6" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="6" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draws single glyph outline of size [code]outline_size[/code] into a canvas item at the position, using [code]font[/code] at the size [code]size[/code]. @@ -788,7 +788,7 @@ </argument> <argument index="4" name="clip_r" type="float" default="-1"> </argument> - <argument index="5" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="5" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout). @@ -809,7 +809,7 @@ </argument> <argument index="5" name="outline_size" type="int" default="1"> </argument> - <argument index="6" name="color" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="6" name="color" type="Color" default="Color(1, 1, 1, 1)"> </argument> <description> Draw the outline of the shaped text into a canvas item at a given position, with [code]color[/code]. [code]pos[/code] specifies the leftmost point of the baseline (for horizontal layout) or topmost point of the baseline (for vertical layout). @@ -976,7 +976,7 @@ </argument> <description> Returns [code]true[/code] if text buffer is configured to display hexadecimal codes in place of invalid characters. - Note: If set to [code]false[/code], nothing is displayed in place of invalid characters. + Note: If set to [code]false[/code], nothing is displayed in place of invalid characters. </description> </method> <method name="shaped_text_get_range" qualifiers="const"> diff --git a/doc/classes/Texture2D.xml b/doc/classes/Texture2D.xml index c33f32c9e4..35b719ae48 100644 --- a/doc/classes/Texture2D.xml +++ b/doc/classes/Texture2D.xml @@ -19,7 +19,7 @@ </argument> <argument index="1" name="position" type="Vector2"> </argument> - <argument index="2" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="2" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="3" name="transpose" type="bool" default="false"> </argument> @@ -36,7 +36,7 @@ </argument> <argument index="2" name="tile" type="bool"> </argument> - <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="4" name="transpose" type="bool" default="false"> </argument> @@ -53,7 +53,7 @@ </argument> <argument index="2" name="src_rect" type="Rect2"> </argument> - <argument index="3" name="modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <argument index="3" name="modulate" type="Color" default="Color(1, 1, 1, 1)"> </argument> <argument index="4" name="transpose" type="bool" default="false"> </argument> diff --git a/doc/classes/TextureProgressBar.xml b/doc/classes/TextureProgressBar.xml index b40759578f..59cde536ad 100644 --- a/doc/classes/TextureProgressBar.xml +++ b/doc/classes/TextureProgressBar.xml @@ -36,7 +36,7 @@ <member name="nine_patch_stretch" type="bool" setter="set_nine_patch_stretch" getter="get_nine_patch_stretch" default="false"> If [code]true[/code], Godot treats the bar's textures like in [NinePatchRect]. Use the [code]stretch_margin_*[/code] properties like [member stretch_margin_bottom] to set up the nine patch's 3×3 grid. When using a radial [member fill_mode], this setting will enable stretching. </member> - <member name="radial_center_offset" type="Vector2" setter="set_radial_center_offset" getter="get_radial_center_offset" default="Vector2( 0, 0 )"> + <member name="radial_center_offset" type="Vector2" setter="set_radial_center_offset" getter="get_radial_center_offset" default="Vector2(0, 0)"> Offsets [member texture_progress] if [member fill_mode] is [constant FILL_CLOCKWISE] or [constant FILL_COUNTER_CLOCKWISE]. </member> <member name="radial_fill_degrees" type="float" setter="set_fill_degrees" getter="get_fill_degrees" default="360.0"> @@ -68,13 +68,13 @@ <member name="texture_under" type="Texture2D" setter="set_under_texture" getter="get_under_texture"> [Texture2D] that draws under the progress bar. The bar's background. </member> - <member name="tint_over" type="Color" setter="set_tint_over" getter="get_tint_over" default="Color( 1, 1, 1, 1 )"> + <member name="tint_over" type="Color" setter="set_tint_over" getter="get_tint_over" default="Color(1, 1, 1, 1)"> Multiplies the color of the bar's [code]texture_over[/code] texture. The effect is similar to [member CanvasItem.modulate], except it only affects this specific texture instead of the entire node. </member> - <member name="tint_progress" type="Color" setter="set_tint_progress" getter="get_tint_progress" default="Color( 1, 1, 1, 1 )"> + <member name="tint_progress" type="Color" setter="set_tint_progress" getter="get_tint_progress" default="Color(1, 1, 1, 1)"> Multiplies the color of the bar's [code]texture_progress[/code] texture. </member> - <member name="tint_under" type="Color" setter="set_tint_under" getter="get_tint_under" default="Color( 1, 1, 1, 1 )"> + <member name="tint_under" type="Color" setter="set_tint_under" getter="get_tint_under" default="Color(1, 1, 1, 1)"> Multiplies the color of the bar's [code]texture_under[/code] texture. </member> </members> diff --git a/doc/classes/Thread.xml b/doc/classes/Thread.xml index 88f46e3937..5ac9416b72 100644 --- a/doc/classes/Thread.xml +++ b/doc/classes/Thread.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Thread" inherits="Reference" version="4.0"> +<class name="Thread" inherits="RefCounted" version="4.0"> <brief_description> A unit of execution in a process. </brief_description> diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml index efcbdf2e95..bb793024eb 100644 --- a/doc/classes/TileData.xml +++ b/doc/classes/TileData.xml @@ -7,7 +7,7 @@ <tutorials> </tutorials> <methods> - <method name="add_collision_shape"> + <method name="add_collision_polygon"> <return type="void"> </return> <argument index="0" name="layer_id" type="int"> @@ -15,27 +15,27 @@ <description> </description> </method> - <method name="get_collision_shape_one_way_margin" qualifiers="const"> + <method name="get_collision_polygon_one_way_margin" qualifiers="const"> <return type="float"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> <description> </description> </method> - <method name="get_collision_shape_shape" qualifiers="const"> - <return type="Shape2D"> + <method name="get_collision_polygon_points" qualifiers="const"> + <return type="PackedVector2Array"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> <description> </description> </method> - <method name="get_collision_shapes_count" qualifiers="const"> + <method name="get_collision_polygons_count" qualifiers="const"> <return type="int"> </return> <argument index="0" name="layer_id" type="int"> @@ -83,68 +83,68 @@ <description> </description> </method> - <method name="is_collision_shape_one_way" qualifiers="const"> + <method name="is_collision_polygon_one_way" qualifiers="const"> <return type="bool"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> <description> </description> </method> - <method name="remove_collision_shape"> + <method name="remove_collision_polygon"> <return type="void"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> <description> </description> </method> - <method name="set_collision_shape_one_way"> + <method name="set_collision_polygon_one_way"> <return type="void"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> <argument index="2" name="one_way" type="bool"> </argument> <description> </description> </method> - <method name="set_collision_shape_one_way_margin"> + <method name="set_collision_polygon_one_way_margin"> <return type="void"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> <argument index="2" name="one_way_margin" type="float"> </argument> <description> </description> </method> - <method name="set_collision_shape_shape"> + <method name="set_collision_polygon_points"> <return type="void"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shape_index" type="int"> + <argument index="1" name="polygon_index" type="int"> </argument> - <argument index="2" name="shape" type="Shape2D"> + <argument index="2" name="polygon" type="PackedVector2Array"> </argument> <description> </description> </method> - <method name="set_collision_shapes_count"> + <method name="set_collision_polygons_count"> <return type="void"> </return> <argument index="0" name="layer_id" type="int"> </argument> - <argument index="1" name="shapes_count" type="int"> + <argument index="1" name="polygons_count" type="int"> </argument> <description> </description> @@ -219,13 +219,13 @@ </member> <member name="flip_v" type="bool" setter="set_flip_v" getter="get_flip_v" default="false"> </member> - <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color( 1, 1, 1, 1 )"> + <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> </member> <member name="probability" type="float" setter="set_probability" getter="get_probability" default="1.0"> </member> <member name="terrain_set" type="int" setter="set_terrain_set" getter="get_terrain_set" default="-1"> </member> - <member name="texture_offset" type="Vector2i" setter="set_texture_offset" getter="get_texture_offset" default="Vector2i( 0, 0 )"> + <member name="texture_offset" type="Vector2i" setter="set_texture_offset" getter="get_texture_offset" default="Vector2i(0, 0)"> </member> <member name="transpose" type="bool" setter="set_transpose" getter="get_transpose" default="false"> </member> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index 93d5dd8037..5a4068ec86 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -103,7 +103,7 @@ </argument> <argument index="1" name="source_id" type="int" default="-1"> </argument> - <argument index="2" name="atlas_coords" type="Vector2i" default="Vector2i( -1, -1 )"> + <argument index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)"> </argument> <argument index="3" name="alternative_tile" type="int" default="-1"> </argument> diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 2015b1f1cd..436e15387d 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -287,9 +287,7 @@ </member> <member name="tile_shape" type="int" setter="set_tile_shape" getter="get_tile_shape" enum="TileSet.TileShape" default="0"> </member> - <member name="tile_size" type="Vector2i" setter="set_tile_size" getter="get_tile_size" default="Vector2i( 16, 16 )"> - </member> - <member name="tile_skew" type="Vector2" setter="set_tile_skew" getter="get_tile_skew" default="Vector2( 0, 0 )"> + <member name="tile_size" type="Vector2i" setter="set_tile_size" getter="get_tile_size" default="Vector2i(16, 16)"> </member> <member name="uv_clipping" type="bool" setter="set_uv_clipping" getter="is_uv_clipping" default="false"> </member> @@ -324,37 +322,37 @@ </constant> <constant name="TILE_OFFSET_AXIS_VERTICAL" value="1" enum="TileOffsetAxis"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_RIGHT_SIDE" value="0" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_RIGHT_SIDE" value="0" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_RIGHT_CORNER" value="1" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_RIGHT_CORNER" value="1" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE" value="2" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE" value="2" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER" value="3" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER" value="3" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_SIDE" value="4" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_BOTTOM_SIDE" value="4" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_CORNER" value="5" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_BOTTOM_CORNER" value="5" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE" value="6" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_BOTTOM_LEFT_SIDE" value="6" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER" value="7" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_BOTTOM_LEFT_CORNER" value="7" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_LEFT_SIDE" value="8" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_LEFT_SIDE" value="8" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_LEFT_CORNER" value="9" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_LEFT_CORNER" value="9" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE" value="10" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_TOP_LEFT_SIDE" value="10" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER" value="11" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_TOP_LEFT_CORNER" value="11" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_TOP_SIDE" value="12" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_TOP_SIDE" value="12" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_TOP_CORNER" value="13" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_TOP_CORNER" value="13" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE" value="14" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_TOP_RIGHT_SIDE" value="14" enum="CellNeighbor"> </constant> - <constant name="TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER" value="15" enum="CellNeighbor"> + <constant name="CELL_NEIGHBOR_TOP_RIGHT_CORNER" value="15" enum="CellNeighbor"> </constant> <constant name="TERRAIN_MODE_MATCH_CORNERS_AND_SIDES" value="0" enum="TerrainMode"> </constant> diff --git a/doc/classes/TileSetAtlasSource.xml b/doc/classes/TileSetAtlasSource.xml index a7a304ca27..8482c356d7 100644 --- a/doc/classes/TileSetAtlasSource.xml +++ b/doc/classes/TileSetAtlasSource.xml @@ -12,9 +12,9 @@ </return> <argument index="0" name="atlas_coords" type="Vector2i"> </argument> - <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i( -1, -1 )"> + <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i(-1, -1)"> </argument> - <argument index="2" name="new_size" type="Vector2i" default="Vector2i( -1, -1 )"> + <argument index="2" name="new_size" type="Vector2i" default="Vector2i(-1, -1)"> </argument> <description> </description> @@ -40,7 +40,7 @@ </return> <argument index="0" name="atlas_coords" type="Vector2i"> </argument> - <argument index="1" name="size" type="Vector2i" default="Vector2i( 1, 1 )"> + <argument index="1" name="size" type="Vector2i" default="Vector2i(1, 1)"> </argument> <description> </description> @@ -154,9 +154,9 @@ </return> <argument index="0" name="atlas_coords" type="Vector2i"> </argument> - <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i( -1, -1 )"> + <argument index="1" name="new_atlas_coords" type="Vector2i" default="Vector2i(-1, -1)"> </argument> - <argument index="2" name="new_size" type="Vector2i" default="Vector2i( -1, -1 )"> + <argument index="2" name="new_size" type="Vector2i" default="Vector2i(-1, -1)"> </argument> <description> </description> @@ -193,13 +193,13 @@ </method> </methods> <members> - <member name="margins" type="Vector2i" setter="set_margins" getter="get_margins" default="Vector2i( 0, 0 )"> + <member name="margins" type="Vector2i" setter="set_margins" getter="get_margins" default="Vector2i(0, 0)"> </member> - <member name="separation" type="Vector2i" setter="set_separation" getter="get_separation" default="Vector2i( 0, 0 )"> + <member name="separation" type="Vector2i" setter="set_separation" getter="get_separation" default="Vector2i(0, 0)"> </member> <member name="texture" type="Texture2D" setter="set_texture" getter="get_texture"> </member> - <member name="tile_size" type="Vector2i" setter="set_texture_region_size" getter="get_texture_region_size" default="Vector2i( 16, 16 )"> + <member name="tile_size" type="Vector2i" setter="set_texture_region_size" getter="get_texture_region_size" default="Vector2i(16, 16)"> </member> </members> <constants> diff --git a/doc/classes/Time.xml b/doc/classes/Time.xml new file mode 100644 index 0000000000..0c7c090e97 --- /dev/null +++ b/doc/classes/Time.xml @@ -0,0 +1,270 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="Time" inherits="Object" version="4.0"> + <brief_description> + Time singleton for working with time. + </brief_description> + <description> + The Time singleton allows converting time between various formats and also getting time information from the system. + This class conforms with as many of the ISO 8601 standards as possible. All dates follow the Proleptic Gregorian calendar. As such, the day before [code]1582-10-15[/code] is [code]1582-10-14[/code], not [code]1582-10-04[/code]. The year before 1 AD (aka 1 BC) is number [code]0[/code], with the year before that (2 BC) being [code]-1[/code], etc. + Conversion methods assume "the same timezone", and do not handle timezone conversions or DST automatically. Leap seconds are also not handled, they must be done manually if desired. Suffixes such as "Z" are not handled, you need to strip them away manually. + [b]Important:[/b] The [code]_from_system[/code] methods use the system clock that the user can manually set. [b]Never use[/b] this method for precise time calculation since its results are subject to automatic adjustments by the user or the operating system. [b]Always use[/b] [method get_ticks_usec] or [method get_ticks_msec] for precise time calculation instead, since they are guaranteed to be monotonic (i.e. never decrease). + </description> + <tutorials> + </tutorials> + <methods> + <method name="get_date_dict_from_system" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <description> + Returns the current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], and [code]dst[/code] (Daylight Savings Time). + The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC. + </description> + </method> + <method name="get_date_dict_from_unix_time" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="unix_time_val" type="int"> + </argument> + <description> + Converts the given Unix timestamp to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], and [code]weekday[/code]. + </description> + </method> + <method name="get_date_string_from_system" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <description> + Returns the current date as an ISO 8601 date string (YYYY-MM-DD). + The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC. + </description> + </method> + <method name="get_date_string_from_unix_time" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="unix_time_val" type="int"> + </argument> + <description> + Converts the given Unix timestamp to an ISO 8601 date string (YYYY-MM-DD). + </description> + </method> + <method name="get_datetime_dict_from_string" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="datetime" type="String"> + </argument> + <argument index="1" name="weekday" type="bool"> + </argument> + <description> + Converts the given ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS) to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. + If [code]weekday[/code] is false, then the [code]weekday[/code] entry is excluded (the calculation is relatively expensive). + </description> + </method> + <method name="get_datetime_dict_from_system" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <description> + Returns the current date as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. + </description> + </method> + <method name="get_datetime_dict_from_unix_time" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="unix_time_val" type="int"> + </argument> + <description> + Converts the given Unix timestamp to a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], and [code]weekday[/code]. + The returned Dictionary's values will be the same as the [method get_datetime_dict_from_system] if the Unix timestamp is the current time, with the exception of Daylight Savings Time as it cannot be determined from the epoch. + </description> + </method> + <method name="get_datetime_string_from_dict" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="datetime" type="Dictionary"> + </argument> + <argument index="1" name="use_space" type="bool"> + </argument> + <description> + Converts the given dictionary of keys to an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS). + The given dictionary can be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. Any other entries (including [code]dst[/code]) are ignored. + If the dictionary is empty, [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the Unix epoch timestamp 0 (1970-01-01 at 00:00:00). + If [code]use_space[/code] is true, use a space instead of the letter T in the middle. + </description> + </method> + <method name="get_datetime_string_from_system" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <argument index="1" name="use_space" type="bool" default="false"> + </argument> + <description> + Returns the current date and time as a dictionary of keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]weekday[/code], [code]dst[/code] (Daylight Savings Time), [code]hour[/code], [code]minute[/code], and [code]second[/code]. + The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC. + If [code]use_space[/code] is true, use a space instead of the letter T in the middle. + </description> + </method> + <method name="get_datetime_string_from_unix_time" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="unix_time_val" type="int"> + </argument> + <argument index="1" name="use_space" type="bool" default="false"> + </argument> + <description> + Converts the given Unix timestamp to an ISO 8601 date and time string (YYYY-MM-DDTHH:MM:SS). + If [code]use_space[/code] is true, use a space instead of the letter T in the middle. + </description> + </method> + <method name="get_ticks_msec" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the amount of time passed in milliseconds since the engine started. + </description> + </method> + <method name="get_ticks_usec" qualifiers="const"> + <return type="int"> + </return> + <description> + Returns the amount of time passed in microseconds since the engine started. + </description> + </method> + <method name="get_time_dict_from_system" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <description> + Returns the current time as a dictionary of keys: [code]hour[/code], [code]minute[/code], and [code]second[/code]. + The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC. + </description> + </method> + <method name="get_time_dict_from_unix_time" qualifiers="const"> + <return type="Dictionary"> + </return> + <argument index="0" name="unix_time_val" type="int"> + </argument> + <description> + Converts the given time to a dictionary of keys: [code]hour[/code], [code]minute[/code], and [code]second[/code]. + </description> + </method> + <method name="get_time_string_from_system" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="utc" type="bool" default="false"> + </argument> + <description> + Returns the current time as an ISO 8601 time string (HH:MM:SS). + The returned values are in the system's local time when [code]utc[/code] is false, otherwise they are in UTC. + </description> + </method> + <method name="get_time_string_from_unix_time" qualifiers="const"> + <return type="String"> + </return> + <argument index="0" name="unix_time_val" type="int"> + </argument> + <description> + Converts the given Unix timestamp to an ISO 8601 time string (HH:MM:SS). + </description> + </method> + <method name="get_time_zone_from_system" qualifiers="const"> + <return type="Dictionary"> + </return> + <description> + Returns the current time zone as a dictionary of keys: [code]bias[/code] and [code]name[/code]. The [code]bias[/code] value is the offset from UTC in minutes, since not all time zones are multiples of an hour from UTC. + </description> + </method> + <method name="get_unix_time_from_datetime_dict" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="datetime" type="Dictionary"> + </argument> + <description> + Converts a dictionary of time values to a Unix timestamp. + The given dictionary can be populated with the following keys: [code]year[/code], [code]month[/code], [code]day[/code], [code]hour[/code], [code]minute[/code], and [code]second[/code]. Any other entries (including [code]dst[/code]) are ignored. + If the dictionary is empty, [code]0[/code] is returned. If some keys are omitted, they default to the equivalent values for the Unix epoch timestamp 0 (1970-01-01 at 00:00:00). + You can pass the output from [method get_datetime_dict_from_unix_time] directly into this function and get the same as what was put in. + </description> + </method> + <method name="get_unix_time_from_datetime_string" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="datetime" type="String"> + </argument> + <description> + Converts the given ISO 8601 date and/or time string to a Unix timestamp. The string can contain a date only, a time only, or both. + </description> + </method> + <method name="get_unix_time_from_system" qualifiers="const"> + <return type="float"> + </return> + <description> + Returns the current Unix timestamp in seconds based on the system time. + </description> + </method> + </methods> + <constants> + <constant name="MONTH_JANUARY" value="1" enum="Month"> + The month of January, represented numerically as [code]01[/code]. + </constant> + <constant name="MONTH_FEBRUARY" value="2" enum="Month"> + The month of February, represented numerically as [code]02[/code]. + </constant> + <constant name="MONTH_MARCH" value="3" enum="Month"> + The month of March, represented numerically as [code]03[/code]. + </constant> + <constant name="MONTH_APRIL" value="4" enum="Month"> + The month of April, represented numerically as [code]04[/code]. + </constant> + <constant name="MONTH_MAY" value="5" enum="Month"> + The month of May, represented numerically as [code]05[/code]. + </constant> + <constant name="MONTH_JUNE" value="6" enum="Month"> + The month of June, represented numerically as [code]06[/code]. + </constant> + <constant name="MONTH_JULY" value="7" enum="Month"> + The month of July, represented numerically as [code]07[/code]. + </constant> + <constant name="MONTH_AUGUST" value="8" enum="Month"> + The month of August, represented numerically as [code]08[/code]. + </constant> + <constant name="MONTH_SEPTEMBER" value="9" enum="Month"> + The month of September, represented numerically as [code]09[/code]. + </constant> + <constant name="MONTH_OCTOBER" value="10" enum="Month"> + The month of October, represented numerically as [code]10[/code]. + </constant> + <constant name="MONTH_NOVEMBER" value="11" enum="Month"> + The month of November, represented numerically as [code]11[/code]. + </constant> + <constant name="MONTH_DECEMBER" value="12" enum="Month"> + The month of December, represented numerically as [code]12[/code]. + </constant> + <constant name="WEEKDAY_SUNDAY" value="0" enum="Weekday"> + The day of the week Sunday, represented numerically as [code]0[/code]. + </constant> + <constant name="WEEKDAY_MONDAY" value="1" enum="Weekday"> + The day of the week Monday, represented numerically as [code]1[/code]. + </constant> + <constant name="WEEKDAY_TUESDAY" value="2" enum="Weekday"> + The day of the week Tuesday, represented numerically as [code]2[/code]. + </constant> + <constant name="WEEKDAY_WEDNESDAY" value="3" enum="Weekday"> + The day of the week Wednesday, represented numerically as [code]3[/code]. + </constant> + <constant name="WEEKDAY_THURSDAY" value="4" enum="Weekday"> + The day of the week Thursday, represented numerically as [code]4[/code]. + </constant> + <constant name="WEEKDAY_FRIDAY" value="5" enum="Weekday"> + The day of the week Friday, represented numerically as [code]5[/code]. + </constant> + <constant name="WEEKDAY_SATURDAY" value="6" enum="Weekday"> + The day of the week Saturday, represented numerically as [code]6[/code]. + </constant> + </constants> +</class> diff --git a/doc/classes/Transform2D.xml b/doc/classes/Transform2D.xml index 6ae7fbcf79..4f9b59c188 100644 --- a/doc/classes/Transform2D.xml +++ b/doc/classes/Transform2D.xml @@ -18,7 +18,7 @@ <return type="Transform2D"> </return> <description> - Constructs a default-initialized [Transform] set to [constant IDENTITY]. + Constructs a default-initialized [Transform2D] set to [constant IDENTITY]. </description> </method> <method name="Transform2D" qualifiers="constructor"> @@ -129,6 +129,16 @@ Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component. </description> </method> + <method name="looking_at" qualifiers="const"> + <return type="Transform2D"> + </return> + <argument index="0" name="target" type="Vector2" default="Transform2D(1, 0, 0, 1, 0, 0)"> + </argument> + <description> + Returns a copy of the transform rotated such that it's rotation on the X-axis points towards the [code]target[/code] position. + Operations take place in global space. + </description> + </method> <method name="operator !=" qualifiers="operator"> <return type="bool"> </return> @@ -169,6 +179,24 @@ <description> </description> </method> + <method name="operator *" qualifiers="operator"> + <return type="Transform2D"> + </return> + <argument index="0" name="right" type="float"> + </argument> + <description> + This operator multiplies all components of the [Transform2D], including the origin vector, which scales it uniformly. + </description> + </method> + <method name="operator *" qualifiers="operator"> + <return type="Transform2D"> + </return> + <argument index="0" name="right" type="int"> + </argument> + <description> + This operator multiplies all components of the [Transform2D], including the origin vector, which scales it uniformly. + </description> + </method> <method name="operator ==" qualifiers="operator"> <return type="bool"> </return> @@ -210,6 +238,15 @@ Scales the transform by the given scale factor, using matrix multiplication. </description> </method> + <method name="set_rotation"> + <return type="void"> + </return> + <argument index="0" name="rotation" type="float"> + </argument> + <description> + Sets the transform's rotation (in radians). + </description> + </method> <method name="translated" qualifiers="const"> <return type="Transform2D"> </return> @@ -222,24 +259,24 @@ </method> </methods> <members> - <member name="origin" type="Vector2" setter="" getter="" default="Vector2( 0, 0 )"> + <member name="origin" type="Vector2" setter="" getter="" default="Vector2(0, 0)"> The origin vector (column 2, the third column). Equivalent to array index [code]2[/code]. The origin vector represents translation. </member> - <member name="x" type="Vector2" setter="" getter="" default="Vector2( 1, 0 )"> + <member name="x" type="Vector2" setter="" getter="" default="Vector2(1, 0)"> The basis matrix's X vector (column 0). Equivalent to array index [code]0[/code]. </member> - <member name="y" type="Vector2" setter="" getter="" default="Vector2( 0, 1 )"> + <member name="y" type="Vector2" setter="" getter="" default="Vector2(0, 1)"> The basis matrix's Y vector (column 1). Equivalent to array index [code]1[/code]. </member> </members> <constants> - <constant name="IDENTITY" value="Transform2D( 1, 0, 0, 1, 0, 0 )"> + <constant name="IDENTITY" value="Transform2D(1, 0, 0, 1, 0, 0)"> The identity [Transform2D] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation. </constant> - <constant name="FLIP_X" value="Transform2D( -1, 0, 0, 1, 0, 0 )"> + <constant name="FLIP_X" value="Transform2D(-1, 0, 0, 1, 0, 0)"> The [Transform2D] that will flip something along the X axis. </constant> - <constant name="FLIP_Y" value="Transform2D( 1, 0, 0, -1, 0, 0 )"> + <constant name="FLIP_Y" value="Transform2D(1, 0, 0, -1, 0, 0)"> The [Transform2D] that will flip something along the Y axis. </constant> </constants> diff --git a/doc/classes/Transform.xml b/doc/classes/Transform3D.xml index 9d8721e2de..5410cbced7 100644 --- a/doc/classes/Transform.xml +++ b/doc/classes/Transform3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Transform" version="4.0"> +<class name="Transform3D" version="4.0"> <brief_description> 3D transformation (3×4 matrix). </brief_description> @@ -16,35 +16,35 @@ <link title="2.5D Demo">https://godotengine.org/asset-library/asset/583</link> </tutorials> <methods> - <method name="Transform" qualifiers="constructor"> - <return type="Transform"> + <method name="Transform3D" qualifiers="constructor"> + <return type="Transform3D"> </return> <description> - Constructs a default-initialized [Transform] set to [constant IDENTITY]. + Constructs a default-initialized [Transform3D] set to [constant IDENTITY]. </description> </method> - <method name="Transform" qualifiers="constructor"> - <return type="Transform"> + <method name="Transform3D" qualifiers="constructor"> + <return type="Transform3D"> </return> - <argument index="0" name="from" type="Transform"> + <argument index="0" name="from" type="Transform3D"> </argument> <description> - Constructs a [Transform] as a copy of the given [Transform]. + Constructs a [Transform3D] as a copy of the given [Transform3D]. </description> </method> - <method name="Transform" qualifiers="constructor"> - <return type="Transform"> + <method name="Transform3D" qualifiers="constructor"> + <return type="Transform3D"> </return> <argument index="0" name="basis" type="Basis"> </argument> <argument index="1" name="origin" type="Vector3"> </argument> <description> - Constructs a Transform from a [Basis] and [Vector3]. + Constructs a Transform3D from a [Basis] and [Vector3]. </description> </method> - <method name="Transform" qualifiers="constructor"> - <return type="Transform"> + <method name="Transform3D" qualifiers="constructor"> + <return type="Transform3D"> </return> <argument index="0" name="x_axis" type="Vector3"> </argument> @@ -55,29 +55,29 @@ <argument index="3" name="origin" type="Vector3"> </argument> <description> - Constructs a Transform from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled). + Constructs a Transform3D from four [Vector3] values (matrix columns). Each axis corresponds to local basis vectors (some of which may be scaled). </description> </method> <method name="affine_inverse" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation. </description> </method> <method name="interpolate_with" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> - <argument index="0" name="xform" type="Transform"> + <argument index="0" name="xform" type="Transform3D"> </argument> <argument index="1" name="weight" type="float"> </argument> <description> - Interpolates the transform to other Transform by weight amount (on the range of 0.0 to 1.0). + Interpolates the transform to other Transform3D by weight amount (on the range of 0.0 to 1.0). </description> </method> <method name="inverse" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> Returns the inverse of the transform, under the assumption that the transformation is composed of rotation and translation (no scaling, use affine_inverse for transforms with scaling). @@ -86,18 +86,18 @@ <method name="is_equal_approx" qualifiers="const"> <return type="bool"> </return> - <argument index="0" name="xform" type="Transform"> + <argument index="0" name="xform" type="Transform3D"> </argument> <description> Returns [code]true[/code] if this transform and [code]transform[/code] are approximately equal, by calling [code]is_equal_approx[/code] on each component. </description> </method> <method name="looking_at" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="target" type="Vector3"> </argument> - <argument index="1" name="up" type="Vector3" default="Vector3( 0, 1, 0 )"> + <argument index="1" name="up" type="Vector3" default="Vector3(0, 1, 0)"> </argument> <description> Returns a copy of the transform rotated such that its -Z axis points towards the [code]target[/code] position. @@ -108,7 +108,7 @@ <method name="operator !=" qualifiers="operator"> <return type="bool"> </return> - <argument index="0" name="right" type="Transform"> + <argument index="0" name="right" type="Transform3D"> </argument> <description> </description> @@ -122,9 +122,9 @@ </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Transform"> + <return type="Transform3D"> </return> - <argument index="0" name="right" type="Transform"> + <argument index="0" name="right" type="Transform3D"> </argument> <description> </description> @@ -145,23 +145,41 @@ <description> </description> </method> + <method name="operator *" qualifiers="operator"> + <return type="Transform3D"> + </return> + <argument index="0" name="right" type="float"> + </argument> + <description> + This operator multiplies all components of the [Transform3D], including the origin vector, which scales it uniformly. + </description> + </method> + <method name="operator *" qualifiers="operator"> + <return type="Transform3D"> + </return> + <argument index="0" name="right" type="int"> + </argument> + <description> + This operator multiplies all components of the [Transform3D], including the origin vector, which scales it uniformly. + </description> + </method> <method name="operator ==" qualifiers="operator"> <return type="bool"> </return> - <argument index="0" name="right" type="Transform"> + <argument index="0" name="right" type="Transform3D"> </argument> <description> </description> </method> <method name="orthonormalized" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> Returns the transform with the basis orthogonal (90 degrees), and normalized axis vectors. </description> </method> <method name="rotated" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="axis" type="Vector3"> </argument> @@ -172,7 +190,7 @@ </description> </method> <method name="scaled" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="scale" type="Vector3"> </argument> @@ -181,7 +199,7 @@ </description> </method> <method name="translated" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="offset" type="Vector3"> </argument> @@ -192,25 +210,25 @@ </method> </methods> <members> - <member name="basis" type="Basis" setter="" getter="" default="Basis( 1, 0, 0, 0, 1, 0, 0, 0, 1 )"> + <member name="basis" type="Basis" setter="" getter="" default="Basis(1, 0, 0, 0, 1, 0, 0, 0, 1)"> The basis is a matrix containing 3 [Vector3] as its columns: X axis, Y axis, and Z axis. These vectors can be interpreted as the basis vectors of local coordinate system traveling with the object. </member> - <member name="origin" type="Vector3" setter="" getter="" default="Vector3( 0, 0, 0 )"> + <member name="origin" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)"> The translation offset of the transform (column 3, the fourth column). Equivalent to array index [code]3[/code]. </member> </members> <constants> - <constant name="IDENTITY" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> - [Transform] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation. + <constant name="IDENTITY" value="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> + [Transform3D] with no translation, rotation or scaling applied. When applied to other data structures, [constant IDENTITY] performs no transformation. </constant> - <constant name="FLIP_X" value="Transform( -1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> - [Transform] with mirroring applied perpendicular to the YZ plane. + <constant name="FLIP_X" value="Transform3D(-1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> + [Transform3D] with mirroring applied perpendicular to the YZ plane. </constant> - <constant name="FLIP_Y" value="Transform( 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0 )"> - [Transform] with mirroring applied perpendicular to the XZ plane. + <constant name="FLIP_Y" value="Transform3D(1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0)"> + [Transform3D] with mirroring applied perpendicular to the XZ plane. </constant> - <constant name="FLIP_Z" value="Transform( 1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0 )"> - [Transform] with mirroring applied perpendicular to the XY plane. + <constant name="FLIP_Z" value="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0)"> + [Transform3D] with mirroring applied perpendicular to the XY plane. </constant> </constants> </class> diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml index c31467c67e..b498b9bb90 100644 --- a/doc/classes/Tree.xml +++ b/doc/classes/Tree.xml @@ -96,6 +96,14 @@ Returns the column index at [code]position[/code], or -1 if no item is there. </description> </method> + <method name="get_column_expand_ratio" qualifiers="const"> + <return type="int"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <description> + </description> + </method> <method name="get_column_title" qualifiers="const"> <return type="String"> </return> @@ -232,7 +240,7 @@ Returns the last pressed button's index. </description> </method> - <method name="get_root"> + <method name="get_root" qualifiers="const"> <return type="TreeItem"> </return> <description> @@ -264,12 +272,50 @@ To tell whether a column of an item is selected, use [method TreeItem.is_selected]. </description> </method> + <method name="is_column_clipping_content" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <description> + </description> + </method> + <method name="is_column_expanding" qualifiers="const"> + <return type="bool"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <description> + </description> + </method> <method name="scroll_to_item"> <return type="void"> </return> <argument index="0" name="item" type="Object"> </argument> <description> + Causes the [Tree] to jump to the specified item. + </description> + </method> + <method name="set_column_clip_content"> + <return type="void"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <argument index="1" name="enable" type="bool"> + </argument> + <description> + </description> + </method> + <method name="set_column_custom_minimum_width"> + <return type="void"> + </return> + <argument index="0" name="column" type="int"> + </argument> + <argument index="1" name="min_width" type="int"> + </argument> + <description> + Overrides the calculated minimum width of a column. It can be set to `0` to restore the default behavior. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio]. </description> </method> <method name="set_column_expand"> @@ -283,15 +329,14 @@ If [code]true[/code], the column will have the "Expand" flag of [Control]. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio]. </description> </method> - <method name="set_column_min_width"> + <method name="set_column_expand_ratio"> <return type="void"> </return> <argument index="0" name="column" type="int"> </argument> - <argument index="1" name="min_width" type="int"> + <argument index="1" name="ratio" type="int"> </argument> <description> - Sets the minimum width of a column. Columns that have the "Expand" flag will use their "min_width" in a similar fashion to [member Control.size_flags_stretch_ratio]. </description> </method> <method name="set_column_title"> @@ -361,7 +406,7 @@ The number of columns. </member> <member name="drop_mode_flags" type="int" setter="set_drop_mode_flags" getter="get_drop_mode_flags" default="0"> - The drop mode as an OR combination of flags. See [enum DropModeFlags] constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. Setting this during [method Control.can_drop_data] is recommended. + The drop mode as an OR combination of flags. See [enum DropModeFlags] constants. Once dropping is done, reverts to [constant DROP_MODE_DISABLED]. Setting this during [method Control._can_drop_data] is recommended. This controls the drop sections, i.e. the decision and drawing of possible drop locations based on the mouse position. </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" override="true" enum="Control.FocusMode" default="2" /> @@ -372,6 +417,12 @@ If [code]true[/code], the tree's root is hidden. </member> <member name="rect_clip_content" type="bool" setter="set_clip_contents" getter="is_clipping_contents" override="true" default="true" /> + <member name="scroll_horizontal_enabled" type="bool" setter="set_h_scroll_enabled" getter="is_h_scroll_enabled" default="true"> + If [code]true[/code], enables horizontal scrolling. + </member> + <member name="scroll_vertical_enabled" type="bool" setter="set_v_scroll_enabled" getter="is_v_scroll_enabled" default="true"> + If [code]true[/code], enables vertical scrolling. + </member> <member name="select_mode" type="int" setter="set_select_mode" getter="get_select_mode" enum="Tree.SelectMode" default="0"> Allows single or multiple selection. See the [enum SelectMode] constants. </member> @@ -533,7 +584,7 @@ <theme_item name="checked" type="Texture2D"> The check icon to display when the [constant TreeItem.CELL_MODE_CHECK] mode cell is checked. </theme_item> - <theme_item name="children_hl_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )"> + <theme_item name="children_hl_line_color" type="Color" default="Color(0.27, 0.27, 0.27, 1)"> The [Color] of the relationship lines between the selected [TreeItem] and its children. </theme_item> <theme_item name="children_hl_line_width" type="int" default="1"> @@ -548,7 +599,7 @@ <theme_item name="custom_button" type="StyleBox"> Default [StyleBox] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell. </theme_item> - <theme_item name="custom_button_font_highlight" type="Color" default="Color( 0.94, 0.94, 0.94, 1 )"> + <theme_item name="custom_button_font_highlight" type="Color" default="Color(0.94, 0.94, 0.94, 1)"> Text [Color] for a [constant TreeItem.CELL_MODE_CUSTOM] mode cell when it's hovered. </theme_item> <theme_item name="custom_button_hover" type="StyleBox"> @@ -563,25 +614,25 @@ <theme_item name="draw_relationship_lines" type="int" default="0"> Draws the relationship lines if not zero, this acts as a boolean. Relationship lines are drawn at the start of child items to show hierarchy. </theme_item> - <theme_item name="drop_position_color" type="Color" default="Color( 1, 0.3, 0.2, 1 )"> + <theme_item name="drop_position_color" type="Color" default="Color(1, 0.3, 0.2, 1)"> [Color] used to draw possible drop locations. See [enum DropModeFlags] constants for further description of drop locations. </theme_item> <theme_item name="font" type="Font"> [Font] of the item's text. </theme_item> - <theme_item name="font_color" type="Color" default="Color( 0.69, 0.69, 0.69, 1 )"> + <theme_item name="font_color" type="Color" default="Color(0.69, 0.69, 0.69, 1)"> Default text [Color] of the item. </theme_item> - <theme_item name="font_outline_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_outline_color" type="Color" default="Color(1, 1, 1, 1)"> The tint of text outline of the item. </theme_item> - <theme_item name="font_selected_color" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="font_selected_color" type="Color" default="Color(1, 1, 1, 1)"> Text [Color] used when the item is selected. </theme_item> <theme_item name="font_size" type="int"> Font size of the item's text. </theme_item> - <theme_item name="guide_color" type="Color" default="Color( 0, 0, 0, 0.1 )"> + <theme_item name="guide_color" type="Color" default="Color(0, 0, 0, 0.1)"> [Color] of the guideline. </theme_item> <theme_item name="hseparation" type="int" default="4"> @@ -593,7 +644,7 @@ <theme_item name="outline_size" type="int" default="0"> The size of the text outline. </theme_item> - <theme_item name="parent_hl_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )"> + <theme_item name="parent_hl_line_color" type="Color" default="Color(0.27, 0.27, 0.27, 1)"> The [Color] of the relationship lines between the selected [TreeItem] and its parents. </theme_item> <theme_item name="parent_hl_line_margin" type="int" default="0"> @@ -602,7 +653,7 @@ <theme_item name="parent_hl_line_width" type="int" default="1"> The width of the relationship lines between the selected [TreeItem] and its parents. </theme_item> - <theme_item name="relationship_line_color" type="Color" default="Color( 0.27, 0.27, 0.27, 1 )"> + <theme_item name="relationship_line_color" type="Color" default="Color(0.27, 0.27, 0.27, 1)"> The default [Color] of the relationship lines. </theme_item> <theme_item name="relationship_line_width" type="int" default="1"> @@ -623,7 +674,7 @@ <theme_item name="selected_focus" type="StyleBox"> [StyleBox] for the selected items, used when the [Tree] is being focused. </theme_item> - <theme_item name="title_button_color" type="Color" default="Color( 0.88, 0.88, 0.88, 1 )"> + <theme_item name="title_button_color" type="Color" default="Color(0.88, 0.88, 0.88, 1)"> Default text [Color] of the title button. </theme_item> <theme_item name="title_button_font" type="Font"> diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml index 0256d83fea..85c9caa101 100644 --- a/doc/classes/TreeItem.xml +++ b/doc/classes/TreeItem.xml @@ -192,7 +192,7 @@ Returns [code]true[/code] if [code]expand_right[/code] is set. </description> </method> - <method name="get_first_child"> + <method name="get_first_child" qualifiers="const"> <return type="TreeItem"> </return> <description> @@ -260,7 +260,7 @@ Returns the metadata value that was set for the given column using [method set_metadata]. </description> </method> - <method name="get_next"> + <method name="get_next" qualifiers="const"> <return type="TreeItem"> </return> <description> @@ -288,7 +288,7 @@ Returns OpenType feature [code]tag[/code] of the item's text. </description> </method> - <method name="get_parent"> + <method name="get_parent" qualifiers="const"> <return type="TreeItem"> </return> <description> @@ -391,7 +391,7 @@ Returns the given column's tooltip. </description> </method> - <method name="get_tree"> + <method name="get_tree" qualifiers="const"> <return type="Tree"> </return> <description> diff --git a/doc/classes/TriangleMesh.xml b/doc/classes/TriangleMesh.xml index 39bee0c2b3..cfdb6fe33e 100644 --- a/doc/classes/TriangleMesh.xml +++ b/doc/classes/TriangleMesh.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TriangleMesh" inherits="Reference" version="4.0"> +<class name="TriangleMesh" inherits="RefCounted" version="4.0"> <brief_description> Internal mesh type. </brief_description> diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml index 00cca40093..253822cf32 100644 --- a/doc/classes/Tween.xml +++ b/doc/classes/Tween.xml @@ -1,453 +1,397 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="Tween" inherits="Node" version="4.0"> +<class name="Tween" inherits="RefCounted" version="4.0"> <brief_description> - Smoothly animates a node's properties over time. + Lightweight object used for general-purpose animation via script, using [Tweener]s. </brief_description> <description> - Tweens are useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them. - [Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween] node; it would be difficult to do the same thing with an [AnimationPlayer] node. - Here is a brief usage example that makes a 2D node move smoothly between two positions: - [codeblocks] - [gdscript] - var tween = get_node("Tween") - tween.interpolate_property($Node2D, "position", - Vector2(0, 0), Vector2(100, 100), 1, - Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) - tween.start() - [/gdscript] - [csharp] - var tween = GetNode<Tween>("Tween"); - tween.InterpolateProperty(GetNode<Node2D>("Node2D"), "position", - new Vector2(0, 0), new Vector2(100, 100), 1, - Tween.TransitionType.Linear, Tween.EaseType.InOut); - tween.Start(); - [/csharp] - [/codeblocks] - Many methods require a property name, such as [code]"position"[/code] above. You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (e.g. [code]position:x[/code]), where it would only apply to that particular component. - Many of the methods accept [code]trans_type[/code] and [code]ease_type[/code]. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best. + Tweens are mostly useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them. + [Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween]; it would be difficult to do the same thing with an [AnimationPlayer] node. Tweens are also more light-weight than [AnimationPlayer], so they are very much suited for simple animations or general tasks that don't require visual tweaking provided by the editor. They can be used in a fire-and-forget manner for some logic that normally would be done by code. You can e.g. make something shoot periodically by using a looped [CallbackTweener] with a delay. + A [Tween] can be created by using either [method SceneTree.create_tween] or [method Node.create_tween]. [Tween]s created manually (i.e. by using [code]Tween.new()[/code]) are invalid. They can't be used for tweening values, but you can do manual interpolation with [method interpolate_value]. + A [Tween] animation is composed of a sequence of [Tweener]s, which by default are executed one after another. You can create a sequence by appending [Tweener]s to the [Tween]. Animating something with a [Tweener] is called tweening. Example tweening sequence looks like this: + [codeblock] + var tween = get_tree().create_tween() + tween.tween_property($Sprite, "modulate", Color.red, 1) + tween.tween_property($Sprite, "scale", Vector2(), 1) + tween.tween_callback($Sprite.queue_free) + [/codeblock] + This sequence will make the [code]$Sprite[/code] node turn red, then shrink and finally the [method Node.queue_free] is called to remove the sprite. See methods [method tween_property], [method tween_interval], [method tween_callback] and [method tween_method] for more usage information. + When a [Tweener] is created with one of the [code]tween_*[/code] methods, a chained method call can be used to tweak the properties of this [Tweener]. For example, if you want to set different transition type in the above example, you can do: + [codeblock] + var tween = get_tree().create_tween() + tween.tween_property($Sprite, "modulate", Color.red, 1).set_trans(Tween.TRANS_SINE) + tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE) + tween.tween_callback($Sprite.queue_free) + [/codeblock] + Most of the [Tween] methods can be chained this way too. In this example the [Tween] is bound and have set a default transition: + [codeblock] + var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC) + tween.tween_property($Sprite, "modulate", Color.red, 1) + tween.tween_property($Sprite, "scale", Vector2(), 1) + tween.tween_callback($Sprite.queue_free) + [/codeblock] + Another interesting use for [Tween]s is animating arbitrary set of objects: + [codeblock] + var tween = create_tween() + for sprite in get_children(): + tween.tween_property(sprite, "position", Vector2(), 1) + [/codeblock] + In the example above, all children of a node are moved one after another to position (0, 0). + Some [Tweener]s use transitions and eases. The first accepts an [enum TransitionType] constant, and refers to the way the timing of the animation is handled (see [url=https://easings.net/]easings.net[/url] for some examples). The second accepts an [enum EaseType] constant, and controls where the [code]trans_type[/code] is applied to the interpolation (in the beginning, the end, or both). If you don't know which transition and easing to pick, you can try different [enum TransitionType] constants with [constant EASE_IN_OUT], and use the one that looks best. [url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/tween_cheatsheet.png]Tween easing and transition types cheatsheet[/url] + [b]Note:[/b] All [Tween]s will automatically start by default. To prevent a [Tween] from autostarting, you can call [method stop] immediately after it was created. </description> <tutorials> </tutorials> <methods> - <method name="follow_method"> - <return type="void"> + <method name="bind_node"> + <return type="Tween"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="method" type="StringName"> - </argument> - <argument index="2" name="initial_val" type="Variant"> - </argument> - <argument index="3" name="target" type="Object"> - </argument> - <argument index="4" name="target_method" type="StringName"> - </argument> - <argument index="5" name="duration" type="float"> - </argument> - <argument index="6" name="trans_type" type="int" enum="Tween.TransitionType" default="0"> - </argument> - <argument index="7" name="ease_type" type="int" enum="Tween.EaseType" default="2"> - </argument> - <argument index="8" name="delay" type="float" default="0"> + <argument index="0" name="node" type="Node"> </argument> <description> - Follows [code]method[/code] of [code]object[/code] and applies the returned value on [code]target_method[/code] of [code]target[/code], beginning from [code]initial_val[/code] for [code]duration[/code] seconds, [code]delay[/code] later. Methods are called with consecutive values. - Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information. + Binds this [Tween] with the given [code]node[/code]. [Tween]s are processed directly by the [SceneTree], so they run independently of the animated nodes. When you bind a [Node] with the [Tween], the [Tween] will halt the animation when the object is not inside tree and the [Tween] will be automatically killed when the bound object is freed. Also [constant TWEEN_PAUSE_BOUND] will make the pausing behavior dependent on the bound node. + For a shorter way to create and bind a [Tween], you can use [method Node.create_tween]. </description> </method> - <method name="follow_property"> - <return type="void"> + <method name="chain"> + <return type="Tween"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="property" type="NodePath"> - </argument> - <argument index="2" name="initial_val" type="Variant"> - </argument> - <argument index="3" name="target" type="Object"> - </argument> - <argument index="4" name="target_property" type="NodePath"> - </argument> - <argument index="5" name="duration" type="float"> - </argument> - <argument index="6" name="trans_type" type="int" enum="Tween.TransitionType" default="0"> - </argument> - <argument index="7" name="ease_type" type="int" enum="Tween.EaseType" default="2"> - </argument> - <argument index="8" name="delay" type="float" default="0"> - </argument> <description> - Follows [code]property[/code] of [code]object[/code] and applies it on [code]target_property[/code] of [code]target[/code], beginning from [code]initial_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. - Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information. + Used to chain two [Tweener]s after [method set_parallel] is called with [code]true[/code]. + [codeblock] + var tween = create_tween().set_parallel(true) + tween.tween_property(...) + tween.tween_property(...) #will run parallelly with above + tween.chain().tween_property(...) #will run after two above are finished + [/codeblock] </description> </method> - <method name="get_runtime" qualifiers="const"> - <return type="float"> + <method name="custom_step"> + <return type="bool"> </return> + <argument index="0" name="delta" type="float"> + </argument> <description> - Returns the total time needed for all tweens to end. If you have two tweens, one lasting 10 seconds and the other 20 seconds, it would return 20 seconds, as by that time all tweens would have finished. + Processes the [Tween] by given [code]delta[/code] value, in seconds. Mostly useful when the [Tween] is paused, for controlling it manually. Can also be used to end the [Tween] animation immediately, by using [code]delta[/code] longer than the whole duration. + Returns [code]true[/code] if the [Tween] still has [Tweener]s that haven't finished. + [b]Note:[/b] The [Tween] will become invalid after finished, but you can call [method stop] after the step, to keep it and reset. </description> </method> - <method name="interpolate_callback"> - <return type="void"> + <method name="interpolate_value"> + <return type="Variant"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="duration" type="float"> + <argument index="0" name="trans_type" type="Variant"> </argument> - <argument index="2" name="callback" type="String"> + <argument index="1" name="ease_type" type="Variant"> </argument> - <argument index="3" name="arg1" type="Variant" default="null"> + <argument index="2" name="elapsed_time" type="float"> </argument> - <argument index="4" name="arg2" type="Variant" default="null"> + <argument index="3" name="initial_value" type="float"> </argument> - <argument index="5" name="arg3" type="Variant" default="null"> + <argument index="4" name="delta_value" type="int" enum="Tween.TransitionType"> </argument> - <argument index="6" name="arg4" type="Variant" default="null"> - </argument> - <argument index="7" name="arg5" type="Variant" default="null"> + <argument index="5" name="duration" type="int" enum="Tween.EaseType"> </argument> <description> - Calls [code]callback[/code] of [code]object[/code] after [code]duration[/code]. [code]arg1[/code]-[code]arg5[/code] are arguments to be passed to the callback. + This method can be used for manual interpolation of a value, when you don't want [Tween] to do animating for you. It's similar to [method @GlobalScope.lerp], but with support for custom transition and easing. + [code]elapsed_time[/code] is the time in seconds that passed after the interping started and it's used to control the position of the interpolation. E.g. when it's equal to half of the [code]duration[/code], the interpolated value will be halfway between initial and final values. This value can also be greater than [code]duration[/code] or lower than 0, which will extrapolate the value. + [code]initial_value[/code] is the starting value of the interpolation. + [code]delta_value[/code] is the change of the value in the interpolation, i.e. it's equal to [code]final_value - initial_value[/code]. + [code]duration[/code] is the total time of the interpolation. </description> </method> - <method name="interpolate_deferred_callback"> - <return type="void"> + <method name="is_running"> + <return type="bool"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="duration" type="float"> - </argument> - <argument index="2" name="callback" type="String"> - </argument> - <argument index="3" name="arg1" type="Variant" default="null"> - </argument> - <argument index="4" name="arg2" type="Variant" default="null"> - </argument> - <argument index="5" name="arg3" type="Variant" default="null"> - </argument> - <argument index="6" name="arg4" type="Variant" default="null"> - </argument> - <argument index="7" name="arg5" type="Variant" default="null"> - </argument> <description> - Calls [code]callback[/code] of [code]object[/code] after [code]duration[/code] on the main thread (similar to [method Object.call_deferred]). [code]arg1[/code]-[code]arg5[/code] are arguments to be passed to the callback. + Returns whether the [Tween] is currently running, i.e. it wasn't paused and it's not finished. </description> </method> - <method name="interpolate_method"> - <return type="void"> + <method name="is_valid"> + <return type="bool"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="method" type="StringName"> - </argument> - <argument index="2" name="initial_val" type="Variant"> - </argument> - <argument index="3" name="final_val" type="Variant"> - </argument> - <argument index="4" name="duration" type="float"> - </argument> - <argument index="5" name="trans_type" type="int" enum="Tween.TransitionType" default="0"> - </argument> - <argument index="6" name="ease_type" type="int" enum="Tween.EaseType" default="2"> - </argument> - <argument index="7" name="delay" type="float" default="0"> - </argument> <description> - Animates [code]method[/code] of [code]object[/code] from [code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. Methods are called with consecutive values. - Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information. + Returns whether the [Tween] is valid. A valid [Tween] is a [Tween] contained by the scene tree (i.e. the array from [method SceneTree.get_processed_tweens] will contain this [Tween]). [Tween] might become invalid when it has finished tweening or was killed, also when created with [code]Tween.new()[/code]. Invalid [Tween] can't have [Tweener]s appended, because it can't animate them. You can however still use [method interpolate_value]. </description> </method> - <method name="interpolate_property"> + <method name="kill"> <return type="void"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="property" type="NodePath"> - </argument> - <argument index="2" name="initial_val" type="Variant"> - </argument> - <argument index="3" name="final_val" type="Variant"> - </argument> - <argument index="4" name="duration" type="float"> - </argument> - <argument index="5" name="trans_type" type="int" enum="Tween.TransitionType" default="0"> - </argument> - <argument index="6" name="ease_type" type="int" enum="Tween.EaseType" default="2"> - </argument> - <argument index="7" name="delay" type="float" default="0"> - </argument> <description> - Animates [code]property[/code] of [code]object[/code] from [code]initial_val[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. Setting the initial value to [code]null[/code] uses the current value of the property. - Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information. + Aborts all tweening operations and invalidates the [Tween]. </description> </method> - <method name="is_active" qualifiers="const"> - <return type="bool"> + <method name="parallel"> + <return type="Tween"> </return> <description> - Returns [code]true[/code] if any tweens are currently running. - [b]Note:[/b] This method doesn't consider tweens that have ended. + Makes the next [Tweener] run parallely to the previous one. Example: + [codeblock] + var tween = create_tween() + tween.tween_property(...) + tween.parallel().tween_property(...) + tween.parallel().tween_property(...) + [/codeblock] + All [Tweener]s in the example will run at the same time. + You can make the [Tween] parallel by default by using [method set_parallel]. </description> </method> - <method name="remove"> + <method name="pause"> <return type="void"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="StringName" default=""""> - </argument> <description> - Stops animation and removes a tween, given its object and property/method pair. By default, all tweens are removed, unless [code]key[/code] is specified. + Pauses the tweening. The animation can be resumed by using [method play]. </description> </method> - <method name="remove_all"> + <method name="play"> <return type="void"> </return> <description> - Stops animation and removes all tweens. + Resumes a paused or stopped [Tween]. </description> </method> - <method name="reset"> - <return type="void"> + <method name="set_ease"> + <return type="Tween"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="StringName" default=""""> + <argument index="0" name="ease" type="int" enum="Tween.EaseType"> </argument> <description> - Resets a tween to its initial value (the one given, not the one before the tween), given its object and property/method pair. By default, all tweens are removed, unless [code]key[/code] is specified. + Sets the default ease type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween]. </description> </method> - <method name="reset_all"> - <return type="void"> + <method name="set_loops"> + <return type="Tween"> </return> + <argument index="0" name="loops" type="int" default="0"> + </argument> <description> - Resets all tweens to their initial values (the ones given, not those before the tween). + Sets the number of times the tweening sequence will be repeated, i.e. [code]set_loops(2)[/code] will run the animation twice. + Calling this method without arguments will make the [Tween] run infinitely, until it is either killed by [method kill] or by freeing bound node, or all the animated objects have been freed (which makes further animation impossible). </description> </method> - <method name="resume"> - <return type="void"> + <method name="set_parallel"> + <return type="Tween"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="StringName" default=""""> + <argument index="0" name="parallel" type="bool" default="true"> </argument> <description> - Continues animating a stopped tween, given its object and property/method pair. By default, all tweens are resumed, unless [code]key[/code] is specified. + If [code]parallel[/code] is [code]true[/code], the [Tweener]s appended after this method will by default run simultanously, as opposed to sequentially. </description> </method> - <method name="resume_all"> - <return type="void"> + <method name="set_pause_mode"> + <return type="Tween"> </return> + <argument index="0" name="mode" type="int" enum="Tween.TweenPauseMode"> + </argument> <description> - Continues animating all stopped tweens. + Determines the behavior of the [Tween] when the [SceneTree] is paused. Check [enum TweenPauseMode] for options. + Default value is [constant TWEEN_PAUSE_BOUND]. </description> </method> - <method name="seek"> - <return type="void"> + <method name="set_process_mode"> + <return type="Tween"> </return> - <argument index="0" name="time" type="float"> + <argument index="0" name="mode" type="int" enum="Tween.TweenProcessMode"> </argument> <description> - Sets the interpolation to the given [code]time[/code] in seconds. + Determines whether the [Tween] should run during idle frame (see [method Node._process]) or physics frame (see [method Node._physics_process]. + Default value is [constant TWEEN_PROCESS_IDLE]. </description> </method> - <method name="set_active"> - <return type="void"> + <method name="set_speed_scale"> + <return type="Tween"> </return> - <argument index="0" name="active" type="bool"> + <argument index="0" name="speed" type="float"> </argument> <description> - Activates/deactivates the tween. See also [method stop_all] and [method resume_all]. + Scales the speed of tweening. This affects all [Tweener]s and their delays. </description> </method> - <method name="start"> - <return type="void"> + <method name="set_trans"> + <return type="Tween"> </return> + <argument index="0" name="trans" type="int" enum="Tween.TransitionType"> + </argument> <description> - Starts the tween. You can define animations both before and after this. + Sets the default transition type for [PropertyTweener]s and [MethodTweener]s animated by this [Tween]. </description> </method> <method name="stop"> <return type="void"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="StringName" default=""""> - </argument> <description> - Stops a tween, given its object and property/method pair. By default, all tweens are stopped, unless [code]key[/code] is specified. + Stops the tweening and resets the [Tween] to its initial state. This will not remove any appended [Tweener]s. </description> </method> - <method name="stop_all"> - <return type="void"> + <method name="tween_callback"> + <return type="CallbackTweener"> </return> + <argument index="0" name="callback" type="Callable"> + </argument> <description> - Stops animating all tweens. + Creates and appends a [CallbackTweener]. This method can be used to call an arbitrary method in any object. Use [method Callable.bind] to bind additional arguments for the call. + Example: object that keeps shooting every 1 second. + [codeblock] + var tween = get_tree().create_tween().set_loops() + tween.tween_callback(shoot).set_delay(1) + [/codeblock] + Example: turning a sprite red and then blue, with 2 second delay. + [codeblock] + var tween = get_tree().create_tween() + tween.tween_callback($Sprite.set_modulate.bind(Color.red)).set_delay(2) + tween.tween_callback($Sprite.set_modulate.bind(Color.blue)).set_delay(2) + [/codeblock] </description> </method> - <method name="targeting_method"> - <return type="void"> + <method name="tween_interval"> + <return type="IntervalTweener"> </return> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="method" type="StringName"> - </argument> - <argument index="2" name="initial" type="Object"> - </argument> - <argument index="3" name="initial_method" type="StringName"> - </argument> - <argument index="4" name="final_val" type="Variant"> + <argument index="0" name="time" type="float"> </argument> - <argument index="5" name="duration" type="float"> + <description> + Creates and appends an [IntervalTweener]. This method can be used to create delays in the tween animation, as an alternative for using the delay in other [Tweener]s or when there's no animation (in which case the [Tween] acts as a timer). [code]time[/code] is the length of the interval, in seconds. + Example: creating an interval in code execution. + [codeblock] + #... some code + var tween = create_tween() + tween.tween_interval(2) + await tween.finished + #... more code + [/codeblock] + Example: creating an object that moves back and forth and jumps every few seconds. + [codeblock] + var tween = create_tween().set_loops() + tween.tween_property("position:x", 200, 1).as_relative() + tween.tween_callback(jump) + tween.tween_interval(2) + tween.tween_property("position:x", -200, 1).as_relative() + tween.tween_callback(jump) + tween.tween_interval(2) + [/codeblock] + </description> + </method> + <method name="tween_method"> + <return type="MethodTweener"> + </return> + <argument index="0" name="method" type="Callable"> </argument> - <argument index="6" name="trans_type" type="int" enum="Tween.TransitionType" default="0"> + <argument index="1" name="from" type="float"> </argument> - <argument index="7" name="ease_type" type="int" enum="Tween.EaseType" default="2"> + <argument index="2" name="to" type="float"> </argument> - <argument index="8" name="delay" type="float" default="0"> + <argument index="3" name="duration" type="float"> </argument> <description> - Animates [code]method[/code] of [code]object[/code] from the value returned by [code]initial_method[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. Methods are animated by calling them with consecutive values. - Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information. + Creates and appends a [MethodTweener]. This method is similar to a combination of [method tween_callback] and [method tween_property]. It calls a method over time with a tweened value provided as an argument. The value is tweened between [code]from[/code] and [code]to[/code] over the time specified by [code]duration[/code], in seconds. Use [method Callable.bind] to bind additional arguments for the call. You can use [method MethodTweener.set_ease] and [method MethodTweener.set_trans] to tweak the easing and transition of the value or [method MethodTweener.set_delay] to delay the tweening. + Example: making a 3D object look from one point to another point. + [codeblock] + var tween = create_tween() + tween.tween_method(look_at.bind(Vector3.UP), Vector3(-1, 0, -1), Vector3(1, 0, -1), 1) #the look_at() method takes up vector as second argument + [/codeblock] + Example: setting a text of a [Label], using an intermediate method and after a delay. + [codeblock] + func _ready(): + var tween = create_tween() + tween.tween_method(set_label_text, 0, 10, 1).set_delay(1) + + func set_label_text(value: int): + $Label.text = "Counting " + str(value) + [/codeblock] </description> </method> - <method name="targeting_property"> - <return type="void"> + <method name="tween_property"> + <return type="PropertyTweener"> </return> <argument index="0" name="object" type="Object"> </argument> <argument index="1" name="property" type="NodePath"> </argument> - <argument index="2" name="initial" type="Object"> - </argument> - <argument index="3" name="initial_val" type="NodePath"> - </argument> - <argument index="4" name="final_val" type="Variant"> + <argument index="2" name="final_val" type="Variant"> </argument> - <argument index="5" name="duration" type="float"> + <argument index="3" name="duration" type="float"> </argument> - <argument index="6" name="trans_type" type="int" enum="Tween.TransitionType" default="0"> - </argument> - <argument index="7" name="ease_type" type="int" enum="Tween.EaseType" default="2"> - </argument> - <argument index="8" name="delay" type="float" default="0"> - </argument> - <description> - Animates [code]property[/code] of [code]object[/code] from the current value of the [code]initial_val[/code] property of [code]initial[/code] to [code]final_val[/code] for [code]duration[/code] seconds, [code]delay[/code] seconds later. - Use [enum TransitionType] for [code]trans_type[/code] and [enum EaseType] for [code]ease_type[/code] parameters. These values control the timing and direction of the interpolation. See the class description for more information. - </description> - </method> - <method name="tell" qualifiers="const"> - <return type="float"> - </return> <description> - Returns the current time of the tween. + Creates and appends a [PropertyTweener]. This method tweens a [code]property[/code] of an [code]object[/code] between an initial value and [code]final_val[/code] in a span of time equal to [code]duration[/code], in seconds. The initial value by default is a value at the time the tweening of the [PropertyTweener] start. For example: + [codeblock] + var tween = create_tween() + tween.tween_property($Sprite, "position", Vector2(100, 200) + tween.tween_property($Sprite, "position", Vector2(200, 300) + [/codeblock] + will move the sprite to position (100, 200) and then to (200, 300). If you use [method PropertyTweener.from] or [method PropertyTweener.from_current], the starting position will be overwritten by the given value instead. See other methods in [PropertyTweener] to see how the tweening can be tweaked further. + [b]Note:[/b] You can find the correct property name by hovering over the property in the Inspector. You can also provide the components of a property directly by using [code]"property:component"[/code] (eg. [code]position:x[/code]), where it would only apply to that particular component. + Example: moving object twice from the same position, with different transition types. + [codeblock] + var tween = create_tween() + tween.tween_property($Sprite, "position", Vector2.RIGHT * 300).as_relative().set_trans(Tween.TRANS_SINE) + tween.tween_property($Sprite, "position", Vector2.RIGHT * 300).as_relative().from_current().set_trans(Tween.TRANS_EXPO) + [/codeblock] </description> </method> </methods> - <members> - <member name="playback_process_mode" type="int" setter="set_tween_process_mode" getter="get_tween_process_mode" enum="Tween.TweenProcessMode" default="1"> - The tween's animation process thread. See [enum TweenProcessMode]. - </member> - <member name="playback_speed" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0"> - The tween's speed multiplier. For example, set it to [code]1.0[/code] for normal speed, [code]2.0[/code] for two times normal speed, or [code]0.5[/code] for half of the normal speed. A value of [code]0[/code] pauses the animation, but see also [method set_active] or [method stop_all] for this. - </member> - <member name="repeat" type="bool" setter="set_repeat" getter="is_repeat" default="false"> - If [code]true[/code], the tween loops. - </member> - </members> <signals> - <signal name="tween_all_completed"> + <signal name="finished"> <description> - Emitted when all processes in a tween end. + Emitted when the [Tween] has finished all tweening. Never emitted when the [Tween] is set to infinite looping (see [method set_loops]). + [b]Note:[/b] The [Tween] is removed (invalidated) after this signal is emitted, but it doesn't happen immediately, but on the next processing frame. Calling [method stop] inside the signal callback will preserve the [Tween]. </description> </signal> - <signal name="tween_completed"> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="NodePath"> + <signal name="loop_finished"> + <argument index="0" name="loop_count" type="int"> </argument> <description> - Emitted when a tween ends. + Emitted when a full loop is complete (see [method set_loops]), providing the loop index. This signal is not emitted after final loop, use [signal finished] instead for this case. </description> </signal> - <signal name="tween_started"> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="NodePath"> + <signal name="step_finished"> + <argument index="0" name="idx" type="int"> </argument> <description> - Emitted when a tween starts. - </description> - </signal> - <signal name="tween_step"> - <argument index="0" name="object" type="Object"> - </argument> - <argument index="1" name="key" type="NodePath"> - </argument> - <argument index="2" name="elapsed" type="float"> - </argument> - <argument index="3" name="value" type="Object"> - </argument> - <description> - Emitted at each step of the animation. + Emitted when one step of the [Tween] is complete, providing the step index. One step is either a single [Tweener] or a group of [Tweener]s running parallelly. </description> </signal> </signals> <constants> <constant name="TWEEN_PROCESS_PHYSICS" value="0" enum="TweenProcessMode"> - The tween updates with the [code]_physics_process[/code] callback. + The [Tween] updates during physics frame. </constant> <constant name="TWEEN_PROCESS_IDLE" value="1" enum="TweenProcessMode"> - The tween updates with the [code]_process[/code] callback. + The [Tween] updates during idle + </constant> + <constant name="TWEEN_PAUSE_BOUND" value="0" enum="TweenPauseMode"> + </constant> + <constant name="TWEEN_PAUSE_STOP" value="1" enum="TweenPauseMode"> + </constant> + <constant name="TWEEN_PAUSE_PROCESS" value="2" enum="TweenPauseMode"> </constant> <constant name="TRANS_LINEAR" value="0" enum="TransitionType"> - The animation is interpolated linearly. </constant> <constant name="TRANS_SINE" value="1" enum="TransitionType"> - The animation is interpolated using a sine function. </constant> <constant name="TRANS_QUINT" value="2" enum="TransitionType"> - The animation is interpolated with a quintic (to the power of 5) function. </constant> <constant name="TRANS_QUART" value="3" enum="TransitionType"> - The animation is interpolated with a quartic (to the power of 4) function. </constant> <constant name="TRANS_QUAD" value="4" enum="TransitionType"> - The animation is interpolated with a quadratic (to the power of 2) function. </constant> <constant name="TRANS_EXPO" value="5" enum="TransitionType"> - The animation is interpolated with an exponential (to the power of x) function. </constant> <constant name="TRANS_ELASTIC" value="6" enum="TransitionType"> - The animation is interpolated with elasticity, wiggling around the edges. </constant> <constant name="TRANS_CUBIC" value="7" enum="TransitionType"> - The animation is interpolated with a cubic (to the power of 3) function. </constant> <constant name="TRANS_CIRC" value="8" enum="TransitionType"> - The animation is interpolated with a function using square roots. </constant> <constant name="TRANS_BOUNCE" value="9" enum="TransitionType"> - The animation is interpolated by bouncing at the end. </constant> <constant name="TRANS_BACK" value="10" enum="TransitionType"> - The animation is interpolated backing out at ends. </constant> <constant name="EASE_IN" value="0" enum="EaseType"> - The interpolation starts slowly and speeds up towards the end. </constant> <constant name="EASE_OUT" value="1" enum="EaseType"> - The interpolation starts quickly and slows down towards the end. </constant> <constant name="EASE_IN_OUT" value="2" enum="EaseType"> - A combination of [constant EASE_IN] and [constant EASE_OUT]. The interpolation is slowest at both ends. </constant> <constant name="EASE_OUT_IN" value="3" enum="EaseType"> - A combination of [constant EASE_IN] and [constant EASE_OUT]. The interpolation is fastest at both ends. </constant> </constants> </class> diff --git a/doc/classes/Tweener.xml b/doc/classes/Tweener.xml new file mode 100644 index 0000000000..5cd502ced9 --- /dev/null +++ b/doc/classes/Tweener.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="Tweener" inherits="RefCounted" version="4.0"> + <brief_description> + Abstract class for all Tweeners used by [Tween]. + </brief_description> + <description> + Tweeners are objects that perform a specific animating task, e.g. interpolating a property or calling a method at a given time. A [Tweener] can't be created manually, you need to use a dedicated method from [Tween] or [Node]. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <signals> + <signal name="finished"> + <description> + Emited when the [Tweener] has just finished its job. + </description> + </signal> + </signals> + <constants> + </constants> +</class> diff --git a/doc/classes/UDPServer.xml b/doc/classes/UDPServer.xml index 6f3ccb8a17..5e2906450c 100644 --- a/doc/classes/UDPServer.xml +++ b/doc/classes/UDPServer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UDPServer" inherits="Reference" version="4.0"> +<class name="UDPServer" inherits="RefCounted" version="4.0"> <brief_description> Helper class to implement a UDP server. </brief_description> diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml index 775bd58bcf..240c1c909f 100644 --- a/doc/classes/Variant.xml +++ b/doc/classes/Variant.xml @@ -5,20 +5,30 @@ </brief_description> <description> In computer programming, a Variant class is a class that is designed to store a variety of other types. Dynamic programming languages like PHP, Lua, JavaScript and GDScript like to use them to store variables' data on the backend. With these Variants, properties are able to change value types freely. - [codeblock] + [codeblocks] + [gdscript] var foo = 2 # foo is dynamically an integer foo = "Now foo is a string!" - foo = Reference.new() # foo is an Object + foo = RefCounted.new() # foo is an Object var bar: int = 2 # bar is a statically typed integer. # bar = "Uh oh! I can't make static variables become a different type!" - [/codeblock] + [/gdscript] + [csharp] + // ... but C# is statically typed. Once a variable has a type it cannot be changed. However you can use the var keyword in methods to let the compiler decide the type automatically. + var foo = 2; // Foo is a 32-bit integer (int). Be cautious, integers in GDScript are 64-bit and the direct C# equivalent is "long". + // foo = "foo was and will always be an integer. It cannot be turned into a string!"; + var boo = "Boo is a string!"; + var ref = new Reference(); // var is especially useful when used together with a constructor. + [/csharp] + [/codeblocks] Godot tracks all scripting API variables within Variants. Without even realizing it, you use Variants all the time. When a particular language enforces its own rules for keeping data typed, then that language is applying its own custom logic over the base Variant scripting API. - GDScript automatically wrap values in them. It keeps all data in plain Variants by default and then optionally enforces custom static typing rules on variable types. - VisualScript tracks properties inside Variants as well, but it also uses static typing. The GUI interface enforces that properties have a particular type that doesn't change over time. - C# is statically typed, but uses the Mono [code]object[/code] type in place of Godot's Variant class when it needs to represent a dynamic value. [code]object[/code] is the Mono runtime's equivalent of the same concept. - The statically-typed language NativeScript C++ does not define a built-in Variant-like class. Godot's GDNative bindings provide their own godot::Variant class for users; Any point at which the C++ code starts interacting with the Godot runtime is a place where you might have to start wrapping data inside Variant objects. The global [method @GlobalScope.typeof] function returns the enumerated value of the Variant type stored in the current variable (see [enum Variant.Type]). - [codeblock] + [codeblocks] + [gdscript] var foo = 2 match typeof(foo): TYPE_NIL: @@ -32,7 +42,19 @@ # Note also that there is not yet any way to get a script's `class_name` string easily. # To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes". # Open your project.godot file to see it up close. - [/codeblock] + [/gdscript] + [csharp] + int foo = 2; + if (foo == null) + { + GD.Print("foo is null"); + } + if (foo is int) + { + GD.Print("foo is an integer"); + } + [/csharp] + [/codeblocks] A Variant takes up only 20 bytes and can store almost any engine datatype inside of it. Variants are rarely used to hold information for long periods of time. Instead, they are used mainly for communication, editing, serialization and moving data around. Godot has specifically invested in making its Variant class as flexible as possible; so much so that it is used for a multitude of operations to facilitate communication between all of Godot's systems. A Variant: diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml index 1390a5e45b..498aefbef0 100644 --- a/doc/classes/Vector2.xml +++ b/doc/classes/Vector2.xml @@ -304,12 +304,6 @@ <method name="operator +" qualifiers="operator"> <return type="Vector2"> </return> - <description> - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="Vector2"> - </return> <argument index="0" name="right" type="Vector2"> </argument> <description> @@ -318,12 +312,6 @@ <method name="operator -" qualifiers="operator"> <return type="Vector2"> </return> - <description> - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="Vector2"> - </return> <argument index="0" name="right" type="Vector2"> </argument> <description> @@ -401,6 +389,18 @@ <description> </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="Vector2"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="Vector2"> + </return> + <description> + </description> + </method> <method name="orthogonal" qualifiers="const"> <return type="Vector2"> </return> @@ -513,25 +513,25 @@ <constant name="AXIS_Y" value="1"> Enumerated value for the Y axis. </constant> - <constant name="ZERO" value="Vector2( 0, 0 )"> + <constant name="ZERO" value="Vector2(0, 0)"> Zero vector, a vector with all components set to [code]0[/code]. </constant> - <constant name="ONE" value="Vector2( 1, 1 )"> + <constant name="ONE" value="Vector2(1, 1)"> One vector, a vector with all components set to [code]1[/code]. </constant> - <constant name="INF" value="Vector2( inf, inf )"> + <constant name="INF" value="Vector2(inf, inf)"> Infinity vector, a vector with all components set to [constant @GDScript.INF]. </constant> - <constant name="LEFT" value="Vector2( -1, 0 )"> + <constant name="LEFT" value="Vector2(-1, 0)"> Left unit vector. Represents the direction of left. </constant> - <constant name="RIGHT" value="Vector2( 1, 0 )"> + <constant name="RIGHT" value="Vector2(1, 0)"> Right unit vector. Represents the direction of right. </constant> - <constant name="UP" value="Vector2( 0, -1 )"> + <constant name="UP" value="Vector2(0, -1)"> Up unit vector. Y is down in 2D, so this vector points -Y. </constant> - <constant name="DOWN" value="Vector2( 0, 1 )"> + <constant name="DOWN" value="Vector2(0, 1)"> Down unit vector. Y is down in 2D, so this vector points +Y. </constant> </constants> diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml index 6efb52b712..5f190de8ca 100644 --- a/doc/classes/Vector2i.xml +++ b/doc/classes/Vector2i.xml @@ -126,12 +126,6 @@ <method name="operator +" qualifiers="operator"> <return type="Vector2i"> </return> - <description> - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="Vector2i"> - </return> <argument index="0" name="right" type="Vector2i"> </argument> <description> @@ -140,12 +134,6 @@ <method name="operator -" qualifiers="operator"> <return type="Vector2i"> </return> - <description> - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="Vector2i"> - </return> <argument index="0" name="right" type="Vector2i"> </argument> <description> @@ -223,6 +211,18 @@ <description> </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="Vector2i"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="Vector2i"> + </return> + <description> + </description> + </method> <method name="sign" qualifiers="const"> <return type="Vector2i"> </return> @@ -246,22 +246,22 @@ <constant name="AXIS_Y" value="1"> Enumerated value for the Y axis. </constant> - <constant name="ZERO" value="Vector2i( 0, 0 )"> + <constant name="ZERO" value="Vector2i(0, 0)"> Zero vector, a vector with all components set to [code]0[/code]. </constant> - <constant name="ONE" value="Vector2i( 1, 1 )"> + <constant name="ONE" value="Vector2i(1, 1)"> One vector, a vector with all components set to [code]1[/code]. </constant> - <constant name="LEFT" value="Vector2i( -1, 0 )"> + <constant name="LEFT" value="Vector2i(-1, 0)"> Left unit vector. Represents the direction of left. </constant> - <constant name="RIGHT" value="Vector2i( 1, 0 )"> + <constant name="RIGHT" value="Vector2i(1, 0)"> Right unit vector. Represents the direction of right. </constant> - <constant name="UP" value="Vector2i( 0, -1 )"> + <constant name="UP" value="Vector2i(0, -1)"> Up unit vector. Y is down in 2D, so this vector points -Y. </constant> - <constant name="DOWN" value="Vector2i( 0, 1 )"> + <constant name="DOWN" value="Vector2i(0, 1)"> Down unit vector. Y is down in 2D, so this vector points +Y. </constant> </constants> diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml index 170bd78067..1361666c18 100644 --- a/doc/classes/Vector3.xml +++ b/doc/classes/Vector3.xml @@ -173,7 +173,7 @@ <return type="Vector3"> </return> <description> - Returns the inverse of the vector. This is the same as [code]Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )[/code]. + Returns the inverse of the vector. This is the same as [code]Vector3(1.0 / v.x, 1.0 / v.y, 1.0 / v.z)[/code]. </description> </method> <method name="is_equal_approx" qualifiers="const"> @@ -286,7 +286,7 @@ <method name="operator *" qualifiers="operator"> <return type="Vector3"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> </description> @@ -294,7 +294,7 @@ <method name="operator *" qualifiers="operator"> <return type="Vector3"> </return> - <argument index="0" name="right" type="Transform"> + <argument index="0" name="right" type="Transform3D"> </argument> <description> </description> @@ -318,12 +318,6 @@ <method name="operator +" qualifiers="operator"> <return type="Vector3"> </return> - <description> - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="Vector3"> - </return> <argument index="0" name="right" type="Vector3"> </argument> <description> @@ -332,12 +326,6 @@ <method name="operator -" qualifiers="operator"> <return type="Vector3"> </return> - <description> - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="Vector3"> - </return> <argument index="0" name="right" type="Vector3"> </argument> <description> @@ -415,6 +403,18 @@ <description> </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="Vector3"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="Vector3"> + </return> + <description> + </description> + </method> <method name="outer" qualifiers="const"> <return type="Basis"> </return> @@ -556,31 +556,31 @@ <constant name="AXIS_Z" value="2"> Enumerated value for the Z axis. Returned by [method max_axis] and [method min_axis]. </constant> - <constant name="ZERO" value="Vector3( 0, 0, 0 )"> + <constant name="ZERO" value="Vector3(0, 0, 0)"> Zero vector, a vector with all components set to [code]0[/code]. </constant> - <constant name="ONE" value="Vector3( 1, 1, 1 )"> + <constant name="ONE" value="Vector3(1, 1, 1)"> One vector, a vector with all components set to [code]1[/code]. </constant> - <constant name="INF" value="Vector3( inf, inf, inf )"> + <constant name="INF" value="Vector3(inf, inf, inf)"> Infinity vector, a vector with all components set to [constant @GDScript.INF]. </constant> - <constant name="LEFT" value="Vector3( -1, 0, 0 )"> + <constant name="LEFT" value="Vector3(-1, 0, 0)"> Left unit vector. Represents the local direction of left, and the global direction of west. </constant> - <constant name="RIGHT" value="Vector3( 1, 0, 0 )"> + <constant name="RIGHT" value="Vector3(1, 0, 0)"> Right unit vector. Represents the local direction of right, and the global direction of east. </constant> - <constant name="UP" value="Vector3( 0, 1, 0 )"> + <constant name="UP" value="Vector3(0, 1, 0)"> Up unit vector. </constant> - <constant name="DOWN" value="Vector3( 0, -1, 0 )"> + <constant name="DOWN" value="Vector3(0, -1, 0)"> Down unit vector. </constant> - <constant name="FORWARD" value="Vector3( 0, 0, -1 )"> + <constant name="FORWARD" value="Vector3(0, 0, -1)"> Forward unit vector. Represents the local direction of forward, and the global direction of north. </constant> - <constant name="BACK" value="Vector3( 0, 0, 1 )"> + <constant name="BACK" value="Vector3(0, 0, 1)"> Back unit vector. Represents the local direction of back, and the global direction of south. </constant> </constants> diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml index 6e8a34b692..e08bafa665 100644 --- a/doc/classes/Vector3i.xml +++ b/doc/classes/Vector3i.xml @@ -134,12 +134,6 @@ <method name="operator +" qualifiers="operator"> <return type="Vector3i"> </return> - <description> - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="Vector3i"> - </return> <argument index="0" name="right" type="Vector3i"> </argument> <description> @@ -148,12 +142,6 @@ <method name="operator -" qualifiers="operator"> <return type="Vector3i"> </return> - <description> - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="Vector3i"> - </return> <argument index="0" name="right" type="Vector3i"> </argument> <description> @@ -231,6 +219,18 @@ <description> </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="Vector3i"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="Vector3i"> + </return> + <description> + </description> + </method> <method name="sign" qualifiers="const"> <return type="Vector3i"> </return> @@ -260,28 +260,28 @@ <constant name="AXIS_Z" value="2"> Enumerated value for the Z axis. </constant> - <constant name="ZERO" value="Vector3i( 0, 0, 0 )"> + <constant name="ZERO" value="Vector3i(0, 0, 0)"> Zero vector, a vector with all components set to [code]0[/code]. </constant> - <constant name="ONE" value="Vector3i( 1, 1, 1 )"> + <constant name="ONE" value="Vector3i(1, 1, 1)"> One vector, a vector with all components set to [code]1[/code]. </constant> - <constant name="LEFT" value="Vector3i( -1, 0, 0 )"> + <constant name="LEFT" value="Vector3i(-1, 0, 0)"> Left unit vector. Represents the local direction of left, and the global direction of west. </constant> - <constant name="RIGHT" value="Vector3i( 1, 0, 0 )"> + <constant name="RIGHT" value="Vector3i(1, 0, 0)"> Right unit vector. Represents the local direction of right, and the global direction of east. </constant> - <constant name="UP" value="Vector3i( 0, 1, 0 )"> + <constant name="UP" value="Vector3i(0, 1, 0)"> Up unit vector. </constant> - <constant name="DOWN" value="Vector3i( 0, -1, 0 )"> + <constant name="DOWN" value="Vector3i(0, -1, 0)"> Down unit vector. </constant> - <constant name="FORWARD" value="Vector3i( 0, 0, -1 )"> + <constant name="FORWARD" value="Vector3i(0, 0, -1)"> Forward unit vector. Represents the local direction of forward, and the global direction of north. </constant> - <constant name="BACK" value="Vector3i( 0, 0, 1 )"> + <constant name="BACK" value="Vector3i(0, 0, 1)"> Back unit vector. Represents the local direction of back, and the global direction of south. </constant> </constants> diff --git a/doc/classes/VelocityTracker3D.xml b/doc/classes/VelocityTracker3D.xml index 98f7533c76..2d5e3a4d30 100644 --- a/doc/classes/VelocityTracker3D.xml +++ b/doc/classes/VelocityTracker3D.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VelocityTracker3D" inherits="Reference" version="4.0"> +<class name="VelocityTracker3D" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml index d905ce4054..12558ebbbc 100644 --- a/doc/classes/VideoPlayer.xml +++ b/doc/classes/VideoPlayer.xml @@ -60,7 +60,7 @@ <member name="buffering_msec" type="int" setter="set_buffering_msec" getter="get_buffering_msec" default="500"> Amount of time in milliseconds to store in buffer while playing. </member> - <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="@"Master""> + <member name="bus" type="StringName" setter="set_bus" getter="get_bus" default="&"Master""> Audio bus to use for sound playback. </member> <member name="expand" type="bool" setter="set_expand" getter="has_expand" default="true"> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 1c33274cb0..00827fe324 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -60,10 +60,11 @@ <method name="get_render_info"> <return type="int"> </return> - <argument index="0" name="info" type="int" enum="Viewport.RenderInfo"> + <argument index="0" name="type" type="int" enum="Viewport.RenderInfoType"> + </argument> + <argument index="1" name="info" type="int" enum="Viewport.RenderInfo"> </argument> <description> - Returns information about the viewport from the rendering pipeline. </description> </method> <method name="get_shadow_atlas_quadrant_subdiv" qualifiers="const"> @@ -81,10 +82,16 @@ <description> Returns the viewport's texture. [b]Note:[/b] Due to the way OpenGL works, the resulting [ViewportTexture] is flipped vertically. You can use [method Image.flip_y] on the result of [method Texture2D.get_image] to flip it back, for example: - [codeblock] + [codeblocks] + [gdscript] var img = get_viewport().get_texture().get_image() img.flip_y() - [/codeblock] + [/gdscript] + [csharp] + Image img = GetViewport().GetTexture().GetImage(); + img.FlipY(); + [/csharp] + [/codeblocks] </description> </method> <method name="get_viewport_rid" qualifiers="const"> @@ -105,7 +112,7 @@ <return type="Variant"> </return> <description> - Returns the drag data from the GUI, that was previously returned by [method Control.get_drag_data]. + Returns the drag data from the GUI, that was previously returned by [method Control._get_drag_data]. </description> </method> <method name="gui_is_dragging" qualifiers="const"> @@ -173,13 +180,6 @@ <description> </description> </method> - <method name="update_worlds"> - <return type="void"> - </return> - <description> - Forces update of the 2D and 3D worlds. - </description> - </method> <method name="warp_mouse"> <return type="void"> </return> @@ -209,6 +209,9 @@ <member name="debug_draw" type="int" setter="set_debug_draw" getter="get_debug_draw" enum="Viewport.DebugDraw" default="0"> The overlay mode for test rendered geometry in debug purposes. </member> + <member name="disable_3d" type="bool" setter="set_disable_3d" getter="is_3d_disabled" default="false"> + Disable 3D rendering (but keep 2D rendering). + </member> <member name="global_canvas_transform" type="Transform2D" setter="set_global_canvas_transform" getter="get_global_canvas_transform"> The global canvas transform of the viewport. The canvas transform is relative to this. </member> @@ -348,23 +351,20 @@ <constant name="RENDER_INFO_OBJECTS_IN_FRAME" value="0" enum="RenderInfo"> Amount of objects in frame. </constant> - <constant name="RENDER_INFO_VERTICES_IN_FRAME" value="1" enum="RenderInfo"> + <constant name="RENDER_INFO_PRIMITIVES_IN_FRAME" value="1" enum="RenderInfo"> Amount of vertices in frame. </constant> - <constant name="RENDER_INFO_MATERIAL_CHANGES_IN_FRAME" value="2" enum="RenderInfo"> - Amount of material changes in frame. + <constant name="RENDER_INFO_DRAW_CALLS_IN_FRAME" value="2" enum="RenderInfo"> + Amount of draw calls in frame. </constant> - <constant name="RENDER_INFO_SHADER_CHANGES_IN_FRAME" value="3" enum="RenderInfo"> - Amount of shader changes in frame. + <constant name="RENDER_INFO_MAX" value="3" enum="RenderInfo"> + Represents the size of the [enum RenderInfo] enum. </constant> - <constant name="RENDER_INFO_SURFACE_CHANGES_IN_FRAME" value="4" enum="RenderInfo"> - Amount of surface changes in frame. + <constant name="RENDER_INFO_TYPE_VISIBLE" value="0" enum="RenderInfoType"> </constant> - <constant name="RENDER_INFO_DRAW_CALLS_IN_FRAME" value="5" enum="RenderInfo"> - Amount of draw calls in frame. + <constant name="RENDER_INFO_TYPE_SHADOW" value="1" enum="RenderInfoType"> </constant> - <constant name="RENDER_INFO_MAX" value="6" enum="RenderInfo"> - Represents the size of the [enum RenderInfo] enum. + <constant name="RENDER_INFO_TYPE_MAX" value="2" enum="RenderInfoType"> </constant> <constant name="DEBUG_DRAW_DISABLED" value="0" enum="DebugDraw"> Objects are displayed normally. @@ -382,14 +382,14 @@ </constant> <constant name="DEBUG_DRAW_NORMAL_BUFFER" value="5" enum="DebugDraw"> </constant> - <constant name="DEBUG_DRAW_GI_PROBE_ALBEDO" value="6" enum="DebugDraw"> - Objects are displayed with only the albedo value from [GIProbe]s. + <constant name="DEBUG_DRAW_VOXEL_GI_ALBEDO" value="6" enum="DebugDraw"> + Objects are displayed with only the albedo value from [VoxelGI]s. </constant> - <constant name="DEBUG_DRAW_GI_PROBE_LIGHTING" value="7" enum="DebugDraw"> - Objects are displayed with only the lighting value from [GIProbe]s. + <constant name="DEBUG_DRAW_VOXEL_GI_LIGHTING" value="7" enum="DebugDraw"> + Objects are displayed with only the lighting value from [VoxelGI]s. </constant> - <constant name="DEBUG_DRAW_GI_PROBE_EMISSION" value="8" enum="DebugDraw"> - Objects are displayed with only the emission color from [GIProbe]s. + <constant name="DEBUG_DRAW_VOXEL_GI_EMISSION" value="8" enum="DebugDraw"> + Objects are displayed with only the emission color from [VoxelGI]s. </constant> <constant name="DEBUG_DRAW_SHADOW_ATLAS" value="9" enum="DebugDraw"> Draws the shadow atlas that stores shadows from [OmniLight3D]s and [SpotLight3D]s in the upper left quadrant of the [Viewport]. diff --git a/doc/classes/VisibilityEnabler2D.xml b/doc/classes/VisibilityEnabler2D.xml deleted file mode 100644 index 02fe7a7cd0..0000000000 --- a/doc/classes/VisibilityEnabler2D.xml +++ /dev/null @@ -1,79 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisibilityEnabler2D" inherits="VisibilityNotifier2D" version="4.0"> - <brief_description> - Enables certain nodes only when approximately visible. - </brief_description> - <description> - The VisibilityEnabler2D will disable [RigidBody2D], [AnimationPlayer], and other nodes when they are not visible. It will only affect nodes with the same root node as the VisibilityEnabler2D, and the root node itself. - If you just want to receive notifications, use [VisibilityNotifier2D] instead. - [b]Note:[/b] For performance reasons, VisibilityEnabler2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node. - [b]Note:[/b] VisibilityEnabler2D will not affect nodes added after scene initialization. - </description> - <tutorials> - </tutorials> - <methods> - <method name="is_enabler_enabled" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="enabler" type="int" enum="VisibilityEnabler2D.Enabler"> - </argument> - <description> - Returns whether the enabler identified by given [enum Enabler] constant is active. - </description> - </method> - <method name="set_enabler"> - <return type="void"> - </return> - <argument index="0" name="enabler" type="int" enum="VisibilityEnabler2D.Enabler"> - </argument> - <argument index="1" name="enabled" type="bool"> - </argument> - <description> - Sets active state of the enabler identified by given [enum Enabler] constant. - </description> - </method> - </methods> - <members> - <member name="freeze_bodies" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true"> - If [code]true[/code], [RigidBody2D] nodes will be paused. - </member> - <member name="pause_animated_sprites" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true"> - If [code]true[/code], [AnimatedSprite2D] nodes will be paused. - </member> - <member name="pause_animations" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true"> - If [code]true[/code], [AnimationPlayer] nodes will be paused. - </member> - <member name="pause_particles" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true"> - If [code]true[/code], [GPUParticles2D] nodes will be paused. - </member> - <member name="physics_process_parent" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="false"> - If [code]true[/code], the parent's [method Node._physics_process] will be stopped. - </member> - <member name="process_parent" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="false"> - If [code]true[/code], the parent's [method Node._process] will be stopped. - </member> - </members> - <constants> - <constant name="ENABLER_PAUSE_ANIMATIONS" value="0" enum="Enabler"> - This enabler will pause [AnimationPlayer] nodes. - </constant> - <constant name="ENABLER_FREEZE_BODIES" value="1" enum="Enabler"> - This enabler will freeze [RigidBody2D] nodes. - </constant> - <constant name="ENABLER_PAUSE_PARTICLES" value="2" enum="Enabler"> - This enabler will stop [GPUParticles2D] nodes. - </constant> - <constant name="ENABLER_PARENT_PROCESS" value="3" enum="Enabler"> - This enabler will stop the parent's _process function. - </constant> - <constant name="ENABLER_PARENT_PHYSICS_PROCESS" value="4" enum="Enabler"> - This enabler will stop the parent's _physics_process function. - </constant> - <constant name="ENABLER_PAUSE_ANIMATED_SPRITES" value="5" enum="Enabler"> - This enabler will stop [AnimatedSprite2D] nodes animations. - </constant> - <constant name="ENABLER_MAX" value="6" enum="Enabler"> - Represents the size of the [enum Enabler] enum. - </constant> - </constants> -</class> diff --git a/doc/classes/VisibilityEnabler3D.xml b/doc/classes/VisibilityEnabler3D.xml deleted file mode 100644 index d78ebb55f2..0000000000 --- a/doc/classes/VisibilityEnabler3D.xml +++ /dev/null @@ -1,55 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisibilityEnabler3D" inherits="VisibilityNotifier3D" version="4.0"> - <brief_description> - Enables certain nodes only when approximately visible. - </brief_description> - <description> - The VisibilityEnabler3D will disable [RigidBody3D] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibilityEnabler3D itself. - If you just want to receive notifications, use [VisibilityNotifier3D] instead. - [b]Note:[/b] VisibilityEnabler3D uses an approximate heuristic for performance reasons. It doesn't take walls and other occlusion into account. The heuristic is an implementation detail and may change in future versions. If you need precise visibility checking, use another method such as adding an [Area3D] node as a child of a [Camera3D] node and/or [method Vector3.dot]. - [b]Note:[/b] VisibilityEnabler3D will not affect nodes added after scene initialization. - </description> - <tutorials> - </tutorials> - <methods> - <method name="is_enabler_enabled" qualifiers="const"> - <return type="bool"> - </return> - <argument index="0" name="enabler" type="int" enum="VisibilityEnabler3D.Enabler"> - </argument> - <description> - Returns whether the enabler identified by given [enum Enabler] constant is active. - </description> - </method> - <method name="set_enabler"> - <return type="void"> - </return> - <argument index="0" name="enabler" type="int" enum="VisibilityEnabler3D.Enabler"> - </argument> - <argument index="1" name="enabled" type="bool"> - </argument> - <description> - Sets active state of the enabler identified by given [enum Enabler] constant. - </description> - </method> - </methods> - <members> - <member name="freeze_bodies" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true"> - If [code]true[/code], [RigidBody3D] nodes will be paused. - </member> - <member name="pause_animations" type="bool" setter="set_enabler" getter="is_enabler_enabled" default="true"> - If [code]true[/code], [AnimationPlayer] nodes will be paused. - </member> - </members> - <constants> - <constant name="ENABLER_PAUSE_ANIMATIONS" value="0" enum="Enabler"> - This enabler will pause [AnimationPlayer] nodes. - </constant> - <constant name="ENABLER_FREEZE_BODIES" value="1" enum="Enabler"> - This enabler will freeze [RigidBody3D] nodes. - </constant> - <constant name="ENABLER_MAX" value="2" enum="Enabler"> - Represents the size of the [enum Enabler] enum. - </constant> - </constants> -</class> diff --git a/doc/classes/VisibilityNotifier2D.xml b/doc/classes/VisibilityNotifier2D.xml deleted file mode 100644 index 761438b77e..0000000000 --- a/doc/classes/VisibilityNotifier2D.xml +++ /dev/null @@ -1,57 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisibilityNotifier2D" inherits="Node2D" version="4.0"> - <brief_description> - Detects approximately when the node is visible on screen. - </brief_description> - <description> - The VisibilityNotifier2D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a viewport. - If you want nodes to be disabled automatically when they exit the screen, use [VisibilityEnabler2D] instead. - [b]Note:[/b] For performance reasons, VisibilityNotifier2D uses an approximate heuristic with precision determined by [member ProjectSettings.world/2d/cell_size]. If you need precise visibility checking, use another method such as adding an [Area2D] node as a child of a [Camera2D] node. - </description> - <tutorials> - <link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link> - </tutorials> - <methods> - <method name="is_on_screen" qualifiers="const"> - <return type="bool"> - </return> - <description> - If [code]true[/code], the bounding rectangle is on the screen. - [b]Note:[/b] It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass. - </description> - </method> - </methods> - <members> - <member name="rect" type="Rect2" setter="set_rect" getter="get_rect" default="Rect2( -10, -10, 20, 20 )"> - The VisibilityNotifier2D's bounding rectangle. - </member> - </members> - <signals> - <signal name="screen_entered"> - <description> - Emitted when the VisibilityNotifier2D enters the screen. - </description> - </signal> - <signal name="screen_exited"> - <description> - Emitted when the VisibilityNotifier2D exits the screen. - </description> - </signal> - <signal name="viewport_entered"> - <argument index="0" name="viewport" type="Viewport"> - </argument> - <description> - Emitted when the VisibilityNotifier2D enters a [Viewport]'s view. - </description> - </signal> - <signal name="viewport_exited"> - <argument index="0" name="viewport" type="Viewport"> - </argument> - <description> - Emitted when the VisibilityNotifier2D exits a [Viewport]'s view. - </description> - </signal> - </signals> - <constants> - </constants> -</class> diff --git a/doc/classes/VisibilityNotifier3D.xml b/doc/classes/VisibilityNotifier3D.xml deleted file mode 100644 index e5d3116612..0000000000 --- a/doc/classes/VisibilityNotifier3D.xml +++ /dev/null @@ -1,56 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="VisibilityNotifier3D" inherits="Node3D" version="4.0"> - <brief_description> - Detects approximately when the node is visible on screen. - </brief_description> - <description> - The VisibilityNotifier3D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a [Camera3D]'s view. - If you want nodes to be disabled automatically when they exit the screen, use [VisibilityEnabler3D] instead. - [b]Note:[/b] VisibilityNotifier3D uses an approximate heuristic for performance reasons. It doesn't take walls and other occlusion into account. The heuristic is an implementation detail and may change in future versions. If you need precise visibility checking, use another method such as adding an [Area3D] node as a child of a [Camera3D] node and/or [method Vector3.dot]. - </description> - <tutorials> - </tutorials> - <methods> - <method name="is_on_screen" qualifiers="const"> - <return type="bool"> - </return> - <description> - If [code]true[/code], the bounding box is on the screen. - [b]Note:[/b] It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass. - </description> - </method> - </methods> - <members> - <member name="aabb" type="AABB" setter="set_aabb" getter="get_aabb" default="AABB( -1, -1, -1, 2, 2, 2 )"> - The VisibilityNotifier3D's bounding box. - </member> - </members> - <signals> - <signal name="camera_entered"> - <argument index="0" name="camera" type="Camera3D"> - </argument> - <description> - Emitted when the VisibilityNotifier3D enters a [Camera3D]'s view. - </description> - </signal> - <signal name="camera_exited"> - <argument index="0" name="camera" type="Camera3D"> - </argument> - <description> - Emitted when the VisibilityNotifier3D exits a [Camera3D]'s view. - </description> - </signal> - <signal name="screen_entered"> - <description> - Emitted when the VisibilityNotifier3D enters the screen. - </description> - </signal> - <signal name="screen_exited"> - <description> - Emitted when the VisibilityNotifier3D exits the screen. - </description> - </signal> - </signals> - <constants> - </constants> -</class> diff --git a/doc/classes/VisibleOnScreenEnabler2D.xml b/doc/classes/VisibleOnScreenEnabler2D.xml new file mode 100644 index 0000000000..c6ae8227d2 --- /dev/null +++ b/doc/classes/VisibleOnScreenEnabler2D.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisibleOnScreenEnabler2D" inherits="VisibleOnScreenNotifier2D" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibleOnScreenEnabler2D.EnableMode" default="0"> + </member> + <member name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath("..")"> + </member> + </members> + <constants> + <constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode"> + </constant> + <constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode"> + </constant> + <constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisibleOnScreenEnabler3D.xml b/doc/classes/VisibleOnScreenEnabler3D.xml new file mode 100644 index 0000000000..3205d6b415 --- /dev/null +++ b/doc/classes/VisibleOnScreenEnabler3D.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisibleOnScreenEnabler3D" inherits="VisibleOnScreenNotifier3D" version="4.0"> + <brief_description> + Enables certain nodes only when approximately visible. + </brief_description> + <description> + The VisibleOnScreenEnabler3D will disable [RigidBody3D] and [AnimationPlayer] nodes when they are not visible. It will only affect other nodes within the same scene as the VisibleOnScreenEnabler3D itself. + If you just want to receive notifications, use [VisibleOnScreenNotifier3D] instead. + [b]Note:[/b] VisibleOnScreenEnabler3D uses an approximate heuristic for performance reasons. It doesn't take walls and other occlusion into account. The heuristic is an implementation detail and may change in future versions. If you need precise visibility checking, use another method such as adding an [Area3D] node as a child of a [Camera3D] node and/or [method Vector3.dot]. + [b]Note:[/b] VisibleOnScreenEnabler3D will not affect nodes added after scene initialization. + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="enable_mode" type="int" setter="set_enable_mode" getter="get_enable_mode" enum="VisibleOnScreenEnabler3D.EnableMode" default="0"> + </member> + <member name="enable_node_path" type="NodePath" setter="set_enable_node_path" getter="get_enable_node_path" default="NodePath("..")"> + </member> + </members> + <constants> + <constant name="ENABLE_MODE_INHERIT" value="0" enum="EnableMode"> + </constant> + <constant name="ENABLE_MODE_ALWAYS" value="1" enum="EnableMode"> + </constant> + <constant name="ENABLE_MODE_WHEN_PAUSED" value="2" enum="EnableMode"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisibleOnScreenNotifier2D.xml b/doc/classes/VisibleOnScreenNotifier2D.xml new file mode 100644 index 0000000000..daad200ca8 --- /dev/null +++ b/doc/classes/VisibleOnScreenNotifier2D.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisibleOnScreenNotifier2D" inherits="Node2D" version="4.0"> + <brief_description> + Detects when the node extents are visible on screen. + </brief_description> + <description> + The VisibleOnScreenNotifier2D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a viewport. + If you want nodes to be disabled automatically when they exit the screen, use [VisibleOnScreenEnabler2D] instead. + </description> + <tutorials> + <link title="2D Dodge The Creeps Demo">https://godotengine.org/asset-library/asset/515</link> + </tutorials> + <methods> + <method name="is_on_screen" qualifiers="const"> + <return type="bool"> + </return> + <description> + If [code]true[/code], the bounding rectangle is on the screen. + [b]Note:[/b] It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass. + </description> + </method> + </methods> + <members> + <member name="rect" type="Rect2" setter="set_rect" getter="get_rect" default="Rect2(-10, -10, 20, 20)"> + The VisibleOnScreenNotifier2D's bounding rectangle. + </member> + </members> + <signals> + <signal name="screen_entered"> + <description> + Emitted when the VisibleOnScreenNotifier2D enters the screen. + </description> + </signal> + <signal name="screen_exited"> + <description> + Emitted when the VisibleOnScreenNotifier2D exits the screen. + </description> + </signal> + </signals> + <constants> + </constants> +</class> diff --git a/doc/classes/VisibleOnScreenNotifier3D.xml b/doc/classes/VisibleOnScreenNotifier3D.xml new file mode 100644 index 0000000000..85ff324fbf --- /dev/null +++ b/doc/classes/VisibleOnScreenNotifier3D.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisibleOnScreenNotifier3D" inherits="VisualInstance3D" version="4.0"> + <brief_description> + Detects approximately when the node is visible on screen. + </brief_description> + <description> + The VisibleOnScreenNotifier3D detects when it is visible on the screen. It also notifies when its bounding rectangle enters or exits the screen or a [Camera3D]'s view. + If you want nodes to be disabled automatically when they exit the screen, use [VisibleOnScreenEnabler3D] instead. + [b]Note:[/b] VisibleOnScreenNotifier3D uses an approximate heuristic for performance reasons. It doesn't take walls and other occlusion into account. The heuristic is an implementation detail and may change in future versions. If you need precise visibility checking, use another method such as adding an [Area3D] node as a child of a [Camera3D] node and/or [method Vector3.dot]. + </description> + <tutorials> + </tutorials> + <methods> + <method name="is_on_screen" qualifiers="const"> + <return type="bool"> + </return> + <description> + If [code]true[/code], the bounding box is on the screen. + [b]Note:[/b] It takes one frame for the node's visibility to be assessed once added to the scene tree, so this method will return [code]false[/code] right after it is instantiated, even if it will be on screen in the draw pass. + </description> + </method> + </methods> + <members> + <member name="aabb" type="AABB" setter="set_aabb" getter="get_aabb" default="AABB(-1, -1, -1, 2, 2, 2)"> + The VisibleOnScreenNotifier3D's bounding box. + </member> + </members> + <signals> + <signal name="screen_entered"> + <description> + Emitted when the VisibleOnScreenNotifier3D enters the screen. + </description> + </signal> + <signal name="screen_exited"> + <description> + Emitted when the VisibleOnScreenNotifier3D exits the screen. + </description> + </signal> + </signals> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml index 01d569d9c8..2a12254b71 100644 --- a/doc/classes/VisualInstance3D.xml +++ b/doc/classes/VisualInstance3D.xml @@ -44,7 +44,7 @@ </return> <description> Returns the transformed [AABB] (also known as the bounding box) for this [VisualInstance3D]. - Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform]. See also [method get_aabb]. + Transformed in this case means the [AABB] plus the position, rotation, and scale of the [Node3D]'s [Transform3D]. See also [method get_aabb]. </description> </method> <method name="set_base"> diff --git a/doc/classes/VisualShader.xml b/doc/classes/VisualShader.xml index ff00a848b9..19b4acd8f1 100644 --- a/doc/classes/VisualShader.xml +++ b/doc/classes/VisualShader.xml @@ -206,7 +206,7 @@ </method> </methods> <members> - <member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2( 0, 0 )"> + <member name="graph_offset" type="Vector2" setter="set_graph_offset" getter="get_graph_offset" default="Vector2(0, 0)"> The offset vector of the whole graph. </member> <member name="version" type="String" setter="set_version" getter="get_version" default=""""> @@ -222,15 +222,19 @@ <constant name="TYPE_LIGHT" value="2" enum="Type"> A shader for light calculations. </constant> - <constant name="TYPE_EMIT" value="3" enum="Type"> + <constant name="TYPE_START" value="3" enum="Type"> </constant> <constant name="TYPE_PROCESS" value="4" enum="Type"> </constant> - <constant name="TYPE_END" value="5" enum="Type"> + <constant name="TYPE_COLLIDE" value="5" enum="Type"> </constant> - <constant name="TYPE_SKY" value="6" enum="Type"> + <constant name="TYPE_START_CUSTOM" value="6" enum="Type"> </constant> - <constant name="TYPE_MAX" value="7" enum="Type"> + <constant name="TYPE_PROCESS_CUSTOM" value="7" enum="Type"> + </constant> + <constant name="TYPE_SKY" value="8" enum="Type"> + </constant> + <constant name="TYPE_MAX" value="9" enum="Type"> Represents the size of the [enum Type] enum. </constant> <constant name="NODE_ID_INVALID" value="-1"> diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml index 6327ab534f..9a74f2322e 100644 --- a/doc/classes/VisualShaderNode.xml +++ b/doc/classes/VisualShaderNode.xml @@ -9,6 +9,13 @@ <link title="VisualShaders">https://docs.godotengine.org/en/latest/tutorials/shading/visual_shaders.html</link> </tutorials> <methods> + <method name="clear_default_input_values"> + <return type="void"> + </return> + <description> + Clears the default input ports value. + </description> + </method> <method name="get_default_input_values" qualifiers="const"> <return type="Array"> </return> @@ -25,6 +32,15 @@ Returns the default value of the input [code]port[/code]. </description> </method> + <method name="remove_input_port_default_value"> + <return type="void"> + </return> + <argument index="0" name="port" type="int"> + </argument> + <description> + Removes the default value of the input [code]port[/code]. + </description> + </method> <method name="set_default_input_values"> <return type="void"> </return> diff --git a/doc/classes/VisualShaderNodeColorConstant.xml b/doc/classes/VisualShaderNodeColorConstant.xml index 8644013ef2..fa1a11c488 100644 --- a/doc/classes/VisualShaderNodeColorConstant.xml +++ b/doc/classes/VisualShaderNodeColorConstant.xml @@ -12,7 +12,7 @@ <methods> </methods> <members> - <member name="constant" type="Color" setter="set_constant" getter="get_constant" default="Color( 1, 1, 1, 1 )"> + <member name="constant" type="Color" setter="set_constant" getter="get_constant" default="Color(1, 1, 1, 1)"> A [Color] constant which represents a state of this node. </member> </members> diff --git a/doc/classes/VisualShaderNodeColorUniform.xml b/doc/classes/VisualShaderNodeColorUniform.xml index 90ef381b76..bdaf301f09 100644 --- a/doc/classes/VisualShaderNodeColorUniform.xml +++ b/doc/classes/VisualShaderNodeColorUniform.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="default_value" type="Color" setter="set_default_value" getter="get_default_value" default="Color( 1, 1, 1, 1 )"> + <member name="default_value" type="Color" setter="set_default_value" getter="get_default_value" default="Color(1, 1, 1, 1)"> A default value to be assigned within the shader. </member> <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> diff --git a/doc/classes/VisualShaderNodeDeterminant.xml b/doc/classes/VisualShaderNodeDeterminant.xml index 6b042f6172..06b05addfa 100644 --- a/doc/classes/VisualShaderNodeDeterminant.xml +++ b/doc/classes/VisualShaderNodeDeterminant.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeDeterminant" inherits="VisualShaderNode" version="4.0"> <brief_description> - Calculates the determinant of a [Transform] within the visual shader graph. + Calculates the determinant of a [Transform3D] within the visual shader graph. </brief_description> <description> Translates to [code]determinant(x)[/code] in the shader language. diff --git a/doc/classes/VisualShaderNodeParticleAccelerator.xml b/doc/classes/VisualShaderNodeParticleAccelerator.xml new file mode 100644 index 0000000000..82aae1df63 --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleAccelerator.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleAccelerator" inherits="VisualShaderNodeOutput" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="VisualShaderNodeParticleAccelerator.Mode" default="0"> + </member> + </members> + <constants> + <constant name="MODE_LINEAR" value="0" enum="Mode"> + </constant> + <constant name="MODE_RADIAL" value="1" enum="Mode"> + </constant> + <constant name="MODE_TANGENTIAL" value="2" enum="Mode"> + </constant> + <constant name="MODE_MAX" value="3" enum="Mode"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleBoxEmitter.xml b/doc/classes/VisualShaderNodeParticleBoxEmitter.xml new file mode 100644 index 0000000000..af33b285d2 --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleBoxEmitter.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleBoxEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleConeVelocity.xml b/doc/classes/VisualShaderNodeParticleConeVelocity.xml new file mode 100644 index 0000000000..7a40c2a7d0 --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleConeVelocity.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleConeVelocity" inherits="VisualShaderNode" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleEmit.xml b/doc/classes/VisualShaderNodeParticleEmit.xml new file mode 100644 index 0000000000..120b12d643 --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleEmit.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleEmit" inherits="VisualShaderNode" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="flags" type="int" setter="set_flags" getter="get_flags" enum="VisualShaderNodeParticleEmit.EmitFlags" default="31"> + </member> + </members> + <constants> + <constant name="EMIT_FLAG_POSITION" value="1" enum="EmitFlags"> + </constant> + <constant name="EMIT_FLAG_ROT_SCALE" value="2" enum="EmitFlags"> + </constant> + <constant name="EMIT_FLAG_VELOCITY" value="4" enum="EmitFlags"> + </constant> + <constant name="EMIT_FLAG_COLOR" value="8" enum="EmitFlags"> + </constant> + <constant name="EMIT_FLAG_CUSTOM" value="16" enum="EmitFlags"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleEmitter.xml b/doc/classes/VisualShaderNodeParticleEmitter.xml new file mode 100644 index 0000000000..3a25fc1c7f --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleEmitter.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleEmitter" inherits="VisualShaderNode" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml b/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml new file mode 100644 index 0000000000..89a53699c9 --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleMultiplyByAxisAngle.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleMultiplyByAxisAngle" inherits="VisualShaderNode" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="degrees_mode" type="bool" setter="set_degrees_mode" getter="is_degrees_mode" default="true"> + </member> + </members> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleOutput.xml b/doc/classes/VisualShaderNodeParticleOutput.xml new file mode 100644 index 0000000000..c8fc66f2ff --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleOutput.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleOutput" inherits="VisualShaderNodeOutput" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleRandomness.xml b/doc/classes/VisualShaderNodeParticleRandomness.xml new file mode 100644 index 0000000000..f19723a663 --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleRandomness.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleRandomness" inherits="VisualShaderNode" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="op_type" type="int" setter="set_op_type" getter="get_op_type" enum="VisualShaderNodeParticleRandomness.OpType" default="0"> + </member> + </members> + <constants> + <constant name="OP_TYPE_SCALAR" value="0" enum="OpType"> + </constant> + <constant name="OP_TYPE_VECTOR" value="1" enum="OpType"> + </constant> + <constant name="OP_TYPE_MAX" value="2" enum="OpType"> + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleRingEmitter.xml b/doc/classes/VisualShaderNodeParticleRingEmitter.xml new file mode 100644 index 0000000000..ee3fbe7faf --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleRingEmitter.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleRingEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeParticleSphereEmitter.xml b/doc/classes/VisualShaderNodeParticleSphereEmitter.xml new file mode 100644 index 0000000000..d43ac518cf --- /dev/null +++ b/doc/classes/VisualShaderNodeParticleSphereEmitter.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeParticleSphereEmitter" inherits="VisualShaderNodeParticleEmitter" version="4.0"> + <brief_description> + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <constants> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeResizableBase.xml b/doc/classes/VisualShaderNodeResizableBase.xml index 9f827a96cc..9052f6854b 100644 --- a/doc/classes/VisualShaderNodeResizableBase.xml +++ b/doc/classes/VisualShaderNodeResizableBase.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 0, 0 )"> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(0, 0)"> The size of the node in the visual shader graph. </member> </members> diff --git a/doc/classes/VisualShaderNodeTransformCompose.xml b/doc/classes/VisualShaderNodeTransformCompose.xml index 41762b0099..b82ce9bdd8 100644 --- a/doc/classes/VisualShaderNodeTransformCompose.xml +++ b/doc/classes/VisualShaderNodeTransformCompose.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformCompose" inherits="VisualShaderNode" version="4.0"> <brief_description> - Composes a [Transform] from four [Vector3]s within the visual shader graph. + Composes a [Transform3D] from four [Vector3]s within the visual shader graph. </brief_description> <description> Creates a 4x4 transform matrix using four vectors of type [code]vec3[/code]. Each vector is one row in the matrix and the last column is a [code]vec4(0, 0, 0, 1)[/code]. diff --git a/doc/classes/VisualShaderNodeTransformConstant.xml b/doc/classes/VisualShaderNodeTransformConstant.xml index b8f054e914..30178752d0 100644 --- a/doc/classes/VisualShaderNodeTransformConstant.xml +++ b/doc/classes/VisualShaderNodeTransformConstant.xml @@ -1,18 +1,18 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformConstant" inherits="VisualShaderNodeConstant" version="4.0"> <brief_description> - A [Transform] constant for use within the visual shader graph. + A [Transform3D] constant for use within the visual shader graph. </brief_description> <description> - A constant [Transform], which can be used as an input node. + A constant [Transform3D], which can be used as an input node. </description> <tutorials> </tutorials> <methods> </methods> <members> - <member name="constant" type="Transform" setter="set_constant" getter="get_constant" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> - A [Transform] constant which represents the state of this node. + <member name="constant" type="Transform3D" setter="set_constant" getter="get_constant" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> + A [Transform3D] constant which represents the state of this node. </member> </members> <constants> diff --git a/doc/classes/VisualShaderNodeTransformDecompose.xml b/doc/classes/VisualShaderNodeTransformDecompose.xml index c8d893db00..b815efc67a 100644 --- a/doc/classes/VisualShaderNodeTransformDecompose.xml +++ b/doc/classes/VisualShaderNodeTransformDecompose.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformDecompose" inherits="VisualShaderNode" version="4.0"> <brief_description> - Decomposes a [Transform] into four [Vector3]s within the visual shader graph. + Decomposes a [Transform3D] into four [Vector3]s within the visual shader graph. </brief_description> <description> Takes a 4x4 transform matrix and decomposes it into four [code]vec3[/code] values, one from each row of the matrix. diff --git a/doc/classes/VisualShaderNodeTransformFunc.xml b/doc/classes/VisualShaderNodeTransformFunc.xml index d0b5c5129d..41a58e1458 100644 --- a/doc/classes/VisualShaderNodeTransformFunc.xml +++ b/doc/classes/VisualShaderNodeTransformFunc.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformFunc" inherits="VisualShaderNode" version="4.0"> <brief_description> - Computes a [Transform] function within the visual shader graph. + Computes a [Transform3D] function within the visual shader graph. </brief_description> <description> - Computes an inverse or transpose function on the provided [Transform]. + Computes an inverse or transpose function on the provided [Transform3D]. </description> <tutorials> </tutorials> @@ -17,10 +17,10 @@ </members> <constants> <constant name="FUNC_INVERSE" value="0" enum="Function"> - Perform the inverse operation on the [Transform] matrix. + Perform the inverse operation on the [Transform3D] matrix. </constant> <constant name="FUNC_TRANSPOSE" value="1" enum="Function"> - Perform the transpose operation on the [Transform] matrix. + Perform the transpose operation on the [Transform3D] matrix. </constant> </constants> </class> diff --git a/doc/classes/VisualShaderNodeTransformMult.xml b/doc/classes/VisualShaderNodeTransformMult.xml index 02b6e0cd1c..f26f60a1f3 100644 --- a/doc/classes/VisualShaderNodeTransformMult.xml +++ b/doc/classes/VisualShaderNodeTransformMult.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformMult" inherits="VisualShaderNode" version="4.0"> <brief_description> - Multiplies [Transform] by [Transform] within the visual shader graph. + Multiplies [Transform3D] by [Transform3D] within the visual shader graph. </brief_description> <description> A multiplication operation on two transforms (4x4 matrices), with support for different multiplication operators. diff --git a/doc/classes/VisualShaderNodeTransformUniform.xml b/doc/classes/VisualShaderNodeTransformUniform.xml index ff6246618d..2f7818ec8a 100644 --- a/doc/classes/VisualShaderNodeTransformUniform.xml +++ b/doc/classes/VisualShaderNodeTransformUniform.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformUniform" inherits="VisualShaderNodeUniform" version="4.0"> <brief_description> - A [Transform] uniform for use within the visual shader graph. + A [Transform3D] uniform for use within the visual shader graph. </brief_description> <description> Translated to [code]uniform mat4[/code] in the shader language. @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="default_value" type="Transform" setter="set_default_value" getter="get_default_value" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="default_value" type="Transform3D" setter="set_default_value" getter="get_default_value" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> A default value to be assigned within the shader. </member> <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> diff --git a/doc/classes/VisualShaderNodeTransformVecMult.xml b/doc/classes/VisualShaderNodeTransformVecMult.xml index 3d5f87f727..2c9c115d9c 100644 --- a/doc/classes/VisualShaderNodeTransformVecMult.xml +++ b/doc/classes/VisualShaderNodeTransformVecMult.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VisualShaderNodeTransformVecMult" inherits="VisualShaderNode" version="4.0"> <brief_description> - Multiplies a [Transform] and a [Vector3] within the visual shader graph. + Multiplies a [Transform3D] and a [Vector3] within the visual shader graph. </brief_description> <description> A multiplication operation on a transform (4x4 matrix) and a vector, with support for different multiplication operators. diff --git a/doc/classes/VisualShaderNodeUVFunc.xml b/doc/classes/VisualShaderNodeUVFunc.xml new file mode 100644 index 0000000000..042644feb0 --- /dev/null +++ b/doc/classes/VisualShaderNodeUVFunc.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="VisualShaderNodeUVFunc" inherits="VisualShaderNode" version="4.0"> + <brief_description> + Contains functions to modify texture coordinates ([code]uv[/code]) to be used within the visual shader graph. + </brief_description> + <description> + </description> + <tutorials> + </tutorials> + <methods> + </methods> + <members> + <member name="function" type="int" setter="set_function" getter="get_function" enum="VisualShaderNodeUVFunc.Function" default="0"> + A function to be applied to the texture coordinates. See [enum Function] for options. + </member> + </members> + <constants> + <constant name="FUNC_PANNING" value="0" enum="Function"> + Translates [code]uv[/code] by using [code]scale[/code] and [code]offset[/code] values using the following formula: [code]uv = uv + offset * scale[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default. + </constant> + <constant name="FUNC_SCALING" value="1" enum="Function"> + Scales [code]uv[/uv] by using [code]scale[/code] and [code]pivot[/code] values using the following formula: [code]uv = (uv - pivot) * scale + pivot[/code]. [code]uv[/code] port is connected to [code]UV[/code] built-in by default. + </constant> + <constant name="FUNC_MAX" value="2" enum="Function"> + Represents the size of the [enum Function] enum. + </constant> + </constants> +</class> diff --git a/doc/classes/VisualShaderNodeVec3Constant.xml b/doc/classes/VisualShaderNodeVec3Constant.xml index b01bb514fe..28c3d22345 100644 --- a/doc/classes/VisualShaderNodeVec3Constant.xml +++ b/doc/classes/VisualShaderNodeVec3Constant.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="constant" type="Vector3" setter="set_constant" getter="get_constant" default="Vector3( 0, 0, 0 )"> + <member name="constant" type="Vector3" setter="set_constant" getter="get_constant" default="Vector3(0, 0, 0)"> A [Vector3] constant which represents the state of this node. </member> </members> diff --git a/doc/classes/VisualShaderNodeVec3Uniform.xml b/doc/classes/VisualShaderNodeVec3Uniform.xml index cd1500f5a1..215e2cfbea 100644 --- a/doc/classes/VisualShaderNodeVec3Uniform.xml +++ b/doc/classes/VisualShaderNodeVec3Uniform.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="default_value" type="Vector3" setter="set_default_value" getter="get_default_value" default="Vector3( 0, 0, 0 )"> + <member name="default_value" type="Vector3" setter="set_default_value" getter="get_default_value" default="Vector3(0, 0, 0)"> A default value to be assigned within the shader. </member> <member name="default_value_enabled" type="bool" setter="set_default_value_enabled" getter="is_default_value_enabled" default="false"> diff --git a/doc/classes/GIProbe.xml b/doc/classes/VoxelGI.xml index 4f56d1ad3e..5b395becb7 100644 --- a/doc/classes/GIProbe.xml +++ b/doc/classes/VoxelGI.xml @@ -1,15 +1,15 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GIProbe" inherits="VisualInstance3D" version="4.0"> +<class name="VoxelGI" inherits="VisualInstance3D" version="4.0"> <brief_description> Real-time global illumination (GI) probe. </brief_description> <description> - [GIProbe]s are used to provide high-quality real-time indirect light to scenes. They precompute the effect of objects that emit light and the effect of static geometry to simulate the behavior of complex light in real-time. [GIProbe]s need to be baked before using, however, once baked, dynamic objects will receive light from them. Further, lights can be fully dynamic or baked. - Having [GIProbe]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/global_illumination/gi_probes/quality]. + [VoxelGI]s are used to provide high-quality real-time indirect light to scenes. They precompute the effect of objects that emit light and the effect of static geometry to simulate the behavior of complex light in real-time. [VoxelGI]s need to be baked before using, however, once baked, dynamic objects will receive light from them. Further, lights can be fully dynamic or baked. + Having [VoxelGI]s in a scene can be expensive, the quality of the probe can be turned down in exchange for better performance in the [ProjectSettings] using [member ProjectSettings.rendering/global_illumination/voxel_gi/quality]. [b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh. </description> <tutorials> - <link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/gi_probes.html</link> + <link title="GI probes">https://docs.godotengine.org/en/latest/tutorials/3d/voxel_gi.html</link> <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> </tutorials> <methods> @@ -21,7 +21,7 @@ <argument index="1" name="create_visual_debug" type="bool" default="false"> </argument> <description> - Bakes the effect from all [GeometryInstance3D]s marked with [constant GeometryInstance3D.GI_MODE_BAKED] and [Light3D]s marked with either [constant Light3D.BAKE_DYNAMIC] or [constant Light3D.BAKE_STATIC]. If [code]create_visual_debug[/code] is [code]true[/code], after baking the light, this will generate a [MultiMesh] that has a cube representing each solid cell with each cube colored to the cell's albedo color. This can be used to visualize the [GIProbe]'s data and debug any issues that may be occurring. + Bakes the effect from all [GeometryInstance3D]s marked with [constant GeometryInstance3D.GI_MODE_BAKED] and [Light3D]s marked with either [constant Light3D.BAKE_DYNAMIC] or [constant Light3D.BAKE_STATIC]. If [code]create_visual_debug[/code] is [code]true[/code], after baking the light, this will generate a [MultiMesh] that has a cube representing each solid cell with each cube colored to the cell's albedo color. This can be used to visualize the [VoxelGI]'s data and debug any issues that may be occurring. </description> </method> <method name="debug_bake"> @@ -33,14 +33,14 @@ </method> </methods> <members> - <member name="data" type="GIProbeData" setter="set_probe_data" getter="get_probe_data"> - The [GIProbeData] resource that holds the data for this [GIProbe]. + <member name="data" type="VoxelGIData" setter="set_probe_data" getter="get_probe_data"> + The [VoxelGIData] resource that holds the data for this [VoxelGI]. </member> - <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3( 10, 10, 10 )"> - The size of the area covered by the [GIProbe]. If you make the extents larger without increasing the subdivisions with [member subdiv], the size of each cell will increase and result in lower detailed lighting. + <member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(10, 10, 10)"> + The size of the area covered by the [VoxelGI]. If you make the extents larger without increasing the subdivisions with [member subdiv], the size of each cell will increase and result in lower detailed lighting. </member> - <member name="subdiv" type="int" setter="set_subdiv" getter="get_subdiv" enum="GIProbe.Subdiv" default="1"> - Number of times to subdivide the grid that the [GIProbe] operates on. A higher number results in finer detail and thus higher visual quality, while lower numbers result in better performance. + <member name="subdiv" type="int" setter="set_subdiv" getter="get_subdiv" enum="VoxelGI.Subdiv" default="1"> + Number of times to subdivide the grid that the [VoxelGI] operates on. A higher number results in finer detail and thus higher visual quality, while lower numbers result in better performance. </member> </members> <constants> diff --git a/doc/classes/GIProbeData.xml b/doc/classes/VoxelGIData.xml index 693df8f819..f613002233 100644 --- a/doc/classes/GIProbeData.xml +++ b/doc/classes/VoxelGIData.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GIProbeData" inherits="Resource" version="4.0"> +<class name="VoxelGIData" inherits="Resource" version="4.0"> <brief_description> </brief_description> <description> @@ -11,7 +11,7 @@ <method name="allocate"> <return type="void"> </return> - <argument index="0" name="to_cell_xform" type="Transform"> + <argument index="0" name="to_cell_xform" type="Transform3D"> </argument> <argument index="1" name="aabb" type="AABB"> </argument> @@ -59,19 +59,13 @@ </description> </method> <method name="get_to_cell_xform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> </description> </method> </methods> <members> - <member name="anisotropy_strength" type="float" setter="set_anisotropy_strength" getter="get_anisotropy_strength" default="0.5"> - </member> - <member name="ao" type="float" setter="set_ao" getter="get_ao" default="0.0"> - </member> - <member name="ao_size" type="float" setter="set_ao_size" getter="get_ao_size" default="0.5"> - </member> <member name="bias" type="float" setter="set_bias" getter="get_bias" default="1.5"> </member> <member name="dynamic_range" type="float" setter="set_dynamic_range" getter="get_dynamic_range" default="4.0"> diff --git a/doc/classes/WeakRef.xml b/doc/classes/WeakRef.xml index 4140df5828..6c9a7de67f 100644 --- a/doc/classes/WeakRef.xml +++ b/doc/classes/WeakRef.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WeakRef" inherits="Reference" version="4.0"> +<class name="WeakRef" inherits="RefCounted" version="4.0"> <brief_description> Holds an [Object], but does not contribute to the reference count if the object is a reference. </brief_description> <description> - A weakref can hold a [Reference], without contributing to the reference counter. A weakref can be created from an [Object] using [method @GlobalScope.weakref]. If this object is not a reference, weakref still works, however, it does not have any effect on the object. Weakrefs are useful in cases where multiple classes have variables that refer to each other. Without weakrefs, using these classes could lead to memory leaks, since both references keep each other from being released. Making part of the variables a weakref can prevent this cyclic dependency, and allows the references to be released. + A weakref can hold a [RefCounted], without contributing to the reference counter. A weakref can be created from an [Object] using [method @GlobalScope.weakref]. If this object is not a reference, weakref still works, however, it does not have any effect on the object. Weakrefs are useful in cases where multiple classes have variables that refer to each other. Without weakrefs, using these classes could lead to memory leaks, since both references keep each other from being released. Making part of the variables a weakref can prevent this cyclic dependency, and allows the references to be released. </description> <tutorials> </tutorials> diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml index 37709753bc..73a95967bd 100644 --- a/doc/classes/Window.xml +++ b/doc/classes/Window.xml @@ -19,6 +19,13 @@ <description> </description> </method> + <method name="get_contents_minimum_size" qualifiers="const"> + <return type="Vector2"> + </return> + <description> + Returns the combined minimum size from the child [Control] nodes of the window. + </description> + </method> <method name="get_flag" qualifiers="const"> <return type="bool"> </return> @@ -218,7 +225,7 @@ <method name="popup"> <return type="void"> </return> - <argument index="0" name="rect" type="Rect2i" default="Rect2i( 0, 0, 0, 0 )"> + <argument index="0" name="rect" type="Rect2i" default="Rect2i(0, 0, 0, 0)"> </argument> <description> </description> @@ -226,7 +233,7 @@ <method name="popup_centered"> <return type="void"> </return> - <argument index="0" name="minsize" type="Vector2i" default="Vector2i( 0, 0 )"> + <argument index="0" name="minsize" type="Vector2i" default="Vector2i(0, 0)"> </argument> <description> </description> @@ -234,7 +241,7 @@ <method name="popup_centered_clamped"> <return type="void"> </return> - <argument index="0" name="minsize" type="Vector2i" default="Vector2i( 0, 0 )"> + <argument index="0" name="minsize" type="Vector2i" default="Vector2i(0, 0)"> </argument> <argument index="1" name="fallback_ratio" type="float" default="0.75"> </argument> @@ -322,25 +329,25 @@ </member> <member name="content_scale_mode" type="int" setter="set_content_scale_mode" getter="get_content_scale_mode" enum="Window.ContentScaleMode" default="0"> </member> - <member name="content_scale_size" type="Vector2i" setter="set_content_scale_size" getter="get_content_scale_size" default="Vector2i( 0, 0 )"> + <member name="content_scale_size" type="Vector2i" setter="set_content_scale_size" getter="get_content_scale_size" default="Vector2i(0, 0)"> </member> <member name="current_screen" type="int" setter="set_current_screen" getter="get_current_screen" default="0"> </member> <member name="exclusive" type="bool" setter="set_exclusive" getter="is_exclusive" default="false"> </member> - <member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i( 0, 0 )"> + <member name="max_size" type="Vector2i" setter="set_max_size" getter="get_max_size" default="Vector2i(0, 0)"> </member> - <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" default="Vector2i( 0, 0 )"> + <member name="min_size" type="Vector2i" setter="set_min_size" getter="get_min_size" default="Vector2i(0, 0)"> </member> <member name="mode" type="int" setter="set_mode" getter="get_mode" enum="Window.Mode" default="0"> </member> - <member name="position" type="Vector2i" setter="set_position" getter="get_position" default="Vector2i( 0, 0 )"> + <member name="position" type="Vector2i" setter="set_position" getter="get_position" default="Vector2i(0, 0)"> </member> - <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i( 100, 100 )"> + <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i(100, 100)"> </member> <member name="theme" type="Theme" setter="set_theme" getter="get_theme"> </member> - <member name="theme_custom_type" type="StringName" setter="set_theme_custom_type" getter="get_theme_custom_type" default="@"""> + <member name="theme_custom_type" type="StringName" setter="set_theme_custom_type" getter="get_theme_custom_type" default="&"""> </member> <member name="title" type="String" setter="set_title" getter="get_title" default=""""> </member> @@ -472,7 +479,7 @@ </theme_item> <theme_item name="scaleborder_size" type="int" default="4"> </theme_item> - <theme_item name="title_color" type="Color" default="Color( 0, 0, 0, 1 )"> + <theme_item name="title_color" type="Color" default="Color(0, 0, 0, 1)"> </theme_item> <theme_item name="title_font" type="Font"> </theme_item> @@ -481,7 +488,7 @@ </theme_item> <theme_item name="title_height" type="int" default="20"> </theme_item> - <theme_item name="title_outline_modulate" type="Color" default="Color( 1, 1, 1, 1 )"> + <theme_item name="title_outline_modulate" type="Color" default="Color(1, 1, 1, 1)"> The color of the title outline. </theme_item> <theme_item name="title_outline_size" type="int" default="0"> diff --git a/doc/classes/WorldEnvironment.xml b/doc/classes/WorldEnvironment.xml index c1cf639ec0..6aa2db00b4 100644 --- a/doc/classes/WorldEnvironment.xml +++ b/doc/classes/WorldEnvironment.xml @@ -5,7 +5,7 @@ </brief_description> <description> The [WorldEnvironment] node is used to configure the default [Environment] for the scene. - The parameters defined in the [WorldEnvironment] can be overridden by an [Environment] node set on the current [Camera3D]. Additionally, only one [WorldEnvironment] may be instanced in a given scene at a time. + The parameters defined in the [WorldEnvironment] can be overridden by an [Environment] node set on the current [Camera3D]. Additionally, only one [WorldEnvironment] may be instantiated in a given scene at a time. The [WorldEnvironment] allows the user to specify default lighting parameters (e.g. ambient lighting), various post-processing effects (e.g. SSAO, DOF, Tonemapping), and how to draw the background (e.g. solid color, skybox). Usually, these are added in order to improve the realism/color balance of the scene. </description> <tutorials> diff --git a/doc/classes/WorldMarginShape3D.xml b/doc/classes/WorldMarginShape3D.xml index a91447056b..9a26f254f1 100644 --- a/doc/classes/WorldMarginShape3D.xml +++ b/doc/classes/WorldMarginShape3D.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="plane" type="Plane" setter="set_plane" getter="get_plane" default="Plane( 0, 1, 0, 0 )"> + <member name="plane" type="Plane" setter="set_plane" getter="get_plane" default="Plane(0, 1, 0, 0)"> The [Plane] used by the [WorldMarginShape3D] for collision. </member> </members> diff --git a/doc/classes/XMLParser.xml b/doc/classes/XMLParser.xml index 2849ea62ab..ab5c58c51c 100644 --- a/doc/classes/XMLParser.xml +++ b/doc/classes/XMLParser.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="XMLParser" inherits="Reference" version="4.0"> +<class name="XMLParser" inherits="RefCounted" version="4.0"> <brief_description> Low-level class for creating parsers for [url=https://en.wikipedia.org/wiki/XML]XML[/url] files. </brief_description> diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml index 034cb51be3..fec98007c3 100644 --- a/doc/classes/XRInterface.xml +++ b/doc/classes/XRInterface.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="XRInterface" inherits="Reference" version="4.0"> +<class name="XRInterface" inherits="RefCounted" version="4.0"> <brief_description> Base class for an AR/VR interface implementation. </brief_description> @@ -46,6 +46,13 @@ If supported, returns the status of our tracking. This will allow you to provide feedback to the user whether there are issues with positional tracking. </description> </method> + <method name="get_view_count"> + <return type="int"> + </return> + <description> + Returns the number of views that need to be rendered for this device. 1 for Monoscopic, 2 for Stereoscopic. + </description> + </method> <method name="initialize"> <return type="bool"> </return> @@ -57,13 +64,6 @@ While currently not used, you can activate additional interfaces. You may wish to do this if you want to track controllers from other platforms. However, at this point in time only one interface can render to an HMD. </description> </method> - <method name="is_stereo"> - <return type="bool"> - </return> - <description> - Returns [code]true[/code] if the current output of this interface is in stereo. - </description> - </method> <method name="uninitialize"> <return type="void"> </return> diff --git a/doc/classes/XRPositionalTracker.xml b/doc/classes/XRPositionalTracker.xml index 5274d952fd..cd8cb71cd9 100644 --- a/doc/classes/XRPositionalTracker.xml +++ b/doc/classes/XRPositionalTracker.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="XRPositionalTracker" inherits="Reference" version="4.0"> +<class name="XRPositionalTracker" inherits="RefCounted" version="4.0"> <brief_description> A tracked object. </brief_description> @@ -69,7 +69,7 @@ </description> </method> <method name="get_transform" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <argument index="0" name="adjust_by_reference_frame" type="bool"> </argument> diff --git a/doc/classes/XRServer.xml b/doc/classes/XRServer.xml index d0edf91fed..149e177700 100644 --- a/doc/classes/XRServer.xml +++ b/doc/classes/XRServer.xml @@ -63,7 +63,7 @@ </description> </method> <method name="get_hmd_transform"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> Returns the primary interface's transformation. @@ -96,7 +96,7 @@ <return type="int"> </return> <description> - Returns the absolute timestamp (in μs) of the last [XRServer] commit of the AR/VR eyes to [RenderingServer]. The value comes from an internal call to [method OS.get_ticks_usec]. + Returns the absolute timestamp (in μs) of the last [XRServer] commit of the AR/VR eyes to [RenderingServer]. The value comes from an internal call to [method Time.get_ticks_usec]. </description> </method> <method name="get_last_frame_usec"> @@ -110,11 +110,11 @@ <return type="int"> </return> <description> - Returns the absolute timestamp (in μs) of the last [XRServer] process callback. The value comes from an internal call to [method OS.get_ticks_usec]. + Returns the absolute timestamp (in μs) of the last [XRServer] process callback. The value comes from an internal call to [method Time.get_ticks_usec]. </description> </method> <method name="get_reference_frame" qualifiers="const"> - <return type="Transform"> + <return type="Transform3D"> </return> <description> Returns the reference frame transform. Mostly used internally and exposed for GDNative build interfaces. diff --git a/doc/classes/YSort.xml b/doc/classes/YSort.xml deleted file mode 100644 index 4ef6a4b4ec..0000000000 --- a/doc/classes/YSort.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="YSort" inherits="Node2D" version="4.0"> - <brief_description> - Sort all child nodes based on their Y positions. - </brief_description> - <description> - Sort all child nodes based on their Y positions. The child node must inherit from [CanvasItem] for it to be sorted. Nodes that have a higher Y position will be drawn later, so they will appear on top of nodes that have a lower Y position. - Nesting of YSort nodes is possible. Children YSort nodes will be sorted in the same space as the parent YSort, allowing to better organize a scene or divide it in multiple ones, yet keep the unique sorting. - </description> - <tutorials> - </tutorials> - <methods> - </methods> - <members> - <member name="sort_enabled" type="bool" setter="set_sort_enabled" getter="is_sort_enabled" default="true"> - If [code]true[/code], child nodes are sorted, otherwise sorting is disabled. - </member> - </members> - <constants> - </constants> -</class> diff --git a/doc/classes/float.xml b/doc/classes/float.xml index 11f6d91b05..585c847d22 100644 --- a/doc/classes/float.xml +++ b/doc/classes/float.xml @@ -113,12 +113,12 @@ </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> - Multiplies each component of the [Quat] by the given [float]. + Multiplies each component of the [Quaternion] by the given [float]. </description> </method> <method name="operator *" qualifiers="operator"> @@ -145,16 +145,6 @@ <method name="operator +" qualifiers="operator"> <return type="float"> </return> - <description> - Unary plus operator. Doesn't have any effect. - [codeblock] - var a = +2.5 # a is 2.5. - [/codeblock] - </description> - </method> - <method name="operator +" qualifiers="operator"> - <return type="float"> - </return> <argument index="0" name="right" type="float"> </argument> <description> @@ -173,17 +163,6 @@ <method name="operator -" qualifiers="operator"> <return type="float"> </return> - <description> - Unary minus operator. Negates the number. - [codeblock] - var a = -2.5 # a is -2.5. - print(-a) # 2.5 - [/codeblock] - </description> - </method> - <method name="operator -" qualifiers="operator"> - <return type="float"> - </return> <argument index="0" name="right" type="float"> </argument> <description> @@ -308,6 +287,18 @@ Returns [code]true[/code] if this [float] is greater than or equal to the given [int]. </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="float"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="float"> + </return> + <description> + </description> + </method> </methods> <constants> </constants> diff --git a/doc/classes/int.xml b/doc/classes/int.xml index 119cdf8eeb..95918c9007 100644 --- a/doc/classes/int.xml +++ b/doc/classes/int.xml @@ -126,21 +126,21 @@ </description> </method> <method name="operator *" qualifiers="operator"> - <return type="float"> + <return type="int"> </return> - <argument index="0" name="right" type="float"> + <argument index="0" name="right" type="int"> </argument> <description> - Multiplies an [int] and a [float]. The result is a [float]. + Multiplies two [int]s. </description> </method> <method name="operator *" qualifiers="operator"> - <return type="int"> + <return type="float"> </return> - <argument index="0" name="right" type="int"> + <argument index="0" name="right" type="float"> </argument> <description> - Multiplies two [int]s. + Multiplies an [int] and a [float]. The result is a [float]. </description> </method> <method name="operator *" qualifiers="operator"> @@ -183,9 +183,9 @@ </description> </method> <method name="operator *" qualifiers="operator"> - <return type="Quat"> + <return type="Quaternion"> </return> - <argument index="0" name="right" type="Quat"> + <argument index="0" name="right" type="Quaternion"> </argument> <description> Multiplies each component of the quaternion by the given integer. @@ -204,16 +204,6 @@ </description> </method> <method name="operator +" qualifiers="operator"> - <return type="int"> - </return> - <description> - Unary plus operator. Doesn't have any effect. - [codeblock] - var a = +1 # a is 1. - [/codeblock] - </description> - </method> - <method name="operator +" qualifiers="operator"> <return type="float"> </return> <argument index="0" name="right" type="float"> @@ -232,17 +222,6 @@ </description> </method> <method name="operator -" qualifiers="operator"> - <return type="int"> - </return> - <description> - Unary minus operator. Negates the number. - [codeblock] - var a = -1 # a is -1. - print(-a) # 1 - [/codeblock] - </description> - </method> - <method name="operator -" qualifiers="operator"> <return type="float"> </return> <argument index="0" name="right" type="float"> @@ -414,6 +393,18 @@ [/codeblock] </description> </method> + <method name="operator unary+" qualifiers="operator"> + <return type="int"> + </return> + <description> + </description> + </method> + <method name="operator unary-" qualifiers="operator"> + <return type="int"> + </return> + <description> + </description> + </method> <method name="operator |" qualifiers="operator"> <return type="int"> </return> diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py index 1c6055f8ca..9be7751d3d 100755 --- a/doc/tools/makerst.py +++ b/doc/tools/makerst.py @@ -350,6 +350,9 @@ def main(): # type: () -> None pattern = re.compile(args.filter) + # Create the output folder recursively if it doesn't already exist. + os.makedirs(args.output, exist_ok=True) + for class_name, class_def in state.classes.items(): if args.filter and not pattern.search(class_def.filepath): continue @@ -358,6 +361,8 @@ def main(): # type: () -> None if not state.errored: print("No errors found.") + if not args.dry_run: + print("Wrote reStructuredText files for each class to: %s" % args.output) else: print("Errors were found in the class reference XML. Please check the messages above.") exit(1) @@ -837,7 +842,7 @@ def rstize_text(text, state): # type: (str, State) -> str inside_code = True elif cmd == "gdscript": tag_depth += 1 - tag_text = "\n .. code-tab:: gdscript GDScript\n" + tag_text = "\n .. code-tab:: gdscript\n" inside_code = True elif cmd == "csharp": tag_depth += 1 diff --git a/doc/translations/ar.po b/doc/translations/ar.po index b4ae664714..4199bca6c7 100644 --- a/doc/translations/ar.po +++ b/doc/translations/ar.po @@ -701,7 +701,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13825,7 +13825,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33036,7 +33036,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33055,12 +33055,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34557,7 +34557,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34691,7 +34691,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41765,30 +41765,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41796,7 +41796,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54060,7 +54060,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59139,7 +59139,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/ca.po b/doc/translations/ca.po index 6485111b20..c72cba18bc 100644 --- a/doc/translations/ca.po +++ b/doc/translations/ca.po @@ -732,7 +732,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13856,7 +13856,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33067,7 +33067,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33086,12 +33086,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34588,7 +34588,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34722,7 +34722,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41796,30 +41796,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41827,7 +41827,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54091,7 +54091,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59170,7 +59170,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot index d14b0d9b1f..321e67f759 100644 --- a/doc/translations/classes.pot +++ b/doc/translations/classes.pot @@ -702,7 +702,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13826,7 +13826,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -20685,9 +20685,9 @@ msgid "" "onready var expression = Expression.new()\n" "\n" "func _ready():\n" -" $LineEdit.connect(\"text_entered\", self, \"_on_text_entered\")\n" +" $LineEdit.connect(\"text_submitted\", self, \"_on_text_submitted\")\n" "\n" -"func _on_text_entered(command):\n" +"func _on_text_submitted(command):\n" " var error = expression.parse(command, [])\n" " if error != OK:\n" " print(expression.get_error_text())\n" @@ -33037,7 +33037,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33056,12 +33056,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -33187,7 +33187,7 @@ msgid "" "Examples:\n" "[codeblock]\n" "connect(\"pressed\", self, \"_on_Button_pressed\") # BaseButton signal\n" -"connect(\"text_entered\", self, \"_on_LineEdit_text_entered\") # LineEdit " +"connect(\"text_submitted\", self, \"_on_LineEdit_text_submitted\") # LineEdit " "signal\n" "connect(\"hit\", self, \"_on_Player_hit\", [ weapon_type, damage ]) # User-" "defined signal\n" @@ -34558,7 +34558,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34692,7 +34692,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41766,30 +41766,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41797,7 +41797,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54061,7 +54061,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59140,7 +59140,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/cs.po b/doc/translations/cs.po index 7b958a5049..3584fc5062 100644 --- a/doc/translations/cs.po +++ b/doc/translations/cs.po @@ -1058,7 +1058,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -14318,7 +14318,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33536,7 +33536,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33555,12 +33555,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -35058,7 +35058,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -35192,7 +35192,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -42266,30 +42266,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -42297,7 +42297,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54562,7 +54562,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59645,7 +59645,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/de.po b/doc/translations/de.po index 2e3e219ba6..76eff809ff 100644 --- a/doc/translations/de.po +++ b/doc/translations/de.po @@ -992,7 +992,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -14154,7 +14154,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33453,7 +33453,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33472,12 +33472,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 #, fuzzy msgid "" @@ -34984,7 +34984,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -35118,7 +35118,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -42226,30 +42226,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -42257,7 +42257,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54558,7 +54558,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59796,7 +59796,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/es.po b/doc/translations/es.po index 3078c1bf90..44b3b22597 100644 --- a/doc/translations/es.po +++ b/doc/translations/es.po @@ -1119,7 +1119,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -18123,7 +18123,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -18150,7 +18150,7 @@ msgstr "" "Ejemplo de uso con una instancia de una escena personalizada<\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var sugerencia = preload(\"algunaEscenaSugerencia.tscn\").instance()\n" +" var sugerencia = preload(\"algunaEscenaSugerencia.tscn\").instantiate()\n" " tooltip.get_node(\"etiqueta\").text = para_texto\n" " return sugerencia\n" "[/codeblock]" @@ -44834,7 +44834,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -44853,9 +44853,9 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" "Toda clase que no es un tipo integrado hereda de esta clase.\n" "Puedes construir Objetos desde lenguajes de scripting, usando [code]Object." @@ -44866,7 +44866,7 @@ msgstr "" "llama al método [method free] desde tu script o elimina la instancia desde C+" "+.\n" "Algunas clases que extienden a Object añaden gestión de memoria. Este es el " -"caso de [Reference], que cuenta las referencias y se borra a sà misma " +"caso de [RefCounted], que cuenta las referencias y se borra a sà misma " "automáticamente cuando deja de estar referenciada. [Node], otro tipo " "fundamental, borra todos sus hijos cuando se libera de la memoria.\n" "Los objetos exportan propiedades, que son principalmente útiles para el " @@ -44887,7 +44887,7 @@ msgstr "" "sencilla de notificar al objeto sobre diferentes eventos, de modo que todos " "ellos pueden ser manejados juntos. Véase [method _notification]." -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 #, fuzzy msgid "" @@ -46525,7 +46525,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -46659,7 +46659,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -53779,30 +53779,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -53810,7 +53810,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -66189,7 +66189,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -71348,7 +71348,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/fa.po b/doc/translations/fa.po index 733d3bb969..2a185fadc5 100644 --- a/doc/translations/fa.po +++ b/doc/translations/fa.po @@ -707,7 +707,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13831,7 +13831,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33042,7 +33042,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33061,12 +33061,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34563,7 +34563,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34697,7 +34697,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41771,30 +41771,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41802,7 +41802,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54066,7 +54066,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59145,7 +59145,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/fi.po b/doc/translations/fi.po index 0a40863a52..a5f470c60b 100644 --- a/doc/translations/fi.po +++ b/doc/translations/fi.po @@ -720,7 +720,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13844,7 +13844,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33055,7 +33055,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33074,12 +33074,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34576,7 +34576,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34710,7 +34710,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41784,30 +41784,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41815,7 +41815,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54080,7 +54080,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59168,7 +59168,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/fr.po b/doc/translations/fr.po index f3e26ebc61..2d9b1db565 100644 --- a/doc/translations/fr.po +++ b/doc/translations/fr.po @@ -1017,7 +1017,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -14162,7 +14162,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33403,7 +33403,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33422,12 +33422,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34927,7 +34927,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -35061,7 +35061,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -42142,30 +42142,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -42173,7 +42173,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54519,7 +54519,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59618,7 +59618,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/id.po b/doc/translations/id.po index 1bce3d6b50..cd841fc553 100644 --- a/doc/translations/id.po +++ b/doc/translations/id.po @@ -733,7 +733,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13857,7 +13857,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33068,7 +33068,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33087,12 +33087,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34589,7 +34589,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34723,7 +34723,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41797,30 +41797,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41828,7 +41828,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54092,7 +54092,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59171,7 +59171,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/it.po b/doc/translations/it.po index 18e162476c..aa085f6158 100644 --- a/doc/translations/it.po +++ b/doc/translations/it.po @@ -985,7 +985,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -14115,7 +14115,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33334,7 +33334,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33353,12 +33353,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34856,7 +34856,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34990,7 +34990,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -42067,30 +42067,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -42098,7 +42098,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54365,7 +54365,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59459,7 +59459,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/ja.po b/doc/translations/ja.po index ede80a35ef..ee900d58c2 100644 --- a/doc/translations/ja.po +++ b/doc/translations/ja.po @@ -1091,7 +1091,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -15045,7 +15045,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -34306,7 +34306,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -34325,12 +34325,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 #, fuzzy msgid "" @@ -35830,7 +35830,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -35964,7 +35964,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -43046,30 +43046,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -43077,7 +43077,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -55349,7 +55349,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -60446,7 +60446,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/ko.po b/doc/translations/ko.po index e71cd06ba7..60416fb63c 100644 --- a/doc/translations/ko.po +++ b/doc/translations/ko.po @@ -709,7 +709,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13833,7 +13833,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33044,7 +33044,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33063,12 +33063,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34565,7 +34565,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34699,7 +34699,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41773,30 +41773,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41804,7 +41804,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54068,7 +54068,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59149,7 +59149,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/nl.po b/doc/translations/nl.po index 032ff95bdb..c0dc01c653 100644 --- a/doc/translations/nl.po +++ b/doc/translations/nl.po @@ -735,7 +735,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13859,7 +13859,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33070,7 +33070,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33089,12 +33089,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34591,7 +34591,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34725,7 +34725,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41799,30 +41799,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41830,7 +41830,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54094,7 +54094,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59173,7 +59173,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/pl.po b/doc/translations/pl.po index b0c94b55be..2664f263cb 100644 --- a/doc/translations/pl.po +++ b/doc/translations/pl.po @@ -737,7 +737,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13877,7 +13877,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33089,7 +33089,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33108,12 +33108,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34610,7 +34610,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34744,7 +34744,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41818,30 +41818,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41849,7 +41849,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54117,7 +54117,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59203,7 +59203,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/pt_BR.po b/doc/translations/pt_BR.po index a508d38859..f86bed9585 100644 --- a/doc/translations/pt_BR.po +++ b/doc/translations/pt_BR.po @@ -748,7 +748,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13872,7 +13872,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33083,7 +33083,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33102,12 +33102,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34604,7 +34604,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34738,7 +34738,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41812,30 +41812,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41843,7 +41843,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54108,7 +54108,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59194,7 +59194,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/ro.po b/doc/translations/ro.po index 96c0161312..b25c3911cc 100644 --- a/doc/translations/ro.po +++ b/doc/translations/ro.po @@ -709,7 +709,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13833,7 +13833,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33044,7 +33044,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33063,12 +33063,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34565,7 +34565,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34699,7 +34699,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41773,30 +41773,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41804,7 +41804,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54068,7 +54068,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59147,7 +59147,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/ru.po b/doc/translations/ru.po index 1108967bc9..cf5289d7f9 100644 --- a/doc/translations/ru.po +++ b/doc/translations/ru.po @@ -1072,7 +1072,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -14338,7 +14338,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33581,7 +33581,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33600,12 +33600,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -35104,7 +35104,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -35238,7 +35238,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -42362,30 +42362,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -42393,7 +42393,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54666,7 +54666,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59891,7 +59891,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/sr_Cyrl.po b/doc/translations/sr_Cyrl.po index d7d2911b97..06399d5e87 100644 --- a/doc/translations/sr_Cyrl.po +++ b/doc/translations/sr_Cyrl.po @@ -719,7 +719,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13843,7 +13843,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33054,7 +33054,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33073,12 +33073,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34575,7 +34575,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34709,7 +34709,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41783,30 +41783,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41814,7 +41814,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54078,7 +54078,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59157,7 +59157,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/th.po b/doc/translations/th.po index 5031ecfb0e..cdf1c6d7e2 100644 --- a/doc/translations/th.po +++ b/doc/translations/th.po @@ -725,7 +725,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13849,7 +13849,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33060,7 +33060,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33079,12 +33079,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34581,7 +34581,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34715,7 +34715,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41789,30 +41789,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41820,7 +41820,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54084,7 +54084,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59163,7 +59163,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/tr.po b/doc/translations/tr.po index a317f4ee83..646a3fb5b3 100644 --- a/doc/translations/tr.po +++ b/doc/translations/tr.po @@ -701,7 +701,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13825,7 +13825,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33036,7 +33036,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33055,12 +33055,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34557,7 +34557,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34691,7 +34691,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41765,30 +41765,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41796,7 +41796,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54060,7 +54060,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59139,7 +59139,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/uk.po b/doc/translations/uk.po index 8ca75e8b19..c2232d81ab 100644 --- a/doc/translations/uk.po +++ b/doc/translations/uk.po @@ -787,7 +787,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13911,7 +13911,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33122,7 +33122,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33141,12 +33141,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34643,7 +34643,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34777,7 +34777,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41851,30 +41851,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41882,7 +41882,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54147,7 +54147,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59237,7 +59237,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/zh_Hans.po b/doc/translations/zh_Hans.po index aee852699c..40d1eb68bc 100644 --- a/doc/translations/zh_Hans.po +++ b/doc/translations/zh_Hans.po @@ -934,7 +934,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -14058,7 +14058,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33272,7 +33272,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33291,12 +33291,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34794,7 +34794,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34928,7 +34928,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -42002,30 +42002,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -42033,7 +42033,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54298,7 +54298,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59381,7 +59381,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/doc/translations/zh_Hant.po b/doc/translations/zh_Hant.po index 242c8cc086..13515dff67 100644 --- a/doc/translations/zh_Hant.po +++ b/doc/translations/zh_Hant.po @@ -738,7 +738,7 @@ msgid "" "the FileSystem dock into the script.\n" "[codeblock]\n" "# Instance a scene.\n" -"var diamond = preload(\"res://diamond.tscn\").instance()\n" +"var diamond = preload(\"res://diamond.tscn\").instantiate()\n" "[/codeblock]" msgstr "" @@ -13862,7 +13862,7 @@ msgid "" "Example of usage with custom scene instance:\n" "[codeblock]\n" "func _make_custom_tooltip(for_text):\n" -" var tooltip = preload(\"SomeTooltipScene.tscn\").instance()\n" +" var tooltip = preload(\"SomeTooltipScene.tscn\").instantiate()\n" " tooltip.get_node(\"Label\").text = for_text\n" " return tooltip\n" "[/codeblock]" @@ -33073,7 +33073,7 @@ msgid "" "to delete instances of it manually. To do so, call the [method free] method " "from your script or delete the instance from C++.\n" "Some classes that extend Object add memory management. This is the case of " -"[Reference], which counts references and deletes itself automatically when " +"[RefCounted], which counts references and deletes itself automatically when " "no longer referenced. [Node], another fundamental type, deletes all its " "children when freed from memory.\n" "Objects export properties, which are mainly useful for storage and editing, " @@ -33092,12 +33092,12 @@ msgid "" "Objects also receive notifications. Notifications are a simple way to notify " "the object about different events, so they can all be handled together. See " "[method _notification].\n" -"[b]Note:[/b] Unlike references to a [Reference], references to an Object " +"[b]Note:[/b] Unlike references to a [RefCounted], references to an Object " "stored in a variable can become invalid without warning. Therefore, it's " -"recommended to use [Reference] for data classes instead of [Object]." +"recommended to use [RefCounted] for data classes instead of [Object]." msgstr "" -#: doc/classes/Object.xml:23 doc/classes/Reference.xml:12 +#: doc/classes/Object.xml:23 doc/classes/RefCounted.xml:12 #: doc/classes/Resource.xml:11 msgid "" "https://docs.godotengine.org/en/latest/getting_started/workflow/" @@ -34594,7 +34594,7 @@ msgid "Changes the [Color] at the given index." msgstr "" #: doc/classes/PackedDataContainerRef.xml:4 -msgid "Reference version of [PackedDataContainer]." +msgid "RefCounted version of [PackedDataContainer]." msgstr "" #: doc/classes/PackedFloat32Array.xml:4 @@ -34728,7 +34728,7 @@ msgid "" "[codeblock]\n" "# Use `load()` instead of `preload()` if the path isn't known at compile-" "time.\n" -"var scene = preload(\"res://scene.tscn\").instance()\n" +"var scene = preload(\"res://scene.tscn\").instantiate()\n" "# Add the node as a child of the node the script is attached to.\n" "add_child(scene)\n" "[/codeblock]\n" @@ -41802,30 +41802,30 @@ msgid "" "the half extents." msgstr "" -#: doc/classes/Reference.xml:4 +#: doc/classes/RefCounted.xml:4 msgid "Base class for reference-counted objects." msgstr "" -#: doc/classes/Reference.xml:7 +#: doc/classes/RefCounted.xml:7 msgid "" "Base class for any object that keeps a reference count. [Resource] and many " "other helper objects inherit this class.\n" "Unlike [Object]s, References keep an internal reference counter so that they " "are automatically released when no longer in use, and only then. References " "therefore do not need to be freed manually with [method Object.free].\n" -"In the vast majority of use cases, instantiating and using [Reference]-" +"In the vast majority of use cases, instantiating and using [RefCounted]-" "derived types is all you need to do. The methods provided in this class are " "only for advanced users, and can cause issues if misused." msgstr "" -#: doc/classes/Reference.xml:19 +#: doc/classes/RefCounted.xml:19 msgid "" "Initializes the internal reference counter. Use this only if you really know " "what you are doing.\n" "Returns whether the initialization was successful." msgstr "" -#: doc/classes/Reference.xml:27 +#: doc/classes/RefCounted.xml:27 msgid "" "Increments the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -41833,7 +41833,7 @@ msgid "" "code] otherwise." msgstr "" -#: doc/classes/Reference.xml:35 +#: doc/classes/RefCounted.xml:35 msgid "" "Decrements the internal reference counter. Use this only if you really know " "what you are doing.\n" @@ -54098,7 +54098,7 @@ msgid "" "[codeblock]\n" "var foo = 2 # foo is dynamically an integer\n" "foo = \"Now foo is a string!\"\n" -"foo = Reference.new() # foo is an Object\n" +"foo = RefCounted.new() # foo is an Object\n" "var bar: int = 2 # bar is a statically typed integer.\n" "# bar = \"Uh oh! I can't make static variables become a different type!\"\n" "[/codeblock]\n" @@ -59181,7 +59181,7 @@ msgstr "" #: doc/classes/WeakRef.xml:7 msgid "" -"A weakref can hold a [Reference], without contributing to the reference " +"A weakref can hold a [RefCounted], without contributing to the reference " "counter. A weakref can be created from an [Object] using [method @GDScript." "weakref]. If this object is not a reference, weakref still works, however, " "it does not have any effect on the object. Weakrefs are useful in cases " diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 8b2e786146..f7f7f2dd22 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -59,7 +59,7 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) { Ref<Image> img; - img.instance(); + img.instantiate(); // the value of p_force_linear does not matter since it only applies to 16 bit Error err = PNGDriverCommon::png_to_image(p_png, p_size, false, img); @@ -101,6 +101,6 @@ Vector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { ImageLoaderPNG::ImageLoaderPNG() { Image::_png_mem_loader_func = load_mem_png; - Image::lossless_unpacker = lossless_unpack_png; - Image::lossless_packer = lossless_pack_png; + Image::png_unpacker = lossless_unpack_png; + Image::png_packer = lossless_pack_png; } diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index b737a287d1..2971880985 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -30,8 +30,8 @@ #include "resource_saver_png.h" +#include "core/io/file_access.h" #include "core/io/image.h" -#include "core/os/file_access.h" #include "drivers/png/png_driver_common.h" #include "scene/resources/texture.h" diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index 18262c74c4..83702ea2cc 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -40,7 +40,7 @@ void register_core_driver_types() { image_loader_png = memnew(ImageLoaderPNG); ImageLoader::add_image_format_loader(image_loader_png); - resource_saver_png.instance(); + resource_saver_png.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_png); } diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index 28a7053d25..8b19308967 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -33,7 +33,7 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include <dirent.h> #include <sys/stat.h> diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index ec23df62d0..6ea55219bb 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -264,7 +264,7 @@ void FileAccessUnix::store_8(uint8_t p_dest) { void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND_MSG(!f, "File must be opened before use."); - ERR_FAIL_COND(!p_src); + ERR_FAIL_COND(!p_src && p_length > 0); ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); } diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 5b1599c67f..8b27c308e1 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_UNIX_H #define FILE_ACCESS_UNIX_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/memory.h" #include <stdio.h> diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index e8f8ae4717..8a880ab9c8 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -41,19 +41,7 @@ #include <windows.h> #include <ws2tcpip.h> #ifndef UWP_ENABLED -#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4) -// MinGW-w64 on Ubuntu 12.04 (our Travis build env) has bugs in this code where -// some includes are missing in dependencies of iphlpapi.h for WINVER >= 0x0600 (Vista). -// We don't use this Vista code for now, so working it around by disabling it. -// MinGW-w64 >= 4.0 seems to be better judging by its headers. -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 // Windows XP, disable Vista API #include <iphlpapi.h> -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 // Re-enable Vista API -#else -#include <iphlpapi.h> -#endif // MINGW hack #endif #else // UNIX #include <netdb.h> diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 222aef998c..efeaf32ff7 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -466,7 +466,7 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { FD_ZERO(&ex); FD_SET(_sock, &ex); struct timeval timeout = { p_timeout / 1000, (p_timeout % 1000) * 1000 }; - // For blocking operation, pass nullptr timeout pointer to select. + // For blocking operation, pass nullptr timeout pointer to select. struct timeval *tp = nullptr; if (p_timeout >= 0) { // If timeout is non-negative, we want to specify the timeout instead. diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 15cd7bee92..a5c61bbea5 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -195,8 +195,8 @@ OS::Time OS_Unix::get_time(bool utc) const { } Time ret; ret.hour = lt.tm_hour; - ret.min = lt.tm_min; - ret.sec = lt.tm_sec; + ret.minute = lt.tm_min; + ret.second = lt.tm_sec; get_time_zone_info(); return ret; } diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 43b2a24172..d3d49503d8 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -31,7 +31,7 @@ #include "rendering_device_vulkan.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "core/templates/hashfuncs.h" #include "drivers/vulkan/vulkan_context.h" @@ -1398,12 +1398,15 @@ Error RenderingDeviceVulkan::_buffer_allocate(Buffer *p_buffer, uint32_t p_size, p_buffer->buffer_info.range = p_size; p_buffer->usage = p_usage; + buffer_memory += p_size; + return OK; } Error RenderingDeviceVulkan::_buffer_free(Buffer *p_buffer) { ERR_FAIL_COND_V(p_buffer->size == 0, ERR_INVALID_PARAMETER); + buffer_memory -= p_buffer->size; vmaDestroyBuffer(allocator, p_buffer->buffer, p_buffer->allocation); p_buffer->buffer = VK_NULL_HANDLE; p_buffer->allocation = nullptr; @@ -1896,7 +1899,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T VkResult err = vmaCreateImage(allocator, &image_create_info, &allocInfo, &texture.image, &texture.allocation, &texture.allocation_info); ERR_FAIL_COND_V_MSG(err, RID(), "vmaCreateImage failed with error " + itos(err) + "."); - + image_memory += texture.allocation_info.size; texture.type = p_format.texture_type; texture.format = p_format.format; texture.width = image_create_info.extent.width; @@ -2029,7 +2032,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_data.size()) { for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { - texture_update(id, i, p_data[i]); + _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL, true); } } return id; @@ -2276,10 +2279,14 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p } Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) { + return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false); +} + +Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V_MSG(draw_list || compute_list, ERR_INVALID_PARAMETER, - "Updating textures in is forbidden during creation of a draw or compute list"); + ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER, + "Updating textures is forbidden during creation of a draw or compute list"); Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER); @@ -2320,7 +2327,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con const uint8_t *r = p_data.ptr(); - VkCommandBuffer command_buffer = p_post_barrier ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + VkCommandBuffer command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer; //barrier to transfer { @@ -2373,7 +2380,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); uint32_t alloc_offset, alloc_size; - Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, p_post_barrier); + Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, !p_use_setup_queue); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); uint8_t *write_ptr; @@ -3244,12 +3251,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f /**** ATTACHMENT ****/ /********************/ -VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) { - Vector<VkAttachmentDescription> attachments; - Vector<VkAttachmentReference> color_references; - Vector<VkAttachmentReference> depth_stencil_references; - Vector<VkAttachmentReference> resolve_references; - +VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count, Vector<TextureSamples> *r_samples) { // Set up dependencies from/to external equivalent to the default (implicit) one, and then amend them const VkPipelineStageFlags default_access_mask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | @@ -3262,27 +3264,31 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF { 0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, default_access_mask, 0, 0 } }; VkSubpassDependency &dependency_from_external = dependencies[0]; VkSubpassDependency &dependency_to_external = dependencies[1]; + LocalVector<int32_t> attachment_last_pass; + attachment_last_pass.resize(p_attachments.size()); - for (int i = 0; i < p_format.size(); i++) { - ERR_FAIL_INDEX_V(p_format[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); - ERR_FAIL_INDEX_V(p_format[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); - ERR_FAIL_COND_V_MSG(!(p_format[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), + Vector<VkAttachmentDescription> attachments; + + for (int i = 0; i < p_attachments.size(); i++) { + ERR_FAIL_INDEX_V(p_attachments[i].format, DATA_FORMAT_MAX, VK_NULL_HANDLE); + ERR_FAIL_INDEX_V(p_attachments[i].samples, TEXTURE_SAMPLES_MAX, VK_NULL_HANDLE); + ERR_FAIL_COND_V_MSG(!(p_attachments[i].usage_flags & (TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT)), VK_NULL_HANDLE, "Texture format for index (" + itos(i) + ") requires an attachment (depth, stencil or resolve) bit set."); VkAttachmentDescription description = {}; description.flags = 0; - description.format = vulkan_formats[p_format[i].format]; - description.samples = rasterization_sample_count[p_format[i].samples]; + description.format = vulkan_formats[p_attachments[i].format]; + description.samples = rasterization_sample_count[p_attachments[i].samples]; - bool is_depth_stencil = p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - bool is_sampled = p_format[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT; - bool is_storage = p_format[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT; + bool is_sampled = p_attachments[i].usage_flags & TEXTURE_USAGE_SAMPLING_BIT; + bool is_storage = p_attachments[i].usage_flags & TEXTURE_USAGE_STORAGE_BIT; + bool is_depth = p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; // For each UNDEFINED, assume the prior use was a *read*, as we'd be discarding the output of a write // Also, each UNDEFINED will do an immediate layout transition (write), s.t. we must ensure execution synchronization vs. - // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that + // the read. If this is a performance issue, one could track the actual last accessor of each resource, adding only that // stage - switch (is_depth_stencil ? p_initial_depth_action : p_initial_color_action) { + switch (is_depth ? p_initial_depth_action : p_initial_action) { case INITIAL_ACTION_CLEAR_REGION: case INITIAL_ACTION_CLEAR: { description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; @@ -3291,11 +3297,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF dependency_from_external.srcStageMask |= reading_stages; } break; case INITIAL_ACTION_KEEP: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; @@ -3308,11 +3314,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } break; case INITIAL_ACTION_DROP: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; //don't care what is there description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; @@ -3326,11 +3332,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } break; case INITIAL_ACTION_CLEAR_REGION_CONTINUE: case INITIAL_ACTION_CONTINUE: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; description.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { description.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; description.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; @@ -3346,14 +3352,14 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } - switch (is_depth_stencil ? p_final_depth_action : p_final_color_action) { + switch (is_depth ? p_final_depth_action : p_final_action) { case FINAL_ACTION_READ: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); update_external_dependency_for_store(dependency_to_external, is_sampled, is_storage, false); - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); @@ -3366,11 +3372,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } break; case FINAL_ACTION_DISCARD: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = is_sampled ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : (is_storage ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); @@ -3381,11 +3387,11 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } break; case FINAL_ACTION_CONTINUE: { - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + if (p_attachments[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; description.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + } else if (p_attachments[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { description.storeOp = VK_ATTACHMENT_STORE_OP_STORE; description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; description.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; @@ -3401,27 +3407,194 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF } } + attachment_last_pass[i] = -1; + attachments.push_back(description); + } + + LocalVector<VkSubpassDescription> subpasses; + LocalVector<LocalVector<VkAttachmentReference>> color_reference_array; + LocalVector<LocalVector<VkAttachmentReference>> input_reference_array; + LocalVector<LocalVector<VkAttachmentReference>> resolve_reference_array; + LocalVector<LocalVector<uint32_t>> preserve_reference_array; + LocalVector<VkAttachmentReference> depth_reference_array; + + subpasses.resize(p_passes.size()); + color_reference_array.resize(p_passes.size()); + input_reference_array.resize(p_passes.size()); + resolve_reference_array.resize(p_passes.size()); + preserve_reference_array.resize(p_passes.size()); + depth_reference_array.resize(p_passes.size()); + + LocalVector<VkSubpassDependency> subpass_dependencies; + + for (int i = 0; i < p_passes.size(); i++) { + const FramebufferPass *pass = &p_passes[i]; - VkAttachmentReference reference; - reference.attachment = i; + LocalVector<VkAttachmentReference> &color_references = color_reference_array[i]; - if (p_format[i].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { - reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + TextureSamples texture_samples = TEXTURE_SAMPLES_1; + bool is_multisample_first = true; + + for (int j = 0; j < pass->color_attachments.size(); j++) { + int32_t attachment = pass->color_attachments[j]; + VkAttachmentReference reference; + if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { + reference.attachment = VK_ATTACHMENT_UNUSED; + reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; + } else { + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), color attachment (" + itos(j) + ")."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as color attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + + if (is_multisample_first) { + texture_samples = p_attachments[attachment].samples; + is_multisample_first = false; + } else { + ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples."); + } + reference.attachment = attachment; + reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachment_last_pass[attachment] = i; + } color_references.push_back(reference); - } else if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { - reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - depth_stencil_references.push_back(reference); - } else if (p_format[i].usage_flags & TEXTURE_USAGE_RESOLVE_ATTACHMENT_BIT) { - reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + + LocalVector<VkAttachmentReference> &input_references = input_reference_array[i]; + + for (int j = 0; j < pass->input_attachments.size(); j++) { + int32_t attachment = pass->input_attachments[j]; + VkAttachmentReference reference; + if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { + reference.attachment = VK_ATTACHMENT_UNUSED; + reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; + } else { + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), input attachment (" + itos(j) + ")."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as input attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + reference.attachment = attachment; + reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + attachment_last_pass[attachment] = i; + } + input_references.push_back(reference); + } + + LocalVector<VkAttachmentReference> &resolve_references = resolve_reference_array[i]; + + if (pass->resolve_attachments.size() > 0) { + ERR_FAIL_COND_V_MSG(pass->resolve_attachments.size() != pass->color_attachments.size(), VK_NULL_HANDLE, "The amount of resolve attachments (" + itos(pass->resolve_attachments.size()) + ") must match the number of color attachments (" + itos(pass->color_attachments.size()) + ")."); + ERR_FAIL_COND_V_MSG(texture_samples == TEXTURE_SAMPLES_1, VK_NULL_HANDLE, "Resolve attachments specified, but color attachments are not multisample."); + } + for (int j = 0; j < pass->resolve_attachments.size(); j++) { + int32_t attachment = pass->resolve_attachments[j]; + VkAttachmentReference reference; + if (attachment == FramebufferPass::ATTACHMENT_UNUSED) { + reference.attachment = VK_ATTACHMENT_UNUSED; + reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; + } else { + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + ")."); + ERR_FAIL_COND_V_MSG(pass->color_attachments[j] == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachment (" + itos(j) + "), the respective color attachment is marked as unused."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not usable as resolve attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + bool multisample = p_attachments[attachment].samples > TEXTURE_SAMPLES_1; + ERR_FAIL_COND_V_MSG(multisample, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), resolve attachments can't be multisample."); + reference.attachment = attachment; + reference.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + attachment_last_pass[attachment] = i; + } resolve_references.push_back(reference); - // if resolves are done, we need to ensure the copy is safe - dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_TRANSFER_BIT; - dependency_to_external.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; + } + + LocalVector<uint32_t> &preserve_references = preserve_reference_array[i]; + + for (int j = 0; j < pass->preserve_attachments.size(); j++) { + int32_t attachment = pass->preserve_attachments[j]; + + ERR_FAIL_COND_V_MSG(attachment == FramebufferPass::ATTACHMENT_UNUSED, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + "). Preserve attachments can't be unused."); + + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), preserve attachment (" + itos(j) + ")."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + + attachment_last_pass[attachment] = i; + + preserve_references.push_back(attachment); + } + + VkAttachmentReference &depth_stencil_reference = depth_reference_array[i]; + + if (pass->depth_attachment != FramebufferPass::ATTACHMENT_UNUSED) { + int32_t attachment = pass->depth_attachment; + ERR_FAIL_INDEX_V_MSG(attachment, p_attachments.size(), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), depth attachment."); + ERR_FAIL_COND_V_MSG(!(p_attachments[attachment].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT), VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it's marked as depth, but it's not a depth attachment."); + ERR_FAIL_COND_V_MSG(attachment_last_pass[attachment] == i, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), it already was used for something else before in this pass."); + depth_stencil_reference.attachment = attachment; + depth_stencil_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachment_last_pass[attachment] = i; + + if (is_multisample_first) { + texture_samples = p_attachments[attachment].samples; + is_multisample_first = false; + } else { + ERR_FAIL_COND_V_MSG(texture_samples != p_attachments[attachment].samples, VK_NULL_HANDLE, "Invalid framebuffer depth format attachment(" + itos(attachment) + "), in pass (" + itos(i) + "), if an attachment is marked as multisample, all of them should be multisample and use the same number of samples including the depth."); + } + + } else { + depth_stencil_reference.attachment = VK_ATTACHMENT_UNUSED; + depth_stencil_reference.layout = VK_IMAGE_LAYOUT_UNDEFINED; + } + + VkSubpassDescription &subpass = subpasses[i]; + subpass.flags = 0; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.inputAttachmentCount = input_references.size(); + if (input_references.size()) { + subpass.pInputAttachments = input_references.ptr(); + } else { + subpass.pInputAttachments = nullptr; + } + subpass.colorAttachmentCount = color_references.size(); + if (color_references.size()) { + subpass.pColorAttachments = color_references.ptr(); + } else { + subpass.pColorAttachments = nullptr; + } + if (depth_stencil_reference.attachment != VK_ATTACHMENT_UNUSED) { + subpass.pDepthStencilAttachment = &depth_stencil_reference; + } else { + subpass.pDepthStencilAttachment = nullptr; + } + + if (resolve_references.size()) { + subpass.pResolveAttachments = resolve_references.ptr(); } else { - ERR_FAIL_V_MSG(VK_NULL_HANDLE, "Texture index " + itos(i) + " is neither color, depth stencil or resolve so it can't be used as attachment."); + subpass.pResolveAttachments = nullptr; } + subpass.preserveAttachmentCount = preserve_references.size(); + if (preserve_references.size()) { + subpass.pPreserveAttachments = preserve_references.ptr(); + } else { + subpass.pPreserveAttachments = nullptr; + } + + if (r_samples) { + r_samples->push_back(texture_samples); + } + + if (i > 0) { + VkSubpassDependency dependency; + dependency.srcSubpass = i - 1; + dependency.dstSubpass = i; + dependency.srcStageMask = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + + dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + subpass_dependencies.push_back(dependency); + } + /* // NOTE: Big Mallet Approach -- any layout transition causes a full barrier if (reference.layout != description.initialLayout) { // NOTE: this should be smarter based on the texture's knowledge of its previous role @@ -3433,57 +3606,82 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF dependency_to_external.dstStageMask |= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; dependency_to_external.dstAccessMask |= VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; } + */ } - ERR_FAIL_COND_V_MSG(depth_stencil_references.size() > 1, VK_NULL_HANDLE, - "Formats can only have one depth/stencil attachment, supplied (" + itos(depth_stencil_references.size()) + ")."); - - ERR_FAIL_COND_V_MSG(resolve_references.size() > 1, VK_NULL_HANDLE, - "Formats can only have one resolve attachment, supplied (" + itos(resolve_references.size()) + ")."); - - VkSubpassDescription subpass; - subpass.flags = 0; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.inputAttachmentCount = 0; //unsupported for now - subpass.pInputAttachments = nullptr; - subpass.colorAttachmentCount = color_references.size(); - subpass.pColorAttachments = color_references.ptr(); - subpass.pDepthStencilAttachment = depth_stencil_references.ptr(); - subpass.pResolveAttachments = resolve_references.ptr(); - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = nullptr; - VkRenderPassCreateInfo render_pass_create_info; render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; render_pass_create_info.pNext = nullptr; render_pass_create_info.flags = 0; render_pass_create_info.attachmentCount = attachments.size(); render_pass_create_info.pAttachments = attachments.ptr(); - render_pass_create_info.subpassCount = 1; - render_pass_create_info.pSubpasses = &subpass; + render_pass_create_info.subpassCount = subpasses.size(); + render_pass_create_info.pSubpasses = subpasses.ptr(); // Commenting this because it seems it just avoids raster and compute to work at the same time. // Other barriers seem to be protecting the render pass fine. // render_pass_create_info.dependencyCount = 2; // render_pass_create_info.pDependencies = dependencies; - render_pass_create_info.dependencyCount = 0; - render_pass_create_info.pDependencies = nullptr; + render_pass_create_info.dependencyCount = subpass_dependencies.size(); + if (subpass_dependencies.size()) { + render_pass_create_info.pDependencies = subpass_dependencies.ptr(); + } else { + render_pass_create_info.pDependencies = nullptr; + } + + const uint32_t view_mask = (1 << p_view_count) - 1; + const uint32_t correlation_mask = (1 << p_view_count) - 1; + VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info; + + if (p_view_count > 1) { + const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities(); + + // For now this only works with multiview! + ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported"); + + // Make sure we limit this to the number of views we support. + ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass"); + + render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO; + render_pass_multiview_create_info.pNext = nullptr; + render_pass_multiview_create_info.subpassCount = 1; + render_pass_multiview_create_info.pViewMasks = &view_mask; + render_pass_multiview_create_info.dependencyCount = 0; + render_pass_multiview_create_info.pViewOffsets = nullptr; + render_pass_multiview_create_info.correlationMaskCount = 1; + render_pass_multiview_create_info.pCorrelationMasks = &correlation_mask; + + render_pass_create_info.pNext = &render_pass_multiview_create_info; + } VkRenderPass render_pass; VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass); ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass failed with error " + itos(res) + "."); - if (r_color_attachment_count) { - *r_color_attachment_count = color_references.size(); - } return render_pass; } -RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format) { +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count) { + FramebufferPass pass; + for (int i = 0; i < p_format.size(); i++) { + if (p_format[i].usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + pass.depth_attachment = i; + } else { + pass.color_attachments.push_back(i); + } + } + + Vector<FramebufferPass> passes; + passes.push_back(pass); + return framebuffer_format_create_multipass(p_format, passes, p_view_count); +} +RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count) { _THREAD_SAFE_METHOD_ FramebufferFormatKey key; - key.attachments = p_format; + key.attachments = p_attachments; + key.passes = p_passes; + key.view_count = p_view_count; const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key); if (E) { @@ -3491,8 +3689,8 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c return E->get(); } - int color_references; - VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, &color_references); //actions don't matter for this use case + Vector<TextureSamples> samples; + VkRenderPass render_pass = _render_pass_create(p_attachments, p_passes, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, p_view_count, &samples); //actions don't matter for this use case if (render_pass == VK_NULL_HANDLE) { //was likely invalid return INVALID_ID; @@ -3502,15 +3700,16 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c E = framebuffer_format_cache.insert(key, id); FramebufferFormat fb_format; fb_format.E = E; - fb_format.color_attachments = color_references; fb_format.render_pass = render_pass; - fb_format.samples = p_format[0].samples; + fb_format.pass_samples = samples; + fb_format.view_count = p_view_count; framebuffer_formats[id] = fb_format; return id; } RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create_empty(TextureSamples p_samples) { FramebufferFormatKey key; + key.passes.push_back(FramebufferPass()); const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key); if (E) { @@ -3556,18 +3755,18 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c FramebufferFormat fb_format; fb_format.E = E; - fb_format.color_attachments = 0; fb_format.render_pass = render_pass; - fb_format.samples = p_samples; + fb_format.pass_samples.push_back(p_samples); framebuffer_formats[id] = fb_format; return id; } -RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format) { +RenderingDevice::TextureSamples RenderingDeviceVulkan::framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass) { Map<FramebufferFormatID, FramebufferFormat>::Element *E = framebuffer_formats.find(p_format); ERR_FAIL_COND_V(!E, TEXTURE_SAMPLES_1); + ERR_FAIL_COND_V(p_pass >= uint32_t(E->get().pass_samples.size()), TEXTURE_SAMPLES_1); - return E->get().samples; + return E->get().pass_samples[p_pass]; } /***********************/ @@ -3580,11 +3779,36 @@ RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, Textur framebuffer.format_id = framebuffer_format_create_empty(p_samples); ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID()); framebuffer.size = p_size; + framebuffer.view_count = 1; return framebuffer_owner.make_rid(framebuffer); } -RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check) { +RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) { + _THREAD_SAFE_METHOD_ + + FramebufferPass pass; + + for (int i = 0; i < p_texture_attachments.size(); i++) { + Texture *texture = texture_owner.getornull(p_texture_attachments[i]); + ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer"); + + if (texture->usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { + pass.depth_attachment = i; + } else { + pass.color_attachments.push_back(i); + } + } + + Vector<FramebufferPass> passes; + passes.push_back(pass); + + return framebuffer_create_multipass(p_texture_attachments, passes, p_format_check, p_view_count); +} + +RID RenderingDeviceVulkan::framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { _THREAD_SAFE_METHOD_ Vector<AttachmentFormat> attachments; @@ -3594,6 +3818,8 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac Texture *texture = texture_owner.getornull(p_texture_attachments[i]); ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture."); + ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer"); + if (i == 0) { size.width = texture->width; size.height = texture->height; @@ -3609,7 +3835,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac attachments.push_back(af); } - FramebufferFormatID format_id = framebuffer_format_create(attachments); + FramebufferFormatID format_id = framebuffer_format_create_multipass(attachments, p_passes, p_view_count); if (format_id == INVALID_ID) { return RID(); } @@ -3621,6 +3847,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac framebuffer.format_id = format_id; framebuffer.texture_ids = p_texture_attachments; framebuffer.size = size; + framebuffer.view_count = p_view_count; RID id = framebuffer_owner.make_rid(framebuffer); @@ -4147,6 +4374,8 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages uint32_t stages_processed = 0; + Vector<Shader::SpecializationConstant> specialization_constants; + bool is_compute = false; uint32_t compute_local_size[3] = { 0, 0, 0 }; @@ -4333,6 +4562,62 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages } } + { + //specialization constants + + uint32_t sc_count = 0; + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating specialization constants."); + + if (sc_count) { + Vector<SpvReflectSpecializationConstant *> spec_constants; + spec_constants.resize(sc_count); + + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining specialization constants."); + + for (uint32_t j = 0; j < sc_count; j++) { + int32_t existing = -1; + Shader::SpecializationConstant sconst; + sconst.constant.constant_id = spec_constants[j]->constant_id; + switch (spec_constants[j]->constant_type) { + case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sconst.constant.bool_value = spec_constants[j]->default_value.int_bool_value != 0; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + sconst.constant.int_value = spec_constants[j]->default_value.int_bool_value; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; + sconst.constant.float_value = spec_constants[j]->default_value.float_value; + } break; + } + sconst.stage_flags = 1 << p_stages[i].shader_stage; + + print_line("spec constant " + itos(i) + ": " + String(spec_constants[j]->name) + " type " + itos(spec_constants[j]->constant_type) + " id " + itos(spec_constants[j]->constant_id)); + + for (int k = 0; k < specialization_constants.size(); k++) { + if (specialization_constants[k].constant.constant_id == sconst.constant.constant_id) { + ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.type != sconst.constant.type, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their types differ."); + ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.int_value != sconst.constant.int_value, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their default values differ."); + existing = k; + break; + } + } + + if (existing > 0) { + specialization_constants.write[existing].stage_flags |= sconst.stage_flags; + } else { + specialization_constants.push_back(sconst); + } + } + } + } + if (stage == SHADER_STAGE_VERTEX) { uint32_t iv_count = 0; result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr); @@ -4370,8 +4655,9 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining output variables."); for (uint32_t j = 0; j < ov_count; j++) { - if (output_vars[j]) { - fragment_outputs = MAX(fragment_outputs, output_vars[j]->location + 1); + const SpvReflectInterfaceVariable *refvar = output_vars[j]; + if (refvar != nullptr && refvar->built_in != SpvBuiltInFragDepth) { + fragment_outputs |= 1 << refvar->location; } } } @@ -4422,12 +4708,13 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages Shader shader; shader.vertex_input_mask = vertex_input_mask; - shader.fragment_outputs = fragment_outputs; + shader.fragment_output_mask = fragment_outputs; shader.push_constant = push_constant; shader.is_compute = is_compute; shader.compute_local_size[0] = compute_local_size[0]; shader.compute_local_size[1] = compute_local_size[1]; shader.compute_local_size[2] = compute_local_size[2]; + shader.specialization_constants = specialization_constants; String error_text; @@ -5163,6 +5450,49 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms, write.pTexelBufferView = nullptr; } break; case UNIFORM_TYPE_INPUT_ATTACHMENT: { + ERR_FAIL_COND_V_MSG(shader->is_compute, RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") supplied for compute shader (this is not allowed)."); + + if (uniform.ids.size() != set_uniform.length) { + if (set_uniform.length > 1) { + ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") is an array of (" + itos(set_uniform.length) + ") textures, so it should be provided equal number of texture IDs to satisfy it (IDs provided: " + itos(uniform.ids.size()) + ")."); + } else { + ERR_FAIL_V_MSG(RID(), "InputAttachment (binding: " + itos(uniform.binding) + ") should provide one ID referencing a texture (IDs provided: " + itos(uniform.ids.size()) + ")."); + } + } + + Vector<VkDescriptorImageInfo> image_info; + + for (int j = 0; j < uniform.ids.size(); j++) { + Texture *texture = texture_owner.getornull(uniform.ids[j]); + + ERR_FAIL_COND_V_MSG(!texture, RID(), + "InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture."); + + ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(), + "InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform."); + + VkDescriptorImageInfo img_info; + img_info.sampler = VK_NULL_HANDLE; + img_info.imageView = texture->view; + + if (texture->owner.is_valid()) { + texture = texture_owner.getornull(texture->owner); + ERR_FAIL_COND_V(!texture, RID()); //bug, should never happen + } + + img_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_info.push_back(img_info); + } + + write.dstArrayElement = 0; + write.descriptorCount = uniform.ids.size(); + write.descriptorType = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + write.pImageInfo = image_infos.push_back(image_info)->get().ptr(); + write.pBufferInfo = nullptr; + write.pTexelBufferView = nullptr; + + type_size = uniform.ids.size(); } break; default: { } @@ -5234,6 +5564,13 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { return uniform_set_owner.owns(p_uniform_set); } +void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) { + UniformSet *us = uniform_set_owner.getornull(p_uniform_set); + ERR_FAIL_COND(!us); + us->invalidated_callback = p_callback; + us->invalidated_callback_userdata = p_userdata; +} + Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier) { _THREAD_SAFE_METHOD_ @@ -5373,7 +5710,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { /**** RENDER PIPELINE ****/ /*************************/ -RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags) { +RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { _THREAD_SAFE_METHOD_ //needs a shader @@ -5392,8 +5729,16 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma { //validate shader vs framebuffer - ERR_FAIL_COND_V_MSG(shader->fragment_outputs != fb_format.color_attachments, RID(), - "Mismatch fragment output bindings (" + itos(shader->fragment_outputs) + ") and framebuffer color buffers (" + itos(fb_format.color_attachments) + ") when binding both in render pipeline."); + ERR_FAIL_COND_V_MSG(p_for_render_pass >= uint32_t(fb_format.E->key().passes.size()), RID(), "Render pass requested for pipeline creation (" + itos(p_for_render_pass) + ") is out of bounds"); + const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass]; + uint32_t output_mask = 0; + for (int i = 0; i < pass.color_attachments.size(); i++) { + if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) { + output_mask |= 1 << i; + } + } + ERR_FAIL_COND_V_MSG(shader->fragment_output_mask != output_mask, RID(), + "Mismatch fragment shader output mask (" + itos(shader->fragment_output_mask) + ") and framebuffer color output mask (" + itos(output_mask) + ") when binding both in render pipeline."); } //vertex VkPipelineVertexInputStateCreateInfo pipeline_vertex_input_state_create_info; @@ -5578,44 +5923,53 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma ERR_FAIL_INDEX_V(p_blend_state.logic_op, LOGIC_OP_MAX, RID()); color_blend_state_create_info.logicOp = logic_operations[p_blend_state.logic_op]; - ERR_FAIL_COND_V(fb_format.color_attachments != p_blend_state.attachments.size(), RID()); - Vector<VkPipelineColorBlendAttachmentState> attachment_states; + { + const FramebufferPass &pass = fb_format.E->key().passes[p_for_render_pass]; + + for (int i = 0; i < pass.color_attachments.size(); i++) { + if (pass.color_attachments[i] != FramebufferPass::ATTACHMENT_UNUSED) { + int idx = attachment_states.size(); + + ERR_FAIL_INDEX_V(idx, p_blend_state.attachments.size(), RID()); + VkPipelineColorBlendAttachmentState state; + state.blendEnable = p_blend_state.attachments[idx].enable_blend; + + ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].src_color_blend_factor, BLEND_FACTOR_MAX, RID()); + state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[idx].src_color_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].dst_color_blend_factor, BLEND_FACTOR_MAX, RID()); + state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[idx].dst_color_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].color_blend_op, BLEND_OP_MAX, RID()); + state.colorBlendOp = blend_operations[p_blend_state.attachments[idx].color_blend_op]; + + ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); + state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[idx].src_alpha_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); + state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[idx].dst_alpha_blend_factor]; + ERR_FAIL_INDEX_V(p_blend_state.attachments[idx].alpha_blend_op, BLEND_OP_MAX, RID()); + state.alphaBlendOp = blend_operations[p_blend_state.attachments[idx].alpha_blend_op]; + + state.colorWriteMask = 0; + if (p_blend_state.attachments[idx].write_r) { + state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; + } + if (p_blend_state.attachments[idx].write_g) { + state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; + } + if (p_blend_state.attachments[idx].write_b) { + state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; + } + if (p_blend_state.attachments[idx].write_a) { + state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; + } - for (int i = 0; i < p_blend_state.attachments.size(); i++) { - VkPipelineColorBlendAttachmentState state; - state.blendEnable = p_blend_state.attachments[i].enable_blend; - - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_color_blend_factor, BLEND_FACTOR_MAX, RID()); - state.srcColorBlendFactor = blend_factors[p_blend_state.attachments[i].src_color_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_color_blend_factor, BLEND_FACTOR_MAX, RID()); - state.dstColorBlendFactor = blend_factors[p_blend_state.attachments[i].dst_color_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].color_blend_op, BLEND_OP_MAX, RID()); - state.colorBlendOp = blend_operations[p_blend_state.attachments[i].color_blend_op]; - - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].src_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); - state.srcAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].src_alpha_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].dst_alpha_blend_factor, BLEND_FACTOR_MAX, RID()); - state.dstAlphaBlendFactor = blend_factors[p_blend_state.attachments[i].dst_alpha_blend_factor]; - ERR_FAIL_INDEX_V(p_blend_state.attachments[i].alpha_blend_op, BLEND_OP_MAX, RID()); - state.alphaBlendOp = blend_operations[p_blend_state.attachments[i].alpha_blend_op]; - - state.colorWriteMask = 0; - if (p_blend_state.attachments[i].write_r) { - state.colorWriteMask |= VK_COLOR_COMPONENT_R_BIT; - } - if (p_blend_state.attachments[i].write_g) { - state.colorWriteMask |= VK_COLOR_COMPONENT_G_BIT; - } - if (p_blend_state.attachments[i].write_b) { - state.colorWriteMask |= VK_COLOR_COMPONENT_B_BIT; - } - if (p_blend_state.attachments[i].write_a) { - state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT; + attachment_states.push_back(state); + idx++; + }; } - attachment_states.push_back(state); - }; + ERR_FAIL_COND_V(attachment_states.size() != p_blend_state.attachments.size(), RID()); + } color_blend_state_create_info.attachmentCount = attachment_states.size(); color_blend_state_create_info.pAttachments = attachment_states.ptr(); @@ -5674,8 +6028,63 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma graphics_pipeline_create_info.pNext = nullptr; graphics_pipeline_create_info.flags = 0; - graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size(); - graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); + Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages; + Vector<VkSpecializationInfo> specialization_info; + Vector<Vector<VkSpecializationMapEntry>> specialization_map_entries; + Vector<uint32_t> specialization_constant_data; + + if (shader->specialization_constants.size()) { + specialization_constant_data.resize(shader->specialization_constants.size()); + uint32_t *data_ptr = specialization_constant_data.ptrw(); + specialization_info.resize(pipeline_stages.size()); + specialization_map_entries.resize(pipeline_stages.size()); + for (int i = 0; i < shader->specialization_constants.size(); i++) { + //see if overriden + const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; + data_ptr[i] = sc.constant.int_value; //just copy the 32 bits + + for (int j = 0; j < p_specialization_constants.size(); j++) { + const PipelineSpecializationConstant &psc = p_specialization_constants[j]; + if (psc.constant_id == sc.constant.constant_id) { + ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); + data_ptr[i] = sc.constant.int_value; + break; + } + } + + VkSpecializationMapEntry entry; + + entry.constantID = sc.constant.constant_id; + entry.offset = i * sizeof(uint32_t); + entry.size = sizeof(uint32_t); + + for (int j = 0; j < SHADER_STAGE_MAX; j++) { + if (sc.stage_flags & (1 << j)) { + VkShaderStageFlagBits stage = shader_stage_masks[j]; + for (int k = 0; k < pipeline_stages.size(); k++) { + if (pipeline_stages[k].stage == stage) { + specialization_map_entries.write[k].push_back(entry); + } + } + } + } + } + + for (int k = 0; k < pipeline_stages.size(); k++) { + if (specialization_map_entries[k].size()) { + specialization_info.write[k].dataSize = specialization_constant_data.size() * sizeof(uint32_t); + specialization_info.write[k].pData = data_ptr; + specialization_info.write[k].mapEntryCount = specialization_map_entries[k].size(); + specialization_info.write[k].pMapEntries = specialization_map_entries[k].ptr(); + + pipeline_stages.write[k].pSpecializationInfo = specialization_info.ptr(); + } + } + } + + graphics_pipeline_create_info.stageCount = pipeline_stages.size(); + graphics_pipeline_create_info.pStages = pipeline_stages.ptr(); + graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; graphics_pipeline_create_info.pTessellationState = &tessellation_create_info; @@ -5688,7 +6097,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma graphics_pipeline_create_info.layout = shader->pipeline_layout; graphics_pipeline_create_info.renderPass = fb_format.render_pass; - graphics_pipeline_create_info.subpass = 0; + graphics_pipeline_create_info.subpass = p_for_render_pass; graphics_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; graphics_pipeline_create_info.basePipelineIndex = 0; @@ -5705,6 +6114,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma #ifdef DEBUG_ENABLED pipeline.validation.dynamic_state = p_dynamic_state_flags; pipeline.validation.framebuffer_format = p_framebuffer_format; + pipeline.validation.render_pass = p_for_render_pass; pipeline.validation.vertex_format = p_vertex_format; pipeline.validation.uses_restart_indices = input_assembly_create_info.primitiveRestartEnable; @@ -5743,7 +6153,7 @@ bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { /**** COMPUTE PIPELINE ****/ /**************************/ -RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { +RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { _THREAD_SAFE_METHOD_ //needs a shader @@ -5765,6 +6175,44 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; compute_pipeline_create_info.basePipelineIndex = 0; + VkSpecializationInfo specialization_info; + Vector<VkSpecializationMapEntry> specialization_map_entries; + Vector<uint32_t> specialization_constant_data; + + if (shader->specialization_constants.size()) { + specialization_constant_data.resize(shader->specialization_constants.size()); + uint32_t *data_ptr = specialization_constant_data.ptrw(); + for (int i = 0; i < shader->specialization_constants.size(); i++) { + //see if overriden + const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; + data_ptr[i] = sc.constant.int_value; //just copy the 32 bits + + for (int j = 0; j < p_specialization_constants.size(); j++) { + const PipelineSpecializationConstant &psc = p_specialization_constants[j]; + if (psc.constant_id == sc.constant.constant_id) { + ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); + data_ptr[i] = sc.constant.int_value; + break; + } + } + + VkSpecializationMapEntry entry; + + entry.constantID = sc.constant.constant_id; + entry.offset = i * sizeof(uint32_t); + entry.size = sizeof(uint32_t); + + specialization_map_entries.push_back(entry); + } + + specialization_info.dataSize = specialization_constant_data.size() * sizeof(uint32_t); + specialization_info.pData = data_ptr; + specialization_info.mapEntryCount = specialization_map_entries.size(); + specialization_info.pMapEntries = specialization_map_entries.ptr(); + + compute_pipeline_create_info.stage.pSpecializationInfo = &specialization_info; + } + ComputePipeline pipeline; VkResult err = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline); ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + "."); @@ -5843,13 +6291,14 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di ERR_FAIL_COND_V_MSG(compute_list != nullptr, INVALID_ID, "Only one draw/compute list can be active at the same time."); VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; - draw_list = memnew(DrawList); - draw_list->command_buffer = command_buffer; + + Size2i size = Size2i(context->window_get_width(p_screen), context->window_get_height(p_screen)); + + _draw_list_allocate(Rect2i(Vector2i(), size), 0, 0); #ifdef DEBUG_ENABLED - draw_list->validation.framebuffer_format = screen_get_framebuffer_format(); + draw_list_framebuffer_format = screen_get_framebuffer_format(); #endif - draw_list_count = 0; - draw_list_split = false; + draw_list_subpass_count = 1; VkRenderPassBeginInfo render_pass_begin; render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; @@ -5857,8 +6306,8 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di render_pass_begin.renderPass = context->window_get_render_pass(p_screen); render_pass_begin.framebuffer = context->window_get_framebuffer(p_screen); - render_pass_begin.renderArea.extent.width = context->window_get_width(p_screen); - render_pass_begin.renderArea.extent.height = context->window_get_height(p_screen); + render_pass_begin.renderArea.extent.width = size.width; + render_pass_begin.renderArea.extent.height = size.height; render_pass_begin.renderArea.offset.x = 0; render_pass_begin.renderArea.offset.y = 0; @@ -5898,18 +6347,19 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin_for_screen(Di return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } -Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass) { +Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count) { Framebuffer::VersionKey vk; vk.initial_color_action = p_initial_color_action; vk.final_color_action = p_final_color_action; vk.initial_depth_action = p_initial_depth_action; vk.final_depth_action = p_final_depth_action; + vk.view_count = p_framebuffer->view_count; if (!p_framebuffer->framebuffers.has(vk)) { //need to create this version Framebuffer::Version version; - version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action); + version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, framebuffer_formats[p_framebuffer->format_id].E->key().passes, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, p_framebuffer->view_count); VkFramebufferCreateInfo framebuffer_create_info; framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; @@ -5933,11 +6383,14 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu VkResult err = vkCreateFramebuffer(device, &framebuffer_create_info, nullptr, &version.framebuffer); ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkCreateFramebuffer failed with error " + itos(err) + "."); + version.subpass_count = framebuffer_formats[p_framebuffer->format_id].E->key().passes.size(); + p_framebuffer->framebuffers.insert(vk, version); } const Framebuffer::Version &version = p_framebuffer->framebuffers[vk]; *r_framebuffer = version.framebuffer; *r_render_pass = version.render_pass; + *r_subpass_count = version.subpass_count; return OK; } @@ -6127,15 +6580,23 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values - int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; - ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, INVALID_ID, - "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); + int color_count = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); + + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + color_count++; + } + } + + ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, INVALID_ID, + "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer color attachments (" + itos(color_count) + ")."); } VkFramebuffer vkframebuffer; VkRenderPass render_pass; - Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass); + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass, &draw_list_subpass_count); ERR_FAIL_COND_V(err != OK, INVALID_ID); VkCommandBuffer command_buffer = frames[frame].draw_command_buffer; @@ -6145,13 +6606,14 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu return INVALID_ID; } - draw_list = memnew(DrawList); - draw_list->command_buffer = command_buffer; + draw_list_render_pass = render_pass; + draw_list_vkframebuffer = vkframebuffer; + + _draw_list_allocate(Rect2i(viewport_offset, viewport_size), 0, 0); #ifdef DEBUG_ENABLED - draw_list->validation.framebuffer_format = framebuffer->format_id; + draw_list_framebuffer_format = framebuffer->format_id; #endif - draw_list_count = 0; - draw_list_split = false; + draw_list_current_subpass = 0; if (needs_clear_color || needs_clear_depth) { _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); @@ -6175,7 +6637,6 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu vkCmdSetScissor(command_buffer, 0, 1, &scissor); - draw_list->viewport = Rect2i(viewport_offset, viewport_size); return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; } @@ -6217,47 +6678,23 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p if (p_initial_color_action == INITIAL_ACTION_CLEAR) { //check clear values - int color_attachments = framebuffer_formats[framebuffer->format_id].color_attachments; - ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_attachments, ERR_INVALID_PARAMETER, - "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_attachments) + ")."); - } - - if (p_splits > (uint32_t)split_draw_list_allocators.size()) { - uint32_t from = split_draw_list_allocators.size(); - split_draw_list_allocators.resize(p_splits); - for (uint32_t i = from; i < p_splits; i++) { - VkCommandPoolCreateInfo cmd_pool_info; - cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmd_pool_info.pNext = nullptr; - cmd_pool_info.queueFamilyIndex = context->get_graphics_queue(); - cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &split_draw_list_allocators.write[i].command_pool); - ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "vkCreateCommandPool failed with error " + itos(res) + "."); - - for (int j = 0; j < frame_count; j++) { - VkCommandBuffer command_buffer; - - VkCommandBufferAllocateInfo cmdbuf; - //no command buffer exists, create it. - cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - cmdbuf.pNext = nullptr; - cmdbuf.commandPool = split_draw_list_allocators[i].command_pool; - cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; - cmdbuf.commandBufferCount = 1; - - VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &command_buffer); - ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkAllocateCommandBuffers failed with error " + itos(err) + "."); + int color_count = 0; + for (int i = 0; i < framebuffer->texture_ids.size(); i++) { + Texture *texture = texture_owner.getornull(framebuffer->texture_ids[i]); - split_draw_list_allocators.write[i].command_buffers.push_back(command_buffer); + if (texture->usage_flags & TEXTURE_USAGE_COLOR_ATTACHMENT_BIT) { + color_count++; } } + + ERR_FAIL_COND_V_MSG(p_clear_color_values.size() != color_count, ERR_INVALID_PARAMETER, + "Clear color values supplied (" + itos(p_clear_color_values.size()) + ") differ from the amount required for framebuffer (" + itos(color_count) + ")."); } VkFramebuffer vkframebuffer; VkRenderPass render_pass; - Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass); + Error err = _draw_list_setup_framebuffer(framebuffer, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, &vkframebuffer, &render_pass, &draw_list_subpass_count); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); VkCommandBuffer frame_command_buffer = frames[frame].draw_command_buffer; @@ -6267,53 +6704,24 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p return ERR_CANT_CREATE; } - draw_list = memnew_arr(DrawList, p_splits); - draw_list_count = p_splits; - draw_list_split = true; + draw_list_current_subpass = 0; - for (uint32_t i = 0; i < p_splits; i++) { - //take a command buffer and initialize it - VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame]; - - VkCommandBufferInheritanceInfo inheritance_info; - inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - inheritance_info.pNext = nullptr; - inheritance_info.renderPass = render_pass; - inheritance_info.subpass = 0; - inheritance_info.framebuffer = vkframebuffer; - inheritance_info.occlusionQueryEnable = false; - inheritance_info.queryFlags = 0; //? - inheritance_info.pipelineStatistics = 0; - - VkCommandBufferBeginInfo cmdbuf_begin; - cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmdbuf_begin.pNext = nullptr; - cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; - cmdbuf_begin.pInheritanceInfo = &inheritance_info; - - VkResult res = vkResetCommandBuffer(command_buffer, 0); - if (res) { - memdelete_arr(draw_list); - draw_list = nullptr; - ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkResetCommandBuffer failed with error " + itos(res) + "."); - } - - res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin); - if (res) { - memdelete_arr(draw_list); - draw_list = nullptr; - ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkBeginCommandBuffer failed with error " + itos(res) + "."); - } - - draw_list[i].command_buffer = command_buffer; #ifdef DEBUG_ENABLED - draw_list[i].validation.framebuffer_format = framebuffer->format_id; + draw_list_framebuffer_format = framebuffer->format_id; #endif + draw_list_render_pass = render_pass; + draw_list_vkframebuffer = vkframebuffer; - if (i == 0 && (needs_clear_color || needs_clear_depth)) { - _draw_list_insert_clear_region(draw_list, framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); - } + err = _draw_list_allocate(Rect2i(viewport_offset, viewport_size), p_splits, 0); + if (err != OK) { + return err; + } + if (needs_clear_color || needs_clear_depth) { + _draw_list_insert_clear_region(&draw_list[0], framebuffer, viewport_offset, viewport_size, needs_clear_color, p_clear_color_values, needs_clear_depth, p_clear_depth, p_clear_stencil); + } + + for (uint32_t i = 0; i < p_splits; i++) { VkViewport viewport; viewport.x = viewport_offset.x; viewport.y = viewport_offset.y; @@ -6322,7 +6730,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p viewport.minDepth = 0; viewport.maxDepth = 1.0; - vkCmdSetViewport(command_buffer, 0, 1, &viewport); + vkCmdSetViewport(draw_list[i].command_buffer, 0, 1, &viewport); VkRect2D scissor; scissor.offset.x = viewport_offset.x; @@ -6330,10 +6738,8 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p scissor.extent.width = viewport_size.width; scissor.extent.height = viewport_size.height; - vkCmdSetScissor(command_buffer, 0, 1, &scissor); + vkCmdSetScissor(draw_list[i].command_buffer, 0, 1, &scissor); r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; - - draw_list[i].viewport = Rect2i(viewport_offset, viewport_size); } return OK; @@ -6378,7 +6784,7 @@ void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RI const RenderPipeline *pipeline = render_pipeline_owner.getornull(p_render_pipeline); ERR_FAIL_COND(!pipeline); #ifdef DEBUG_ENABLED - ERR_FAIL_COND(pipeline->validation.framebuffer_format != dl->validation.framebuffer_format); + ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer_format && pipeline->validation.render_pass != draw_list_current_subpass); #endif if (p_render_pipeline == dl->state.pipeline) { @@ -6717,30 +7123,162 @@ void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) { vkCmdSetScissor(dl->command_buffer, 0, 1, &scissor); } -void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) { - _THREAD_SAFE_METHOD_ +RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass() { + ERR_FAIL_COND_V(draw_list == nullptr, INVALID_ID); + ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID); - ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); + draw_list_current_subpass++; + + Rect2i viewport; + _draw_list_free(&viewport); + + vkCmdNextSubpass(frames[frame].draw_command_buffer, VK_SUBPASS_CONTENTS_INLINE); + + _draw_list_allocate(viewport, 0, draw_list_current_subpass); + + return int64_t(ID_TYPE_DRAW_LIST) << ID_BASE_SHIFT; +} +Error RenderingDeviceVulkan::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) { + ERR_FAIL_COND_V(draw_list == nullptr, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER); + draw_list_current_subpass++; + + Rect2i viewport; + _draw_list_free(&viewport); + + vkCmdNextSubpass(frames[frame].draw_command_buffer, VK_SUBPASS_CONTENTS_INLINE); + + _draw_list_allocate(viewport, p_splits, draw_list_current_subpass); + + for (uint32_t i = 0; i < p_splits; i++) { + r_split_ids[i] = (int64_t(ID_TYPE_SPLIT_DRAW_LIST) << ID_BASE_SHIFT) + i; + } + + return OK; +} + +Error RenderingDeviceVulkan::_draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass) { + if (p_splits == 0) { + draw_list = memnew(DrawList); + draw_list->command_buffer = frames[frame].draw_command_buffer; + draw_list->viewport = p_viewport; + draw_list_count = 0; + draw_list_split = false; + } else { + if (p_splits > (uint32_t)split_draw_list_allocators.size()) { + uint32_t from = split_draw_list_allocators.size(); + split_draw_list_allocators.resize(p_splits); + for (uint32_t i = from; i < p_splits; i++) { + VkCommandPoolCreateInfo cmd_pool_info; + cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_info.pNext = nullptr; + cmd_pool_info.queueFamilyIndex = context->get_graphics_queue(); + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VkResult res = vkCreateCommandPool(device, &cmd_pool_info, nullptr, &split_draw_list_allocators.write[i].command_pool); + ERR_FAIL_COND_V_MSG(res, ERR_CANT_CREATE, "vkCreateCommandPool failed with error " + itos(res) + "."); + + for (int j = 0; j < frame_count; j++) { + VkCommandBuffer command_buffer; + + VkCommandBufferAllocateInfo cmdbuf; + //no command buffer exists, create it. + cmdbuf.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + cmdbuf.pNext = nullptr; + cmdbuf.commandPool = split_draw_list_allocators[i].command_pool; + cmdbuf.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + cmdbuf.commandBufferCount = 1; + + VkResult err = vkAllocateCommandBuffers(device, &cmdbuf, &command_buffer); + ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "vkAllocateCommandBuffers failed with error " + itos(err) + "."); + + split_draw_list_allocators.write[i].command_buffers.push_back(command_buffer); + } + } + } + draw_list = memnew_arr(DrawList, p_splits); + draw_list_count = p_splits; + draw_list_split = true; + + for (uint32_t i = 0; i < p_splits; i++) { + //take a command buffer and initialize it + VkCommandBuffer command_buffer = split_draw_list_allocators[i].command_buffers[frame]; + + VkCommandBufferInheritanceInfo inheritance_info; + inheritance_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + inheritance_info.pNext = nullptr; + inheritance_info.renderPass = draw_list_render_pass; + inheritance_info.subpass = p_subpass; + inheritance_info.framebuffer = draw_list_vkframebuffer; + inheritance_info.occlusionQueryEnable = false; + inheritance_info.queryFlags = 0; //? + inheritance_info.pipelineStatistics = 0; + + VkCommandBufferBeginInfo cmdbuf_begin; + cmdbuf_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmdbuf_begin.pNext = nullptr; + cmdbuf_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT | VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + cmdbuf_begin.pInheritanceInfo = &inheritance_info; + + VkResult res = vkResetCommandBuffer(command_buffer, 0); + if (res) { + memdelete_arr(draw_list); + draw_list = nullptr; + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkResetCommandBuffer failed with error " + itos(res) + "."); + } + + res = vkBeginCommandBuffer(command_buffer, &cmdbuf_begin); + if (res) { + memdelete_arr(draw_list); + draw_list = nullptr; + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "vkBeginCommandBuffer failed with error " + itos(res) + "."); + } + + draw_list[i].command_buffer = command_buffer; + draw_list[i].viewport = p_viewport; + } + } + + return OK; +} + +void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) { if (draw_list_split) { //send all command buffers VkCommandBuffer *command_buffers = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer) * draw_list_count); for (uint32_t i = 0; i < draw_list_count; i++) { vkEndCommandBuffer(draw_list[i].command_buffer); command_buffers[i] = draw_list[i].command_buffer; + if (r_last_viewport) { + if (i == 0 || draw_list[i].viewport_set) { + *r_last_viewport = draw_list[i].viewport; + } + } } vkCmdExecuteCommands(frames[frame].draw_command_buffer, draw_list_count, command_buffers); - vkCmdEndRenderPass(frames[frame].draw_command_buffer); memdelete_arr(draw_list); draw_list = nullptr; } else { + if (r_last_viewport) { + *r_last_viewport = draw_list->viewport; + } //just end the list - vkCmdEndRenderPass(draw_list->command_buffer); memdelete(draw_list); draw_list = nullptr; } +} + +void RenderingDeviceVulkan::draw_list_end(uint32_t p_post_barrier) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive."); + + _draw_list_free(); + + vkCmdEndRenderPass(frames[frame].draw_command_buffer); for (int i = 0; i < draw_list_bound_textures.size(); i++) { Texture *texture = texture_owner.getornull(draw_list_bound_textures[i]); @@ -7465,6 +8003,10 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) { } else if (uniform_set_owner.owns(p_id)) { UniformSet *uniform_set = uniform_set_owner.getornull(p_id); frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); + if (uniform_set->invalidated_callback != nullptr) { + uniform_set->invalidated_callback(p_id, uniform_set->invalidated_callback_userdata); + } + uniform_set_owner.free(p_id); } else if (render_pipeline_owner.owns(p_id)) { RenderPipeline *pipeline = render_pipeline_owner.getornull(p_id); @@ -7749,6 +8291,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) { vkDestroyImageView(device, texture->view, nullptr); if (texture->owner.is_null()) { //actually owns the image and the allocation too + image_memory -= texture->allocation_info.size; vmaDestroyImage(allocator, texture->image, texture->allocation); } frames[p_frame].textures_to_dispose_of.pop_front(); @@ -7772,10 +8315,16 @@ uint32_t RenderingDeviceVulkan::get_frame_delay() const { return frame_count; } -uint64_t RenderingDeviceVulkan::get_memory_usage() const { - VmaStats stats; - vmaCalculateStats(allocator, &stats); - return stats.total.usedBytes; +uint64_t RenderingDeviceVulkan::get_memory_usage(MemoryType p_type) const { + if (p_type == MEMORY_BUFFERS) { + return buffer_memory; + } else if (p_type == MEMORY_TEXTURES) { + return image_memory; + } else { + VmaStats stats; + vmaCalculateStats(allocator, &stats); + return stats.total.usedBytes; + } } void RenderingDeviceVulkan::_flush(bool p_current_frame) { diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index a2527d5c33..8b95ff43b8 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -156,6 +156,7 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t texture_upload_region_size_px = 0; Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false); + Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue); /*****************/ /**** SAMPLER ****/ @@ -234,7 +235,87 @@ class RenderingDeviceVulkan : public RenderingDevice { struct FramebufferFormatKey { Vector<AttachmentFormat> attachments; + Vector<FramebufferPass> passes; + uint32_t view_count = 1; bool operator<(const FramebufferFormatKey &p_key) const { + if (view_count != p_key.view_count) { + return view_count < p_key.view_count; + } + + uint32_t pass_size = passes.size(); + uint32_t key_pass_size = p_key.passes.size(); + if (pass_size != key_pass_size) { + return pass_size < key_pass_size; + } + const FramebufferPass *pass_ptr = passes.ptr(); + const FramebufferPass *key_pass_ptr = p_key.passes.ptr(); + + for (uint32_t i = 0; i < pass_size; i++) { + { //compare color attachments + uint32_t attachment_size = pass_ptr[i].color_attachments.size(); + uint32_t key_attachment_size = key_pass_ptr[i].color_attachments.size(); + if (attachment_size != key_attachment_size) { + return attachment_size < key_attachment_size; + } + const int32_t *pass_attachment_ptr = pass_ptr[i].color_attachments.ptr(); + const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].color_attachments.ptr(); + + for (uint32_t j = 0; j < attachment_size; j++) { + if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) { + return pass_attachment_ptr[j] < key_pass_attachment_ptr[j]; + } + } + } + { //compare input attachments + uint32_t attachment_size = pass_ptr[i].input_attachments.size(); + uint32_t key_attachment_size = key_pass_ptr[i].input_attachments.size(); + if (attachment_size != key_attachment_size) { + return attachment_size < key_attachment_size; + } + const int32_t *pass_attachment_ptr = pass_ptr[i].input_attachments.ptr(); + const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].input_attachments.ptr(); + + for (uint32_t j = 0; j < attachment_size; j++) { + if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) { + return pass_attachment_ptr[j] < key_pass_attachment_ptr[j]; + } + } + } + { //compare resolve attachments + uint32_t attachment_size = pass_ptr[i].resolve_attachments.size(); + uint32_t key_attachment_size = key_pass_ptr[i].resolve_attachments.size(); + if (attachment_size != key_attachment_size) { + return attachment_size < key_attachment_size; + } + const int32_t *pass_attachment_ptr = pass_ptr[i].resolve_attachments.ptr(); + const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].resolve_attachments.ptr(); + + for (uint32_t j = 0; j < attachment_size; j++) { + if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) { + return pass_attachment_ptr[j] < key_pass_attachment_ptr[j]; + } + } + } + { //compare preserve attachments + uint32_t attachment_size = pass_ptr[i].preserve_attachments.size(); + uint32_t key_attachment_size = key_pass_ptr[i].preserve_attachments.size(); + if (attachment_size != key_attachment_size) { + return attachment_size < key_attachment_size; + } + const int32_t *pass_attachment_ptr = pass_ptr[i].preserve_attachments.ptr(); + const int32_t *key_pass_attachment_ptr = key_pass_ptr[i].preserve_attachments.ptr(); + + for (uint32_t j = 0; j < attachment_size; j++) { + if (pass_attachment_ptr[j] != key_pass_attachment_ptr[j]) { + return pass_attachment_ptr[j] < key_pass_attachment_ptr[j]; + } + } + } + if (pass_ptr[i].depth_attachment != key_pass_ptr[i].depth_attachment) { + return pass_ptr[i].depth_attachment < key_pass_ptr[i].depth_attachment; + } + } + int as = attachments.size(); int bs = p_key.attachments.size(); if (as != bs) { @@ -261,16 +342,15 @@ class RenderingDeviceVulkan : public RenderingDevice { } }; - VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = nullptr); - + VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_attachments, const Vector<FramebufferPass> &p_passes, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, uint32_t p_view_count = 1, Vector<TextureSamples> *r_samples = nullptr); // This is a cache and it's never freed, it ensures // IDs for a given format are always unique. Map<FramebufferFormatKey, FramebufferFormatID> framebuffer_format_cache; struct FramebufferFormat { const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E; VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec) - int color_attachments = 0; //used for pipeline validation - TextureSamples samples; + Vector<TextureSamples> pass_samples; + uint32_t view_count = 1; // number of views }; Map<FramebufferFormatID, FramebufferFormat> framebuffer_formats; @@ -282,11 +362,17 @@ class RenderingDeviceVulkan : public RenderingDevice { FinalAction final_color_action; InitialAction initial_depth_action; FinalAction final_depth_action; + uint32_t view_count; + bool operator<(const VersionKey &p_key) const { if (initial_color_action == p_key.initial_color_action) { if (final_color_action == p_key.final_color_action) { if (initial_depth_action == p_key.initial_depth_action) { - return final_depth_action < p_key.final_depth_action; + if (final_depth_action == p_key.final_depth_action) { + return view_count < p_key.view_count; + } else { + return final_depth_action < p_key.final_depth_action; + } } else { return initial_depth_action < p_key.initial_depth_action; } @@ -305,10 +391,12 @@ class RenderingDeviceVulkan : public RenderingDevice { struct Version { VkFramebuffer framebuffer = VK_NULL_HANDLE; VkRenderPass render_pass = VK_NULL_HANDLE; //this one is owned + uint32_t subpass_count = 1; }; Map<VersionKey, Version> framebuffers; Size2 size; + uint32_t view_count; }; RID_Owner<Framebuffer, true> framebuffer_owner; @@ -524,7 +612,7 @@ class RenderingDeviceVulkan : public RenderingDevice { }; uint32_t vertex_input_mask = 0; //inputs used, this is mostly for validation - int fragment_outputs = 0; + uint32_t fragment_output_mask = 0; struct PushConstant { uint32_t push_constant_size = 0; @@ -535,11 +623,17 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t compute_local_size[3] = { 0, 0, 0 }; + struct SpecializationConstant { + PipelineSpecializationConstant constant; + uint32_t stage_flags = 0; + }; + bool is_compute = false; int max_output = 0; Vector<Set> sets; Vector<uint32_t> set_formats; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; + Vector<SpecializationConstant> specialization_constants; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; }; @@ -644,6 +738,8 @@ class RenderingDeviceVulkan : public RenderingDevice { LocalVector<AttachableTexture> attachable_textures; //used for validation Vector<Texture *> mutable_sampled_textures; //used for layout change Vector<Texture *> mutable_storage_textures; //used for layout change + UniformSetInvalidatedCallback invalidated_callback = nullptr; + void *invalidated_callback_userdata = nullptr; }; RID_Owner<UniformSet, true> uniform_set_owner; @@ -668,6 +764,7 @@ class RenderingDeviceVulkan : public RenderingDevice { #ifdef DEBUG_ENABLED struct Validation { FramebufferFormatID framebuffer_format = 0; + uint32_t render_pass = 0; uint32_t dynamic_state = 0; VertexFormatID vertex_format = 0; bool uses_restart_indices = false; @@ -723,6 +820,7 @@ class RenderingDeviceVulkan : public RenderingDevice { struct DrawList { VkCommandBuffer command_buffer = VK_NULL_HANDLE; // If persistent, this is owned, otherwise it's shared with the ringbuffer. Rect2i viewport; + bool viewport_set = false; struct SetState { uint32_t pipeline_expected_format = 0; @@ -746,7 +844,6 @@ class RenderingDeviceVulkan : public RenderingDevice { #ifdef DEBUG_ENABLED struct Validation { bool active = true; // Means command buffer was not closed, so you can keep adding things. - FramebufferFormatID framebuffer_format = INVALID_ID; // Actual render pass values. uint32_t dynamic_state = 0; VertexFormatID vertex_format = INVALID_ID; @@ -782,7 +879,15 @@ class RenderingDeviceVulkan : public RenderingDevice { }; DrawList *draw_list = nullptr; // One for regular draw lists, multiple for split. + uint32_t draw_list_subpass_count = 0; uint32_t draw_list_count = 0; + VkRenderPass draw_list_render_pass; + VkFramebuffer draw_list_vkframebuffer; +#ifdef DEBUG_ENABLED + FramebufferFormatID draw_list_framebuffer_format = INVALID_ID; +#endif + uint32_t draw_list_current_subpass = 0; + bool draw_list_split = false; Vector<RID> draw_list_bound_textures; Vector<RID> draw_list_storage_textures; @@ -790,10 +895,12 @@ class RenderingDeviceVulkan : public RenderingDevice { bool draw_list_unbind_depth_textures = false; void _draw_list_insert_clear_region(DrawList *draw_list, Framebuffer *framebuffer, Point2i viewport_offset, Point2i viewport_size, bool p_clear_color, const Vector<Color> &p_clear_colors, bool p_clear_depth, float p_depth, uint32_t p_stencil); - Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass); + Error _draw_list_setup_framebuffer(Framebuffer *p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, VkFramebuffer *r_framebuffer, VkRenderPass *r_render_pass, uint32_t *r_subpass_count); Error _draw_list_render_pass_begin(Framebuffer *framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_colors, float p_clear_depth, uint32_t p_clear_stencil, Point2i viewport_offset, Point2i viewport_size, VkFramebuffer vkframebuffer, VkRenderPass render_pass, VkCommandBuffer command_buffer, VkSubpassContents subpass_contents, const Vector<RID> &p_storage_textures); _FORCE_INLINE_ DrawList *_get_draw_list_ptr(DrawListID p_id); Buffer *_get_buffer_from_owner(RID p_buffer, VkPipelineStageFlags &dst_stage_mask, VkAccessFlags &dst_access, uint32_t p_post_barrier); + Error _draw_list_allocate(const Rect2i &p_viewport, uint32_t p_splits, uint32_t p_subpass); + void _draw_list_free(Rect2i *r_last_viewport = nullptr); /**********************/ /**** COMPUTE LIST ****/ @@ -907,6 +1014,9 @@ class RenderingDeviceVulkan : public RenderingDevice { VulkanContext *context = nullptr; + uint64_t image_memory = 0; + uint64_t buffer_memory = 0; + void _free_internal(RID p_id); void _flush(bool p_current_frame); @@ -938,11 +1048,13 @@ public: /**** FRAMEBUFFER ****/ /*********************/ - virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format); + virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1); + virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1); virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1); - virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format); + virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0); - virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID); + virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); + virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID); virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer); @@ -984,6 +1096,7 @@ public: virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); virtual bool uniform_set_is_valid(RID p_uniform_set); + virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata); virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL); @@ -993,14 +1106,14 @@ public: /**** RENDER PIPELINE ****/ /*************************/ - virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0); + virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()); virtual bool render_pipeline_is_valid(RID p_pipeline); /**************************/ /**** COMPUTE PIPELINE ****/ /**************************/ - virtual RID compute_pipeline_create(RID p_shader); + virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()); virtual bool compute_pipeline_is_valid(RID p_pipeline); /****************/ @@ -1032,6 +1145,9 @@ public: virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect); virtual void draw_list_disable_scissor(DrawListID p_list); + virtual DrawListID draw_list_switch_to_next_pass(); + virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids); + virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL); /***********************/ @@ -1088,7 +1204,7 @@ public: virtual RenderingDevice *create_local_device(); - virtual uint64_t get_memory_usage() const; + virtual uint64_t get_memory_usage(MemoryType p_type) const; virtual void set_resource_name(RID p_id, const String p_name); diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 38455bdbed..d35c519320 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -337,6 +337,9 @@ Error VulkanContext::_initialize_extensions() { extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; enabled_debug_utils = true; } + if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) { + extension_names[enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME; + } if (enabled_extension_count >= MAX_EXTENSIONS) { free(instance_extensions); ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); @@ -504,6 +507,8 @@ Error VulkanContext::_check_capabilities() { // assume not supported until proven otherwise multiview_capabilities.is_supported = false; + multiview_capabilities.geometry_shader_is_supported = false; + multiview_capabilities.tessellation_shader_is_supported = false; multiview_capabilities.max_view_count = 0; multiview_capabilities.max_instance_count = 0; subgroup_capabilities.size = 0; @@ -529,7 +534,8 @@ Error VulkanContext::_check_capabilities() { device_features_func(gpu, &device_features); multiview_capabilities.is_supported = multiview_features.multiview; - // For now we ignore if multiview is available in geometry and tessellation as we do not currently support those + multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader; + multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader; } // check extended properties @@ -573,7 +579,7 @@ Error VulkanContext::_check_capabilities() { #ifdef DEBUG_ENABLED print_line("- Vulkan multiview supported:"); - print_line(" max views: " + itos(multiview_capabilities.max_view_count)); + print_line(" max view count: " + itos(multiview_capabilities.max_view_count)); print_line(" max instances: " + itos(multiview_capabilities.max_instance_count)); } else { print_line("- Vulkan multiview not supported"); @@ -694,8 +700,25 @@ Error VulkanContext::_create_physical_device() { free(physical_devices); ERR_FAIL_V(ERR_CANT_CREATE); } - /* for now, just grab the first physical device */ + + // TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances. + // The device should really be a preference, but for now choosing a discrete GPU over the + // integrated one is better than the default. + + // Default to first device uint32_t device_index = 0; + + for (uint32_t i = 0; i < gpu_count; ++i) { + VkPhysicalDeviceProperties props; + vkGetPhysicalDeviceProperties(physical_devices[i], &props); + + if (props.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { + // Prefer discrete GPU. + device_index = i; + break; + } + } + gpu = physical_devices[device_index]; free(physical_devices); @@ -755,6 +778,10 @@ Error VulkanContext::_create_physical_device() { swapchainExtFound = 1; extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME; } + if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, device_extensions[i].extensionName)) { + // if multiview is supported, enable it + extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME; + } if (enabled_extension_count >= MAX_EXTENSIONS) { free(device_extensions); ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG"); @@ -947,17 +974,50 @@ Error VulkanContext::_create_device() { queues[1].flags = 0; sdevice.queueCreateInfoCount = 2; } + +#ifdef VK_VERSION_1_2 + VkPhysicalDeviceVulkan11Features vulkan11features; + + vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; + vulkan11features.pNext = nullptr; + // !BAS! Need to figure out which ones of these we want enabled... + vulkan11features.storageBuffer16BitAccess = 0; + vulkan11features.uniformAndStorageBuffer16BitAccess = 0; + vulkan11features.storagePushConstant16 = 0; + vulkan11features.storageInputOutput16 = 0; + vulkan11features.multiview = multiview_capabilities.is_supported; + vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; + vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; + vulkan11features.variablePointersStorageBuffer = 0; + vulkan11features.variablePointers = 0; + vulkan11features.protectedMemory = 0; + vulkan11features.samplerYcbcrConversion = 0; + vulkan11features.shaderDrawParameters = 0; + + sdevice.pNext = &vulkan11features; +#elif VK_VERSION_1_1 + VkPhysicalDeviceMultiviewFeatures multiview_features; + + multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + multiview_features.pNext = nullptr; + multiview_features.multiview = multiview_capabilities.is_supported; + multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported; + multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported; + + sdevice.pNext = &multiview_features; +#endif + err = vkCreateDevice(gpu, &sdevice, nullptr, &device); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); return OK; } -Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) { +Error VulkanContext::_initialize_queues(VkSurfaceKHR p_surface) { // Iterate over each queue to learn whether it supports presenting: VkBool32 *supportsPresent = (VkBool32 *)malloc(queue_family_count * sizeof(VkBool32)); for (uint32_t i = 0; i < queue_family_count; i++) { - fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supportsPresent[i]); + fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supportsPresent[i]); } // Search for a graphics and a present queue in the array of queue @@ -1031,10 +1091,10 @@ Error VulkanContext::_initialize_queues(VkSurfaceKHR surface) { // Get the list of VkFormat's that are supported: uint32_t formatCount; - VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, nullptr); + VkResult err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, nullptr); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR)); - err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, surfFormats); + err = fpGetPhysicalDeviceSurfaceFormatsKHR(gpu, p_surface, &formatCount, surfFormats); if (err) { free(surfFormats); ERR_FAIL_V(ERR_CANT_CREATE); @@ -1109,9 +1169,6 @@ Error VulkanContext::_create_semaphores() { err = vkCreateFence(device, &fence_ci, nullptr, &fences[i]); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &image_acquired_semaphores[i]); - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &draw_complete_semaphores[i]); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); @@ -1132,7 +1189,7 @@ bool VulkanContext::_use_validation_layers() { return Engine::get_singleton()->is_validation_layers_enabled(); } -Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) { +Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) { ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER); if (!queues_initialized) { @@ -1141,15 +1198,40 @@ Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfa // is created. Error err = _initialize_queues(p_surface); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + } else { + // make sure any of the surfaces supports present (validation layer complains if this is not done). + bool any_supports_present = false; + for (uint32_t i = 0; i < queue_family_count; i++) { + VkBool32 supports; + fpGetPhysicalDeviceSurfaceSupportKHR(gpu, i, p_surface, &supports); + if (supports) { + any_supports_present = true; + break; + } + } + + ERR_FAIL_COND_V_MSG(!any_supports_present, ERR_CANT_CREATE, "Surface passed for sub-window creation does not support presenting"); } Window window; window.surface = p_surface; window.width = p_width; window.height = p_height; + window.vsync_mode = p_vsync_mode; Error err = _update_swap_chain(&window); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); + VkSemaphoreCreateInfo semaphoreCreateInfo = { + /*sType*/ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + /*pNext*/ nullptr, + /*flags*/ 0, + }; + + for (uint32_t i = 0; i < FRAME_LAG; i++) { + VkResult vkerr = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &window.image_acquired_semaphores[i]); + ERR_FAIL_COND_V(vkerr, ERR_CANT_CREATE); + } + windows[p_window_id] = window; return OK; } @@ -1189,6 +1271,10 @@ VkFramebuffer VulkanContext::window_get_framebuffer(DisplayServer::WindowID p_wi void VulkanContext::window_destroy(DisplayServer::WindowID p_window_id) { ERR_FAIL_COND(!windows.has(p_window_id)); _clean_up_swap_chain(&windows[p_window_id]); + for (uint32_t i = 0; i < FRAME_LAG; i++) { + vkDestroySemaphore(device, windows[p_window_id].image_acquired_semaphores[i], nullptr); + } + vkDestroySurfaceKHR(inst, windows[p_window_id].surface, nullptr); windows.erase(p_window_id); } @@ -1275,7 +1361,6 @@ Error VulkanContext::_update_swap_chain(Window *window) { } // The FIFO present mode is guaranteed by the spec to be supported // and to have no tearing. It's a great default present mode to use. - VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; // There are times when you may wish to use another present mode. The // following code shows how to select them, and the comments provide some @@ -1304,16 +1389,41 @@ Error VulkanContext::_update_swap_chain(Window *window) { // the application wants the late image to be immediately displayed, even // though that may mean some tearing. - if (window->presentMode != swapchainPresentMode) { - for (size_t i = 0; i < presentModeCount; ++i) { - if (presentModes[i] == window->presentMode) { - swapchainPresentMode = window->presentMode; - break; - } + VkPresentModeKHR requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR; + switch (window->vsync_mode) { + case DisplayServer::VSYNC_MAILBOX: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR; + break; + case DisplayServer::VSYNC_ADAPTIVE: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR; + break; + case DisplayServer::VSYNC_ENABLED: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR; + break; + case DisplayServer::VSYNC_DISABLED: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_IMMEDIATE_KHR; + break; + } + + // Check if the requested mode is available. + bool present_mode_available = false; + for (uint32_t i = 0; i < presentModeCount; i++) { + if (presentModes[i] == requested_present_mode) { + present_mode_available = true; } } + + // Set the windows present mode if it is available, otherwise FIFO is used (guaranteed supported). + if (present_mode_available) { + window->presentMode = requested_present_mode; + } else { + WARN_PRINT("Requested VSync mode is not available!"); + window->vsync_mode = DisplayServer::VSYNC_ENABLED; //Set to default + } + + print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode))); + free(presentModes); - ERR_FAIL_COND_V_MSG(swapchainPresentMode != window->presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n"); // Determine the number of VkImages to use in the swap chain. // Application desires to acquire 3 images at a time for triple @@ -1370,7 +1480,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { /*pQueueFamilyIndices*/ nullptr, /*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform, /*compositeAlpha*/ compositeAlpha, - /*presentMode*/ swapchainPresentMode, + /*presentMode*/ window->presentMode, /*clipped*/ true, /*oldSwapchain*/ VK_NULL_HANDLE, }; @@ -1643,6 +1753,8 @@ Error VulkanContext::prepare_buffers() { for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { Window *w = &E->get(); + w->semaphore_acquired = false; + if (w->swapchain == VK_NULL_HANDLE) { continue; } @@ -1651,7 +1763,7 @@ Error VulkanContext::prepare_buffers() { // Get the index of the next available swapchain image: err = fpAcquireNextImageKHR(device, w->swapchain, UINT64_MAX, - image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer); + w->image_acquired_semaphores[frame_index], VK_NULL_HANDLE, &w->current_buffer); if (err == VK_ERROR_OUT_OF_DATE_KHR) { // swapchain is out of date (e.g. the window was resized) and @@ -1664,8 +1776,10 @@ Error VulkanContext::prepare_buffers() { // presentation engine will still present the image correctly. print_verbose("Vulkan: Early suboptimal swapchain."); break; + } else if (err != VK_SUCCESS) { + ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully."); } else { - ERR_FAIL_COND_V(err, ERR_CANT_CREATE); + w->semaphore_acquired = true; } } while (err != VK_SUCCESS); } @@ -1715,14 +1829,25 @@ Error VulkanContext::swap_buffers() { commands_to_submit = command_buffer_count; } + VkSemaphore *semaphores_to_acquire = (VkSemaphore *)alloca(windows.size() * sizeof(VkSemaphore)); + uint32_t semaphores_to_acquire_count = 0; + + for (Map<int, Window>::Element *E = windows.front(); E; E = E->next()) { + Window *w = &E->get(); + + if (w->semaphore_acquired) { + semaphores_to_acquire[semaphores_to_acquire_count++] = w->image_acquired_semaphores[frame_index]; + } + } + VkPipelineStageFlags pipe_stage_flags; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = nullptr; submit_info.pWaitDstStageMask = &pipe_stage_flags; pipe_stage_flags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &image_acquired_semaphores[frame_index]; + submit_info.waitSemaphoreCount = semaphores_to_acquire_count; + submit_info.pWaitSemaphores = semaphores_to_acquire; submit_info.commandBufferCount = commands_to_submit; submit_info.pCommandBuffers = commands_ptr; submit_info.signalSemaphoreCount = 1; @@ -2062,6 +2187,17 @@ String VulkanContext::get_device_pipeline_cache_uuid() const { return pipeline_cache_id; } +DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const { + ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get VSync mode for window with WindowID " + itos(p_window) + " because it does not exist."); + return windows[p_window].vsync_mode; +} + +void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) { + ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set VSync mode for window with WindowID " + itos(p_window) + " because it does not exist."); + windows[p_window].vsync_mode = p_mode; + _update_swap_chain(&windows[p_window]); +} + VulkanContext::VulkanContext() { command_buffer_queue.resize(1); // First one is always the setup command. command_buffer_queue.write[0] = nullptr; @@ -2074,7 +2210,6 @@ VulkanContext::~VulkanContext() { if (device_initialized) { for (uint32_t i = 0; i < FRAME_LAG; i++) { vkDestroyFence(device, fences[i], nullptr); - vkDestroySemaphore(device, image_acquired_semaphores[i], nullptr); vkDestroySemaphore(device, draw_complete_semaphores[i], nullptr); if (separate_present_queue) { vkDestroySemaphore(device, image_ownership_semaphores[i], nullptr); diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 3d9b295c5a..83e9524046 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -56,8 +56,10 @@ public: struct MultiviewCapabilities { bool is_supported; - int32_t max_view_count; - int32_t max_instance_count; + bool geometry_shader_is_supported; + bool tessellation_shader_is_supported; + uint32_t max_view_count; + uint32_t max_instance_count; }; private: @@ -68,7 +70,6 @@ private: }; VkInstance inst = VK_NULL_HANDLE; - VkSurfaceKHR surface = VK_NULL_HANDLE; VkPhysicalDevice gpu = VK_NULL_HANDLE; VkPhysicalDeviceProperties gpu_props; uint32_t queue_family_count = 0; @@ -99,7 +100,6 @@ private: VkQueue present_queue = VK_NULL_HANDLE; VkColorSpaceKHR color_space; VkFormat format; - VkSemaphore image_acquired_semaphores[FRAME_LAG]; VkSemaphore draw_complete_semaphores[FRAME_LAG]; VkSemaphore image_ownership_semaphores[FRAME_LAG]; int frame_index = 0; @@ -119,9 +119,12 @@ private: VkSwapchainKHR swapchain = VK_NULL_HANDLE; SwapchainImageResources *swapchain_image_resources = VK_NULL_HANDLE; VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; + VkSemaphore image_acquired_semaphores[FRAME_LAG]; + bool semaphore_acquired = false; uint32_t current_buffer = 0; int width = 0; int height = 0; + DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED; VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue. VkRenderPass render_pass = VK_NULL_HANDLE; }; @@ -206,7 +209,7 @@ private: Error _create_physical_device(); - Error _initialize_queues(VkSurfaceKHR surface); + Error _initialize_queues(VkSurfaceKHR p_surface); Error _create_device(); @@ -220,7 +223,7 @@ private: protected: virtual const char *_get_platform_surface_extension() const = 0; - virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height); + virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height); virtual bool _use_validation_layers(); @@ -274,6 +277,9 @@ public: String get_device_name() const; String get_device_pipeline_cache_uuid() const; + void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode); + DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const; + VulkanContext(); virtual ~VulkanContext(); }; diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 55f9e6de17..325bae5b56 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -208,7 +208,7 @@ String DirAccessWindows::get_current_dir(bool p_include_drive) { bool DirAccessWindows::file_exists(String p_file) { GLOBAL_LOCK_FUNCTION - if (!p_file.is_abs_path()) { + if (!p_file.is_absolute_path()) { p_file = get_current_dir().plus_file(p_file); } diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index b151b631e9..1ba4e70e42 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.h @@ -33,7 +33,7 @@ #ifdef WINDOWS_ENABLED -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" /** @author Juan Linietsky <reduz@gmail.com> diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 1f46b44f5e..d6deda7b5d 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -294,6 +294,7 @@ void FileAccessWindows::store_8(uint8_t p_dest) { void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { ERR_FAIL_COND(!f); + ERR_FAIL_COND(!p_src && p_length > 0); if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == READ) { if (last_error != ERR_FILE_EOF) { diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 95f3a75548..7280fc3237 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -33,7 +33,7 @@ #ifdef WINDOWS_ENABLED -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/memory.h" #include <stdio.h> diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index d195561a85..7ed603410d 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -310,7 +310,7 @@ void InputEventConfigurationDialog::_update_input_list() { MouseButton mouse_buttons[9] = { MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN, MOUSE_BUTTON_WHEEL_LEFT, MOUSE_BUTTON_WHEEL_RIGHT, MOUSE_BUTTON_XBUTTON1, MOUSE_BUTTON_XBUTTON2 }; for (int i = 0; i < 9; i++) { Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_button_index(mouse_buttons[i]); String desc = get_event_text(mb); @@ -333,8 +333,8 @@ void InputEventConfigurationDialog::_update_input_list() { for (int i = 0; i < JOY_BUTTON_MAX; i++) { Ref<InputEventJoypadButton> joyb; - joyb.instance(); - joyb->set_button_index(i); + joyb.instantiate(); + joyb->set_button_index((JoyButton)i); String desc = get_event_text(joyb); if (!search_term.is_empty() && desc.findn(search_term) == -1) { @@ -358,8 +358,8 @@ void InputEventConfigurationDialog::_update_input_list() { int axis = i / 2; int direction = (i & 1) ? 1 : -1; Ref<InputEventJoypadMotion> joym; - joym.instance(); - joym->set_axis(axis); + joym.instantiate(); + joym->set_axis((JoyAxis)axis); joym->set_axis_value(direction); String desc = get_event_text(joym); @@ -458,7 +458,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() { case InputEventConfigurationDialog::INPUT_KEY: { int kc = selected->get_meta("__keycode"); Ref<InputEventKey> k; - k.instance(); + k.instantiate(); if (physical_key_checkbox->is_pressed()) { k->set_physical_keycode(kc); @@ -481,8 +481,8 @@ void InputEventConfigurationDialog::_input_list_item_selected() { case InputEventConfigurationDialog::INPUT_MOUSE_BUTTON: { int idx = selected->get_meta("__index"); Ref<InputEventMouseButton> mb; - mb.instance(); - mb->set_button_index(idx); + mb.instantiate(); + mb->set_button_index((MouseButton)idx); // Maintain modifier state from checkboxes mb->set_alt_pressed(mod_checkboxes[MOD_ALT]->is_pressed()); mb->set_shift_pressed(mod_checkboxes[MOD_SHIFT]->is_pressed()); @@ -495,7 +495,7 @@ void InputEventConfigurationDialog::_input_list_item_selected() { } break; case InputEventConfigurationDialog::INPUT_JOY_BUTTON: { int idx = selected->get_meta("__index"); - Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference(idx); + Ref<InputEventJoypadButton> jb = InputEventJoypadButton::create_reference((JoyButton)idx); _set_event(jb); } break; case InputEventConfigurationDialog::INPUT_JOY_MOTION: { @@ -503,8 +503,8 @@ void InputEventConfigurationDialog::_input_list_item_selected() { int value = selected->get_meta("__value"); Ref<InputEventJoypadMotion> jm; - jm.instance(); - jm->set_axis(axis); + jm.instantiate(); + jm->set_axis((JoyAxis)axis); jm->set_axis_value(value); _set_event(jm); } break; @@ -969,9 +969,9 @@ void ActionMapEditor::_notification(int p_what) { } void ActionMapEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &ActionMapEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ActionMapEditor::drop_data_fw); ADD_SIGNAL(MethodInfo("action_added", PropertyInfo(Variant::STRING, "name"))); ADD_SIGNAL(MethodInfo("action_edited", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::DICTIONARY, "new_action"))); @@ -1106,7 +1106,7 @@ ActionMapEditor::ActionMapEditor() { add_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); add_edit->set_placeholder(TTR("Add New Action")); add_edit->set_clear_button_enabled(true); - add_edit->connect("text_entered", callable_mp(this, &ActionMapEditor::_add_action)); + add_edit->connect("text_submitted", callable_mp(this, &ActionMapEditor::_add_action)); add_hbox->add_child(add_edit); Button *add_button = memnew(Button); @@ -1123,11 +1123,12 @@ ActionMapEditor::ActionMapEditor() { action_tree->set_hide_root(true); action_tree->set_column_titles_visible(true); action_tree->set_column_title(0, TTR("Action")); + action_tree->set_column_clip_content(0, true); action_tree->set_column_title(1, TTR("Deadzone")); action_tree->set_column_expand(1, false); - action_tree->set_column_min_width(1, 80 * EDSCALE); + action_tree->set_column_custom_minimum_width(1, 80 * EDSCALE); action_tree->set_column_expand(2, false); - action_tree->set_column_min_width(2, 50 * EDSCALE); + action_tree->set_column_custom_minimum_width(2, 50 * EDSCALE); action_tree->connect("item_edited", callable_mp(this, &ActionMapEditor::_action_edited)); action_tree->connect("item_activated", callable_mp(this, &ActionMapEditor::_tree_item_activated)); action_tree->connect("button_pressed", callable_mp(this, &ActionMapEditor::_tree_button_pressed)); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 3620fda4f8..1aa676d11c 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -165,7 +165,7 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { Dictionary d_old = animation->track_get_key_value(track, key); Dictionary d_new = d_old.duplicate(); d_new[p_name] = p_value; @@ -412,7 +412,7 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { Dictionary d = animation->track_get_key_value(track, key); ERR_FAIL_COND_V(!d.has(name), false); r_ret = d[p_name]; @@ -523,9 +523,9 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { p_list->push_back(PropertyInfo(Variant::VECTOR3, "location")); - p_list->push_back(PropertyInfo(Variant::QUAT, "rotation")); + p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation")); p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); } break; @@ -781,7 +781,7 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { Dictionary d_old = animation->track_get_key_value(track, key); Dictionary d_new = d_old.duplicate(); d_new[p_name] = p_value; @@ -1012,7 +1012,7 @@ public: } switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { Dictionary d = animation->track_get_key_value(track, key); ERR_FAIL_COND_V(!d.has(name), false); r_ret = d[p_name]; @@ -1162,37 +1162,35 @@ public: if (same_track_type) { switch (animation->track_get_type(first_track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { p_list->push_back(PropertyInfo(Variant::VECTOR3, "location")); - p_list->push_back(PropertyInfo(Variant::QUAT, "rotation")); + p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation")); p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale")); } break; case Animation::TYPE_VALUE: { - if (!same_key_type) { - break; - } + if (same_key_type) { + Variant v = animation->track_get_key_value(first_track, first_key); - Variant v = animation->track_get_key_value(first_track, first_key); - - if (hint.type != Variant::NIL) { - PropertyInfo pi = hint; - pi.name = "value"; - p_list->push_back(pi); - } else { - PropertyHint hint = PROPERTY_HINT_NONE; - String hint_string; - - if (v.get_type() == Variant::OBJECT) { - //could actually check the object property if exists..? yes i will! - Ref<Resource> res = v; - if (res.is_valid()) { - hint = PROPERTY_HINT_RESOURCE_TYPE; - hint_string = res->get_class(); + if (hint.type != Variant::NIL) { + PropertyInfo pi = hint; + pi.name = "value"; + p_list->push_back(pi); + } else { + PropertyHint hint = PROPERTY_HINT_NONE; + String hint_string; + + if (v.get_type() == Variant::OBJECT) { + //could actually check the object property if exists..? yes i will! + Ref<Resource> res = v; + if (res.is_valid()) { + hint = PROPERTY_HINT_RESOURCE_TYPE; + hint_string = res->get_class(); + } } - } - if (v.get_type() != Variant::NIL) { - p_list->push_back(PropertyInfo(v.get_type(), "value", hint, hint_string)); + if (v.get_type() != Variant::NIL) { + p_list->push_back(PropertyInfo(v.get_type(), "value", hint, hint_string)); + } } } @@ -1586,6 +1584,10 @@ void AnimationTimelineEdit::set_zoom(Range *p_zoom) { zoom->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_zoom_changed)); } +void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) { + track_edit = p_track_edit; +} + void AnimationTimelineEdit::set_play_position(float p_pos) { play_position_pos = p_pos; play_position->update(); @@ -1643,7 +1645,31 @@ void AnimationTimelineEdit::_play_position_draw() { void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); - Ref<InputEventMouseButton> mb = p_event; + const Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { + get_zoom()->set_value(get_zoom()->get_value() * 1.05); + accept_event(); + } + + if (mb.is_valid() && mb->is_pressed() && mb->is_command_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { + get_zoom()->set_value(get_zoom()->get_value() / 1.05); + accept_event(); + } + + if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { + if (track_edit) { + track_edit->get_editor()->goto_prev_step(true); + } + accept_event(); + } + + if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { + if (track_edit) { + track_edit->get_editor()->goto_next_step(true); + } + accept_event(); + } if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) { dragging_hsize = true; @@ -1742,6 +1768,7 @@ AnimationTimelineEdit::AnimationTimelineEdit() { editing = false; name_limit = 150 * EDSCALE; zoom = nullptr; + track_edit = nullptr; play_position_pos = 0; play_position = memnew(Control); @@ -2007,7 +2034,7 @@ void AnimationTrackEdit::_notification(int p_what) { interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2; interp_mode_rect.size = icon->get_size(); - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { draw_texture(icon, interp_mode_rect.position); } //make it easier to click @@ -2017,7 +2044,7 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += icon->get_width() + hsep; interp_mode_rect.size.x += hsep; - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); interp_mode_rect.size.x += down_icon->get_width(); } else { @@ -2040,7 +2067,7 @@ void AnimationTrackEdit::_notification(int p_what) { loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2; loop_mode_rect.size = icon->get_size(); - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { draw_texture(icon, loop_mode_rect.position); } @@ -2050,7 +2077,7 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += icon->get_width() + hsep; loop_mode_rect.size.x += hsep; - if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); loop_mode_rect.size.x += down_icon->get_width(); } else { @@ -2308,6 +2335,7 @@ void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) { void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) { timeline = p_timeline; + timeline->set_track_edit(this); timeline->connect("zoom_changed", callable_mp(this, &AnimationTrackEdit::_zoom_changed)); timeline->connect("name_limit_changed", callable_mp(this, &AnimationTrackEdit::_zoom_changed)); } @@ -2350,7 +2378,7 @@ void AnimationTrackEdit::_zoom_changed() { play_position->update(); } -void AnimationTrackEdit::_path_entered(const String &p_text) { +void AnimationTrackEdit::_path_submitted(const String &p_text) { undo_redo->create_action(TTR("Change Track Path")); undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text); undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track)); @@ -2441,7 +2469,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const { if (key_idx != -1) { String text = TTR("Time (s): ") + rtos(animation->track_get_key_time(track, key_idx)) + "\n"; switch (animation->track_get_type(track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { Dictionary d = animation->track_get_key_value(track, key_idx); if (d.has("location")) { text += "Pos: " + String(d["location"]) + "\n"; @@ -2725,7 +2753,7 @@ void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) { path = memnew(LineEdit); path_popup->add_child(path); path->set_anchors_and_offsets_preset(PRESET_WIDE); - path->connect("text_entered", callable_mp(this, &AnimationTrackEdit::_path_entered)); + path->connect("text_submitted", callable_mp(this, &AnimationTrackEdit::_path_submitted)); } path->set_text(animation->track_get_path(track)); @@ -3310,7 +3338,7 @@ static bool track_type_is_resettable(Animation::TrackType p_type) { [[fallthrough]]; case Animation::TYPE_BEZIER: [[fallthrough]]; - case Animation::TYPE_TRANSFORM: + case Animation::TYPE_TRANSFORM3D: return true; default: return false; @@ -3376,7 +3404,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { case Variant::FLOAT: case Variant::VECTOR2: case Variant::VECTOR3: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::PLANE: case Variant::COLOR: { // Valid. @@ -3459,7 +3487,7 @@ void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_bezi insert_queue = false; } -void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform &p_xform) { +void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform) { if (!keying) { return; } @@ -3479,7 +3507,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ int track_idx = -1; for (int i = 0; i < animation->get_track_count(); i++) { - if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM) { + if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM3D) { continue; } if (animation->track_get_path(i) != np) { @@ -3496,7 +3524,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ id.path = np; id.track_idx = track_idx; id.value = p_xform; - id.type = Animation::TYPE_TRANSFORM; + id.type = Animation::TYPE_TRANSFORM3D; id.query = "node '" + p_node->get_name() + "'"; id.advance = false; @@ -3732,7 +3760,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { return player->get_animation("RESET"); } else { Ref<Animation> reset_anim; - reset_anim.instance(); + reset_anim.instantiate(); reset_anim->set_length(ANIM_MIN_LENGTH); undo_redo->add_do_method(player, "add_animation", "RESET", reset_anim); undo_redo->add_do_method(AnimationPlayerEditor::singleton, "_animation_player_changed", player); @@ -3845,7 +3873,7 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool subindices.push_back(":y"); subindices.push_back(":z"); } break; - case Variant::QUAT: { + case Variant::QUATERNION: { subindices.push_back(":x"); subindices.push_back(":y"); subindices.push_back(":z"); @@ -3911,11 +3939,11 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD h.type == Variant::RECT2 || h.type == Variant::VECTOR3 || h.type == Variant::AABB || - h.type == Variant::QUAT || + h.type == Variant::QUATERNION || h.type == Variant::COLOR || h.type == Variant::PLANE || h.type == Variant::TRANSFORM2D || - h.type == Variant::TRANSFORM) { + h.type == Variant::TRANSFORM3D) { update_mode = Animation::UPDATE_CONTINUOUS; } @@ -3945,12 +3973,12 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD value = p_id.value; } break; - case Animation::TYPE_TRANSFORM: { - Transform tr = p_id.value; + case Animation::TYPE_TRANSFORM3D: { + Transform3D tr = p_id.value; Dictionary d; d["location"] = tr.origin; d["scale"] = tr.basis.get_scale(); - d["rotation"] = Quat(tr.basis); + d["rotation"] = Quaternion(tr.basis); value = d; } break; case Animation::TYPE_BEZIER: { @@ -4368,8 +4396,8 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { ERR_FAIL_COND(!node); NodePath path_to = root->get_path_to(node); - if (adding_track_type == Animation::TYPE_TRANSFORM && !node->is_class("Node3D")) { - EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to 3D-based nodes.")); + if (adding_track_type == Animation::TYPE_TRANSFORM3D && !node->is_class("Node3D")) { + EditorNode::get_singleton()->show_warning(TTR("Transform3D tracks only apply to 3D-based nodes.")); return; } @@ -4379,7 +4407,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { prop_selector->set_type_filter(Vector<Variant::Type>()); prop_selector->select_property_from_instance(node); } break; - case Animation::TYPE_TRANSFORM: + case Animation::TYPE_TRANSFORM3D: case Animation::TYPE_METHOD: { undo_redo->create_action(TTR("Add Track")); undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type); @@ -4394,7 +4422,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { filter.push_back(Variant::FLOAT); filter.push_back(Variant::VECTOR2); filter.push_back(Variant::VECTOR3); - filter.push_back(Variant::QUAT); + filter.push_back(Variant::QUATERNION); filter.push_back(Variant::PLANE); filter.push_back(Variant::COLOR); @@ -4422,7 +4450,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { } if (node == AnimationPlayerEditor::singleton->get_player()) { - EditorNode::get_singleton()->show_warning(TTR("An animation player can't animate itself, only other players.")); + EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players.")); return; } @@ -4464,11 +4492,11 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) { h.type == Variant::RECT2 || h.type == Variant::VECTOR3 || h.type == Variant::AABB || - h.type == Variant::QUAT || + h.type == Variant::QUATERNION || h.type == Variant::COLOR || h.type == Variant::PLANE || h.type == Variant::TRANSFORM2D || - h.type == Variant::TRANSFORM) { + h.type == Variant::TRANSFORM3D) { update_mode = Animation::UPDATE_CONTINUOUS; } @@ -4548,7 +4576,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { } switch (animation->track_get_type(p_track)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { if (!root->has_node(animation->track_get_path(p_track))) { EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key.")); return; @@ -4560,11 +4588,11 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { return; } - Transform xf = base->get_transform(); + Transform3D xf = base->get_transform(); Vector3 loc = xf.get_origin(); Vector3 scale = xf.basis.get_scale_local(); - Quat rot = xf.basis; + Quaternion rot = xf.basis; undo_redo->create_action(TTR("Add Transform Track Key")); undo_redo->add_do_method(animation.ptr(), "transform_track_insert_key", p_track, p_ofs, loc, rot, scale); @@ -4969,6 +4997,16 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { scroll->accept_event(); } + if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { + goto_prev_step(true); + scroll->accept_event(); + } + + if (mb.is_valid() && mb->is_pressed() && mb->is_alt_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { + goto_next_step(true); + scroll->accept_event(); + } + if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->is_pressed()) { box_selecting = true; @@ -5143,6 +5181,56 @@ void AnimationTrackEditor::_edit_menu_about_to_popup() { edit->get_popup()->set_item_disabled(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), !player->can_apply_reset()); } +void AnimationTrackEditor::goto_prev_step(bool p_from_mouse_event) { + if (animation.is_null()) { + return; + } + float step = animation->get_step(); + if (step == 0) { + step = 1; + } + if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + // Use more precise snapping when holding Shift. + // This is used when scrobbling the timeline using Alt + Mouse wheel. + step *= 0.25; + } + + float pos = timeline->get_play_position(); + pos = Math::snapped(pos - step, step); + if (pos < 0) { + pos = 0; + } + set_anim_pos(pos); + emit_signal("timeline_changed", pos, true); +} + +void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event) { + if (animation.is_null()) { + return; + } + float step = animation->get_step(); + if (step == 0) { + step = 1; + } + if (p_from_mouse_event && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + // Use more precise snapping when holding Shift. + // This is used when scrobbling the timeline using Alt + Mouse wheel. + // Do not use precise snapping when using the menu action or keyboard shortcut, + // as the default keyboard shortcut requires pressing Shift. + step *= 0.25; + } + + float pos = timeline->get_play_position(); + + pos = Math::snapped(pos + step, step); + if (pos > animation->get_length()) { + pos = animation->get_length(); + } + set_anim_pos(pos); + + emit_signal("timeline_changed", pos, true); +} + void AnimationTrackEditor::_edit_menu_pressed(int p_option) { last_menu_track_opt = p_option; switch (p_option) { @@ -5182,7 +5270,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } switch (animation->track_get_type(i)) { - case Animation::TYPE_TRANSFORM: + case Animation::TYPE_TRANSFORM3D: text += " (Transform)"; break; case Animation::TYPE_METHOD: @@ -5246,7 +5334,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case EDIT_PASTE_TRACKS: { if (track_clipboard.size() == 0) { - EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty")); + EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!")); break; } @@ -5428,42 +5516,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } } break; case EDIT_GOTO_NEXT_STEP: { - if (animation.is_null()) { - break; - } - float step = animation->get_step(); - if (step == 0) { - step = 1; - } - - float pos = timeline->get_play_position(); - - pos = Math::snapped(pos + step, step); - if (pos > animation->get_length()) { - pos = animation->get_length(); - } - set_anim_pos(pos); - - emit_signal("timeline_changed", pos, true); - + goto_next_step(false); } break; case EDIT_GOTO_PREV_STEP: { - if (animation.is_null()) { - break; - } - float step = animation->get_step(); - if (step == 0) { - step = 1; - } - - float pos = timeline->get_play_position(); - pos = Math::snapped(pos - step, step); - if (pos < 0) { - pos = 0; - } - set_anim_pos(pos); - emit_signal("timeline_changed", pos, true); - + goto_prev_step(false); } break; case EDIT_APPLY_RESET: { AnimationPlayerEditor::singleton->get_player()->apply_reset(true); @@ -5927,7 +5983,7 @@ AnimationTrackEditor::AnimationTrackEditor() { //default plugins Ref<AnimationTrackEditDefaultPlugin> def_plugin; - def_plugin.instance(); + def_plugin.instantiate(); add_track_edit_plugin(def_plugin); //dialogs diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index 8befc830fa..6d977e5a3f 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -49,10 +49,13 @@ class AnimationPlayer; +class AnimationTrackEdit; + class AnimationTimelineEdit : public Range { GDCLASS(AnimationTimelineEdit, Range); Ref<Animation> animation; + AnimationTrackEdit *track_edit; int name_limit; Range *zoom; Range *h_scroll; @@ -101,6 +104,7 @@ public: virtual Size2 get_minimum_size() const override; void set_animation(const Ref<Animation> &p_animation); + void set_track_edit(AnimationTrackEdit *p_track_edit); void set_zoom(Range *p_zoom); Range *get_zoom() const { return zoom; } void set_undo_redo(UndoRedo *p_undo_redo); @@ -173,7 +177,7 @@ class AnimationTrackEdit : public Control { void _menu_selected(int p_index); - void _path_entered(const String &p_text); + void _path_submitted(const String &p_text); void _play_position_draw(); bool _is_value_key_valid(const Variant &p_key_value, Variant::Type &r_valid_type) const; @@ -236,8 +240,8 @@ public: AnimationTrackEdit(); }; -class AnimationTrackEditPlugin : public Reference { - GDCLASS(AnimationTrackEditPlugin, Reference); +class AnimationTrackEditPlugin : public RefCounted { + GDCLASS(AnimationTrackEditPlugin, RefCounted); public: virtual AnimationTrackEdit *create_value_track_edit(Object *p_object, Variant::Type p_type, const String &p_property, PropertyHint p_hint, const String &p_hint_string, int p_usage); @@ -275,25 +279,6 @@ public: class AnimationTrackEditor : public VBoxContainer { GDCLASS(AnimationTrackEditor, VBoxContainer); - enum { - EDIT_COPY_TRACKS, - EDIT_COPY_TRACKS_CONFIRM, - EDIT_PASTE_TRACKS, - EDIT_SCALE_SELECTION, - EDIT_SCALE_FROM_CURSOR, - EDIT_SCALE_CONFIRM, - EDIT_DUPLICATE_SELECTION, - EDIT_DUPLICATE_TRANSPOSED, - EDIT_DELETE_SELECTION, - EDIT_GOTO_NEXT_STEP, - EDIT_GOTO_PREV_STEP, - EDIT_APPLY_RESET, - EDIT_OPTIMIZE_ANIMATION, - EDIT_OPTIMIZE_ANIMATION_CONFIRM, - EDIT_CLEAN_UP_ANIMATION, - EDIT_CLEAN_UP_ANIMATION_CONFIRM - }; - Ref<Animation> animation; Node *root; @@ -508,6 +493,25 @@ protected: void _notification(int p_what); public: + enum { + EDIT_COPY_TRACKS, + EDIT_COPY_TRACKS_CONFIRM, + EDIT_PASTE_TRACKS, + EDIT_SCALE_SELECTION, + EDIT_SCALE_FROM_CURSOR, + EDIT_SCALE_CONFIRM, + EDIT_DUPLICATE_SELECTION, + EDIT_DUPLICATE_TRANSPOSED, + EDIT_DELETE_SELECTION, + EDIT_GOTO_NEXT_STEP, + EDIT_GOTO_PREV_STEP, + EDIT_APPLY_RESET, + EDIT_OPTIMIZE_ANIMATION, + EDIT_OPTIMIZE_ANIMATION_CONFIRM, + EDIT_CLEAN_UP_ANIMATION, + EDIT_CLEAN_UP_ANIMATION_CONFIRM + }; + void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin); void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin); @@ -526,7 +530,7 @@ public: void set_anim_pos(float p_pos); void insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists = false); void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance); - void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform &p_xform); + void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform); void show_select_node_warning(bool p_show); @@ -538,6 +542,12 @@ public: float snap_time(float p_value, bool p_relative = false); bool is_grouping_tracks(); + /** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */ + void goto_prev_step(bool p_from_mouse_event); + + /** If `p_from_mouse_event` is `true`, handle Shift key presses for precise snapping. */ + void goto_next_step(bool p_from_mouse_event); + MenuButton *get_edit_menu(); AnimationTrackEditor(); ~AnimationTrackEditor(); diff --git a/editor/array_property_edit.h b/editor/array_property_edit.h index fa3dcbe038..d7e11936a3 100644 --- a/editor/array_property_edit.h +++ b/editor/array_property_edit.h @@ -33,8 +33,8 @@ #include "scene/main/node.h" -class ArrayPropertyEdit : public Reference { - GDCLASS(ArrayPropertyEdit, Reference); +class ArrayPropertyEdit : public RefCounted { + GDCLASS(ArrayPropertyEdit, RefCounted); int page; ObjectID obj; diff --git a/editor/audio_stream_preview.cpp b/editor/audio_stream_preview.cpp index 539657afd7..ad6e3ac1dc 100644 --- a/editor/audio_stream_preview.cpp +++ b/editor/audio_stream_preview.cpp @@ -192,7 +192,7 @@ Ref<AudioStreamPreview> AudioStreamPreviewGenerator::generate_preview(const Ref< } } - preview->preview.instance(); + preview->preview.instantiate(); preview->preview->preview = maxmin; preview->preview->length = len_s; diff --git a/editor/audio_stream_preview.h b/editor/audio_stream_preview.h index accc7275c0..9cf47fd51a 100644 --- a/editor/audio_stream_preview.h +++ b/editor/audio_stream_preview.h @@ -36,8 +36,8 @@ #include "scene/main/node.h" #include "servers/audio/audio_stream.h" -class AudioStreamPreview : public Reference { - GDCLASS(AudioStreamPreview, Reference); +class AudioStreamPreview : public RefCounted { + GDCLASS(AudioStreamPreview, RefCounted); friend class AudioStream; Vector<uint8_t> preview; float length; @@ -75,6 +75,15 @@ class AudioStreamPreviewGenerator : public Node { thread = p_rhs.thread; return *this; } + Preview(const Preview &p_rhs) { + preview = p_rhs.preview; + base_stream = p_rhs.base_stream; + playback = p_rhs.playback; + generating.set_to(generating.is_set()); + id = p_rhs.id; + thread = p_rhs.thread; + } + Preview() {} }; Map<ObjectID, Preview> previews; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index be42eab636..03914bec3b 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -105,6 +105,11 @@ void FindReplaceBar::_notification(int p_what) { hide_button->set_custom_minimum_size(hide_button->get_normal_texture()->get_size()); } else if (p_what == NOTIFICATION_THEME_CHANGED) { matches_label->add_theme_color_override("font_color", results_count > 0 ? get_theme_color("font_color", "Label") : get_theme_color("error_color", "Editor")); + } else if (p_what == NOTIFICATION_PREDELETE) { + if (base_text_editor) { + base_text_editor->remove_find_replace_bar(); + base_text_editor = nullptr; + } } } @@ -117,7 +122,7 @@ void FindReplaceBar::_unhandled_input(const Ref<InputEvent> &p_event) { } Control *focus_owner = get_focus_owner(); - if (text_editor->has_focus() || (focus_owner && vbc_lineedit->is_a_parent_of(focus_owner))) { + if (text_editor->has_focus() || (focus_owner && vbc_lineedit->is_ancestor_of(focus_owner))) { bool accepted = true; switch (k->get_keycode()) { @@ -539,7 +544,7 @@ void FindReplaceBar::_search_text_changed(const String &p_text) { search_current(); } -void FindReplaceBar::_search_text_entered(const String &p_text) { +void FindReplaceBar::_search_text_submitted(const String &p_text) { if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { search_prev(); } else { @@ -547,7 +552,7 @@ void FindReplaceBar::_search_text_entered(const String &p_text) { } } -void FindReplaceBar::_replace_text_entered(const String &p_text) { +void FindReplaceBar::_replace_text_submitted(const String &p_text) { if (selection_only->is_pressed() && text_editor->is_selection_active()) { _replace_all(); _hide_bar(); @@ -583,15 +588,33 @@ void FindReplaceBar::set_error(const String &p_label) { emit_signal("error", p_label); } -void FindReplaceBar::set_text_edit(CodeEdit *p_text_edit) { +void FindReplaceBar::set_text_edit(CodeTextEditor *p_text_editor) { + if (p_text_editor == base_text_editor) { + return; + } + + if (base_text_editor) { + base_text_editor->remove_find_replace_bar(); + base_text_editor = nullptr; + text_editor->disconnect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed)); + text_editor = nullptr; + } + + if (!p_text_editor) { + return; + } + results_count = -1; - text_editor = p_text_edit; + base_text_editor = p_text_editor; + text_editor = base_text_editor->get_text_editor(); text_editor->connect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed)); + + _update_results_count(); + _update_matches_label(); } void FindReplaceBar::_bind_methods() { ClassDB::bind_method("_unhandled_input", &FindReplaceBar::_unhandled_input); - ClassDB::bind_method("_search_current", &FindReplaceBar::search_current); ADD_SIGNAL(MethodInfo("search")); @@ -629,7 +652,7 @@ FindReplaceBar::FindReplaceBar() { vbc_lineedit->add_child(search_text); search_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); search_text->connect("text_changed", callable_mp(this, &FindReplaceBar::_search_text_changed)); - search_text->connect("text_entered", callable_mp(this, &FindReplaceBar::_search_text_entered)); + search_text->connect("text_submitted", callable_mp(this, &FindReplaceBar::_search_text_submitted)); matches_label = memnew(Label); hbc_button_search->add_child(matches_label); @@ -663,7 +686,7 @@ FindReplaceBar::FindReplaceBar() { replace_text = memnew(LineEdit); vbc_lineedit->add_child(replace_text); replace_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - replace_text->connect("text_entered", callable_mp(this, &FindReplaceBar::_replace_text_entered)); + replace_text->connect("text_submitted", callable_mp(this, &FindReplaceBar::_replace_text_submitted)); replace = memnew(Button); hbc_button_replace->add_child(replace); @@ -715,8 +738,8 @@ void CodeTextEditor::_input(const Ref<InputEvent> &event) { accept_event(); return; } - if (ED_IS_SHORTCUT("script_text_editor/clone_down", key_event)) { - clone_lines_down(); + if (ED_IS_SHORTCUT("script_text_editor/duplicate_selection", key_event)) { + duplicate_selection(); accept_event(); return; } @@ -916,7 +939,7 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line")); text_editor->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/indent/type")); text_editor->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size")); - text_editor->set_auto_indent(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent")); + text_editor->set_auto_indent_enabled(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent")); text_editor->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs")); text_editor->set_draw_spaces(EditorSettings::get_singleton()->get("text_editor/indent/draw_spaces")); text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/navigation/smooth_scrolling")); @@ -926,7 +949,7 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_draw_line_numbers(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_numbers")); text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/appearance/line_numbers_zero_padded")); text_editor->set_draw_bookmarks_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/show_bookmark_gutter")); - text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding")); + text_editor->set_line_folding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding")); text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding")); text_editor->set_wrap_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/word_wrap")); text_editor->set_show_line_length_guidelines(EditorSettings::get_singleton()->get("text_editor/appearance/show_line_length_guidelines")); @@ -939,6 +962,25 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete")); } +void CodeTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) { + if (find_replace_bar) { + return; + } + + find_replace_bar = p_bar; + find_replace_bar->set_text_edit(this); + find_replace_bar->connect("error", callable_mp(error, &Label::set_text)); +} + +void CodeTextEditor::remove_find_replace_bar() { + if (!find_replace_bar) { + return; + } + + find_replace_bar->disconnect("error", callable_mp(error, &Label::set_text)); + find_replace_bar = nullptr; +} + void CodeTextEditor::trim_trailing_whitespace() { bool trimed_whitespace = false; for (int i = 0; i < text_editor->get_line_count(); i++) { @@ -1222,7 +1264,7 @@ void CodeTextEditor::_delete_line(int p_line) { text_editor->cursor_set_line(1); text_editor->cursor_set_column(0); } - text_editor->backspace_at_cursor(); + text_editor->backspace(); text_editor->unfold_line(p_line); text_editor->cursor_set_line(p_line); } @@ -1245,7 +1287,7 @@ void CodeTextEditor::delete_lines() { text_editor->end_complex_operation(); } -void CodeTextEditor::clone_lines_down() { +void CodeTextEditor::duplicate_selection() { const int cursor_column = text_editor->cursor_get_column(); int from_line = text_editor->cursor_get_line(); int to_line = text_editor->cursor_get_line(); @@ -1469,6 +1511,7 @@ void CodeTextEditor::set_error_pos(int p_line, int p_column) { void CodeTextEditor::goto_error() { if (error->get_text() != "") { + text_editor->unfold_line(error_line); text_editor->cursor_set_line(error_line); text_editor->cursor_set_column(error_column); text_editor->center_viewport_to_cursor(); @@ -1578,15 +1621,19 @@ void CodeTextEditor::validate_script() { idle->start(); } -void CodeTextEditor::_warning_label_gui_input(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { - _warning_button_pressed(); - } +void CodeTextEditor::_error_button_pressed() { + _set_show_errors_panel(!is_errors_panel_opened); + _set_show_warnings_panel(false); } void CodeTextEditor::_warning_button_pressed() { _set_show_warnings_panel(!is_warnings_panel_opened); + _set_show_errors_panel(false); +} + +void CodeTextEditor::_set_show_errors_panel(bool p_show) { + is_errors_panel_opened = p_show; + emit_signal("show_errors_panel", p_show); } void CodeTextEditor::_set_show_warnings_panel(bool p_show) { @@ -1619,6 +1666,7 @@ void CodeTextEditor::_notification(int p_what) { _update_font(); } break; case NOTIFICATION_ENTER_TREE: { + error_button->set_icon(get_theme_icon("StatusError", "EditorIcons")); warning_button->set_icon(get_theme_icon("NodeWarning", "EditorIcons")); add_theme_constant_override("separation", 4 * EDSCALE); } break; @@ -1628,16 +1676,28 @@ void CodeTextEditor::_notification(int p_what) { } set_process_input(is_visible_in_tree()); } break; + case NOTIFICATION_PREDELETE: { + if (find_replace_bar) { + find_replace_bar->set_text_edit(nullptr); + } + } break; default: break; } } -void CodeTextEditor::set_warning_nb(int p_warning_nb) { - warning_count_label->set_text(itos(p_warning_nb)); - warning_count_label->set_visible(p_warning_nb > 0); - warning_button->set_visible(p_warning_nb > 0); - if (!p_warning_nb) { +void CodeTextEditor::set_error_count(int p_error_count) { + error_button->set_text(itos(p_error_count)); + error_button->set_visible(p_error_count > 0); + if (!p_error_count) { + _set_show_errors_panel(false); + } +} + +void CodeTextEditor::set_warning_count(int p_warning_count) { + warning_button->set_text(itos(p_warning_count)); + warning_button->set_visible(p_warning_count > 0); + if (!p_warning_count) { _set_show_warnings_panel(false); } } @@ -1704,6 +1764,7 @@ void CodeTextEditor::_bind_methods() { ADD_SIGNAL(MethodInfo("validate_script")); ADD_SIGNAL(MethodInfo("load_theme_settings")); + ADD_SIGNAL(MethodInfo("show_errors_panel")); ADD_SIGNAL(MethodInfo("show_warnings_panel")); } @@ -1760,17 +1821,9 @@ CodeTextEditor::CodeTextEditor() { } break; } - // Added second so it opens at the bottom, so it won't shift the entire text editor when opening. - find_replace_bar = memnew(FindReplaceBar); - add_child(find_replace_bar); - find_replace_bar->set_h_size_flags(SIZE_EXPAND_FILL); - find_replace_bar->hide(); - - find_replace_bar->set_text_edit(text_editor); - text_editor->set_draw_line_numbers(true); text_editor->set_brace_matching(true); - text_editor->set_auto_indent(true); + text_editor->set_auto_indent_enabled(true); status_bar = memnew(HBoxContainer); add_child(status_bar); @@ -1808,7 +1861,22 @@ CodeTextEditor::CodeTextEditor() { error->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); error->set_mouse_filter(MOUSE_FILTER_STOP); error->connect("gui_input", callable_mp(this, &CodeTextEditor::_error_pressed)); - find_replace_bar->connect("error", callable_mp(error, &Label::set_text)); + + // Errors + error_button = memnew(Button); + error_button->set_flat(true); + status_bar->add_child(error_button); + error_button->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); + error_button->set_default_cursor_shape(CURSOR_POINTING_HAND); + error_button->connect("pressed", callable_mp(this, &CodeTextEditor::_error_button_pressed)); + error_button->set_tooltip(TTR("Errors")); + + error_button->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor")); + error_button->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts")); + error_button->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("status_source_size", "EditorFonts")); + + is_errors_panel_opened = false; + set_error_count(0); // Warnings warning_button = memnew(Button); @@ -1819,20 +1887,12 @@ CodeTextEditor::CodeTextEditor() { warning_button->connect("pressed", callable_mp(this, &CodeTextEditor::_warning_button_pressed)); warning_button->set_tooltip(TTR("Warnings")); - warning_count_label = memnew(Label); - status_bar->add_child(warning_count_label); - warning_count_label->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); - warning_count_label->set_align(Label::ALIGN_RIGHT); - warning_count_label->set_default_cursor_shape(CURSOR_POINTING_HAND); - warning_count_label->set_mouse_filter(MOUSE_FILTER_STOP); - warning_count_label->set_tooltip(TTR("Warnings")); - warning_count_label->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor")); - warning_count_label->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts")); - warning_count_label->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("status_source_size", "EditorFonts")); - warning_count_label->connect("gui_input", callable_mp(this, &CodeTextEditor::_warning_label_gui_input)); + warning_button->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("warning_color", "Editor")); + warning_button->add_theme_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("status_source", "EditorFonts")); + warning_button->add_theme_font_size_override("font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("status_source_size", "EditorFonts")); is_warnings_panel_opened = false; - set_warning_nb(0); + set_warning_count(0); // Line and column line_and_col_txt = memnew(Label); diff --git a/editor/code_editor.h b/editor/code_editor.h index e6dadbd6fa..0e5a84b3d5 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -57,6 +57,8 @@ public: GotoLineDialog(); }; +class CodeTextEditor; + class FindReplaceBar : public HBoxContainer { GDCLASS(FindReplaceBar, HBoxContainer); @@ -77,6 +79,7 @@ class FindReplaceBar : public HBoxContainer { HBoxContainer *hbc_button_replace; HBoxContainer *hbc_option_replace; + CodeTextEditor *base_text_editor = nullptr; CodeEdit *text_editor; int result_line; @@ -96,8 +99,8 @@ class FindReplaceBar : public HBoxContainer { void _editor_text_changed(); void _search_options_changed(bool p_pressed); void _search_text_changed(const String &p_text); - void _search_text_entered(const String &p_text); - void _replace_text_entered(const String &p_text); + void _search_text_submitted(const String &p_text); + void _replace_text_submitted(const String &p_text); void _update_size(); protected: @@ -120,7 +123,7 @@ public: bool is_selection_only() const; void set_error(const String &p_label); - void set_text_edit(CodeEdit *p_text_edit); + void set_text_edit(CodeTextEditor *p_text_editor); void popup_search(bool p_show_only = false); void popup_replace(); @@ -138,12 +141,12 @@ class CodeTextEditor : public VBoxContainer { GDCLASS(CodeTextEditor, VBoxContainer); CodeEdit *text_editor; - FindReplaceBar *find_replace_bar; + FindReplaceBar *find_replace_bar = nullptr; HBoxContainer *status_bar; Button *toggle_scripts_button; + Button *error_button; Button *warning_button; - Label *warning_count_label; Label *line_and_col_txt; @@ -181,8 +184,9 @@ class CodeTextEditor : public VBoxContainer { CodeTextEditorCodeCompleteFunc code_complete_func; void *code_complete_ud; - void _warning_label_gui_input(const Ref<InputEvent> &p_event); + void _error_button_pressed(); void _warning_button_pressed(); + void _set_show_errors_panel(bool p_show); void _set_show_warnings_panel(bool p_show); void _error_pressed(const Ref<InputEvent> &p_event); @@ -202,6 +206,7 @@ protected: static void _bind_methods(); bool is_warnings_panel_opened; + bool is_errors_panel_opened; public: void trim_trailing_whitespace(); @@ -220,7 +225,7 @@ public: void move_lines_up(); void move_lines_down(); void delete_lines(); - void clone_lines_down(); + void duplicate_selection(); /// Toggle inline comment on currently selected lines, or on current line if nothing is selected, /// by adding or removing comment delimiter @@ -235,7 +240,8 @@ public: Variant get_edit_state(); void set_edit_state(const Variant &p_state); - void set_warning_nb(int p_warning_nb); + void set_error_count(int p_error_count); + void set_warning_count(int p_warning_count); void update_editor_settings(); void set_error(const String &p_error); @@ -243,6 +249,8 @@ public: void update_line_and_column() { _line_col_changed(); } CodeEdit *get_text_editor() { return text_editor; } FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } + void set_find_replace_bar(FindReplaceBar *p_bar); + void remove_find_replace_bar(); virtual void apply_code() {} void goto_error(); diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index de2be710c5..de6407da73 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -146,7 +146,7 @@ void ConnectDialog::_item_activated() { _ok_pressed(); // From AcceptDialog. } -void ConnectDialog::_text_entered(const String &p_text) { +void ConnectDialog::_text_submitted(const String &p_text) { _ok_pressed(); // From AcceptDialog. } @@ -203,8 +203,8 @@ void ConnectDialog::_add_bind() { case Variant::PLANE: value = Plane(); break; - case Variant::QUAT: - value = Quat(); + case Variant::QUATERNION: + value = Quaternion(); break; case Variant::AABB: value = AABB(); @@ -212,8 +212,8 @@ void ConnectDialog::_add_bind() { case Variant::BASIS: value = Basis(); break; - case Variant::TRANSFORM: - value = Transform(); + case Variant::TRANSFORM3D: + value = Transform3D(); break; case Variant::COLOR: value = Color(); @@ -443,10 +443,10 @@ ConnectDialog::ConnectDialog() { type_list->add_item("Rect2", Variant::RECT2); type_list->add_item("Vector3", Variant::VECTOR3); type_list->add_item("Plane", Variant::PLANE); - type_list->add_item("Quat", Variant::QUAT); + type_list->add_item("Quaternion", Variant::QUATERNION); type_list->add_item("AABB", Variant::AABB); type_list->add_item("Basis", Variant::BASIS); - type_list->add_item("Transform", Variant::TRANSFORM); + type_list->add_item("Transform3D", Variant::TRANSFORM3D); type_list->add_item("Color", Variant::COLOR); type_list->select(0); @@ -471,7 +471,7 @@ ConnectDialog::ConnectDialog() { dst_method = memnew(LineEdit); dst_method->set_h_size_flags(Control::SIZE_EXPAND_FILL); - dst_method->connect("text_entered", callable_mp(this, &ConnectDialog::_text_entered)); + dst_method->connect("text_submitted", callable_mp(this, &ConnectDialog::_text_submitted)); dstm_hb->add_child(dst_method); advanced = memnew(CheckButton); diff --git a/editor/connections_dialog.h b/editor/connections_dialog.h index 18feba0a61..b9911c1cc5 100644 --- a/editor/connections_dialog.h +++ b/editor/connections_dialog.h @@ -105,7 +105,7 @@ private: void ok_pressed() override; void _cancel_pressed(); void _item_activated(); - void _text_entered(const String &_text); + void _text_submitted(const String &_text); void _tree_node_selected(); void _add_bind(); void _remove_bind(); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 1c0a55e4ec..027cee3f1c 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -130,7 +130,7 @@ bool CreateDialog::_should_hide_type(const String &p_type) const { } if (ClassDB::class_exists(p_type)) { - if (!ClassDB::can_instance(p_type)) { + if (!ClassDB::can_instantiate(p_type)) { return true; // Can't create abstract class. } @@ -234,8 +234,8 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_text(0, p_type); } - bool can_instance = (p_cpp_type && ClassDB::can_instance(p_type)) || !p_cpp_type; - if (!can_instance) { + bool can_instantiate = (p_cpp_type && ClassDB::can_instantiate(p_type)) || !p_cpp_type; + if (!can_instantiate) { r_item->set_custom_color(0, search_options->get_theme_color("disabled_font_color", "Editor")); r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, "NodeDisabled")); r_item->set_selectable(0, false); @@ -247,7 +247,7 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_collapsed(false); } else { // Don't collapse the root node or an abstract node on the first tree level. - bool should_collapse = p_type != base_type && (r_item->get_parent()->get_text(0) != base_type || can_instance); + bool should_collapse = p_type != base_type && (r_item->get_parent()->get_text(0) != base_type || can_instantiate); if (should_collapse && bool(EditorSettings::get_singleton()->get("docks/scene_tree/start_create_dialog_fully_expanded"))) { should_collapse = false; // Collapse all nodes anyway. @@ -432,7 +432,7 @@ Variant CreateDialog::instance_selected() { obj = EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom); } } else { - obj = ClassDB::instance(selected->get_text(0)); + obj = ClassDB::instantiate(selected->get_text(0)); } // Check if any Object-type property should be instantiated. @@ -442,7 +442,7 @@ Variant CreateDialog::instance_selected() { for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { PropertyInfo pi = E->get(); if (pi.type == Variant::OBJECT && pi.usage & PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT) { - Object *prop = ClassDB::instance(pi.class_name); + Object *prop = ClassDB::instantiate(pi.class_name); ((Object *)obj)->set(pi.name, prop); } } @@ -643,9 +643,9 @@ void CreateDialog::_load_favorites_and_history() { void CreateDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list); - ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &CreateDialog::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &CreateDialog::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &CreateDialog::drop_data_fw); ADD_SIGNAL(MethodInfo("create")); ADD_SIGNAL(MethodInfo("favorites_updated")); diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index ded0ee3aa7..5f90680115 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -65,7 +65,7 @@ EditorDebuggerNode::EditorDebuggerNode() { add_child(tabs); Ref<StyleBoxEmpty> empty; - empty.instance(); + empty.instantiate(); tabs->add_theme_style_override("panel", empty); auto_switch_remote_scene_tree = EDITOR_DEF("debugger/auto_switch_to_remote_scene_tree", false); diff --git a/editor/debugger/editor_debugger_server.cpp b/editor/debugger/editor_debugger_server.cpp index 662f247062..e8524e0702 100644 --- a/editor/debugger/editor_debugger_server.cpp +++ b/editor/debugger/editor_debugger_server.cpp @@ -60,7 +60,7 @@ EditorDebuggerServer *EditorDebuggerServerTCP::create(const String &p_protocol) } EditorDebuggerServerTCP::EditorDebuggerServerTCP() { - server.instance(); + server.instantiate(); } Error EditorDebuggerServerTCP::start() { diff --git a/editor/debugger/editor_debugger_server.h b/editor/debugger/editor_debugger_server.h index 6458421e7a..6216d0df3d 100644 --- a/editor/debugger/editor_debugger_server.h +++ b/editor/debugger/editor_debugger_server.h @@ -32,9 +32,9 @@ #define EDITOR_DEBUGGER_CONNECTION_H #include "core/debugger/remote_debugger_peer.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class EditorDebuggerServer : public Reference { +class EditorDebuggerServer : public RefCounted { public: typedef EditorDebuggerServer *(*CreateServerFunc)(const String &p_uri); diff --git a/editor/debugger/editor_network_profiler.cpp b/editor/debugger/editor_network_profiler.cpp index 2d57dff69d..1c781c4d98 100644 --- a/editor/debugger/editor_network_profiler.cpp +++ b/editor/debugger/editor_network_profiler.cpp @@ -178,19 +178,24 @@ EditorNetworkProfiler::EditorNetworkProfiler() { counters_display->set_column_titles_visible(true); counters_display->set_column_title(0, TTR("Node")); counters_display->set_column_expand(0, true); - counters_display->set_column_min_width(0, 60 * EDSCALE); + counters_display->set_column_clip_content(0, true); + counters_display->set_column_custom_minimum_width(0, 60 * EDSCALE); counters_display->set_column_title(1, TTR("Incoming RPC")); counters_display->set_column_expand(1, false); - counters_display->set_column_min_width(1, 120 * EDSCALE); + counters_display->set_column_clip_content(1, true); + counters_display->set_column_custom_minimum_width(1, 120 * EDSCALE); counters_display->set_column_title(2, TTR("Incoming RSET")); counters_display->set_column_expand(2, false); - counters_display->set_column_min_width(2, 120 * EDSCALE); + counters_display->set_column_clip_content(2, true); + counters_display->set_column_custom_minimum_width(2, 120 * EDSCALE); counters_display->set_column_title(3, TTR("Outgoing RPC")); counters_display->set_column_expand(3, false); - counters_display->set_column_min_width(3, 120 * EDSCALE); + counters_display->set_column_clip_content(3, true); + counters_display->set_column_custom_minimum_width(3, 120 * EDSCALE); counters_display->set_column_title(4, TTR("Outgoing RSET")); counters_display->set_column_expand(4, false); - counters_display->set_column_min_width(4, 120 * EDSCALE); + counters_display->set_column_clip_content(4, true); + counters_display->set_column_custom_minimum_width(4, 120 * EDSCALE); add_child(counters_display); frame_delay = memnew(Timer); diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index d60e2783ec..5f4d1b6f36 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -305,17 +305,17 @@ void EditorProfiler::_update_plot() { } Ref<Image> img; - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8, graph_image); if (reset_texture) { if (graph_texture.is_null()) { - graph_texture.instance(); + graph_texture.instantiate(); } graph_texture->create_from_image(img); } - graph_texture->update(img, true); + graph_texture->update(img); graph->set_texture(graph_texture); graph->update(); @@ -631,13 +631,16 @@ EditorProfiler::EditorProfiler() { variables->set_column_titles_visible(true); variables->set_column_title(0, TTR("Name")); variables->set_column_expand(0, true); - variables->set_column_min_width(0, 60 * EDSCALE); + variables->set_column_clip_content(0, true); + variables->set_column_expand_ratio(0, 60); variables->set_column_title(1, TTR("Time")); variables->set_column_expand(1, false); - variables->set_column_min_width(1, 100 * EDSCALE); + variables->set_column_clip_content(1, true); + variables->set_column_expand_ratio(1, 100); variables->set_column_title(2, TTR("Calls")); variables->set_column_expand(2, false); - variables->set_column_min_width(2, 60 * EDSCALE); + variables->set_column_clip_content(2, true); + variables->set_column_expand_ratio(2, 60); variables->connect("item_edited", callable_mp(this, &EditorProfiler::_item_edited)); graph = memnew(TextureRect); diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 5bb10b3794..a0e8a3bd35 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -299,17 +299,17 @@ void EditorVisualProfiler::_update_plot() { } Ref<Image> img; - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8, graph_image); if (reset_texture) { if (graph_texture.is_null()) { - graph_texture.instance(); + graph_texture.instantiate(); } graph_texture->create_from_image(img); } - graph_texture->update(img, true); + graph_texture->update(img); graph->set_texture(graph_texture); graph->update(); @@ -773,13 +773,16 @@ EditorVisualProfiler::EditorVisualProfiler() { variables->set_column_titles_visible(true); variables->set_column_title(0, TTR("Name")); variables->set_column_expand(0, true); - variables->set_column_min_width(0, 60); + variables->set_column_clip_content(0, true); + variables->set_column_custom_minimum_width(0, 60); variables->set_column_title(1, TTR("CPU")); variables->set_column_expand(1, false); - variables->set_column_min_width(1, 60 * EDSCALE); + variables->set_column_clip_content(1, true); + variables->set_column_custom_minimum_width(1, 60 * EDSCALE); variables->set_column_title(2, TTR("GPU")); variables->set_column_expand(2, false); - variables->set_column_min_width(2, 60 * EDSCALE); + variables->set_column_clip_content(2, true); + variables->set_column_custom_minimum_width(2, 60 * EDSCALE); variables->connect("cell_selected", callable_mp(this, &EditorVisualProfiler::_item_selected)); graph = memnew(TextureRect); diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 7493cc2a8d..b877ab030f 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -1643,9 +1643,11 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { error_tree->set_columns(2); error_tree->set_column_expand(0, false); - error_tree->set_column_min_width(0, 140); + error_tree->set_column_custom_minimum_width(0, 140); + error_tree->set_column_clip_content(0, true); error_tree->set_column_expand(1, true); + error_tree->set_column_clip_content(1, true); error_tree->set_select_mode(Tree::SELECT_ROW); error_tree->set_hide_root(true); @@ -1731,13 +1733,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { vmem_tree->set_column_expand(0, true); vmem_tree->set_column_expand(1, false); vmem_tree->set_column_title(1, TTR("Type")); - vmem_tree->set_column_min_width(1, 100 * EDSCALE); + vmem_tree->set_column_custom_minimum_width(1, 100 * EDSCALE); vmem_tree->set_column_expand(2, false); vmem_tree->set_column_title(2, TTR("Format")); - vmem_tree->set_column_min_width(2, 150 * EDSCALE); + vmem_tree->set_column_custom_minimum_width(2, 150 * EDSCALE); vmem_tree->set_column_expand(3, false); vmem_tree->set_column_title(3, TTR("Usage")); - vmem_tree->set_column_min_width(3, 80 * EDSCALE); + vmem_tree->set_column_custom_minimum_width(3, 80 * EDSCALE); vmem_tree->set_hide_root(true); tabs->add_child(vmem_vb); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index c085205f63..ef571e5c7a 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -30,8 +30,8 @@ #include "dependency_editor.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "editor_node.h" #include "editor_scale.h" #include "scene/gui/margin_container.h" @@ -226,7 +226,11 @@ DependencyEditor::DependencyEditor() { tree->set_columns(2); tree->set_column_titles_visible(true); tree->set_column_title(0, TTR("Resource")); + tree->set_column_clip_content(0, true); + tree->set_column_expand_ratio(0, 2); tree->set_column_title(1, TTR("Path")); + tree->set_column_clip_content(1, true); + tree->set_column_expand_ratio(1, 1); tree->set_hide_root(true); tree->connect("button_pressed", callable_mp(this, &DependencyEditor::_load_pressed)); @@ -769,9 +773,11 @@ OrphanResourcesDialog::OrphanResourcesDialog() { files = memnew(Tree); files->set_columns(2); files->set_column_titles_visible(true); - files->set_column_min_width(1, 100); + files->set_column_custom_minimum_width(1, 100 * EDSCALE); files->set_column_expand(0, true); + files->set_column_clip_content(0, true); files->set_column_expand(1, false); + files->set_column_clip_content(1, true); files->set_column_title(0, TTR("Resource")); files->set_column_title(1, TTR("Owns")); files->set_hide_root(true); diff --git a/editor/dictionary_property_edit.h b/editor/dictionary_property_edit.h index e0fd945491..d1401c5e5f 100644 --- a/editor/dictionary_property_edit.h +++ b/editor/dictionary_property_edit.h @@ -33,8 +33,8 @@ #include "scene/main/node.h" -class DictionaryPropertyEdit : public Reference { - GDCLASS(DictionaryPropertyEdit, Reference); +class DictionaryPropertyEdit : public RefCounted { + GDCLASS(DictionaryPropertyEdit, RefCounted); ObjectID obj; StringName property; diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index e29c9593c3..befafec6cb 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -34,9 +34,9 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" #include "core/io/compression.h" +#include "core/io/dir_access.h" #include "core/io/marshalls.h" #include "core/object/script_language.h" -#include "core/os/dir_access.h" #include "core/version.h" #include "scene/resources/theme.h" @@ -206,14 +206,14 @@ static Variant get_documentation_default_value(const StringName &p_class_name, c Variant default_value = Variant(); r_default_value_valid = false; - if (ClassDB::can_instance(p_class_name)) { + if (ClassDB::can_instantiate(p_class_name)) { default_value = ClassDB::class_get_default_property_value(p_class_name, p_property_name, &r_default_value_valid); } else { - // Cannot get default value of classes that can't be instanced + // Cannot get default value of classes that can't be instantiated List<StringName> inheriting_classes; ClassDB::get_direct_inheriters_from_class(p_class_name, &inheriting_classes); for (List<StringName>::Element *E2 = inheriting_classes.front(); E2; E2 = E2->next()) { - if (ClassDB::can_instance(E2->get())) { + if (ClassDB::can_instantiate(E2->get())) { default_value = ClassDB::class_get_default_property_value(E2->get(), p_property_name, &r_default_value_valid); if (r_default_value_valid) { break; diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index 7527514dca..b8504ad02a 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -141,7 +141,7 @@ EditorAbout::EditorAbout() { version_btn = memnew(LinkButton); String hash = String(VERSION_HASH); if (hash.length() != 0) { - hash = "." + hash.left(9); + hash = " " + vformat("[%s]", hash.left(9)); } version_btn->set_text(VERSION_FULL_NAME + hash); // Set the text to copy in metadata as it slightly differs from the button's text. diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index 9dcd550f5c..83319ee5a5 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -30,9 +30,9 @@ #include "editor_asset_installer.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/zip_io.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "editor_node.h" #include "progress_dialog.h" @@ -132,14 +132,54 @@ void EditorAssetInstaller::open(const String &p_path, int p_depth) { Map<String, Ref<Texture2D>> extension_guess; { - extension_guess["png"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["bmp"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["dds"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["exr"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["hdr"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); extension_guess["jpg"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); - extension_guess["atlastex"] = tree->get_theme_icon("AtlasTexture", "EditorIcons"); + extension_guess["jpeg"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["png"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["svg"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["svgz"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["tga"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + extension_guess["webp"] = tree->get_theme_icon("ImageTexture", "EditorIcons"); + + extension_guess["wav"] = tree->get_theme_icon("AudioStreamSample", "EditorIcons"); + extension_guess["ogg"] = tree->get_theme_icon("AudioStreamOGGVorbis", "EditorIcons"); + extension_guess["mp3"] = tree->get_theme_icon("AudioStreamMP3", "EditorIcons"); + extension_guess["scn"] = tree->get_theme_icon("PackedScene", "EditorIcons"); extension_guess["tscn"] = tree->get_theme_icon("PackedScene", "EditorIcons"); - extension_guess["shader"] = tree->get_theme_icon("Shader", "EditorIcons"); + extension_guess["escn"] = tree->get_theme_icon("PackedScene", "EditorIcons"); + extension_guess["dae"] = tree->get_theme_icon("PackedScene", "EditorIcons"); + extension_guess["gltf"] = tree->get_theme_icon("PackedScene", "EditorIcons"); + extension_guess["glb"] = tree->get_theme_icon("PackedScene", "EditorIcons"); + + extension_guess["gdshader"] = tree->get_theme_icon("Shader", "EditorIcons"); extension_guess["gd"] = tree->get_theme_icon("GDScript", "EditorIcons"); + if (Engine::get_singleton()->has_singleton("GodotSharp")) { + extension_guess["cs"] = tree->get_theme_icon("CSharpScript", "EditorIcons"); + } else { + // Mark C# support as unavailable. + extension_guess["cs"] = tree->get_theme_icon("ImportFail", "EditorIcons"); + } extension_guess["vs"] = tree->get_theme_icon("VisualScript", "EditorIcons"); + + extension_guess["res"] = tree->get_theme_icon("Resource", "EditorIcons"); + extension_guess["tres"] = tree->get_theme_icon("Resource", "EditorIcons"); + extension_guess["atlastex"] = tree->get_theme_icon("AtlasTexture", "EditorIcons"); + // By default, OBJ files are imported as Mesh resources rather than PackedScenes. + extension_guess["obj"] = tree->get_theme_icon("Mesh", "EditorIcons"); + + extension_guess["txt"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["md"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["rst"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["json"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["yml"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["yaml"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["toml"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["cfg"] = tree->get_theme_icon("TextFile", "EditorIcons"); + extension_guess["ini"] = tree->get_theme_icon("TextFile", "EditorIcons"); } Ref<Texture2D> generic_extension = tree->get_theme_icon("Object", "EditorIcons"); diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp index 1b4a505edb..85541c093a 100644 --- a/editor/editor_atlas_packer.cpp +++ b/editor/editor_atlas_packer.cpp @@ -105,7 +105,7 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h } Ref<BitMap> src_bitmap; - src_bitmap.instance(); + src_bitmap.instantiate(); src_bitmap->create(aabb.size / divide_by); int w = src_bitmap->get_size().width; diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 4317760379..3e3428ad93 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -525,7 +525,7 @@ void EditorAudioBus::_effect_add(int p_which) { StringName name = effect_options->get_item_metadata(p_which); - Object *fx = ClassDB::instance(name); + Object *fx = ClassDB::instantiate(name); ERR_FAIL_COND(!fx); AudioEffect *afx = Object::cast_to<AudioEffect>(fx); ERR_FAIL_COND(!afx); @@ -757,9 +757,9 @@ void EditorAudioBus::_bind_methods() { ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus); ClassDB::bind_method("update_send", &EditorAudioBus::update_send); ClassDB::bind_method("_gui_input", &EditorAudioBus::_gui_input); - ClassDB::bind_method("get_drag_data_fw", &EditorAudioBus::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &EditorAudioBus::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &EditorAudioBus::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &EditorAudioBus::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &EditorAudioBus::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &EditorAudioBus::drop_data_fw); ADD_SIGNAL(MethodInfo("duplicate_request")); ADD_SIGNAL(MethodInfo("delete_request")); @@ -782,7 +782,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { set_v_size_flags(SIZE_EXPAND_FILL); track_name = memnew(LineEdit); - track_name->connect("text_entered", callable_mp(this, &EditorAudioBus::_name_changed)); + track_name->connect("text_submitted", callable_mp(this, &EditorAudioBus::_name_changed)); track_name->connect("focus_exited", callable_mp(this, &EditorAudioBus::_name_focus_exit)); vb->add_child(track_name); @@ -921,7 +921,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) { ClassDB::get_inheriters_from_class("AudioEffect", &effects); effects.sort_custom<StringName::AlphCompare>(); for (List<StringName>::Element *E = effects.front(); E; E = E->next()) { - if (!ClassDB::can_instance(E->get())) { + if (!ClassDB::can_instantiate(E->get())) { continue; } @@ -1238,7 +1238,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) { } else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) { if (new_layout) { Ref<AudioBusLayout> empty_state; - empty_state.instance(); + empty_state.instantiate(); AudioServer::get_singleton()->set_bus_layout(empty_state); } diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index d46df05f6e..12ae55fbc1 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -327,7 +327,7 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { add_autoload->set_disabled(false); } -void EditorAutoloadSettings::_autoload_text_entered(const String p_name) { +void EditorAutoloadSettings::_autoload_text_submitted(const String p_name) { if (autoload_add_path->get_text() != "" && _autoload_name_is_valid(p_name, nullptr)) { _autoload_add(); } @@ -349,14 +349,14 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { Node *n = nullptr; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; - n = ps->instance(); + n = ps->instantiate(); } else if (res->is_class("Script")) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); ERR_FAIL_COND_V_MSG(!valid_type, nullptr, "Script does not inherit a Node: " + p_path + "."); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_FAIL_COND_V_MSG(obj == nullptr, nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + "."); @@ -749,9 +749,9 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) { void EditorAutoloadSettings::_bind_methods() { ClassDB::bind_method("_autoload_open", &EditorAutoloadSettings::_autoload_open); - ClassDB::bind_method("get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &EditorAutoloadSettings::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &EditorAutoloadSettings::drop_data_fw); ClassDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload); ClassDB::bind_method("autoload_add", &EditorAutoloadSettings::autoload_add); @@ -859,7 +859,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() { autoload_add_name = memnew(LineEdit); autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL); - autoload_add_name->connect("text_entered", callable_mp(this, &EditorAutoloadSettings::_autoload_text_entered)); + autoload_add_name->connect("text_submitted", callable_mp(this, &EditorAutoloadSettings::_autoload_text_submitted)); autoload_add_name->connect("text_changed", callable_mp(this, &EditorAutoloadSettings::_autoload_text_changed)); hbc->add_child(autoload_add_name); @@ -882,18 +882,17 @@ EditorAutoloadSettings::EditorAutoloadSettings() { tree->set_column_title(0, TTR("Name")); tree->set_column_expand(0, true); - tree->set_column_min_width(0, 100); + tree->set_column_expand_ratio(0, 1); tree->set_column_title(1, TTR("Path")); tree->set_column_expand(1, true); - tree->set_column_min_width(1, 100); + tree->set_column_clip_content(1, true); + tree->set_column_expand_ratio(1, 2); - tree->set_column_title(2, TTR("Singleton")); + tree->set_column_title(2, TTR("Global Variable")); tree->set_column_expand(2, false); - tree->set_column_min_width(2, 80 * EDSCALE); tree->set_column_expand(3, false); - tree->set_column_min_width(3, 120 * EDSCALE); tree->connect("cell_selected", callable_mp(this, &EditorAutoloadSettings::_autoload_selected)); tree->connect("item_edited", callable_mp(this, &EditorAutoloadSettings::_autoload_edited)); @@ -915,7 +914,7 @@ EditorAutoloadSettings::~EditorAutoloadSettings() { void EditorAutoloadSettings::_set_autoload_add_path(const String &p_text) { autoload_add_path->set_text(p_text); - autoload_add_path->emit_signal("text_entered", p_text); + autoload_add_path->emit_signal("text_submitted", p_text); } void EditorAutoloadSettings::_browse_autoload_add_path() { diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index 762457463c..b709728856 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -81,7 +81,7 @@ class EditorAutoloadSettings : public VBoxContainer { void _autoload_button_pressed(Object *p_item, int p_column, int p_button); void _autoload_activated(); void _autoload_path_text_changed(const String p_path); - void _autoload_text_entered(const String p_name); + void _autoload_text_submitted(const String p_name); void _autoload_text_changed(const String p_name); void _autoload_open(const String &fpath); void _autoload_file_callback(const String &p_path); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 6405af3876..3823d7e14f 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -31,9 +31,9 @@ #include "editor_data.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "editor_node.h" #include "editor_settings.h" #include "scene/resources/packed_scene.h" @@ -83,7 +83,7 @@ void EditorHistory::cleanup_history() { void EditorHistory::_add_object(ObjectID p_object, const String &p_property, int p_level_change, bool p_inspector_only) { Object *obj = ObjectDB::get_instance(p_object); ERR_FAIL_COND(!obj); - Reference *r = Object::cast_to<Reference>(obj); + RefCounted *r = Object::cast_to<RefCounted>(obj); Obj o; if (r) { o.ref = REF(r); @@ -476,7 +476,7 @@ Variant EditorData::instance_custom_type(const String &p_type, const String &p_i if (get_custom_types()[p_inherits][i].name == p_type) { Ref<Script> script = get_custom_types()[p_inherits][i].script; - Variant ob = ClassDB::instance(p_inherits); + Variant ob = ClassDB::instantiate(p_inherits); ERR_FAIL_COND_V(!ob, Variant()); Node *n = Object::cast_to<Node>(ob); if (n) { @@ -603,7 +603,7 @@ bool EditorData::check_and_update_scene(int p_idx) { if (must_reload) { Ref<PackedScene> pscene; - pscene.instance(); + pscene.instantiate(); EditorProgress ep("update_scene", TTR("Updating Scene"), 2); ep.step(TTR("Storing local changes..."), 0); @@ -611,7 +611,7 @@ bool EditorData::check_and_update_scene(int p_idx) { Error err = pscene->pack(edited_scene[p_idx].root); ERR_FAIL_COND_V(err != OK, false); ep.step(TTR("Updating scene..."), 1); - Node *new_scene = pscene->instance(PackedScene::GEN_EDIT_STATE_MAIN); + Node *new_scene = pscene->instantiate(PackedScene::GEN_EDIT_STATE_MAIN); ERR_FAIL_COND_V(!new_scene, false); //transfer selection @@ -908,7 +908,7 @@ StringName EditorData::script_class_get_base(const String &p_class) const { Variant EditorData::script_class_instance(const String &p_class) { if (ScriptServer::is_global_class(p_class)) { - Variant obj = ClassDB::instance(ScriptServer::get_global_class_native_base(p_class)); + Variant obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(p_class)); if (obj) { Ref<Script> script = script_class_load_script(p_class); if (script.is_valid()) { diff --git a/editor/editor_dir_dialog.h b/editor/editor_dir_dialog.h index 05451b7bda..ef473b0779 100644 --- a/editor/editor_dir_dialog.h +++ b/editor/editor_dir_dialog.h @@ -31,7 +31,7 @@ #ifndef EDITOR_DIR_DIALOG_H #define EDITOR_DIR_DIALOG_H -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "editor/editor_file_system.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 40313fbeff..fc483b46b7 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -33,14 +33,14 @@ #include "core/config/project_settings.h" #include "core/crypto/crypto_core.h" #include "core/io/config_file.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/io/zip_io.h" #include "core/object/script_language.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/version.h" #include "editor/editor_file_system.h" #include "editor/plugins/script_editor_plugin.h" @@ -151,7 +151,7 @@ void EditorExportPreset::set_export_path(const String &p_path) { export_path = p_path; /* NOTE(SonerSound): if there is a need to implement a PropertyHint that specifically indicates a relative path, * this should be removed. */ - if (export_path.is_abs_path()) { + if (export_path.is_absolute_path()) { String res_path = OS::get_singleton()->get_resource_dir(); export_path = res_path.path_to_file(export_path); } @@ -430,7 +430,7 @@ bool EditorExportPlatform::exists_export_template(String template_file_name, Str Ref<EditorExportPreset> EditorExportPlatform::create_preset() { Ref<EditorExportPreset> preset; - preset.instance(); + preset.instantiate(); preset->platform = Ref<EditorExportPlatform>(this); List<ExportOption> options; @@ -873,7 +873,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & if (FileAccess::exists(path + ".import")) { //file is imported, replace by what it imports Ref<ConfigFile> config; - config.instance(); + config.instantiate(); err = config->load(path + ".import"); if (err != OK) { ERR_PRINT("Could not parse: '" + path + "', not exported."); @@ -1391,7 +1391,7 @@ EditorExport *EditorExport::singleton = nullptr; void EditorExport::_save() { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); for (int i = 0; i < export_presets.size(); i++) { Ref<EditorExportPreset> preset = export_presets[i]; String section = "preset." + itos(i); @@ -1546,7 +1546,7 @@ void EditorExport::_notification(int p_what) { void EditorExport::load_config() { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load("res://export_presets.cfg"); if (err != OK) { return; diff --git a/editor/editor_export.h b/editor/editor_export.h index c96c8fdbce..c9401df9c2 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -31,8 +31,8 @@ #ifndef EDITOR_EXPORT_H #define EDITOR_EXPORT_H +#include "core/io/dir_access.h" #include "core/io/resource.h" -#include "core/os/dir_access.h" #include "scene/main/node.h" #include "scene/main/timer.h" #include "scene/resources/texture.h" @@ -42,8 +42,8 @@ class EditorExportPlatform; class EditorFileSystemDirectory; struct EditorProgress; -class EditorExportPreset : public Reference { - GDCLASS(EditorExportPreset, Reference); +class EditorExportPreset : public RefCounted { + GDCLASS(EditorExportPreset, RefCounted); public: enum ExportFilter { @@ -161,8 +161,8 @@ struct SharedObject { SharedObject() {} }; -class EditorExportPlatform : public Reference { - GDCLASS(EditorExportPlatform, Reference); +class EditorExportPlatform : public RefCounted { + GDCLASS(EditorExportPlatform, RefCounted); public: typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total, const Vector<String> &p_enc_in_filters, const Vector<String> &p_enc_ex_filters, const Vector<uint8_t> &p_key); @@ -284,8 +284,8 @@ public: EditorExportPlatform(); }; -class EditorExportPlugin : public Reference { - GDCLASS(EditorExportPlugin, Reference); +class EditorExportPlugin : public RefCounted { + GDCLASS(EditorExportPlugin, RefCounted); friend class EditorExportPlatform; diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index d232153206..58d2b6e86e 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -30,8 +30,8 @@ #include "editor_feature_profile.h" +#include "core/io/dir_access.h" #include "core/io/json.h" -#include "core/os/dir_access.h" #include "editor/editor_settings.h" #include "editor_node.h" #include "editor_scale.h" @@ -161,21 +161,21 @@ String EditorFeatureProfile::get_feature_description(Feature p_feature) { } Error EditorFeatureProfile::save_to_file(const String &p_path) { - Dictionary json; - json["type"] = "feature_profile"; + Dictionary data; + data["type"] = "feature_profile"; Array dis_classes; for (Set<StringName>::Element *E = disabled_classes.front(); E; E = E->next()) { dis_classes.push_back(String(E->get())); } dis_classes.sort(); - json["disabled_classes"] = dis_classes; + data["disabled_classes"] = dis_classes; Array dis_editors; for (Set<StringName>::Element *E = disabled_editors.front(); E; E = E->next()) { dis_editors.push_back(String(E->get())); } dis_editors.sort(); - json["disabled_editors"] = dis_editors; + data["disabled_editors"] = dis_editors; Array dis_props; @@ -185,7 +185,7 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) { } } - json["disabled_properties"] = dis_props; + data["disabled_properties"] = dis_props; Array dis_features; for (int i = 0; i < FEATURE_MAX; i++) { @@ -194,12 +194,13 @@ Error EditorFeatureProfile::save_to_file(const String &p_path) { } } - json["disabled_features"] = dis_features; + data["disabled_features"] = dis_features; FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE); ERR_FAIL_COND_V_MSG(!f, ERR_CANT_CREATE, "Cannot create file '" + p_path + "'."); - String text = JSON::print(json, "\t"); + JSON json; + String text = json.stringify(data, "\t"); f->store_string(text); f->close(); return OK; @@ -212,26 +213,24 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) { return err; } - String err_str; - int err_line; - Variant v; - err = JSON::parse(text, v, err_str, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(err_line) + ": " + err_str); + ERR_PRINT("Error parsing '" + p_path + "' on line " + itos(json.get_error_line()) + ": " + json.get_error_message()); return ERR_PARSE_ERROR; } - Dictionary json = v; + Dictionary data = json.get_data(); - if (!json.has("type") || String(json["type"]) != "feature_profile") { + if (!data.has("type") || String(data["type"]) != "feature_profile") { ERR_PRINT("Error parsing '" + p_path + "', it's not a feature profile."); return ERR_PARSE_ERROR; } disabled_classes.clear(); - if (json.has("disabled_classes")) { - Array disabled_classes_arr = json["disabled_classes"]; + if (data.has("disabled_classes")) { + Array disabled_classes_arr = data["disabled_classes"]; for (int i = 0; i < disabled_classes_arr.size(); i++) { disabled_classes.insert(disabled_classes_arr[i]); } @@ -239,8 +238,8 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) { disabled_editors.clear(); - if (json.has("disabled_editors")) { - Array disabled_editors_arr = json["disabled_editors"]; + if (data.has("disabled_editors")) { + Array disabled_editors_arr = data["disabled_editors"]; for (int i = 0; i < disabled_editors_arr.size(); i++) { disabled_editors.insert(disabled_editors_arr[i]); } @@ -248,16 +247,16 @@ Error EditorFeatureProfile::load_from_file(const String &p_path) { disabled_properties.clear(); - if (json.has("disabled_properties")) { - Array disabled_properties_arr = json["disabled_properties"]; + if (data.has("disabled_properties")) { + Array disabled_properties_arr = data["disabled_properties"]; for (int i = 0; i < disabled_properties_arr.size(); i++) { String s = disabled_properties_arr[i]; set_disable_class_property(s.get_slice(":", 0), s.get_slice(":", 1), true); } } - if (json.has("disabled_features")) { - Array disabled_features_arr = json["disabled_features"]; + if (data.has("disabled_features")) { + Array disabled_features_arr = data["disabled_features"]; for (int i = 0; i < FEATURE_MAX; i++) { bool found = false; String f = feature_identifiers[i]; @@ -312,7 +311,7 @@ void EditorFeatureProfileManager::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { current_profile = EDITOR_GET("_default_feature_profile"); if (current_profile != String()) { - current.instance(); + current.instantiate(); Error err = current->load_from_file(EditorSettings::get_singleton()->get_feature_profiles_dir().plus_file(current_profile + ".profile")); if (err != OK) { ERR_PRINT("Error loading default feature profile: " + current_profile); @@ -474,7 +473,7 @@ void EditorFeatureProfileManager::_create_new_profile() { } Ref<EditorFeatureProfile> new_profile; - new_profile.instance(); + new_profile.instantiate(); new_profile->save_to_file(file); _update_profile_list(name); @@ -731,7 +730,7 @@ void EditorFeatureProfileManager::_update_selected_profile() { ERR_FAIL_COND(current.is_null()); //nothing selected, current should never be null } else { //reload edited, if different from current - edited.instance(); + edited.instantiate(); Error err = edited->load_from_file(EditorSettings::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile")); ERR_FAIL_COND_MSG(err != OK, "Error when loading EditorSettings from file '" + EditorSettings::get_singleton()->get_feature_profiles_dir().plus_file(profile + ".profile") + "'."); } @@ -780,7 +779,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths //test it first for (int i = 0; i < p_paths.size(); i++) { Ref<EditorFeatureProfile> profile; - profile.instance(); + profile.instantiate(); Error err = profile->load_from_file(p_paths[i]); String basefile = p_paths[i].get_file(); if (err != OK) { @@ -799,7 +798,7 @@ void EditorFeatureProfileManager::_import_profiles(const Vector<String> &p_paths //do it second for (int i = 0; i < p_paths.size(); i++) { Ref<EditorFeatureProfile> profile; - profile.instance(); + profile.instantiate(); Error err = profile->load_from_file(p_paths[i]); ERR_CONTINUE(err != OK); String basefile = p_paths[i].get_file(); diff --git a/editor/editor_feature_profile.h b/editor/editor_feature_profile.h index e118b5f287..d31498bfc6 100644 --- a/editor/editor_feature_profile.h +++ b/editor/editor_feature_profile.h @@ -31,8 +31,8 @@ #ifndef EDITOR_FEATURE_PROFILE_H #define EDITOR_FEATURE_PROFILE_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "editor/editor_file_dialog.h" #include "editor_help.h" #include "scene/gui/dialogs.h" @@ -41,8 +41,8 @@ #include "scene/gui/split_container.h" #include "scene/gui/tree.h" -class EditorFeatureProfile : public Reference { - GDCLASS(EditorFeatureProfile, Reference); +class EditorFeatureProfile : public RefCounted { + GDCLASS(EditorFeatureProfile, RefCounted); public: enum Feature { diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 75815fa750..fe4c6f490d 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -30,7 +30,7 @@ #include "editor_file_dialog.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -230,14 +230,14 @@ void EditorFileDialog::update_dir() { } } -void EditorFileDialog::_dir_entered(String p_dir) { +void EditorFileDialog::_dir_submitted(String p_dir) { dir_access->change_dir(p_dir); invalidate(); update_dir(); _push_history(); } -void EditorFileDialog::_file_entered(const String &p_file) { +void EditorFileDialog::_file_submitted(const String &p_file) { _action_pressed(); } @@ -294,6 +294,9 @@ void EditorFileDialog::_post_popup() { if (res && name == "res://") { name = "/"; } else { + if (name.ends_with("/")) { + name = name.substr(0, name.length() - 1); + } name = name.get_file() + "/"; } bool exists = dir_access->dir_exists(recentd[i]); @@ -1541,7 +1544,7 @@ EditorFileDialog::EditorFileDialog() { pathhb->add_child(memnew(VSeparator)); Ref<ButtonGroup> view_mode_group; - view_mode_group.instance(); + view_mode_group.instantiate(); mode_thumbnails = memnew(Button); mode_thumbnails->set_flat(true); @@ -1673,8 +1676,8 @@ EditorFileDialog::EditorFileDialog() { item_list->connect("multi_selected", callable_mp(this, &EditorFileDialog::_multi_selected), varray(), CONNECT_DEFERRED); item_list->connect("item_activated", callable_mp(this, &EditorFileDialog::_item_dc_selected), varray()); item_list->connect("nothing_selected", callable_mp(this, &EditorFileDialog::_items_clear_selection)); - dir->connect("text_entered", callable_mp(this, &EditorFileDialog::_dir_entered)); - file->connect("text_entered", callable_mp(this, &EditorFileDialog::_file_entered)); + dir->connect("text_submitted", callable_mp(this, &EditorFileDialog::_dir_submitted)); + file->connect("text_submitted", callable_mp(this, &EditorFileDialog::_file_submitted)); filter->connect("item_selected", callable_mp(this, &EditorFileDialog::_filter_selected)); confirm_save = memnew(ConfirmationDialog); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 5a5e3a8807..d789956a3e 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -31,7 +31,7 @@ #ifndef EDITORFILEDIALOG_H #define EDITORFILEDIALOG_H -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "scene/gui/box_container.h" #include "scene/gui/dialogs.h" #include "scene/gui/item_list.h" @@ -167,8 +167,8 @@ private: void _item_menu_id_pressed(int p_option); void _select_drive(int p_idx); - void _dir_entered(String p_dir); - void _file_entered(const String &p_file); + void _dir_submitted(String p_dir); + void _file_submitted(const String &p_file); void _action_pressed(); void _save_confirm_pressed(); void _cancel_pressed(); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 69663b9ed9..a2507f3cf2 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -31,10 +31,10 @@ #include "editor_file_system.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_importer.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" #include "editor_node.h" @@ -1475,8 +1475,6 @@ void EditorFileSystem::update_file(const String &p_file) { if (cpos == -1) { // The file did not exist, it was added. - - late_added_files.insert(p_file); // Remember that it was added. This mean it will be scanned and imported on editor restart. int idx = 0; String file_name = p_file.get_file(); @@ -1526,7 +1524,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector Map<String, String> base_paths; for (int i = 0; i < p_files.size(); i++) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(p_files[i] + ".import"); ERR_CONTINUE(err != OK); ERR_CONTINUE(!config->has_section_key("remap", "importer")); @@ -1708,7 +1706,7 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName //use existing if (p_custom_options == nullptr) { Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); Error err = cf->load(p_file + ".import"); if (err == OK) { if (cf->has_section("params")) { @@ -1723,9 +1721,6 @@ void EditorFileSystem::_reimport_file(const String &p_file, const Map<StringName } } } - - } else { - late_added_files.insert(p_file); //imported files do not call update_file(), but just in case.. } if (importer_name == "keep") { @@ -1934,19 +1929,6 @@ void EditorFileSystem::_reimport_thread(uint32_t p_index, ImportThreadData *p_im } void EditorFileSystem::reimport_files(const Vector<String> &p_files) { - { - // Ensure that ProjectSettings::IMPORTED_FILES_PATH exists. - DirAccess *da = DirAccess::open("res://"); - if (da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) { - Error err = da->make_dir_recursive(ProjectSettings::IMPORTED_FILES_PATH); - if (err || da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) { - memdelete(da); - ERR_FAIL_MSG("Failed to create '" + ProjectSettings::IMPORTED_FILES_PATH + "' folder."); - } - } - memdelete(da); - } - importing = true; EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); @@ -2086,7 +2068,7 @@ void EditorFileSystem::_move_group_files(EditorFileSystemDirectory *efd, const S files[i]->import_group_file = p_new_location; Ref<ConfigFile> config; - config.instance(); + config.instantiate(); String path = efd->get_file_path(i) + ".import"; Error err = config->load(path); if (err != OK) { @@ -2177,13 +2159,9 @@ EditorFileSystem::EditorFileSystem() { scanning_changes = false; scanning_changes_done = false; - DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (da->change_dir(ProjectSettings::IMPORTED_FILES_PATH) != OK) { - da->make_dir(ProjectSettings::IMPORTED_FILES_PATH); - } // This should probably also work on Unix and use the string it returns for FAT32 or exFAT + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT"); - memdelete(da); scan_total = 0; update_script_classes_queued.clear(); diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 855c320856..37eee13c16 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -31,7 +31,7 @@ #ifndef EDITOR_FILE_SYSTEM_H #define EDITOR_FILE_SYSTEM_H -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/thread.h" #include "core/os/thread_safe.h" #include "core/templates/safe_refcount.h" @@ -148,7 +148,6 @@ class EditorFileSystem : public Node { void _scan_filesystem(); - Set<String> late_added_files; //keep track of files that were added, these will be re-scanned Set<String> late_update_files; void _save_late_updated_files(); diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp index 97a2c67c26..5d6c415d39 100644 --- a/editor/editor_folding.cpp +++ b/editor/editor_folding.cpp @@ -30,7 +30,7 @@ #include "editor_folding.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "editor_inspector.h" #include "editor_settings.h" @@ -50,7 +50,7 @@ Vector<String> EditorFolding::_get_unfolds(const Object *p_object) { void EditorFolding::save_resource_folding(const RES &p_resource, const String &p_path) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Vector<String> unfolds = _get_unfolds(p_resource.ptr()); config->set_value("folding", "sections_unfolded", unfolds); @@ -70,7 +70,7 @@ void EditorFolding::_set_unfolds(Object *p_object, const Vector<String> &p_unfol void EditorFolding::load_resource_folding(RES p_resource, const String &p_path) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; file = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(file); @@ -137,7 +137,7 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path } Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Array unfolds, res_unfolds; Set<RES> resources; @@ -155,7 +155,7 @@ void EditorFolding::save_scene_folding(const Node *p_scene, const String &p_path void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); String path = EditorSettings::get_singleton()->get_project_settings_dir(); String file = p_path.get_file() + "-folding-" + p_path.md5_text() + ".cfg"; diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 8a5142459c..d548196a2d 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -31,7 +31,7 @@ #include "editor_fonts.h" #include "builtin_fonts.gen.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "editor_scale.h" #include "editor_settings.h" #include "scene/resources/default_theme/default_theme.h" @@ -55,7 +55,7 @@ // the custom spacings might only work with Noto Sans #define MAKE_DEFAULT_FONT(m_name) \ Ref<Font> m_name; \ - m_name.instance(); \ + m_name.instantiate(); \ if (CustomFont.is_valid()) { \ m_name->add_data(CustomFont); \ m_name->add_data(DefaultFont); \ @@ -68,7 +68,7 @@ #define MAKE_BOLD_FONT(m_name) \ Ref<Font> m_name; \ - m_name.instance(); \ + m_name.instantiate(); \ if (CustomFontBold.is_valid()) { \ m_name->add_data(CustomFontBold); \ m_name->add_data(DefaultFontBold); \ @@ -81,7 +81,7 @@ #define MAKE_SOURCE_FONT(m_name) \ Ref<Font> m_name; \ - m_name.instance(); \ + m_name.instantiate(); \ if (CustomFontSource.is_valid()) { \ m_name->add_data(CustomFontSource); \ m_name->add_data(dfmono); \ @@ -129,7 +129,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { String custom_font_path = EditorSettings::get_singleton()->get("interface/editor/main_font"); Ref<FontData> CustomFont; if (custom_font_path.length() > 0 && dir->file_exists(custom_font_path)) { - CustomFont.instance(); + CustomFont.instantiate(); CustomFont->load_resource(custom_font_path, default_font_size); CustomFont->set_antialiased(font_antialiased); CustomFont->set_hinting(font_hinting); @@ -143,7 +143,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { String custom_font_path_bold = EditorSettings::get_singleton()->get("interface/editor/main_font_bold"); Ref<FontData> CustomFontBold; if (custom_font_path_bold.length() > 0 && dir->file_exists(custom_font_path_bold)) { - CustomFontBold.instance(); + CustomFontBold.instantiate(); CustomFontBold->load_resource(custom_font_path_bold, default_font_size); CustomFontBold->set_antialiased(font_antialiased); CustomFontBold->set_hinting(font_hinting); @@ -157,7 +157,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { String custom_font_path_source = EditorSettings::get_singleton()->get("interface/editor/code_font"); Ref<FontData> CustomFontSource; if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) { - CustomFontSource.instance(); + CustomFontSource.instantiate(); CustomFontSource->load_resource(custom_font_path_source, default_font_size); CustomFontSource->set_antialiased(font_antialiased); CustomFontSource->set_hinting(font_hinting); @@ -178,105 +178,105 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Droid Sans */ Ref<FontData> DefaultFont; - DefaultFont.instance(); + DefaultFont.instantiate(); DefaultFont->load_memory(_font_NotoSansUI_Regular, _font_NotoSansUI_Regular_size, "ttf", default_font_size); DefaultFont->set_antialiased(font_antialiased); DefaultFont->set_hinting(font_hinting); DefaultFont->set_force_autohinter(true); //just looks better..i think? Ref<FontData> DefaultFontBold; - DefaultFontBold.instance(); + DefaultFontBold.instantiate(); DefaultFontBold->load_memory(_font_NotoSansUI_Bold, _font_NotoSansUI_Bold_size, "ttf", default_font_size); DefaultFontBold->set_antialiased(font_antialiased); DefaultFontBold->set_hinting(font_hinting); DefaultFontBold->set_force_autohinter(true); // just looks better..i think? Ref<FontData> FontFallback; - FontFallback.instance(); + FontFallback.instantiate(); FontFallback->load_memory(_font_DroidSansFallback, _font_DroidSansFallback_size, "ttf", default_font_size); FontFallback->set_antialiased(font_antialiased); FontFallback->set_hinting(font_hinting); FontFallback->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontJapanese; - FontJapanese.instance(); + FontJapanese.instantiate(); FontJapanese->load_memory(_font_DroidSansJapanese, _font_DroidSansJapanese_size, "ttf", default_font_size); FontJapanese->set_antialiased(font_antialiased); FontJapanese->set_hinting(font_hinting); FontJapanese->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontArabic; - FontArabic.instance(); + FontArabic.instantiate(); FontArabic->load_memory(_font_NotoNaskhArabicUI_Regular, _font_NotoNaskhArabicUI_Regular_size, "ttf", default_font_size); FontArabic->set_antialiased(font_antialiased); FontArabic->set_hinting(font_hinting); FontArabic->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontBengali; - FontBengali.instance(); + FontBengali.instantiate(); FontBengali->load_memory(_font_NotoSansBengali_Regular, _font_NotoSansBengali_Regular_size, "ttf", default_font_size); FontBengali->set_antialiased(font_antialiased); FontBengali->set_hinting(font_hinting); FontBengali->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontGeorgian; - FontGeorgian.instance(); + FontGeorgian.instantiate(); FontGeorgian->load_memory(_font_NotoSansGeorgian_Regular, _font_NotoSansGeorgian_Regular_size, "ttf", default_font_size); FontGeorgian->set_antialiased(font_antialiased); FontGeorgian->set_hinting(font_hinting); FontGeorgian->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontHebrew; - FontHebrew.instance(); + FontHebrew.instantiate(); FontHebrew->load_memory(_font_NotoSansHebrew_Regular, _font_NotoSansHebrew_Regular_size, "ttf", default_font_size); FontHebrew->set_antialiased(font_antialiased); FontHebrew->set_hinting(font_hinting); FontHebrew->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontMalayalam; - FontMalayalam.instance(); + FontMalayalam.instantiate(); FontMalayalam->load_memory(_font_NotoSansMalayalamUI_Regular, _font_NotoSansMalayalamUI_Regular_size, "ttf", default_font_size); FontMalayalam->set_antialiased(font_antialiased); FontMalayalam->set_hinting(font_hinting); FontMalayalam->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontOriya; - FontOriya.instance(); + FontOriya.instantiate(); FontOriya->load_memory(_font_NotoSansOriyaUI_Regular, _font_NotoSansOriyaUI_Regular_size, "ttf", default_font_size); FontOriya->set_antialiased(font_antialiased); FontOriya->set_hinting(font_hinting); FontOriya->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontSinhala; - FontSinhala.instance(); + FontSinhala.instantiate(); FontSinhala->load_memory(_font_NotoSansSinhalaUI_Regular, _font_NotoSansSinhalaUI_Regular_size, "ttf", default_font_size); FontSinhala->set_antialiased(font_antialiased); FontSinhala->set_hinting(font_hinting); FontSinhala->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontTamil; - FontTamil.instance(); + FontTamil.instantiate(); FontTamil->load_memory(_font_NotoSansTamilUI_Regular, _font_NotoSansTamilUI_Regular_size, "ttf", default_font_size); FontTamil->set_antialiased(font_antialiased); FontTamil->set_hinting(font_hinting); FontTamil->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontTelugu; - FontTelugu.instance(); + FontTelugu.instantiate(); FontTelugu->load_memory(_font_NotoSansTeluguUI_Regular, _font_NotoSansTeluguUI_Regular_size, "ttf", default_font_size); FontTelugu->set_antialiased(font_antialiased); FontTelugu->set_hinting(font_hinting); FontTelugu->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontThai; - FontThai.instance(); + FontThai.instantiate(); FontThai->load_memory(_font_NotoSansThaiUI_Regular, _font_NotoSansThaiUI_Regular_size, "ttf", default_font_size); FontThai->set_antialiased(font_antialiased); FontThai->set_hinting(font_hinting); FontThai->set_force_autohinter(true); //just looks better..i think? Ref<FontData> FontHindi; - FontHindi.instance(); + FontHindi.instantiate(); FontHindi->load_memory(_font_NotoSansDevanagariUI_Regular, _font_NotoSansDevanagariUI_Regular_size, "ttf", default_font_size); FontHindi->set_antialiased(font_antialiased); FontHindi->set_hinting(font_hinting); @@ -285,7 +285,7 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Hack */ Ref<FontData> dfmono; - dfmono.instance(); + dfmono.instantiate(); dfmono->load_memory(_font_Hack_Regular, _font_Hack_Regular_size, "ttf", default_font_size); dfmono->set_antialiased(font_antialiased); dfmono->set_hinting(font_hinting); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 9361981db6..16db465a4a 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1761,7 +1761,7 @@ FindBar::FindBar() { search_text->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); search_text->set_h_size_flags(SIZE_EXPAND_FILL); search_text->connect("text_changed", callable_mp(this, &FindBar::_search_text_changed)); - search_text->connect("text_entered", callable_mp(this, &FindBar::_search_text_entered)); + search_text->connect("text_submitted", callable_mp(this, &FindBar::_search_text_submitted)); matches_label = memnew(Label); add_child(matches_label); @@ -1849,9 +1849,6 @@ bool FindBar::_search(bool p_search_previous) { bool keep = prev_search == stext; bool ret = rich_text_label->search(stext, keep, p_search_previous); - if (!ret) { - ret = rich_text_label->search(stext, false, p_search_previous); - } prev_search = stext; @@ -1878,7 +1875,7 @@ void FindBar::_update_results_count() { int from_pos = 0; while (true) { - int pos = full_text.find(searched, from_pos); + int pos = full_text.findn(searched, from_pos); if (pos == -1) { break; } @@ -1912,7 +1909,7 @@ void FindBar::_unhandled_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid()) { - if (k->is_pressed() && (rich_text_label->has_focus() || is_a_parent_of(get_focus_owner()))) { + if (k->is_pressed() && (rich_text_label->has_focus() || is_ancestor_of(get_focus_owner()))) { bool accepted = true; switch (k->get_keycode()) { @@ -1935,7 +1932,7 @@ void FindBar::_search_text_changed(const String &p_text) { search_next(); } -void FindBar::_search_text_entered(const String &p_text) { +void FindBar::_search_text_submitted(const String &p_text) { if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { search_prev(); } else { diff --git a/editor/editor_help.h b/editor/editor_help.h index 65e20f060c..69bb72c52d 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -61,7 +61,7 @@ class FindBar : public HBoxContainer { void _hide_bar(); void _search_text_changed(const String &p_text); - void _search_text_entered(const String &p_text); + void _search_text_submitted(const String &p_text); void _update_results_count(); void _update_matches_label(); diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index b93ffa9321..a9bbb92079 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -237,9 +237,11 @@ EditorHelpSearch::EditorHelpSearch() { results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); results_tree->set_columns(2); results_tree->set_column_title(0, TTR("Name")); + results_tree->set_column_clip_content(0, true); results_tree->set_column_title(1, TTR("Member Type")); results_tree->set_column_expand(1, false); - results_tree->set_column_min_width(1, 150 * EDSCALE); + results_tree->set_column_custom_minimum_width(1, 150 * EDSCALE); + results_tree->set_column_clip_content(1, true); results_tree->set_custom_minimum_size(Size2(0, 100) * EDSCALE); results_tree->set_hide_root(true); results_tree->set_select_mode(Tree::SELECT_ROW); diff --git a/editor/editor_help_search.h b/editor/editor_help_search.h index 350a02315f..75da2d5aba 100644 --- a/editor/editor_help_search.h +++ b/editor/editor_help_search.h @@ -83,7 +83,7 @@ public: EditorHelpSearch(); }; -class EditorHelpSearch::Runner : public Reference { +class EditorHelpSearch::Runner : public RefCounted { enum Phase { PHASE_MATCH_CLASSES_INIT, PHASE_MATCH_CLASSES, diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 20abe72750..4dd57cb1a8 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -380,7 +380,7 @@ StringName EditorProperty::get_edited_property() { void EditorProperty::update_property() { if (get_script_instance()) { - get_script_instance()->call("update_property"); + get_script_instance()->call("_update_property"); } } @@ -417,7 +417,7 @@ bool EditorPropertyRevert::may_node_be_in_instance(Node *p_node) { return might_be; // or might not be } -bool EditorPropertyRevert::get_instanced_node_original_property(Node *p_node, const StringName &p_prop, Variant &value) { +bool EditorPropertyRevert::get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value) { Node *node = p_node; Node *orig = node; @@ -524,7 +524,7 @@ bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringNam if (node && EditorPropertyRevert::may_node_be_in_instance(node)) { //check for difference including instantiation Variant vorig; - if (EditorPropertyRevert::get_instanced_node_original_property(node, p_property, vorig)) { + if (EditorPropertyRevert::get_instantiated_node_original_property(node, p_property, vorig)) { Variant v = p_object->get(p_property); if (EditorPropertyRevert::is_node_property_different(node, v, vorig)) { @@ -753,7 +753,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) { call_deferred("emit_changed", property, object->get(property).operator int64_t() + 1, "", false); } - call_deferred("update_property"); + call_deferred("_update_property"); } } if (delete_rect.has_point(mpos)) { @@ -764,7 +764,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) { Variant vorig; Node *node = Object::cast_to<Node>(object); - if (node && EditorPropertyRevert::may_node_be_in_instance(node) && EditorPropertyRevert::get_instanced_node_original_property(node, property, vorig)) { + if (node && EditorPropertyRevert::may_node_be_in_instance(node) && EditorPropertyRevert::get_instantiated_node_original_property(node, property, vorig)) { emit_changed(property, vorig.duplicate(true)); update_property(); return; @@ -965,9 +965,7 @@ void EditorProperty::_bind_methods() { ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx"))); - MethodInfo vm; - vm.name = "update_property"; - BIND_VMETHOD(vm); + BIND_VMETHOD(MethodInfo("_update_property")); } EditorProperty::EditorProperty() { @@ -1023,24 +1021,24 @@ void EditorInspectorPlugin::add_property_editor_for_multiple_properties(const St bool EditorInspectorPlugin::can_handle(Object *p_object) { if (get_script_instance()) { - return get_script_instance()->call("can_handle", p_object); + return get_script_instance()->call("_can_handle", p_object); } return false; } void EditorInspectorPlugin::parse_begin(Object *p_object) { if (get_script_instance()) { - get_script_instance()->call("parse_begin", p_object); + get_script_instance()->call("_parse_begin", p_object); } } void EditorInspectorPlugin::parse_category(Object *p_object, const String &p_parse_category) { if (get_script_instance()) { - get_script_instance()->call("parse_category", p_object, p_parse_category); + get_script_instance()->call("_parse_category", p_object, p_parse_category); } } -bool EditorInspectorPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if (get_script_instance()) { Variant arg[6] = { p_object, p_type, p_path, p_hint, p_hint_text, p_usage @@ -1050,14 +1048,14 @@ bool EditorInspectorPlugin::parse_property(Object *p_object, Variant::Type p_typ }; Callable::CallError err; - return get_script_instance()->call("parse_property", (const Variant **)&argptr, 6, err); + return get_script_instance()->call("_parse_property", (const Variant **)&argptr, 6, err); } return false; } void EditorInspectorPlugin::parse_end() { if (get_script_instance()) { - get_script_instance()->call("parse_end"); + get_script_instance()->call("_parse_end"); } } @@ -1066,30 +1064,11 @@ void EditorInspectorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_property_editor", "property", "editor"), &EditorInspectorPlugin::add_property_editor); ClassDB::bind_method(D_METHOD("add_property_editor_for_multiple_properties", "label", "properties", "editor"), &EditorInspectorPlugin::add_property_editor_for_multiple_properties); - MethodInfo vm; - vm.name = "can_handle"; - vm.return_val.type = Variant::BOOL; - vm.arguments.push_back(PropertyInfo(Variant::OBJECT, "object")); - BIND_VMETHOD(vm); - vm.name = "parse_begin"; - vm.return_val.type = Variant::NIL; - BIND_VMETHOD(vm); - vm.name = "parse_category"; - vm.arguments.push_back(PropertyInfo(Variant::STRING, "category")); - BIND_VMETHOD(vm); - vm.arguments.pop_back(); - vm.name = "parse_property"; - vm.return_val.type = Variant::BOOL; - vm.arguments.push_back(PropertyInfo(Variant::INT, "type")); - vm.arguments.push_back(PropertyInfo(Variant::STRING, "path")); - vm.arguments.push_back(PropertyInfo(Variant::INT, "hint")); - vm.arguments.push_back(PropertyInfo(Variant::STRING, "hint_text")); - vm.arguments.push_back(PropertyInfo(Variant::INT, "usage")); - BIND_VMETHOD(vm); - vm.arguments.clear(); - vm.name = "parse_end"; - vm.return_val.type = Variant::NIL; - BIND_VMETHOD(vm); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_handle", PropertyInfo(Variant::OBJECT, "object"))); + BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_begin")); + BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_category", PropertyInfo(Variant::STRING, "category"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_parse_property", PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "hint"), PropertyInfo(Variant::STRING, "hint_text"), PropertyInfo(Variant::INT, "usage"))); + BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_end")); } //////////////////////////////////////////////// @@ -1203,15 +1182,19 @@ void EditorInspectorSection::_notification(int p_what) { Size2 size = get_size(); Point2 offset; + Rect2 rect; offset.y = font->get_height(font_size); if (arrow.is_valid()) { offset.y = MAX(offset.y, arrow->get_height()); } offset.y += get_theme_constant("vseparation", "Tree"); - offset.x += get_theme_constant("inspector_margin", "Editor"); - - Rect2 rect(offset, size - offset); + if (is_layout_rtl()) { + rect = Rect2(offset, size - offset - Vector2(get_theme_constant("inspector_margin", "Editor"), 0)); + } else { + offset.x += get_theme_constant("inspector_margin", "Editor"); + rect = Rect2(offset, size - offset); + } //set children for (int i = 0; i < get_child_count(); i++) { @@ -1290,7 +1273,7 @@ void EditorInspectorSection::_notification(int p_what) { Control *editor_property = Object::cast_to<Control>(vbox->get_child(child_idx)); // Test can_drop_data and can_drop_data_fw, since can_drop_data only works if set up with forwarding or if script attached. - if (editor_property && (editor_property->can_drop_data(Point2(), dd) || editor_property->call("can_drop_data_fw", Point2(), dd, this))) { + if (editor_property && (editor_property->can_drop_data(Point2(), dd) || editor_property->call("_can_drop_data_fw", Point2(), dd, this))) { children_can_drop = true; break; } @@ -1454,7 +1437,7 @@ EditorInspectorSection::~EditorInspectorSection() { Ref<EditorInspectorPlugin> EditorInspector::inspector_plugins[MAX_PLUGINS]; int EditorInspector::inspector_plugin_count = 0; -EditorProperty *EditorInspector::instantiate_property_editor(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +EditorProperty *EditorInspector::instantiate_property_editor(Object *p_object, const Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { for (int i = inspector_plugin_count - 1; i >= 0; i--) { inspector_plugins[i]->parse_property(p_object, p_type, p_path, p_hint, p_hint_text, p_usage, p_wide); if (inspector_plugins[i]->added_editors.size()) { diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 348dea7086..ee70bd4397 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -40,7 +40,7 @@ class UndoRedo; class EditorPropertyRevert { public: static bool may_node_be_in_instance(Node *p_node); - static bool get_instanced_node_original_property(Node *p_node, const StringName &p_prop, Variant &value); + static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value); static bool is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig); static bool can_property_revert(Object *p_object, const StringName &p_property); @@ -83,7 +83,7 @@ private: bool draw_top_bg; bool _is_property_different(const Variant &p_current, const Variant &p_orig); - bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value); + bool _get_instantiated_node_original_property(const StringName &p_prop, Variant &value); void _focusable_focused(int p_index); bool selectable; @@ -175,8 +175,8 @@ public: EditorProperty(); }; -class EditorInspectorPlugin : public Reference { - GDCLASS(EditorInspectorPlugin, Reference); +class EditorInspectorPlugin : public RefCounted { + GDCLASS(EditorInspectorPlugin, RefCounted); friend class EditorInspector; struct AddedEditor { @@ -198,7 +198,7 @@ public: virtual bool can_handle(Object *p_object); virtual void parse_begin(Object *p_object); virtual void parse_category(Object *p_object, const String &p_parse_category); - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false); + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false); virtual void parse_end(); }; @@ -271,7 +271,7 @@ class EditorInspector : public ScrollContainer { VBoxContainer *main_vbox; - //map use to cache the instanced editors + //map use to cache the instantiated editors Map<StringName, List<EditorProperty *>> editor_property_map; List<EditorInspectorSection *> sections; Set<StringName> pending; @@ -356,7 +356,7 @@ public: static void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); static void cleanup_plugins(); - static EditorProperty *instantiate_property_editor(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false); + static EditorProperty *instantiate_property_editor(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false); void set_undo_redo(UndoRedo *p_undo_redo); diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp index 0bf1863459..437841ccc1 100644 --- a/editor/editor_layouts_dialog.cpp +++ b/editor/editor_layouts_dialog.cpp @@ -83,7 +83,7 @@ void EditorLayoutsDialog::_post_popup() { layout_names->clear(); Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 35d8021394..b3e90236a6 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -103,7 +103,7 @@ void EditorLog::_start_state_save_timer() { void EditorLog::_save_state() { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); // Load and amend existing config if it exists. config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); @@ -122,22 +122,21 @@ void EditorLog::_load_state() { is_loading_state = true; Ref<ConfigFile> config; - config.instance(); - Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); - - if (err == OK) { - const String section = "editor_log"; - for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) { - E->get()->set_active(config->get_value(section, "log_filter_" + itos(E->key()), false)); - } + config.instantiate(); + config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); - collapse = config->get_value(section, "collapse", false); - collapse_button->set_pressed(collapse); - bool show_search = config->get_value(section, "show_search", true); - search_box->set_visible(show_search); - show_search_button->set_pressed(show_search); + // Run the below code even if config->load returns an error, since we want the defaults to be set even if the file does not exist yet. + const String section = "editor_log"; + for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) { + E->get()->set_active(config->get_value(section, "log_filter_" + itos(E->key()), true)); } + collapse = config->get_value(section, "collapse", false); + collapse_button->set_pressed(collapse); + bool show_search = config->get_value(section, "show_search", true); + search_box->set_visible(show_search); + show_search_button->set_pressed(show_search); + is_loading_state = false; } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 85d19eb747..4cfa2d7338 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -32,17 +32,19 @@ #include "core/config/project_settings.h" #include "core/core_bind.h" +#include "core/extension/native_extension_manager.h" #include "core/input/input.h" #include "core/io/config_file.h" +#include "core/io/file_access.h" #include "core/io/image_loader.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/io/stream_peer_ssl.h" #include "core/object/class_db.h" #include "core/object/message_queue.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/string/print_string.h" #include "core/string/translation.h" #include "core/version.h" @@ -119,7 +121,6 @@ #include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/asset_library_editor_plugin.h" #include "editor/plugins/audio_stream_editor_plugin.h" -#include "editor/plugins/baked_lightmap_editor_plugin.h" #include "editor/plugins/camera_3d_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/collision_polygon_2d_editor_plugin.h" @@ -132,13 +133,14 @@ #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/editor_preview_plugins.h" #include "editor/plugins/font_editor_plugin.h" -#include "editor/plugins/gi_probe_editor_plugin.h" #include "editor/plugins/gpu_particles_2d_editor_plugin.h" #include "editor/plugins/gpu_particles_3d_editor_plugin.h" #include "editor/plugins/gpu_particles_collision_sdf_editor_plugin.h" #include "editor/plugins/gradient_editor_plugin.h" +#include "editor/plugins/input_event_editor_plugin.h" #include "editor/plugins/item_list_editor_plugin.h" #include "editor/plugins/light_occluder_2d_editor_plugin.h" +#include "editor/plugins/lightmap_gi_editor_plugin.h" #include "editor/plugins/line_2d_editor_plugin.h" #include "editor/plugins/material_editor_plugin.h" #include "editor/plugins/mesh_editor_plugin.h" @@ -175,6 +177,7 @@ #include "editor/plugins/tiles/tiles_editor_plugin.h" #include "editor/plugins/version_control_editor_plugin.h" #include "editor/plugins/visual_shader_editor_plugin.h" +#include "editor/plugins/voxel_gi_editor_plugin.h" #include "editor/progress_dialog.h" #include "editor/project_export.h" #include "editor/project_settings_editor.h" @@ -484,8 +487,8 @@ void EditorNode::_update_from_settings() { RS::get_singleton()->environment_set_sdfgi_frames_to_converge(frames_to_converge); RS::EnvironmentSDFGIRayCount ray_count = RS::EnvironmentSDFGIRayCount(int(GLOBAL_GET("rendering/global_illumination/sdfgi/probe_ray_count"))); RS::get_singleton()->environment_set_sdfgi_ray_count(ray_count); - RS::GIProbeQuality gi_probe_quality = RS::GIProbeQuality(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality"))); - RS::get_singleton()->gi_probe_set_quality(gi_probe_quality); + RS::VoxelGIQuality voxel_gi_quality = RS::VoxelGIQuality(int(GLOBAL_GET("rendering/global_illumination/voxel_gi/quality"))); + RS::get_singleton()->voxel_gi_set_quality(voxel_gi_quality); RS::get_singleton()->environment_set_volumetric_fog_volume_size(GLOBAL_GET("rendering/environment/volumetric_fog/volume_size"), GLOBAL_GET("rendering/environment/volumetric_fog/volume_depth")); RS::get_singleton()->environment_set_volumetric_fog_filter_active(bool(GLOBAL_GET("rendering/environment/volumetric_fog/use_filter"))); RS::get_singleton()->canvas_set_shadow_texture_size(GLOBAL_GET("rendering/2d/shadow_atlas/size")); @@ -589,8 +592,7 @@ void EditorNode::_notification(int p_what) { _initializing_addons = false; } - RenderingServer::get_singleton()->viewport_set_hide_scenario(get_scene_root()->get_viewport_rid(), true); - RenderingServer::get_singleton()->viewport_set_hide_canvas(get_scene_root()->get_viewport_rid(), true); + RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true); RenderingServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(), true); feature_profile_manager->notify_changed(); @@ -608,7 +610,7 @@ void EditorNode::_notification(int p_what) { } break; case NOTIFICATION_APPLICATION_FOCUS_IN: { - // Restore the original FPS cap after focusing back on the editor + // Restore the original FPS cap after focusing back on the editor. OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec"))); EditorFileSystem::get_singleton()->scan_changes(); @@ -616,7 +618,12 @@ void EditorNode::_notification(int p_what) { } break; case NOTIFICATION_APPLICATION_FOCUS_OUT: { - // Set a low FPS cap to decrease CPU/GPU usage while the editor is unfocused + // Save on focus loss before applying the FPS limit to avoid slowing down the saving process. + if (EDITOR_GET("interface/editor/save_on_focus_loss")) { + _menu_option_confirm(FILE_SAVE_SCENE, false); + } + + // Set a low FPS cap to decrease CPU/GPU usage while the editor is unfocused. OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/unfocused_low_processor_mode_sleep_usec"))); } break; @@ -702,6 +709,7 @@ void EditorNode::_notification(int p_what) { p->set_item_icon(p->get_item_index(HELP_DOCS), gui_base->get_theme_icon("Instance", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_QA), gui_base->get_theme_icon("Instance", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_REPORT_A_BUG), gui_base->get_theme_icon("Instance", "EditorIcons")); + p->set_item_icon(p->get_item_index(HELP_SUGGEST_A_FEATURE), gui_base->get_theme_icon("Instance", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_SEND_DOCS_FEEDBACK), gui_base->get_theme_icon("Instance", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_COMMUNITY), gui_base->get_theme_icon("Instance", "EditorIcons")); p->set_item_icon(p->get_item_index(HELP_ABOUT), gui_base->get_theme_icon("Godot", "EditorIcons")); @@ -770,7 +778,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) { if (!res->editor_can_reload_from_file()) { continue; } - if (!res->get_path().is_resource_file() && !res->get_path().is_abs_path()) { + if (!res->get_path().is_resource_file() && !res->get_path().is_absolute_path()) { continue; } if (!FileAccess::exists(res->get_path())) { @@ -1237,7 +1245,7 @@ void EditorNode::_get_scene_metadata(const String &p_file) { String path = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); Error err = cf->load(path); if (err != OK || !cf->has_section("editor_states")) { @@ -1271,7 +1279,7 @@ void EditorNode::_set_scene_metadata(const String &p_file, int p_idx) { String path = EditorSettings::get_singleton()->get_project_settings_dir().plus_file(p_file.get_file() + "-editstate-" + p_file.md5_text() + ".cfg"); Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); Dictionary md; @@ -1416,7 +1424,7 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) { // We cannot fallback on the 2D editor, because it may not have been used yet, // which would result in an invalid texture. if (c3d == 0 && c2d == 0) { - img.instance(); + img.instantiate(); img->create(1, 1, false, Image::FORMAT_RGB8); } else if (c3d < c2d) { Ref<ViewportTexture> viewport_texture = scene_root->get_texture(); @@ -1587,6 +1595,8 @@ void EditorNode::_save_scene(String p_file, int idx) { return; } + scene->propagate_notification(NOTIFICATION_EDITOR_PRE_SAVE); + editor_data.apply_changes_in_editors(); List<Ref<AnimatedValuesBackup>> anim_backups; _reset_animation_players(scene, &anim_backups); @@ -1599,16 +1609,16 @@ void EditorNode::_save_scene(String p_file, int idx) { if (ResourceCache::has(p_file)) { // something may be referencing this resource and we are good with that. // we must update it, but also let the previous scene state go, as - // old version still work for referencing changes in instanced or inherited scenes + // old version still work for referencing changes in instantiated or inherited scenes sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(p_file))); if (sdata.is_valid()) { sdata->recreate_state(); } else { - sdata.instance(); + sdata.instantiate(); } } else { - sdata.instance(); + sdata.instantiate(); } Error err = sdata->pack(scene); @@ -1617,15 +1627,6 @@ void EditorNode::_save_scene(String p_file, int idx) { return; } - // force creation of node path cache - // (hacky but needed for the tree to update properly) - Node *dummy_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!dummy_scene) { - show_accept(TTR("Couldn't save scene. Likely dependencies (instances or inheritance) couldn't be satisfied."), TTR("OK")); - return; - } - memdelete(dummy_scene); - int flg = 0; if (EditorSettings::get_singleton()->get("filesystem/on_save/compress_binary_resources")) { flg |= ResourceSaver::FLAG_COMPRESS; @@ -1658,6 +1659,8 @@ void EditorNode::_save_scene(String p_file, int idx) { } else { _dialog_display_save_error(p_file, err); } + + scene->propagate_notification(NOTIFICATION_EDITOR_POST_SAVE); } void EditorNode::save_all_scenes() { @@ -1839,11 +1842,11 @@ void EditorNode::_dialog_action(String p_file) { } Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err == ERR_FILE_CANT_OPEN || err == ERR_FILE_NOT_FOUND) { - config.instance(); // new config + config.instantiate(); // new config } else if (err != OK) { show_warning(TTR("An error occurred while trying to save the editor layout.\nMake sure the editor's user data path is writable.")); return; @@ -1867,7 +1870,7 @@ void EditorNode::_dialog_action(String p_file) { } Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK || !config->has_section(p_file)) { @@ -2072,7 +2075,7 @@ void EditorNode::_edit_current() { editable_warning = TTR("This resource belongs to a scene that was imported, so it's not editable.\nPlease read the documentation relevant to importing scenes to better understand this workflow."); } else { if ((!get_edited_scene() || get_edited_scene()->get_filename() != base_path) && ResourceLoader::get_resource_type(base_path) == "PackedScene") { - editable_warning = TTR("This resource belongs to a scene that was instanced or inherited.\nChanges to it won't be kept when saving the current scene."); + editable_warning = TTR("This resource belongs to a scene that was instantiated or inherited.\nChanges to it won't be kept when saving the current scene."); } } } else if (current_res->get_path().is_resource_file()) { @@ -2157,9 +2160,14 @@ void EditorNode::_edit_current() { if (!inspector_only) { EditorPlugin *main_plugin = editor_data.get_editor(current_obj); - for (int i = 0; i < editor_table.size(); i++) { - if (editor_table[i] == main_plugin && !main_editor_buttons[i]->is_visible()) { - main_plugin = nullptr; //if button is not visible, then no plugin active + int plugin_index = 0; + for (; plugin_index < editor_table.size(); plugin_index++) { + if (editor_table[plugin_index] == main_plugin) { + if (!main_editor_buttons[plugin_index]->is_visible()) { + main_plugin = nullptr; //if button is not visible, then no plugin active + } + + break; } } @@ -2173,26 +2181,8 @@ void EditorNode::_edit_current() { else if (main_plugin != editor_plugin_screen && (!ScriptEditor::get_singleton() || !ScriptEditor::get_singleton()->is_visible_in_tree() || ScriptEditor::get_singleton()->can_take_away_focus())) { // update screen main_plugin - - if (!changing_scene) { - if (editor_plugin_screen) { - editor_plugin_screen->make_visible(false); - } - editor_plugin_screen = main_plugin; - editor_plugin_screen->edit(current_obj); - - editor_plugin_screen->make_visible(true); - - int plugin_count = editor_data.get_editor_plugin_count(); - for (int i = 0; i < plugin_count; i++) { - editor_data.get_editor_plugin(i)->notify_main_screen_changed(editor_plugin_screen->get_name()); - } - - for (int i = 0; i < editor_table.size(); i++) { - main_editor_buttons[i]->set_pressed(editor_table[i] == main_plugin); - } - } - + _editor_select(plugin_index); + main_plugin->edit(current_obj); } else { editor_plugin_screen->edit(current_obj); } @@ -2411,11 +2401,13 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } break; - case FILE_CLOSE_ALL_AND_QUIT: - case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER: case FILE_CLOSE: { + _scene_tab_closed(editor_data.get_edited_scene()); + } break; + case FILE_CLOSE_ALL_AND_QUIT: + case FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER: { if (!p_confirmed) { - tab_closing = p_option == FILE_CLOSE ? editor_data.get_edited_scene() : _next_unsaved_scene(false); + tab_closing = _next_unsaved_scene(false); _scene_tab_changed(tab_closing); if (unsaved_cache || p_option == FILE_CLOSE_ALL_AND_QUIT || p_option == FILE_CLOSE_ALL_AND_RUN_PROJECT_MANAGER) { @@ -2428,8 +2420,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { break; } } - } else if (p_option == FILE_CLOSE) { - tab_closing = editor_data.get_edited_scene(); } if (!editor_data.get_edited_scene_root(tab_closing)) { // empty tab @@ -2701,6 +2691,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case FILE_EXPLORE_ANDROID_BUILD_TEMPLATES: { OS::get_singleton()->shell_open("file://" + ProjectSettings::get_singleton()->get_resource_path().plus_file("android")); } break; + case RUN_RELOAD_CURRENT_PROJECT: { + restart_editor(); + } break; case FILE_QUIT: case RUN_PROJECT_MANAGER: { if (!p_confirmed) { @@ -2720,7 +2713,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } save_confirmation->get_ok_button()->set_text(TTR("Save & Quit")); - save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes the following scene(s) before opening Project Manager?")) + unsaved_scenes); + save_confirmation->set_text((p_option == FILE_QUIT ? TTR("Save changes to the following scene(s) before quitting?") : TTR("Save changes to the following scene(s) before opening Project Manager?")) + unsaved_scenes); save_confirmation->popup_centered(); } } @@ -2804,6 +2797,9 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case HELP_REPORT_A_BUG: { OS::get_singleton()->shell_open("https://github.com/godotengine/godot/issues"); } break; + case HELP_SUGGEST_A_FEATURE: { + OS::get_singleton()->shell_open("https://github.com/godotengine/godot-proposals#readme"); + } break; case HELP_SEND_DOCS_FEEDBACK: { OS::get_singleton()->shell_open("https://github.com/godotengine/godot-docs/issues"); } break; @@ -2832,7 +2828,7 @@ void EditorNode::_request_screenshot() { } void EditorNode::_screenshot(bool p_use_utc) { - String name = "editor_screenshot_" + OS::get_singleton()->get_iso_date_time(p_use_utc).replace(":", "") + ".png"; + String name = "editor_screenshot_" + Time::get_singleton()->get_datetime_string_from_system(p_use_utc).replace(":", "") + ".png"; NodePath path = String("user://") + name; _save_screenshot(path); if (EditorSettings::get_singleton()->get("interface/editor/automatically_open_screenshots")) { @@ -3144,7 +3140,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, } Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); if (!DirAccess::exists(p_addon.get_base_dir())) { _remove_plugin_from_enabled(p_addon); WARN_PRINT("Addon '" + p_addon + "' failed to load. No directory found. Removing from enabled plugins."); @@ -3525,7 +3521,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b sdata->set_path(lpath, true); //take over path } - Node *new_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_MAIN); + Node *new_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_MAIN); if (!new_scene) { sdata.unref(); @@ -3589,11 +3585,11 @@ void EditorNode::open_request(const String &p_path) { } void EditorNode::request_instance_scene(const String &p_path) { - scene_tree_dock->instance(p_path); + scene_tree_dock->instantiate(p_path); } -void EditorNode::request_instance_scenes(const Vector<String> &p_files) { - scene_tree_dock->instance_scenes(p_files); +void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) { + scene_tree_dock->instantiate_scenes(p_files); } ImportDock *EditorNode::get_import_dock() { @@ -3617,8 +3613,8 @@ void EditorNode::_inherit_request(String p_file) { _dialog_action(p_file); } -void EditorNode::_instance_request(const Vector<String> &p_files) { - request_instance_scenes(p_files); +void EditorNode::_instantiate_request(const Vector<String> &p_files) { + request_instantiate_scenes(p_files); } void EditorNode::_close_messages() { @@ -3736,10 +3732,6 @@ bool EditorNode::is_scene_in_use(const String &p_path) { return false; } -void EditorNode::register_editor_paths(bool p_for_project_manager) { - EditorPaths::create(p_for_project_manager); -} - void EditorNode::register_editor_types() { ResourceLoader::set_timestamp_on_load(true); ResourceSaver::set_timestamp_on_save(true); @@ -3784,9 +3776,12 @@ void EditorNode::register_editor_types() { ClassDB::register_class<EditorScenePostImport>(); //ClassDB::register_type<EditorImportExport>(); ClassDB::register_class<EditorDebuggerPlugin>(); + + NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR); } void EditorNode::unregister_editor_types() { + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_EDITOR); _init_callbacks.clear(); if (EditorPaths::get_singleton()) { EditorPaths::free(); @@ -3880,6 +3875,21 @@ Ref<ImageTexture> EditorNode::_load_custom_class_icon(const String &p_path) cons return nullptr; } +void EditorNode::_pick_main_scene_custom_action(const String &p_custom_action_name) { + if (p_custom_action_name == "select_current") { + Node *scene = editor_data.get_edited_scene_root(); + + if (!scene) { + show_accept(TTR("There is no defined scene to run."), TTR("OK")); + return; + } + + pick_main_scene->hide(); + current_option = SETTINGS_PICK_MAIN_SCENE; + _dialog_action(scene->get_filename()); + } +} + Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String &p_fallback) const { ERR_FAIL_COND_V(!p_object || !gui_base, nullptr); @@ -4356,7 +4366,7 @@ void EditorNode::_save_docks() { return; //scanning, do not touch docks } Ref<ConfigFile> config; - config.instance(); + config.instantiate(); // Load and amend existing config if it exists. config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); @@ -4421,7 +4431,7 @@ void EditorNode::_dock_split_dragged(int ofs) { void EditorNode::_load_docks() { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); if (err != OK) { //no config @@ -4654,7 +4664,7 @@ bool EditorNode::has_scenes_in_session() { return false; } Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_project_settings_dir().plus_file("editor_layout.cfg")); if (err != OK) { return false; @@ -4674,6 +4684,14 @@ bool EditorNode::ensure_main_scene(bool p_from_native) { current_option = -1; pick_main_scene->set_text(TTR("No main scene has ever been defined, select one?\nYou can change it later in \"Project Settings\" under the 'application' category.")); pick_main_scene->popup_centered(); + + if (editor_data.get_edited_scene_root()) { + select_current_scene_button->set_disabled(false); + select_current_scene_button->grab_focus(); + } else { + select_current_scene_button->set_disabled(true); + } + return false; } @@ -4747,7 +4765,7 @@ void EditorNode::_update_layouts_menu() { editor_layouts->add_shortcut(ED_SHORTCUT("layout/default", TTR("Default")), SETTINGS_LAYOUT_DEFAULT); Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; //no config @@ -4790,7 +4808,7 @@ void EditorNode::_layout_menu_option(int p_id) { } break; default: { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config()); if (err != OK) { return; //no config @@ -5341,7 +5359,7 @@ void EditorNode::reload_scene(const String &p_path) { if (scene_idx == -1) { if (get_edited_scene()) { - //scene is not open, so at it might be instanced. We'll refresh the whole scene later. + //scene is not open, so at it might be instantiated. We'll refresh the whole scene later. editor_data.get_undo_redo().clear_history(); } return; @@ -5698,34 +5716,10 @@ EditorNode::EditorNode() { int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale"); switch (display_scale) { - case 0: { + case 0: // Try applying a suitable display scale automatically. - // The code below is adapted in `editor/editor_settings.cpp` and `editor/project_manager.cpp`. - // Make sure to update those when modifying the code below. -#ifdef OSX_ENABLED - editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale()); -#else - const int screen = DisplayServer::get_singleton()->window_get_current_screen(); - float scale; - if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) { - // hiDPI display. - scale = 2.0; - } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) { - // Likely a hiDPI display, but we aren't certain due to the returned DPI. - // Use an intermediate scale to handle this situation. - scale = 1.5; - } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) { - // Small loDPI display. Use a smaller display scale so that editor elements fit more easily. - // Icons won't look great, but this is better than having editor elements overflow from its window. - scale = 0.75; - } else { - scale = 1.0; - } - - editor_set_scale(scale); -#endif - } break; - + editor_set_scale(EditorSettings::get_singleton()->get_auto_display_scale()); + break; case 1: editor_set_scale(0.75); break; @@ -5762,87 +5756,87 @@ EditorNode::EditorNode() { { //register importers at the beginning, so dialogs are created with the right extensions Ref<ResourceImporterTexture> import_texture; - import_texture.instance(); + import_texture.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_texture); Ref<ResourceImporterLayeredTexture> import_cubemap; - import_cubemap.instance(); + import_cubemap.instantiate(); import_cubemap->set_mode(ResourceImporterLayeredTexture::MODE_CUBEMAP); ResourceFormatImporter::get_singleton()->add_importer(import_cubemap); Ref<ResourceImporterLayeredTexture> import_array; - import_array.instance(); + import_array.instantiate(); import_array->set_mode(ResourceImporterLayeredTexture::MODE_2D_ARRAY); ResourceFormatImporter::get_singleton()->add_importer(import_array); Ref<ResourceImporterLayeredTexture> import_cubemap_array; - import_cubemap_array.instance(); + import_cubemap_array.instantiate(); import_cubemap_array->set_mode(ResourceImporterLayeredTexture::MODE_CUBEMAP_ARRAY); ResourceFormatImporter::get_singleton()->add_importer(import_cubemap_array); Ref<ResourceImporterLayeredTexture> import_3d; - import_3d.instance(); + import_3d.instantiate(); import_3d->set_mode(ResourceImporterLayeredTexture::MODE_3D); ResourceFormatImporter::get_singleton()->add_importer(import_3d); Ref<ResourceImporterImage> import_image; - import_image.instance(); + import_image.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_image); Ref<ResourceImporterTextureAtlas> import_texture_atlas; - import_texture_atlas.instance(); + import_texture_atlas.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_texture_atlas); Ref<ResourceImporterCSVTranslation> import_csv_translation; - import_csv_translation.instance(); + import_csv_translation.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_csv_translation); Ref<ResourceImporterWAV> import_wav; - import_wav.instance(); + import_wav.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_wav); Ref<ResourceImporterOBJ> import_obj; - import_obj.instance(); + import_obj.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_obj); Ref<ResourceImporterShaderFile> import_shader_file; - import_shader_file.instance(); + import_shader_file.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_shader_file); Ref<ResourceImporterScene> import_scene; - import_scene.instance(); + import_scene.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_scene); { Ref<EditorSceneImporterCollada> import_collada; - import_collada.instance(); + import_collada.instantiate(); import_scene->add_importer(import_collada); Ref<EditorOBJImporter> import_obj2; - import_obj2.instance(); + import_obj2.instantiate(); import_scene->add_importer(import_obj2); Ref<EditorSceneImporterESCN> import_escn; - import_escn.instance(); + import_escn.instantiate(); import_scene->add_importer(import_escn); } Ref<ResourceImporterBitMap> import_bitmap; - import_bitmap.instance(); + import_bitmap.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(import_bitmap); } { Ref<EditorInspectorDefaultPlugin> eidp; - eidp.instance(); + eidp.instantiate(); EditorInspector::add_inspector_plugin(eidp); Ref<EditorInspectorRootMotionPlugin> rmp; - rmp.instance(); + rmp.instantiate(); EditorInspector::add_inspector_plugin(rmp); Ref<EditorInspectorShaderModePlugin> smp; - smp.instance(); + smp.instantiate(); EditorInspector::add_inspector_plugin(smp); } @@ -5878,6 +5872,7 @@ EditorNode::EditorNode() { EDITOR_DEF("run/output/always_open_output_on_play", true); EDITOR_DEF("run/output/always_close_output_on_stop", true); EDITOR_DEF("run/auto_save/save_before_running", true); + EDITOR_DEF("interface/editor/save_on_focus_loss", false); EDITOR_DEF_RST("interface/editor/save_each_scene_on_quit", true); EDITOR_DEF("interface/editor/show_update_spinner", false); EDITOR_DEF("interface/editor/update_continuously", false); @@ -6144,9 +6139,9 @@ EditorNode::EditorNode() { scene_root_parent->set_v_size_flags(Control::SIZE_EXPAND_FILL); scene_root = memnew(SubViewport); - //scene_root->set_usage(Viewport::USAGE_2D); canvas BG mode prevents usage of this as 2D + scene_root->set_embed_subwindows_hint(true); + scene_root->set_disable_3d(true); - RenderingServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport_rid(), true); scene_root->set_disable_input(true); scene_root->set_as_audio_listener_2d(true); @@ -6300,6 +6295,7 @@ EditorNode::EditorNode() { tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES); p->add_separator(); + p->add_item(TTR("Reload Current Project"), RUN_RELOAD_CURRENT_PROJECT); #ifdef OSX_ENABLED p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q), RUN_PROJECT_MANAGER, true); #else @@ -6392,6 +6388,7 @@ EditorNode::EditorNode() { p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/online_docs", TTR("Online Documentation")), HELP_DOCS); p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/q&a", TTR("Questions & Answers")), HELP_QA); p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/report_a_bug", TTR("Report a Bug")), HELP_REPORT_A_BUG); + p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/suggest_a_feature", TTR("Suggest a Feature")), HELP_SUGGEST_A_FEATURE); p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/send_docs_feedback", TTR("Send Docs Feedback")), HELP_SEND_DOCS_FEEDBACK); p->add_icon_shortcut(gui_base->get_theme_icon("Instance", "EditorIcons"), ED_SHORTCUT("editor/community", TTR("Community")), HELP_COMMUNITY); p->add_separator(); @@ -6543,7 +6540,7 @@ EditorNode::EditorNode() { filesystem_dock = memnew(FileSystemDock(this)); filesystem_dock->connect("inherit", callable_mp(this, &EditorNode::_inherit_request)); - filesystem_dock->connect("instance", callable_mp(this, &EditorNode::_instance_request)); + filesystem_dock->connect("instance", callable_mp(this, &EditorNode::_instantiate_request)); filesystem_dock->connect("display_mode_changed", callable_mp(this, &EditorNode::_save_docks)); // Scene: Top left @@ -6583,7 +6580,7 @@ EditorNode::EditorNode() { const String docks_section = "docks"; overridden_default_layout = -1; - default_layout.instance(); + default_layout.instantiate(); // Dock numbers are based on DockSlot enum value + 1 default_layout->set_value(docks_section, "dock_3", "Scene,Import"); default_layout->set_value(docks_section, "dock_4", "FileSystem"); @@ -6628,7 +6625,7 @@ EditorNode::EditorNode() { version_btn->set_text(VERSION_FULL_CONFIG); String hash = String(VERSION_HASH); if (hash.length() != 0) { - hash = "." + hash.left(9); + hash = " " + vformat("[%s]", hash.left(9)); } // Set the text to copy in metadata as it slightly differs from the button's text. version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash); @@ -6818,8 +6815,8 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(TilesEditorPlugin(this))); add_editor_plugin(memnew(SpriteFramesEditorPlugin(this))); add_editor_plugin(memnew(TextureRegionEditorPlugin(this))); - add_editor_plugin(memnew(GIProbeEditorPlugin(this))); - add_editor_plugin(memnew(BakedLightmapEditorPlugin(this))); + add_editor_plugin(memnew(VoxelGIEditorPlugin(this))); + add_editor_plugin(memnew(LightmapGIEditorPlugin(this))); add_editor_plugin(memnew(OccluderInstance3DEditorPlugin(this))); add_editor_plugin(memnew(Path2DEditorPlugin(this))); add_editor_plugin(memnew(Path3DEditorPlugin(this))); @@ -6843,6 +6840,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(MeshEditorPlugin(this))); add_editor_plugin(memnew(MaterialEditorPlugin(this))); add_editor_plugin(memnew(GPUParticlesCollisionSDFEditorPlugin(this))); + add_editor_plugin(memnew(InputEventEditorPlugin(this))); for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) { add_editor_plugin(EditorPlugins::create(i, this)); @@ -6864,31 +6862,31 @@ EditorNode::EditorNode() { { Ref<StandardMaterial3DConversionPlugin> spatial_mat_convert; - spatial_mat_convert.instance(); + spatial_mat_convert.instantiate(); resource_conversion_plugins.push_back(spatial_mat_convert); Ref<CanvasItemMaterialConversionPlugin> canvas_item_mat_convert; - canvas_item_mat_convert.instance(); + canvas_item_mat_convert.instantiate(); resource_conversion_plugins.push_back(canvas_item_mat_convert); Ref<ParticlesMaterialConversionPlugin> particles_mat_convert; - particles_mat_convert.instance(); + particles_mat_convert.instantiate(); resource_conversion_plugins.push_back(particles_mat_convert); Ref<ProceduralSkyMaterialConversionPlugin> procedural_sky_mat_convert; - procedural_sky_mat_convert.instance(); + procedural_sky_mat_convert.instantiate(); resource_conversion_plugins.push_back(procedural_sky_mat_convert); Ref<PanoramaSkyMaterialConversionPlugin> panorama_sky_mat_convert; - panorama_sky_mat_convert.instance(); + panorama_sky_mat_convert.instantiate(); resource_conversion_plugins.push_back(panorama_sky_mat_convert); Ref<PhysicalSkyMaterialConversionPlugin> physical_sky_mat_convert; - physical_sky_mat_convert.instance(); + physical_sky_mat_convert.instantiate(); resource_conversion_plugins.push_back(physical_sky_mat_convert); Ref<VisualShaderConversionPlugin> vshader_convert; - vshader_convert.instance(); + vshader_convert.instantiate(); resource_conversion_plugins.push_back(vshader_convert); } update_spinner_step_msec = OS::get_singleton()->get_ticks_msec(); @@ -6901,12 +6899,12 @@ EditorNode::EditorNode() { editor_plugins_force_input_forwarding = memnew(EditorPluginList); Ref<EditorExportTextSceneToBinaryPlugin> export_text_to_binary_plugin; - export_text_to_binary_plugin.instance(); + export_text_to_binary_plugin.instantiate(); EditorExport::get_singleton()->add_export_plugin(export_text_to_binary_plugin); Ref<PackedSceneEditorTranslationParserPlugin> packed_scene_translation_parser_plugin; - packed_scene_translation_parser_plugin.instance(); + packed_scene_translation_parser_plugin.instantiate(); EditorTranslationParser::get_singleton()->add_parser(packed_scene_translation_parser_plugin, EditorTranslationParser::STANDARD); _edit_current(); @@ -6927,7 +6925,7 @@ EditorNode::EditorNode() { saved_version = 1; unsaved_cache = true; - _last_instanced_scene = nullptr; + _last_instantiated_scene = nullptr; quick_open = memnew(EditorQuickOpen); gui_base->add_child(quick_open); @@ -6971,6 +6969,8 @@ EditorNode::EditorNode() { gui_base->add_child(pick_main_scene); pick_main_scene->get_ok_button()->set_text(TTR("Select")); pick_main_scene->connect("confirmed", callable_mp(this, &EditorNode::_menu_option), varray(SETTINGS_PICK_MAIN_SCENE)); + select_current_scene_button = pick_main_scene->add_button(TTR("Select Current"), true, "select_current"); + pick_main_scene->connect("custom_action", callable_mp(this, &EditorNode::_pick_main_scene_custom_action)); for (int i = 0; i < _init_callbacks.size(); i++) { _init_callbacks[i](); diff --git a/editor/editor_node.h b/editor/editor_node.h index 9625b318e0..07bed6999b 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -164,6 +164,7 @@ private: RUN_PLAY_CUSTOM_SCENE, RUN_SETTINGS, RUN_PROJECT_DATA_FOLDER, + RUN_RELOAD_CURRENT_PROJECT, RUN_PROJECT_MANAGER, RUN_VCS_SETTINGS, RUN_VCS_SHUT_DOWN, @@ -193,6 +194,7 @@ private: HELP_DOCS, HELP_QA, HELP_REPORT_A_BUG, + HELP_SUGGEST_A_FEATURE, HELP_SEND_DOCS_FEEDBACK, HELP_COMMUNITY, HELP_ABOUT, @@ -299,6 +301,7 @@ private: ConfirmationDialog *save_confirmation; ConfirmationDialog *import_confirmation; ConfirmationDialog *pick_main_scene; + Button *select_current_scene_button; AcceptDialog *accept; EditorAbout *about; AcceptDialog *warning; @@ -331,7 +334,7 @@ private: EditorNativeShaderSourceVisualizer *native_shader_source_visualizer; String defer_load_scene; - Node *_last_instanced_scene; + Node *_last_instantiated_scene; EditorLog *log; CenterContainer *tabs_center; @@ -490,7 +493,7 @@ private: void _discard_changes(const String &p_str = String()); void _inherit_request(String p_file); - void _instance_request(const Vector<String> &p_files); + void _instantiate_request(const Vector<String> &p_files); void _display_top_editors(bool p_display); void _set_top_editors(Vector<EditorPlugin *> p_editor_plugins_over); @@ -661,6 +664,8 @@ private: bool _is_class_editor_disabled_by_feature_profile(const StringName &p_class); Ref<ImageTexture> _load_custom_class_icon(const String &p_path) const; + void _pick_main_scene_custom_action(const String &p_custom_action_name); + protected: void _notification(int p_what); @@ -769,7 +774,7 @@ public: static VSplitContainer *get_top_split() { return singleton->top_split; } void request_instance_scene(const String &p_path); - void request_instance_scenes(const Vector<String> &p_files); + void request_instantiate_scenes(const Vector<String> &p_files); FileSystemDock *get_filesystem_dock(); ImportDock *get_import_dock(); SceneTreeDock *get_scene_tree_dock(); @@ -798,7 +803,6 @@ public: Error export_preset(const String &p_preset, const String &p_path, bool p_debug, bool p_pack_only); - static void register_editor_paths(bool p_for_project_manager); static void register_editor_types(); static void unregister_editor_types(); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index d1c52b4310..63281ae1aa 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -59,15 +59,40 @@ void EditorPath::_add_children_to_popup(Object *p_obj, int p_depth) { Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj); - int index = get_popup()->get_item_count(); - get_popup()->add_icon_item(icon, E->get().name.capitalize(), objects.size()); - get_popup()->set_item_h_offset(index, p_depth * 10 * EDSCALE); + String proper_name = ""; + Vector<String> name_parts = E->get().name.split("/"); + + for (int i = 0; i < name_parts.size(); i++) { + if (i > 0) { + proper_name += " > "; + } + proper_name += name_parts[i].capitalize(); + } + + int index = sub_objects_menu->get_item_count(); + sub_objects_menu->add_icon_item(icon, proper_name, objects.size()); + sub_objects_menu->set_item_h_offset(index, p_depth * 10 * EDSCALE); objects.push_back(obj->get_instance_id()); _add_children_to_popup(obj, p_depth + 1); } } +void EditorPath::_show_popup() { + sub_objects_menu->clear(); + + Size2 size = get_size(); + Point2 gp = get_screen_position(); + gp.y += size.y; + + sub_objects_menu->set_position(gp); + sub_objects_menu->set_size(Size2(size.width, 1)); + sub_objects_menu->set_parent_rect(Rect2(Point2(gp - sub_objects_menu->get_position()), size)); + + sub_objects_menu->take_mouse_focus(); + sub_objects_menu->popup(); +} + void EditorPath::_about_to_show() { Object *obj = ObjectDB::get_instance(history->get_path_object(history->get_path_size() - 1)); if (!obj) { @@ -75,13 +100,11 @@ void EditorPath::_about_to_show() { } objects.clear(); - get_popup()->clear(); - get_popup()->set_size(Size2(get_size().width, 1)); _add_children_to_popup(obj); - if (get_popup()->get_item_count() == 0) { - get_popup()->add_item(TTR("No sub-resources found.")); - get_popup()->set_item_disabled(0, true); + if (sub_objects_menu->get_item_count() == 0) { + sub_objects_menu->add_item(TTR("No sub-resources found.")); + sub_objects_menu->set_item_disabled(0, true); } } @@ -94,7 +117,7 @@ void EditorPath::update_path() { Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(obj); if (icon.is_valid()) { - set_icon(icon); + current_object_icon->set_texture(icon); } if (i == history->get_path_size() - 1) { @@ -120,12 +143,26 @@ void EditorPath::update_path() { name = obj->get_class(); } - set_text(" " + name); // An extra space so the text is not too close of the icon. + current_object_label->set_text(" " + name); // An extra space so the text is not too close of the icon. set_tooltip(obj->get_class()); } } } +void EditorPath::clear_path() { + set_disabled(true); + set_tooltip(""); + + current_object_label->set_text(""); + current_object_icon->set_texture(nullptr); + sub_objects_icon->set_visible(false); +} + +void EditorPath::enable_path() { + set_disabled(false); + sub_objects_icon->set_visible(true); +} + void EditorPath::_id_pressed(int p_idx) { ERR_FAIL_INDEX(p_idx, objects.size()); @@ -139,8 +176,16 @@ void EditorPath::_id_pressed(int p_idx) { void EditorPath::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: { update_path(); + + sub_objects_icon->set_texture(get_theme_icon("select_arrow", "Tree")); + current_object_label->add_theme_font_override("font", get_theme_font("main", "EditorFonts")); + } break; + + case NOTIFICATION_READY: { + connect("pressed", callable_mp(this, &EditorPath::_show_popup)); } break; } } @@ -150,8 +195,35 @@ void EditorPath::_bind_methods() { EditorPath::EditorPath(EditorHistory *p_history) { history = p_history; - set_clip_text(true); - set_text_align(ALIGN_LEFT); - get_popup()->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show)); - get_popup()->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed)); + + MarginContainer *main_mc = memnew(MarginContainer); + main_mc->set_anchors_and_offsets_preset(PRESET_WIDE); + main_mc->add_theme_constant_override("margin_left", 4 * EDSCALE); + main_mc->add_theme_constant_override("margin_right", 6 * EDSCALE); + add_child(main_mc); + + HBoxContainer *main_hb = memnew(HBoxContainer); + main_mc->add_child(main_hb); + + current_object_icon = memnew(TextureRect); + current_object_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + main_hb->add_child(current_object_icon); + + current_object_label = memnew(Label); + current_object_label->set_clip_text(true); + current_object_label->set_align(Label::ALIGN_LEFT); + current_object_label->set_h_size_flags(SIZE_EXPAND_FILL); + main_hb->add_child(current_object_label); + + sub_objects_icon = memnew(TextureRect); + sub_objects_icon->set_visible(false); + sub_objects_icon->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED); + main_hb->add_child(sub_objects_icon); + + sub_objects_menu = memnew(PopupMenu); + add_child(sub_objects_menu); + sub_objects_menu->connect("about_to_popup", callable_mp(this, &EditorPath::_about_to_show)); + sub_objects_menu->connect("id_pressed", callable_mp(this, &EditorPath::_id_pressed)); + + set_tooltip(TTR("Open a list of sub-resources.")); } diff --git a/editor/editor_path.h b/editor/editor_path.h index d1090947f9..cabfa931d6 100644 --- a/editor/editor_path.h +++ b/editor/editor_path.h @@ -32,16 +32,24 @@ #define EDITOR_PATH_H #include "editor_data.h" -#include "scene/gui/menu_button.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/popup_menu.h" -class EditorPath : public MenuButton { - GDCLASS(EditorPath, MenuButton); +class EditorPath : public Button { + GDCLASS(EditorPath, Button); EditorHistory *history; + TextureRect *current_object_icon; + Label *current_object_label; + TextureRect *sub_objects_icon; + PopupMenu *sub_objects_menu; + Vector<ObjectID> objects; EditorPath(); + void _show_popup(); void _id_pressed(int p_idx); void _about_to_show(); void _add_children_to_popup(Object *p_obj, int p_depth = 0); @@ -52,6 +60,8 @@ protected: public: void update_path(); + void clear_path(); + void enable_path(); EditorPath(EditorHistory *p_history); }; diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index 474da4fb96..c9817190dd 100644 --- a/editor/editor_paths.cpp +++ b/editor/editor_paths.cpp @@ -29,8 +29,12 @@ /*************************************************************************/ #include "editor_paths.h" -#include "core/os/dir_access.h" + +#include "core/config/engine.h" +#include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/os/os.h" +#include "main/main.h" // For `is_project_manager`. EditorPaths *EditorPaths::singleton = nullptr; @@ -41,23 +45,32 @@ bool EditorPaths::are_paths_valid() const { String EditorPaths::get_data_dir() const { return data_dir; } + String EditorPaths::get_config_dir() const { return config_dir; } + String EditorPaths::get_cache_dir() const { return cache_dir; } + +String EditorPaths::get_project_data_dir() const { + return project_data_dir; +} + bool EditorPaths::is_self_contained() const { return self_contained; } + String EditorPaths::get_self_contained_file() const { return self_contained_file; } -void EditorPaths::create(bool p_for_project_manager) { +void EditorPaths::create() { ERR_FAIL_COND(singleton != nullptr); - memnew(EditorPaths(p_for_project_manager)); + memnew(EditorPaths()); } + void EditorPaths::free() { ERR_FAIL_COND(singleton == nullptr); memdelete(singleton); @@ -71,9 +84,10 @@ void EditorPaths::_bind_methods() { ClassDB::bind_method(D_METHOD("get_self_contained_file"), &EditorPaths::get_self_contained_file); } -EditorPaths::EditorPaths(bool p_for_project_mamanger) { +EditorPaths::EditorPaths() { singleton = this; + // Self-contained mode if a `._sc_` or `_sc_` file is present in executable dir. String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); { DirAccessRef d = DirAccess::create_for_path(exe_path); @@ -100,13 +114,13 @@ EditorPaths::EditorPaths(bool p_for_project_mamanger) { cache_path = exe_path; cache_dir = data_dir.plus_file("cache"); } else { - // Typically XDG_DATA_HOME or %APPDATA% + // Typically XDG_DATA_HOME or %APPDATA%. data_path = OS::get_singleton()->get_data_path(); data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name()); - // Can be different from data_path e.g. on Linux or macOS + // Can be different from data_path e.g. on Linux or macOS. config_path = OS::get_singleton()->get_config_path(); config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name()); - // Can be different from above paths, otherwise a subfolder of data_dir + // Can be different from above paths, otherwise a subfolder of data_dir. cache_path = OS::get_singleton()->get_cache_path(); if (cache_path == data_path) { cache_dir = data_dir.plus_file("cache"); @@ -116,37 +130,83 @@ EditorPaths::EditorPaths(bool p_for_project_mamanger) { } paths_valid = (data_path != "" && config_path != "" && cache_path != ""); + ERR_FAIL_COND_MSG(!paths_valid, "Editor data, config, or cache paths are invalid."); - if (paths_valid) { - DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + // Validate or create each dir and its relevant subdirectories. + + DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + + // Data dir. + { if (dir->change_dir(data_dir) != OK) { dir->make_dir_recursive(data_dir); if (dir->change_dir(data_dir) != OK) { - ERR_PRINT("Cannot create data directory!"); + ERR_PRINT("Could not create editor data directory: " + data_dir); + paths_valid = false; + } + } + + if (!dir->dir_exists("templates")) { + dir->make_dir("templates"); + } + } + + // Config dir. + { + if (dir->change_dir(config_dir) != OK) { + dir->make_dir_recursive(config_dir); + if (dir->change_dir(config_dir) != OK) { + ERR_PRINT("Could not create editor config directory: " + config_dir); paths_valid = false; } } - // Validate/create cache dir + if (!dir->dir_exists("text_editor_themes")) { + dir->make_dir("text_editor_themes"); + } + if (!dir->dir_exists("script_templates")) { + dir->make_dir("script_templates"); + } + if (!dir->dir_exists("feature_profiles")) { + dir->make_dir("feature_profiles"); + } + } - if (dir->change_dir(EditorPaths::get_singleton()->get_cache_dir()) != OK) { + // Cache dir. + { + if (dir->change_dir(cache_dir) != OK) { dir->make_dir_recursive(cache_dir); if (dir->change_dir(cache_dir) != OK) { - ERR_PRINT("Cannot create cache directory!"); + ERR_PRINT("Could not create editor cache directory: " + cache_dir); + paths_valid = false; } } + } - if (p_for_project_mamanger) { - Engine::get_singleton()->set_shader_cache_path(get_data_dir()); - } else { - DirAccessRef dir2 = DirAccess::open("res://"); - if (dir2->change_dir(".godot") != OK) { //ensure the .godot subdir exists - if (dir2->make_dir(".godot") != OK) { - ERR_PRINT("Cannot create res://.godot directory!"); - } + // Validate or create project-specific editor data dir (`res://.godot`), + // including shader cache subdir. + + if (Main::is_project_manager() || Main::is_cmdline_tool()) { + // Nothing to create, use shared editor data dir for shader cache. + Engine::get_singleton()->set_shader_cache_path(data_dir); + } else { + DirAccessRef dir_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (dir_res->change_dir(project_data_dir) != OK) { + dir_res->make_dir_recursive(project_data_dir); + if (dir_res->change_dir(project_data_dir) != OK) { + ERR_PRINT("Could not create project data directory (" + project_data_dir + ") in: " + dir_res->get_current_dir()); + paths_valid = false; } + } + Engine::get_singleton()->set_shader_cache_path(project_data_dir); - Engine::get_singleton()->set_shader_cache_path("res://.godot"); + // Editor metadata dir. + if (!dir_res->dir_exists("editor")) { + dir_res->make_dir("editor"); + } + // Imported assets dir. + if (!dir_res->dir_exists(ProjectSettings::IMPORTED_FILES_PATH)) { + dir_res->make_dir(ProjectSettings::IMPORTED_FILES_PATH); } } } diff --git a/editor/editor_paths.h b/editor/editor_paths.h index c1be33f5c2..2c156b7c96 100644 --- a/editor/editor_paths.h +++ b/editor/editor_paths.h @@ -28,20 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef EDITORPATHS_H -#define EDITORPATHS_H +#ifndef EDITOR_PATHS_H +#define EDITOR_PATHS_H -#include "core/config/engine.h" +#include "core/object/class_db.h" +#include "core/string/ustring.h" class EditorPaths : public Object { GDCLASS(EditorPaths, Object) - bool paths_valid = false; - String data_dir; //editor data dir - String config_dir; //editor config dir - String cache_dir; //editor cache dir - bool self_contained = false; //true if running self contained - String self_contained_file; //self contained file with configuration + bool paths_valid = false; // If any of the paths can't be created, this is false. + String data_dir; // Editor data (templates, shader cache, etc.). + String config_dir; // Editor config (settings, profiles, themes, etc.). + String cache_dir; // Editor cache (thumbnails, tmp generated files). + String project_data_dir = "res://.godot"; // Project-specific data (metadata, shader cache, etc.). + bool self_contained = false; // Self-contained means everything goes to `editor_data` dir. + String self_contained_file; // Self-contained file with configuration. static EditorPaths *singleton; @@ -54,6 +56,8 @@ public: String get_data_dir() const; String get_config_dir() const; String get_cache_dir() const; + String get_project_data_dir() const; + bool is_self_contained() const; String get_self_contained_file() const; @@ -61,10 +65,10 @@ public: return singleton; } - static void create(bool p_for_project_manager); + static void create(); static void free(); - EditorPaths(bool p_for_project_mamanger = false); + EditorPaths(); }; -#endif // EDITORPATHS_H +#endif // EDITOR_PATHS_H diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index c5097a17a5..63de06d5e2 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -60,7 +60,7 @@ Array EditorInterface::_make_mesh_previews(const Array &p_meshes, int p_preview_ return ret; } -Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform> *p_transforms, int p_preview_size) { +Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size) { int size = p_preview_size; RID scenario = RS::get_singleton()->scenario_create(); @@ -94,7 +94,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh continue; } - Transform mesh_xform; + Transform3D mesh_xform; if (p_transforms != nullptr) { mesh_xform = (*p_transforms)[i]; } @@ -105,7 +105,7 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh AABB aabb = mesh->get_aabb(); Vector3 ofs = aabb.position + aabb.size * 0.5; aabb.position -= ofs; - Transform xform; + Transform3D xform; xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6); xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) * xform.basis; AABB rot_aabb = xform.xform(aabb); @@ -119,11 +119,11 @@ Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh xform.invert(); xform = mesh_xform * xform; - RS::get_singleton()->camera_set_transform(camera, xform * Transform(Basis(), Vector3(0, 0, 3))); + RS::get_singleton()->camera_set_transform(camera, xform * Transform3D(Basis(), Vector3(0, 0, 3))); RS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01, 1000.0); - RS::get_singleton()->instance_set_transform(light_instance, xform * Transform().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0))); - RS::get_singleton()->instance_set_transform(light_instance2, xform * Transform().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0))); + RS::get_singleton()->instance_set_transform(light_instance, xform * Transform3D().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0))); + RS::get_singleton()->instance_set_transform(light_instance2, xform * Transform3D().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0))); ep.step(TTR("Thumbnail..."), i); Main::iteration(); @@ -553,21 +553,21 @@ void EditorPlugin::notify_resource_saved(const Ref<Resource> &p_resource) { } bool EditorPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { - if (get_script_instance() && get_script_instance()->has_method("forward_canvas_gui_input")) { - return get_script_instance()->call("forward_canvas_gui_input", p_event); + if (get_script_instance() && get_script_instance()->has_method("_forward_canvas_gui_input")) { + return get_script_instance()->call("_forward_canvas_gui_input", p_event); } return false; } void EditorPlugin::forward_canvas_draw_over_viewport(Control *p_overlay) { - if (get_script_instance() && get_script_instance()->has_method("forward_canvas_draw_over_viewport")) { - get_script_instance()->call("forward_canvas_draw_over_viewport", p_overlay); + if (get_script_instance() && get_script_instance()->has_method("_forward_canvas_draw_over_viewport")) { + get_script_instance()->call("_forward_canvas_draw_over_viewport", p_overlay); } } void EditorPlugin::forward_canvas_force_draw_over_viewport(Control *p_overlay) { - if (get_script_instance() && get_script_instance()->has_method("forward_canvas_force_draw_over_viewport")) { - get_script_instance()->call("forward_canvas_force_draw_over_viewport", p_overlay); + if (get_script_instance() && get_script_instance()->has_method("_forward_canvas_force_draw_over_viewport")) { + get_script_instance()->call("_forward_canvas_force_draw_over_viewport", p_overlay); } } @@ -591,110 +591,110 @@ int EditorPlugin::update_overlays() const { } bool EditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) { - if (get_script_instance() && get_script_instance()->has_method("forward_spatial_gui_input")) { - return get_script_instance()->call("forward_spatial_gui_input", p_camera, p_event); + if (get_script_instance() && get_script_instance()->has_method("_forward_spatial_gui_input")) { + return get_script_instance()->call("_forward_spatial_gui_input", p_camera, p_event); } return false; } void EditorPlugin::forward_spatial_draw_over_viewport(Control *p_overlay) { - if (get_script_instance() && get_script_instance()->has_method("forward_spatial_draw_over_viewport")) { - get_script_instance()->call("forward_spatial_draw_over_viewport", p_overlay); + if (get_script_instance() && get_script_instance()->has_method("_forward_spatial_draw_over_viewport")) { + get_script_instance()->call("_forward_spatial_draw_over_viewport", p_overlay); } } void EditorPlugin::forward_spatial_force_draw_over_viewport(Control *p_overlay) { - if (get_script_instance() && get_script_instance()->has_method("forward_spatial_force_draw_over_viewport")) { - get_script_instance()->call("forward_spatial_force_draw_over_viewport", p_overlay); + if (get_script_instance() && get_script_instance()->has_method("_forward_spatial_force_draw_over_viewport")) { + get_script_instance()->call("_forward_spatial_force_draw_over_viewport", p_overlay); } } String EditorPlugin::get_name() const { - if (get_script_instance() && get_script_instance()->has_method("get_plugin_name")) { - return get_script_instance()->call("get_plugin_name"); + if (get_script_instance() && get_script_instance()->has_method("_get_plugin_name")) { + return get_script_instance()->call("_get_plugin_name"); } return String(); } const Ref<Texture2D> EditorPlugin::get_icon() const { - if (get_script_instance() && get_script_instance()->has_method("get_plugin_icon")) { - return get_script_instance()->call("get_plugin_icon"); + if (get_script_instance() && get_script_instance()->has_method("_get_plugin_icon")) { + return get_script_instance()->call("_get_plugin_icon"); } return Ref<Texture2D>(); } bool EditorPlugin::has_main_screen() const { - if (get_script_instance() && get_script_instance()->has_method("has_main_screen")) { - return get_script_instance()->call("has_main_screen"); + if (get_script_instance() && get_script_instance()->has_method("_has_main_screen")) { + return get_script_instance()->call("_has_main_screen"); } return false; } void EditorPlugin::make_visible(bool p_visible) { - if (get_script_instance() && get_script_instance()->has_method("make_visible")) { - get_script_instance()->call("make_visible", p_visible); + if (get_script_instance() && get_script_instance()->has_method("_make_visible")) { + get_script_instance()->call("_make_visible", p_visible); } } void EditorPlugin::edit(Object *p_object) { - if (get_script_instance() && get_script_instance()->has_method("edit")) { + if (get_script_instance() && get_script_instance()->has_method("_edit")) { if (p_object->is_class("Resource")) { - get_script_instance()->call("edit", Ref<Resource>(Object::cast_to<Resource>(p_object))); + get_script_instance()->call("_edit", Ref<Resource>(Object::cast_to<Resource>(p_object))); } else { - get_script_instance()->call("edit", p_object); + get_script_instance()->call("_edit", p_object); } } } bool EditorPlugin::handles(Object *p_object) const { - if (get_script_instance() && get_script_instance()->has_method("handles")) { - return get_script_instance()->call("handles", p_object); + if (get_script_instance() && get_script_instance()->has_method("_handles")) { + return get_script_instance()->call("_handles", p_object); } return false; } Dictionary EditorPlugin::get_state() const { - if (get_script_instance() && get_script_instance()->has_method("get_state")) { - return get_script_instance()->call("get_state"); + if (get_script_instance() && get_script_instance()->has_method("_get_state")) { + return get_script_instance()->call("_get_state"); } return Dictionary(); } void EditorPlugin::set_state(const Dictionary &p_state) { - if (get_script_instance() && get_script_instance()->has_method("set_state")) { - get_script_instance()->call("set_state", p_state); + if (get_script_instance() && get_script_instance()->has_method("_set_state")) { + get_script_instance()->call("_set_state", p_state); } } void EditorPlugin::clear() { - if (get_script_instance() && get_script_instance()->has_method("clear")) { - get_script_instance()->call("clear"); + if (get_script_instance() && get_script_instance()->has_method("_clear")) { + get_script_instance()->call("_clear"); } } // if editor references external resources/scenes, save them void EditorPlugin::save_external_data() { - if (get_script_instance() && get_script_instance()->has_method("save_external_data")) { - get_script_instance()->call("save_external_data"); + if (get_script_instance() && get_script_instance()->has_method("_save_external_data")) { + get_script_instance()->call("_save_external_data"); } } // if changes are pending in editor, apply them void EditorPlugin::apply_changes() { - if (get_script_instance() && get_script_instance()->has_method("apply_changes")) { - get_script_instance()->call("apply_changes"); + if (get_script_instance() && get_script_instance()->has_method("_apply_changes")) { + get_script_instance()->call("_apply_changes"); } } void EditorPlugin::get_breakpoints(List<String> *p_breakpoints) { - if (get_script_instance() && get_script_instance()->has_method("get_breakpoints")) { - PackedStringArray arr = get_script_instance()->call("get_breakpoints"); + if (get_script_instance() && get_script_instance()->has_method("_get_breakpoints")) { + PackedStringArray arr = get_script_instance()->call("_get_breakpoints"); for (int i = 0; i < arr.size(); i++) { p_breakpoints->push_back(arr[i]); } @@ -717,52 +717,64 @@ void EditorPlugin::remove_undo_redo_inspector_hook_callback(Callable p_callable) } void EditorPlugin::add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) { + ERR_FAIL_COND(!p_parser.is_valid()); EditorTranslationParser::get_singleton()->add_parser(p_parser, EditorTranslationParser::CUSTOM); } void EditorPlugin::remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) { + ERR_FAIL_COND(!p_parser.is_valid()); EditorTranslationParser::get_singleton()->remove_parser(p_parser, EditorTranslationParser::CUSTOM); } void EditorPlugin::add_import_plugin(const Ref<EditorImportPlugin> &p_importer) { + ERR_FAIL_COND(!p_importer.is_valid()); ResourceFormatImporter::get_singleton()->add_importer(p_importer); EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::remove_import_plugin(const Ref<EditorImportPlugin> &p_importer) { + ERR_FAIL_COND(!p_importer.is_valid()); ResourceFormatImporter::get_singleton()->remove_importer(p_importer); EditorFileSystem::get_singleton()->call_deferred("scan"); } void EditorPlugin::add_export_plugin(const Ref<EditorExportPlugin> &p_exporter) { + ERR_FAIL_COND(!p_exporter.is_valid()); EditorExport::get_singleton()->add_export_plugin(p_exporter); } void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter) { + ERR_FAIL_COND(!p_exporter.is_valid()); EditorExport::get_singleton()->remove_export_plugin(p_exporter); } void EditorPlugin::add_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) { + ERR_FAIL_COND(!p_gizmo_plugin.is_valid()); Node3DEditor::get_singleton()->add_gizmo_plugin(p_gizmo_plugin); } void EditorPlugin::remove_spatial_gizmo_plugin(const Ref<EditorNode3DGizmoPlugin> &p_gizmo_plugin) { + ERR_FAIL_COND(!p_gizmo_plugin.is_valid()); Node3DEditor::get_singleton()->remove_gizmo_plugin(p_gizmo_plugin); } void EditorPlugin::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) { + ERR_FAIL_COND(!p_plugin.is_valid()); EditorInspector::add_inspector_plugin(p_plugin); } void EditorPlugin::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) { + ERR_FAIL_COND(!p_plugin.is_valid()); EditorInspector::remove_inspector_plugin(p_plugin); } void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { + ERR_FAIL_COND(!p_importer.is_valid()); ResourceImporterScene::get_singleton()->add_importer(p_importer); } void EditorPlugin::remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { + ERR_FAIL_COND(!p_importer.is_valid()); ResourceImporterScene::get_singleton()->remove_importer(p_importer); } @@ -779,8 +791,8 @@ int find(const PackedStringArray &a, const String &v) { void EditorPlugin::enable_plugin() { // Called when the plugin gets enabled in project settings, after it's added to the tree. // You can implement it to register autoloads. - if (get_script_instance() && get_script_instance()->has_method("enable_plugin")) { - get_script_instance()->call("enable_plugin"); + if (get_script_instance() && get_script_instance()->has_method("_enable_plugin")) { + get_script_instance()->call("_enable_plugin"); } } @@ -788,26 +800,26 @@ void EditorPlugin::disable_plugin() { // Last function called when the plugin gets disabled in project settings. // Implement it to cleanup things from the project, such as unregister autoloads. - if (get_script_instance() && get_script_instance()->has_method("disable_plugin")) { - get_script_instance()->call("disable_plugin"); + if (get_script_instance() && get_script_instance()->has_method("_disable_plugin")) { + get_script_instance()->call("_disable_plugin"); } } void EditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) { - if (get_script_instance() && get_script_instance()->has_method("set_window_layout")) { - get_script_instance()->call("set_window_layout", p_layout); + if (get_script_instance() && get_script_instance()->has_method("_set_window_layout")) { + get_script_instance()->call("_set_window_layout", p_layout); } } void EditorPlugin::get_window_layout(Ref<ConfigFile> p_layout) { - if (get_script_instance() && get_script_instance()->has_method("get_window_layout")) { - get_script_instance()->call("get_window_layout", p_layout); + if (get_script_instance() && get_script_instance()->has_method("_get_window_layout")) { + get_script_instance()->call("_get_window_layout", p_layout); } } bool EditorPlugin::build() { - if (get_script_instance() && get_script_instance()->has_method("build")) { - return get_script_instance()->call("build"); + if (get_script_instance() && get_script_instance()->has_method("_build")) { + return get_script_instance()->call("_build"); } return true; @@ -898,29 +910,29 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("add_debugger_plugin", "script"), &EditorPlugin::add_debugger_plugin); ClassDB::bind_method(D_METHOD("remove_debugger_plugin", "script"), &EditorPlugin::remove_debugger_plugin); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_canvas_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("forward_spatial_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_plugin_name")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "get_plugin_icon")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "has_main_screen")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("make_visible", PropertyInfo(Variant::BOOL, "visible"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("edit", PropertyInfo(Variant::OBJECT, "object"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::OBJECT, "object"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::DICTIONARY, "get_state")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("set_state", PropertyInfo(Variant::DICTIONARY, "state"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("clear")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("save_external_data")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("apply_changes")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::PACKED_STRING_ARRAY, "get_breakpoints")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("set_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("get_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "build")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("enable_plugin")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("disable_plugin")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_forward_canvas_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); + BIND_VMETHOD(MethodInfo("_forward_canvas_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); + BIND_VMETHOD(MethodInfo("_forward_canvas_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_forward_spatial_gui_input", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); + BIND_VMETHOD(MethodInfo("_forward_spatial_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); + BIND_VMETHOD(MethodInfo("_forward_spatial_force_draw_over_viewport", PropertyInfo(Variant::OBJECT, "overlay", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_plugin_name")); + BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "_get_plugin_icon")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_main_screen")); + BIND_VMETHOD(MethodInfo("_make_visible", PropertyInfo(Variant::BOOL, "visible"))); + BIND_VMETHOD(MethodInfo("_edit", PropertyInfo(Variant::OBJECT, "object"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles", PropertyInfo(Variant::OBJECT, "object"))); + BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_state")); + BIND_VMETHOD(MethodInfo("_set_state", PropertyInfo(Variant::DICTIONARY, "state"))); + BIND_VMETHOD(MethodInfo("_clear")); + BIND_VMETHOD(MethodInfo("_save_external_data")); + BIND_VMETHOD(MethodInfo("_apply_changes")); + BIND_VMETHOD(MethodInfo(Variant::PACKED_STRING_ARRAY, "_get_breakpoints")); + BIND_VMETHOD(MethodInfo("_set_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"))); + BIND_VMETHOD(MethodInfo("_get_window_layout", PropertyInfo(Variant::OBJECT, "layout", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_build")); + BIND_VMETHOD(MethodInfo("_enable_plugin")); + BIND_VMETHOD(MethodInfo("_disable_plugin")); ADD_SIGNAL(MethodInfo("scene_changed", PropertyInfo(Variant::OBJECT, "scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("scene_closed", PropertyInfo(Variant::STRING, "filepath"))); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 3f72e468b2..2e1dd0a0c1 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -113,7 +113,7 @@ public: Error save_scene(); void save_scene_as(const String &p_scene, bool p_with_preview = true); - Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform> *p_transforms, int p_preview_size); + Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size); void set_main_screen_editor(const String &p_name); void set_distraction_free_mode(bool p_enter); diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp index e5b62513ff..b4e5a58c21 100644 --- a/editor/editor_plugin_settings.cpp +++ b/editor/editor_plugin_settings.cpp @@ -32,7 +32,7 @@ #include "core/config/project_settings.h" #include "core/io/config_file.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/main_loop.h" #include "editor_node.h" #include "editor_scale.h" @@ -57,7 +57,7 @@ void EditorPluginSettings::update_plugins() { for (int i = 0; i < plugins.size(); i++) { Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); const String path = plugins[i]; Error err2 = cf->load(path); @@ -212,14 +212,19 @@ EditorPluginSettings::EditorPluginSettings() { plugin_list->set_column_title(3, TTR("Status:")); plugin_list->set_column_title(4, TTR("Edit:")); plugin_list->set_column_expand(0, true); + plugin_list->set_column_clip_content(0, true); plugin_list->set_column_expand(1, false); + plugin_list->set_column_clip_content(1, true); plugin_list->set_column_expand(2, false); + plugin_list->set_column_clip_content(2, true); plugin_list->set_column_expand(3, false); + plugin_list->set_column_clip_content(3, true); plugin_list->set_column_expand(4, false); - plugin_list->set_column_min_width(1, 100 * EDSCALE); - plugin_list->set_column_min_width(2, 250 * EDSCALE); - plugin_list->set_column_min_width(3, 80 * EDSCALE); - plugin_list->set_column_min_width(4, 40 * EDSCALE); + plugin_list->set_column_clip_content(4, true); + plugin_list->set_column_custom_minimum_width(1, 100 * EDSCALE); + plugin_list->set_column_custom_minimum_width(2, 250 * EDSCALE); + plugin_list->set_column_custom_minimum_width(3, 80 * EDSCALE); + plugin_list->set_column_custom_minimum_width(4, 40 * EDSCALE); plugin_list->set_hide_root(true); plugin_list->connect("item_edited", callable_mp(this, &EditorPluginSettings::_plugin_activity_changed)); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 7beff4147d..84105f0cb7 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -51,7 +51,7 @@ EditorPropertyNil::EditorPropertyNil() { ///////////////////// TEXT ///////////////////////// -void EditorPropertyText::_text_entered(const String &p_string) { +void EditorPropertyText::_text_submitted(const String &p_string) { if (updating) { return; } @@ -100,7 +100,7 @@ EditorPropertyText::EditorPropertyText() { add_child(text); add_focusable(text); text->connect("text_changed", callable_mp(this, &EditorPropertyText::_text_changed)); - text->connect("text_entered", callable_mp(this, &EditorPropertyText::_text_entered)); + text->connect("text_submitted", callable_mp(this, &EditorPropertyText::_text_submitted)); string_name = false; updating = false; @@ -297,7 +297,7 @@ EditorPropertyPath::EditorPropertyPath() { path = memnew(LineEdit); path->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE); path_hb->add_child(path); - path->connect("text_entered", callable_mp(this, &EditorPropertyPath::_path_selected)); + path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected)); path->connect("focus_exited", callable_mp(this, &EditorPropertyPath::_path_focus_exited)); path->set_h_size_flags(SIZE_EXPAND_FILL); @@ -491,6 +491,7 @@ void EditorPropertyEnum::update_property() { } void EditorPropertyEnum::setup(const Vector<String> &p_options) { + options->clear(); int64_t current_val = 0; for (int i = 0; i < p_options.size(); i++) { Vector<String> text_split = p_options[i].split(":"); @@ -892,11 +893,17 @@ void EditorPropertyFloat::_value_changed(double val) { return; } + if (angle_in_radians) { + val = Math::deg2rad(val); + } emit_changed(get_edited_property(), val); } void EditorPropertyFloat::update_property() { double val = get_edited_object()->get(get_edited_property()); + if (angle_in_radians) { + val = Math::rad2deg(val); + } setting = true; spin->set_value(val); setting = false; @@ -905,7 +912,8 @@ void EditorPropertyFloat::update_property() { void EditorPropertyFloat::_bind_methods() { } -void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser) { +void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix, bool p_angle_in_radians) { + angle_in_radians = p_angle_in_radians; spin->set_min(p_min); spin->set_max(p_max); spin->set_step(p_step); @@ -913,6 +921,7 @@ void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool spin->set_exp_ratio(p_exp_range); spin->set_allow_greater(p_greater); spin->set_allow_lesser(p_lesser); + spin->set_suffix(p_suffix); } EditorPropertyFloat::EditorPropertyFloat() { @@ -921,7 +930,6 @@ EditorPropertyFloat::EditorPropertyFloat() { add_child(spin); add_focusable(spin); spin->connect("value_changed", callable_mp(this, &EditorPropertyFloat::_value_changed)); - setting = false; } ///////////////////// EASING ///////////////////////// @@ -994,9 +1002,8 @@ void EditorPropertyEasing::_draw_easing() { Size2 s = easing_draw->get_size(); - const int points = 48; + const int point_count = 48; - float prev = 1.0; const float exp = get_edited_object()->get(get_edited_property()); const Ref<Font> f = get_theme_font("font", "Label"); @@ -1009,24 +1016,20 @@ void EditorPropertyEasing::_draw_easing() { line_color = get_theme_color("font_color", "Label") * Color(1, 1, 1, 0.9); } - Vector<Point2> lines; - for (int i = 1; i <= points; i++) { - float ifl = i / float(points); - float iflp = (i - 1) / float(points); + Vector<Point2> points; + for (int i = 0; i <= point_count; i++) { + float ifl = i / float(point_count); const float h = 1.0 - Math::ease(ifl, exp); if (flip) { ifl = 1.0 - ifl; - iflp = 1.0 - iflp; } - lines.push_back(Point2(ifl * s.width, h * s.height)); - lines.push_back(Point2(iflp * s.width, prev * s.height)); - prev = h; + points.push_back(Point2(ifl * s.width, h * s.height)); } - easing_draw->draw_multiline(lines, line_color, 1.0); + easing_draw->draw_polyline(points, line_color, 1.0, true); // Draw more decimals for small numbers since higher precision is usually required for fine adjustments. int decimals; if (Math::abs(exp) < 0.1 - CMP_EPSILON) { @@ -1176,7 +1179,7 @@ void EditorPropertyVector2::_notification(int p_what) { void EditorPropertyVector2::_bind_methods() { } -void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 2; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1184,6 +1187,7 @@ void EditorPropertyVector2::setup(double p_min, double p_max, double p_step, boo spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1262,7 +1266,7 @@ void EditorPropertyRect2::_notification(int p_what) { void EditorPropertyRect2::_bind_methods() { } -void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1270,6 +1274,7 @@ void EditorPropertyRect2::setup(double p_min, double p_max, double p_step, bool spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1330,6 +1335,11 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) { v3.x = spin[0]->get_value(); v3.y = spin[1]->get_value(); v3.z = spin[2]->get_value(); + if (angle_in_radians) { + v3.x = Math::deg2rad(v3.x); + v3.y = Math::deg2rad(v3.y); + v3.z = Math::deg2rad(v3.z); + } emit_changed(get_edited_property(), v3, p_name); } @@ -1338,6 +1348,11 @@ void EditorPropertyVector3::update_property() { } void EditorPropertyVector3::update_using_vector(Vector3 p_vector) { + if (angle_in_radians) { + p_vector.x = Math::rad2deg(p_vector.x); + p_vector.y = Math::rad2deg(p_vector.y); + p_vector.z = Math::rad2deg(p_vector.z); + } setting = true; spin[0]->set_value(p_vector.x); spin[1]->set_value(p_vector.y); @@ -1350,6 +1365,12 @@ Vector3 EditorPropertyVector3::get_vector() { v3.x = spin[0]->get_value(); v3.y = spin[1]->get_value(); v3.z = spin[2]->get_value(); + if (angle_in_radians) { + v3.x = Math::deg2rad(v3.x); + v3.y = Math::deg2rad(v3.y); + v3.z = Math::deg2rad(v3.z); + } + return v3; } @@ -1367,7 +1388,8 @@ void EditorPropertyVector3::_notification(int p_what) { void EditorPropertyVector3::_bind_methods() { } -void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix, bool p_angle_in_radians) { + angle_in_radians = p_angle_in_radians; for (int i = 0; i < 3; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1375,6 +1397,7 @@ void EditorPropertyVector3::setup(double p_min, double p_max, double p_step, boo spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1411,7 +1434,6 @@ EditorPropertyVector3::EditorPropertyVector3(bool p_force_wide) { if (!horizontal) { set_label_reference(spin[0]); //show text and buttons around this } - setting = false; } ///////////////////// VECTOR2i ///////////////////////// @@ -1449,7 +1471,7 @@ void EditorPropertyVector2i::_notification(int p_what) { void EditorPropertyVector2i::_bind_methods() { } -void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider) { +void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 2; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1457,6 +1479,7 @@ void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_no_slider) { spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1535,7 +1558,7 @@ void EditorPropertyRect2i::_notification(int p_what) { void EditorPropertyRect2i::_bind_methods() { } -void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_no_slider) { +void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1543,6 +1566,7 @@ void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_no_slider) { spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1629,7 +1653,7 @@ void EditorPropertyVector3i::_notification(int p_what) { void EditorPropertyVector3i::_bind_methods() { } -void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider) { +void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 3; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1637,6 +1661,7 @@ void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_no_slider) { spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1714,7 +1739,7 @@ void EditorPropertyPlane::_notification(int p_what) { void EditorPropertyPlane::_bind_methods() { } -void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1722,6 +1747,7 @@ void EditorPropertyPlane::setup(double p_min, double p_max, double p_step, bool spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1761,14 +1787,14 @@ EditorPropertyPlane::EditorPropertyPlane(bool p_force_wide) { setting = false; } -///////////////////// QUAT ///////////////////////// +///////////////////// QUATERNION ///////////////////////// -void EditorPropertyQuat::_value_changed(double val, const String &p_name) { +void EditorPropertyQuaternion::_value_changed(double val, const String &p_name) { if (setting) { return; } - Quat p; + Quaternion p; p.x = spin[0]->get_value(); p.y = spin[1]->get_value(); p.z = spin[2]->get_value(); @@ -1776,8 +1802,8 @@ void EditorPropertyQuat::_value_changed(double val, const String &p_name) { emit_changed(get_edited_property(), p, p_name); } -void EditorPropertyQuat::update_property() { - Quat val = get_edited_object()->get(get_edited_property()); +void EditorPropertyQuaternion::update_property() { + Quaternion val = get_edited_object()->get(get_edited_property()); setting = true; spin[0]->set_value(val.x); spin[1]->set_value(val.y); @@ -1786,7 +1812,7 @@ void EditorPropertyQuat::update_property() { setting = false; } -void EditorPropertyQuat::_notification(int p_what) { +void EditorPropertyQuaternion::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { Color base = get_theme_color("accent_color", "Editor"); for (int i = 0; i < 3; i++) { @@ -1797,10 +1823,10 @@ void EditorPropertyQuat::_notification(int p_what) { } } -void EditorPropertyQuat::_bind_methods() { +void EditorPropertyQuaternion::_bind_methods() { } -void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyQuaternion::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 4; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1808,10 +1834,11 @@ void EditorPropertyQuat::setup(double p_min, double p_max, double p_step, bool p spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } -EditorPropertyQuat::EditorPropertyQuat() { +EditorPropertyQuaternion::EditorPropertyQuaternion() { bool horizontal = EDITOR_GET("interface/inspector/horizontal_vector_types_editing"); BoxContainer *bc; @@ -1832,7 +1859,7 @@ EditorPropertyQuat::EditorPropertyQuat() { spin[i]->set_label(desc[i]); bc->add_child(spin[i]); add_focusable(spin[i]); - spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuat::_value_changed), varray(desc[i])); + spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyQuaternion::_value_changed), varray(desc[i])); if (horizontal) { spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); } @@ -1889,7 +1916,7 @@ void EditorPropertyAABB::_notification(int p_what) { void EditorPropertyAABB::_bind_methods() { } -void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 6; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1897,6 +1924,7 @@ void EditorPropertyAABB::setup(double p_min, double p_max, double p_step, bool p spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -1965,7 +1993,7 @@ void EditorPropertyTransform2D::_notification(int p_what) { void EditorPropertyTransform2D::_bind_methods() { } -void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 6; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -1973,6 +2001,7 @@ void EditorPropertyTransform2D::setup(double p_min, double p_max, double p_step, spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -2046,7 +2075,7 @@ void EditorPropertyBasis::_notification(int p_what) { void EditorPropertyBasis::_bind_methods() { } -void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 9; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -2054,6 +2083,7 @@ void EditorPropertyBasis::setup(double p_min, double p_max, double p_step, bool spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } @@ -2078,12 +2108,12 @@ EditorPropertyBasis::EditorPropertyBasis() { ///////////////////// TRANSFORM ///////////////////////// -void EditorPropertyTransform::_value_changed(double val, const String &p_name) { +void EditorPropertyTransform3D::_value_changed(double val, const String &p_name) { if (setting) { return; } - Transform p; + Transform3D p; p.basis[0][0] = spin[0]->get_value(); p.basis[1][0] = spin[1]->get_value(); p.basis[2][0] = spin[2]->get_value(); @@ -2100,11 +2130,11 @@ void EditorPropertyTransform::_value_changed(double val, const String &p_name) { emit_changed(get_edited_property(), p, p_name); } -void EditorPropertyTransform::update_property() { +void EditorPropertyTransform3D::update_property() { update_using_transform(get_edited_object()->get(get_edited_property())); } -void EditorPropertyTransform::update_using_transform(Transform p_transform) { +void EditorPropertyTransform3D::update_using_transform(Transform3D p_transform) { setting = true; spin[0]->set_value(p_transform.basis[0][0]); spin[1]->set_value(p_transform.basis[1][0]); @@ -2121,7 +2151,7 @@ void EditorPropertyTransform::update_using_transform(Transform p_transform) { setting = false; } -void EditorPropertyTransform::_notification(int p_what) { +void EditorPropertyTransform3D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { Color base = get_theme_color("accent_color", "Editor"); for (int i = 0; i < 12; i++) { @@ -2132,10 +2162,10 @@ void EditorPropertyTransform::_notification(int p_what) { } } -void EditorPropertyTransform::_bind_methods() { +void EditorPropertyTransform3D::_bind_methods() { } -void EditorPropertyTransform::setup(double p_min, double p_max, double p_step, bool p_no_slider) { +void EditorPropertyTransform3D::setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix) { for (int i = 0; i < 12; i++) { spin[i]->set_min(p_min); spin[i]->set_max(p_max); @@ -2143,10 +2173,11 @@ void EditorPropertyTransform::setup(double p_min, double p_max, double p_step, b spin[i]->set_hide_slider(p_no_slider); spin[i]->set_allow_greater(true); spin[i]->set_allow_lesser(true); + spin[i]->set_suffix(p_suffix); } } -EditorPropertyTransform::EditorPropertyTransform() { +EditorPropertyTransform3D::EditorPropertyTransform3D() { GridContainer *g = memnew(GridContainer); g->set_columns(3); add_child(g); @@ -2159,7 +2190,7 @@ EditorPropertyTransform::EditorPropertyTransform() { g->add_child(spin[i]); spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); add_focusable(spin[i]); - spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyTransform::_value_changed), varray(desc[i])); + spin[i]->connect("value_changed", callable_mp(this, &EditorPropertyTransform3D::_value_changed), varray(desc[i])); } set_bottom_editor(g); setting = false; @@ -2261,7 +2292,7 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) { base_node = get_edited_object()->call("get_root_path"); } - if (!base_node && Object::cast_to<Reference>(get_edited_object())) { + if (!base_node && Object::cast_to<RefCounted>(get_edited_object())) { Node *to_node = get_node(p_path); ERR_FAIL_COND(!to_node); path = get_tree()->get_edited_scene_root()->get_path_to(to_node); @@ -2540,7 +2571,7 @@ void EditorPropertyResource::_viewport_selected(const NodePath &p_path) { } Ref<ViewportTexture> vt; - vt.instance(); + vt.instantiate(); vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node)); vt->setup_local_to_scene(); @@ -2703,31 +2734,97 @@ void EditorInspectorDefaultPlugin::parse_begin(Object *p_object) { //do none } -bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { + Control *editor = EditorInspectorDefaultPlugin::get_editor_for_property(p_object, p_type, p_path, p_hint, p_hint_text, p_usage, p_wide); + if (editor) { + add_property_editor(p_path, editor); + } + return false; +} + +void EditorInspectorDefaultPlugin::parse_end() { + //do none +} + +struct EditorPropertyRangeHint { + bool angle_in_degrees = false; + bool greater = true; + bool lesser = true; + double min = -99999; + double max = 99999; + double step = 0; + String suffix; + bool exp_range = false; + bool hide_slider = true; + bool radians = false; +}; + +static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const String &p_hint_text, double p_default_step) { + EditorPropertyRangeHint hint; + hint.step = p_default_step; + bool degrees = false; + if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { + hint.greater = false; //if using ranged, assume false by default + hint.lesser = false; + + hint.min = p_hint_text.get_slice(",", 0).to_float(); + hint.max = p_hint_text.get_slice(",", 1).to_float(); + if (p_hint_text.get_slice_count(",") >= 3) { + hint.step = p_hint_text.get_slice(",", 2).to_float(); + } + hint.hide_slider = false; + for (int i = 2; i < p_hint_text.get_slice_count(","); i++) { + String slice = p_hint_text.get_slice(",", i).strip_edges(); + if (slice == "radians") { + hint.radians = true; + } else if (slice == "degrees") { + degrees = true; + } else if (slice == "or_greater") { + hint.greater = true; + } else if (slice == "or_lesser") { + hint.lesser = true; + } else if (slice == "noslider") { + hint.hide_slider = true; + } else if (slice == "exp") { + hint.exp_range = true; + } else if (slice.begins_with("suffix:")) { + hint.suffix = " " + slice.replace_first("suffix:", "").strip_edges(); + } + } + } + + if ((hint.radians || degrees) && hint.suffix == String()) { + hint.suffix = U"\u00B0"; + } + + return hint; +} + +EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { double default_float_step = EDITOR_GET("interface/inspector/default_float_step"); switch (p_type) { // atomic types case Variant::NIL: { EditorPropertyNil *editor = memnew(EditorPropertyNil); - add_property_editor(p_path, editor); + return editor; } break; case Variant::BOOL: { EditorPropertyCheck *editor = memnew(EditorPropertyCheck); - add_property_editor(p_path, editor); + return editor; } break; case Variant::INT: { if (p_hint == PROPERTY_HINT_ENUM) { EditorPropertyEnum *editor = memnew(EditorPropertyEnum); Vector<String> options = p_hint_text.split(","); editor->setup(options); - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_FLAGS) { EditorPropertyFlags *editor = memnew(EditorPropertyFlags); Vector<String> options = p_hint_text.split(","); editor->setup(options); - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_LAYERS_2D_PHYSICS || p_hint == PROPERTY_HINT_LAYERS_2D_RENDER || @@ -2760,41 +2857,20 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } EditorPropertyLayers *editor = memnew(EditorPropertyLayers); editor->setup(lt); - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_OBJECT_ID) { EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); editor->setup(p_hint_text); - add_property_editor(p_path, editor); + return editor; } else { EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - int min = 0, max = 65535, step = 1; - bool greater = true, lesser = true; - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - greater = false; //if using ranged, assume false by default - lesser = false; - min = p_hint_text.get_slice(",", 0).to_int(); - max = p_hint_text.get_slice(",", 1).to_int(); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_int(); - } + editor->setup(hint.min, hint.max, hint.step, hint.greater, hint.lesser); - for (int i = 2; i < p_hint_text.get_slice_count(","); i++) { - String slice = p_hint_text.get_slice(",", i).strip_edges(); - if (slice == "or_greater") { - greater = true; - } - if (slice == "or_lesser") { - lesser = true; - } - } - } - - editor->setup(min, max, step, greater, lesser); - - add_property_editor(p_path, editor); + return editor; } } break; case Variant::FLOAT: { @@ -2814,39 +2890,15 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } editor->setup(full, flip); - add_property_editor(p_path, editor); + return editor; } else { EditorPropertyFloat *editor = memnew(EditorPropertyFloat); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - bool exp_range = false; - bool greater = true, lesser = true; - - if ((p_hint == PROPERTY_HINT_RANGE || p_hint == PROPERTY_HINT_EXP_RANGE) && p_hint_text.get_slice_count(",") >= 2) { - greater = false; //if using ranged, assume false by default - lesser = false; - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - exp_range = p_hint == PROPERTY_HINT_EXP_RANGE; - for (int i = 2; i < p_hint_text.get_slice_count(","); i++) { - String slice = p_hint_text.get_slice(",", i).strip_edges(); - if (slice == "or_greater") { - greater = true; - } - if (slice == "or_lesser") { - lesser = true; - } - } - } - editor->setup(min, max, step, hide_slider, exp_range, greater, lesser); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.exp_range, hint.greater, hint.lesser, hint.suffix, hint.radians); - add_property_editor(p_path, editor); + return editor; } } break; case Variant::STRING: { @@ -2854,14 +2906,14 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ EditorPropertyTextEnum *editor = memnew(EditorPropertyTextEnum); Vector<String> options = p_hint_text.split(","); editor->setup(options); - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_MULTILINE_TEXT) { EditorPropertyMultilineText *editor = memnew(EditorPropertyMultilineText); - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_TYPE_STRING) { EditorPropertyClassName *editor = memnew(EditorPropertyClassName); editor->setup("Object", p_hint_text); - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_DIR || p_hint == PROPERTY_HINT_FILE || p_hint == PROPERTY_HINT_SAVE_FILE || p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE) { Vector<String> extensions = p_hint_text.split(","); bool global = p_hint == PROPERTY_HINT_GLOBAL_DIR || p_hint == PROPERTY_HINT_GLOBAL_FILE; @@ -2872,7 +2924,7 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ if (save) { editor->set_save_mode(); } - add_property_editor(p_path, editor); + return editor; } else if (p_hint == PROPERTY_HINT_METHOD_OF_VARIANT_TYPE || p_hint == PROPERTY_HINT_METHOD_OF_BASE_TYPE || p_hint == PROPERTY_HINT_METHOD_OF_INSTANCE || @@ -2910,14 +2962,14 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } } editor->setup(type, p_hint_text); - add_property_editor(p_path, editor); + return editor; } else { EditorPropertyText *editor = memnew(EditorPropertyText); if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) { editor->set_placeholder(p_hint_text); } - add_property_editor(p_path, editor); + return editor; } } break; @@ -2925,204 +2977,82 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ case Variant::VECTOR2: { EditorPropertyVector2 *editor = memnew(EditorPropertyVector2(p_wide)); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::VECTOR2I: { EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide)); - int min = -65535, max = 65535; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - hide_slider = false; - } - - editor->setup(min, max, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); + editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::RECT2: { EditorPropertyRect2 *editor = memnew(EditorPropertyRect2(p_wide)); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::RECT2I: { EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i(p_wide)); - int min = -65535, max = 65535; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - hide_slider = false; - } + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); + editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); - editor->setup(min, max, hide_slider); - add_property_editor(p_path, editor); + return editor; } break; case Variant::VECTOR3: { EditorPropertyVector3 *editor = memnew(EditorPropertyVector3(p_wide)); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix, hint.radians); + return editor; } break; case Variant::VECTOR3I: { EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide)); - int min = -65535, max = 65535; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - - hide_slider = false; - } - - editor->setup(min, max, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); + editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::TRANSFORM2D: { EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::PLANE: { EditorPropertyPlane *editor = memnew(EditorPropertyPlane(p_wide)); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; - case Variant::QUAT: { - EditorPropertyQuat *editor = memnew(EditorPropertyQuat); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + case Variant::QUATERNION: { + EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::AABB: { EditorPropertyAABB *editor = memnew(EditorPropertyAABB); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; case Variant::BASIS: { EditorPropertyBasis *editor = memnew(EditorPropertyBasis); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; - case Variant::TRANSFORM: { - EditorPropertyTransform *editor = memnew(EditorPropertyTransform); - double min = -65535, max = 65535, step = default_float_step; - bool hide_slider = true; - - if (p_hint == PROPERTY_HINT_RANGE && p_hint_text.get_slice_count(",") >= 2) { - min = p_hint_text.get_slice(",", 0).to_float(); - max = p_hint_text.get_slice(",", 1).to_float(); - if (p_hint_text.get_slice_count(",") >= 3) { - step = p_hint_text.get_slice(",", 2).to_float(); - } - hide_slider = false; - } - - editor->setup(min, max, step, hide_slider); - add_property_editor(p_path, editor); + case Variant::TRANSFORM3D: { + EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D); + EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, default_float_step); + editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.suffix); + return editor; } break; @@ -3130,21 +3060,21 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ case Variant::COLOR: { EditorPropertyColor *editor = memnew(EditorPropertyColor); editor->setup(p_hint != PROPERTY_HINT_COLOR_NO_ALPHA); - add_property_editor(p_path, editor); + return editor; } break; case Variant::STRING_NAME: { if (p_hint == PROPERTY_HINT_ENUM) { EditorPropertyTextEnum *editor = memnew(EditorPropertyTextEnum); Vector<String> options = p_hint_text.split(","); editor->setup(options, true); - add_property_editor(p_path, editor); + return editor; } else { EditorPropertyText *editor = memnew(EditorPropertyText); if (p_hint == PROPERTY_HINT_PLACEHOLDER_TEXT) { editor->set_placeholder(p_hint_text); } editor->set_string_name(true); - add_property_editor(p_path, editor); + return editor; } } break; case Variant::NODE_PATH: { @@ -3157,12 +3087,12 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ Vector<StringName> sn = Variant(types); //convert via variant editor->setup(NodePath(), sn, (p_usage & PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT)); } - add_property_editor(p_path, editor); + return editor; } break; case Variant::RID: { EditorPropertyRID *editor = memnew(EditorPropertyRID); - add_property_editor(p_path, editor); + return editor; } break; case Variant::OBJECT: { EditorPropertyResource *editor = memnew(EditorPropertyResource); @@ -3181,70 +3111,66 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } } - add_property_editor(p_path, editor); + return editor; } break; case Variant::DICTIONARY: { EditorPropertyDictionary *editor = memnew(EditorPropertyDictionary); - add_property_editor(p_path, editor); + return editor; } break; case Variant::ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::ARRAY, p_hint_text); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_BYTE_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_BYTE_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_INT32_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_INT32_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_INT64_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_INT64_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_FLOAT32_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_FLOAT32_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_FLOAT64_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_FLOAT64_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_STRING_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_STRING_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_VECTOR2_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_VECTOR2_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_VECTOR3_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_VECTOR3_ARRAY); - add_property_editor(p_path, editor); + return editor; } break; case Variant::PACKED_COLOR_ARRAY: { EditorPropertyArray *editor = memnew(EditorPropertyArray); editor->setup(Variant::PACKED_COLOR_ARRAY); - add_property_editor(p_path, editor); + } break; default: { } } - return false; //can be overridden, although it will most likely be last anyway -} - -void EditorInspectorDefaultPlugin::parse_end() { - //do none + return nullptr; } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 07f496f54d..d880017cc1 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -56,7 +56,7 @@ class EditorPropertyText : public EditorProperty { bool updating; bool string_name; void _text_changed(const String &p_string); - void _text_entered(const String &p_string); + void _text_submitted(const String &p_string); protected: static void _bind_methods(); @@ -298,7 +298,8 @@ public: class EditorPropertyFloat : public EditorProperty { GDCLASS(EditorPropertyFloat, EditorProperty); EditorSpinSlider *spin; - bool setting; + bool setting = false; + bool angle_in_radians = false; void _value_changed(double p_val); protected: @@ -306,7 +307,7 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, bool p_exp_range, bool p_greater, bool p_lesser, const String &p_suffix = String(), bool p_angle_in_radians = false); EditorPropertyFloat(); }; @@ -363,7 +364,7 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); EditorPropertyVector2(bool p_force_wide = false); }; @@ -379,14 +380,15 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); EditorPropertyRect2(bool p_force_wide = false); }; class EditorPropertyVector3 : public EditorProperty { GDCLASS(EditorPropertyVector3, EditorProperty); EditorSpinSlider *spin[3]; - bool setting; + bool setting = false; + bool angle_in_radians = false; void _value_changed(double p_val, const String &p_name); protected: @@ -397,7 +399,7 @@ public: virtual void update_property() override; virtual void update_using_vector(Vector3 p_vector); virtual Vector3 get_vector(); - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String(), bool p_angle_in_radians = false); EditorPropertyVector3(bool p_force_wide = false); }; @@ -413,7 +415,7 @@ protected: public: virtual void update_property() override; - void setup(int p_min, int p_max, bool p_no_slider); + void setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix = String()); EditorPropertyVector2i(bool p_force_wide = false); }; @@ -429,7 +431,7 @@ protected: public: virtual void update_property() override; - void setup(int p_min, int p_max, bool p_no_slider); + void setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix = String()); EditorPropertyRect2i(bool p_force_wide = false); }; @@ -445,7 +447,7 @@ protected: public: virtual void update_property() override; - void setup(int p_min, int p_max, bool p_no_slider); + void setup(int p_min, int p_max, bool p_no_slider, const String &p_suffix = String()); EditorPropertyVector3i(bool p_force_wide = false); }; @@ -461,12 +463,12 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); EditorPropertyPlane(bool p_force_wide = false); }; -class EditorPropertyQuat : public EditorProperty { - GDCLASS(EditorPropertyQuat, EditorProperty); +class EditorPropertyQuaternion : public EditorProperty { + GDCLASS(EditorPropertyQuaternion, EditorProperty); EditorSpinSlider *spin[4]; bool setting; void _value_changed(double p_val, const String &p_name); @@ -477,8 +479,8 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); - EditorPropertyQuat(); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); + EditorPropertyQuaternion(); }; class EditorPropertyAABB : public EditorProperty { @@ -493,7 +495,7 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); EditorPropertyAABB(); }; @@ -509,7 +511,7 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); EditorPropertyTransform2D(); }; @@ -525,12 +527,12 @@ protected: public: virtual void update_property() override; - void setup(double p_min, double p_max, double p_step, bool p_no_slider); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); EditorPropertyBasis(); }; -class EditorPropertyTransform : public EditorProperty { - GDCLASS(EditorPropertyTransform, EditorProperty); +class EditorPropertyTransform3D : public EditorProperty { + GDCLASS(EditorPropertyTransform3D, EditorProperty); EditorSpinSlider *spin[12]; bool setting; void _value_changed(double p_val, const String &p_name); @@ -541,9 +543,9 @@ protected: public: virtual void update_property() override; - virtual void update_using_transform(Transform p_transform); - void setup(double p_min, double p_max, double p_step, bool p_no_slider); - EditorPropertyTransform(); + virtual void update_using_transform(Transform3D p_transform); + void setup(double p_min, double p_max, double p_step, bool p_no_slider, const String &p_suffix = String()); + EditorPropertyTransform3D(); }; class EditorPropertyColor : public EditorProperty { @@ -647,8 +649,10 @@ class EditorInspectorDefaultPlugin : public EditorInspectorPlugin { public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; virtual void parse_end() override; + + static EditorProperty *get_editor_for_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false); }; #endif // EDITOR_PROPERTIES_H diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 3bc29856f1..3216728be1 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -337,7 +337,7 @@ void EditorPropertyArray::update_property() { editor->setup("Object"); prop = editor; } else { - prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", subtype_hint, subtype_hint_string, 0); + prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", subtype_hint, subtype_hint_string, PROPERTY_USAGE_NONE); } prop->set_object_and_property(object.ptr(), prop_name); @@ -550,6 +550,8 @@ void EditorPropertyArray::_length_changed(double p_page) { void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint_string) { array_type = p_array_type; + // The format of p_hint_string is: + // subType/subTypeHint:nextSubtype ... etc if (array_type == Variant::ARRAY && !p_hint_string.is_empty()) { int hint_subtype_separator = p_hint_string.find(":"); if (hint_subtype_separator >= 0) { @@ -567,12 +569,12 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint } void EditorPropertyArray::_bind_methods() { - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &EditorPropertyArray::drop_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorPropertyArray::drop_data_fw); } EditorPropertyArray::EditorPropertyArray() { - object.instance(); + object.instantiate(); page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page")); edit = memnew(Button); edit->set_h_size_flags(SIZE_EXPAND_FILL); @@ -850,8 +852,8 @@ void EditorPropertyDictionary::update_property() { prop = editor; } break; - case Variant::QUAT: { - EditorPropertyQuat *editor = memnew(EditorPropertyQuat); + case Variant::QUATERNION: { + EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion); editor->setup(-100000, 100000, 0.001, true); prop = editor; @@ -868,8 +870,8 @@ void EditorPropertyDictionary::update_property() { prop = editor; } break; - case Variant::TRANSFORM: { - EditorPropertyTransform *editor = memnew(EditorPropertyTransform); + case Variant::TRANSFORM3D: { + EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D); editor->setup(-100000, 100000, 0.001, true); prop = editor; @@ -971,7 +973,7 @@ void EditorPropertyDictionary::update_property() { PanelContainer *pc = memnew(PanelContainer); vbox->add_child(pc); Ref<StyleBoxFlat> flat; - flat.instance(); + flat.instantiate(); for (int j = 0; j < 4; j++) { flat->set_default_margin(Side(j), 2 * EDSCALE); } @@ -1066,7 +1068,7 @@ void EditorPropertyDictionary::_bind_methods() { } EditorPropertyDictionary::EditorPropertyDictionary() { - object.instance(); + object.instantiate(); page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page")); edit = memnew(Button); edit->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index fa5adc788d..aa2d8744b1 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -36,8 +36,8 @@ #include "editor/filesystem_dock.h" #include "scene/gui/button.h" -class EditorPropertyArrayObject : public Reference { - GDCLASS(EditorPropertyArrayObject, Reference); +class EditorPropertyArrayObject : public RefCounted { + GDCLASS(EditorPropertyArrayObject, RefCounted); Variant array; @@ -52,8 +52,8 @@ public: EditorPropertyArrayObject(); }; -class EditorPropertyDictionaryObject : public Reference { - GDCLASS(EditorPropertyDictionaryObject, Reference); +class EditorPropertyDictionaryObject : public RefCounted { + GDCLASS(EditorPropertyDictionaryObject, RefCounted); Variant new_item_key; Variant new_item_value; diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index d1a0bfeded..350fc5eccb 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -271,7 +271,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { } String orig_type = edited_resource->get_class(); - Object *inst = ClassDB::instance(orig_type); + Object *inst = ClassDB::instantiate(orig_type); Ref<Resource> unique_resource = Ref<Resource>(Object::cast_to<Resource>(inst)); ERR_FAIL_COND(unique_resource.is_null()); @@ -334,7 +334,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { Variant obj; if (ScriptServer::is_global_class(intype)) { - obj = ClassDB::instance(ScriptServer::get_global_class_native_base(intype)); + obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(intype)); if (obj) { Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(intype)); if (script.is_valid()) { @@ -342,7 +342,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { } } } else { - obj = ClassDB::instance(intype); + obj = ClassDB::instantiate(intype); } if (!obj) { @@ -361,8 +361,8 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { void EditorResourcePicker::set_create_options(Object *p_menu_node) { // If a subclass implements this method, use it to replace all create items. - if (get_script_instance() && get_script_instance()->has_method("set_create_options")) { - get_script_instance()->call("set_create_options", p_menu_node); + if (get_script_instance() && get_script_instance()->has_method("_set_create_options")) { + get_script_instance()->call("_set_create_options", p_menu_node); return; } @@ -395,7 +395,7 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) { } } - if (!is_custom_resource && !(ScriptServer::is_global_class(t) || ClassDB::can_instance(t))) { + if (!is_custom_resource && !(ScriptServer::is_global_class(t) || ClassDB::can_instantiate(t))) { continue; } @@ -418,8 +418,8 @@ void EditorResourcePicker::set_create_options(Object *p_menu_node) { } bool EditorResourcePicker::handle_menu_selected(int p_which) { - if (get_script_instance() && get_script_instance()->has_method("handle_menu_selected")) { - return get_script_instance()->call("handle_menu_selected", p_which); + if (get_script_instance() && get_script_instance()->has_method("_handle_menu_selected")) { + return get_script_instance()->call("_handle_menu_selected", p_which); } return false; @@ -625,9 +625,9 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_ void EditorResourcePicker::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_resource_preview"), &EditorResourcePicker::_update_resource_preview); - ClassDB::bind_method(D_METHOD("get_drag_data_fw", "position", "from"), &EditorResourcePicker::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw", "position", "data", "from"), &EditorResourcePicker::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &EditorResourcePicker::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::drop_data_fw); ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &EditorResourcePicker::set_base_type); ClassDB::bind_method(D_METHOD("get_base_type"), &EditorResourcePicker::get_base_type); @@ -640,11 +640,11 @@ void EditorResourcePicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_editable", "enable"), &EditorResourcePicker::set_editable); ClassDB::bind_method(D_METHOD("is_editable"), &EditorResourcePicker::is_editable); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("set_create_options", PropertyInfo(Variant::OBJECT, "menu_node"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo("handle_menu_selected", PropertyInfo(Variant::INT, "id"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("_set_create_options", PropertyInfo(Variant::OBJECT, "menu_node"))); + ClassDB::add_virtual_method(get_class_static(), MethodInfo("_handle_menu_selected", PropertyInfo(Variant::INT, "id"))); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_type"), "set_base_type", "get_base_type"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource", 0), "set_edited_resource", "get_edited_resource"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource", PROPERTY_USAGE_NONE), "set_edited_resource", "get_edited_resource"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode"); @@ -857,7 +857,7 @@ void EditorScriptPicker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_script_owner", "owner_node"), &EditorScriptPicker::set_script_owner); ClassDB::bind_method(D_METHOD("get_script_owner"), &EditorScriptPicker::get_script_owner); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "script_owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_script_owner", "get_script_owner"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "script_owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_script_owner", "get_script_owner"); } EditorScriptPicker::EditorScriptPicker() { diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 35cf08b4d7..f904ae80a7 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -31,31 +31,31 @@ #include "editor_resource_preview.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/object/message_queue.h" -#include "core/os/file_access.h" #include "editor_node.h" #include "editor_scale.h" #include "editor_settings.h" bool EditorResourcePreviewGenerator::handles(const String &p_type) const { - if (get_script_instance() && get_script_instance()->has_method("handles")) { - return get_script_instance()->call("handles", p_type); + if (get_script_instance() && get_script_instance()->has_method("_handles")) { + return get_script_instance()->call("_handles", p_type); } - ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::handles needs to be overridden."); + ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::_handles needs to be overridden."); } Ref<Texture2D> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 &p_size) const { - if (get_script_instance() && get_script_instance()->has_method("generate")) { - return get_script_instance()->call("generate", p_from, p_size); + if (get_script_instance() && get_script_instance()->has_method("_generate")) { + return get_script_instance()->call("_generate", p_from, p_size); } - ERR_FAIL_V_MSG(Ref<Texture2D>(), "EditorResourcePreviewGenerator::generate needs to be overridden."); + ERR_FAIL_V_MSG(Ref<Texture2D>(), "EditorResourcePreviewGenerator::_generate needs to be overridden."); } Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 &p_size) const { - if (get_script_instance() && get_script_instance()->has_method("generate_from_path")) { - return get_script_instance()->call("generate_from_path", p_path, p_size); + if (get_script_instance() && get_script_instance()->has_method("_generate_from_path")) { + return get_script_instance()->call("_generate_from_path", p_path, p_size); } RES res = ResourceLoader::load(p_path); @@ -66,27 +66,27 @@ Ref<Texture2D> EditorResourcePreviewGenerator::generate_from_path(const String & } bool EditorResourcePreviewGenerator::generate_small_preview_automatically() const { - if (get_script_instance() && get_script_instance()->has_method("generate_small_preview_automatically")) { - return get_script_instance()->call("generate_small_preview_automatically"); + if (get_script_instance() && get_script_instance()->has_method("_generate_small_preview_automatically")) { + return get_script_instance()->call("_generate_small_preview_automatically"); } return false; } bool EditorResourcePreviewGenerator::can_generate_small_preview() const { - if (get_script_instance() && get_script_instance()->has_method("can_generate_small_preview")) { - return get_script_instance()->call("can_generate_small_preview"); + if (get_script_instance() && get_script_instance()->has_method("_can_generate_small_preview")) { + return get_script_instance()->call("_can_generate_small_preview"); } return false; } void EditorResourcePreviewGenerator::_bind_methods() { - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "handles", PropertyInfo(Variant::STRING, "type"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture2D), "generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(CLASS_INFO(Texture2D), "generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "generate_small_preview_automatically")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "can_generate_small_preview")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_handles", PropertyInfo(Variant::STRING, "type"))); + BIND_VMETHOD(MethodInfo(CLASS_INFO(Texture2D), "_generate", PropertyInfo(Variant::OBJECT, "from", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::VECTOR2, "size"))); + BIND_VMETHOD(MethodInfo(CLASS_INFO(Texture2D), "_generate_from_path", PropertyInfo(Variant::STRING, "path", PROPERTY_HINT_FILE), PropertyInfo(Variant::VECTOR2, "size"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_generate_small_preview_automatically")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_generate_small_preview")); } EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() { @@ -177,7 +177,7 @@ void EditorResourcePreview::_generate_preview(Ref<ImageTexture> &r_texture, Ref< Ref<Image> small_image = r_texture->get_image(); small_image = small_image->duplicate(); small_image->resize(small_thumbnail_size, small_thumbnail_size, Image::INTERPOLATE_CUBIC); - r_small_texture.instance(); + r_small_texture.instantiate(); r_small_texture->create_from_image(small_image); } @@ -293,21 +293,21 @@ void EditorResourcePreview::_thread() { if (cache_valid) { Ref<Image> img; - img.instance(); + img.instantiate(); Ref<Image> small_img; - small_img.instance(); + small_img.instantiate(); if (img->load(cache_base + ".png") != OK) { cache_valid = false; } else { - texture.instance(); + texture.instantiate(); texture->create_from_image(img); if (has_small_texture) { if (small_img->load(cache_base + "_small.png") != OK) { cache_valid = false; } else { - small_texture.instance(); + small_texture.instantiate(); small_texture->create_from_image(small_img); } } diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h index ffeb22162e..67f83220d0 100644 --- a/editor/editor_resource_preview.h +++ b/editor/editor_resource_preview.h @@ -37,8 +37,8 @@ #include "scene/main/node.h" #include "scene/resources/texture.h" -class EditorResourcePreviewGenerator : public Reference { - GDCLASS(EditorResourcePreviewGenerator, Reference); +class EditorResourcePreviewGenerator : public RefCounted { + GDCLASS(EditorResourcePreviewGenerator, RefCounted); protected: static void _bind_methods(); diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp index 1ffa20d1ea..a604022391 100644 --- a/editor/editor_run_native.cpp +++ b/editor/editor_run_native.cpp @@ -49,7 +49,7 @@ void EditorRunNative::_notification(int p_what) { if (!im->is_empty()) { im->resize(16 * EDSCALE, 16 * EDSCALE); Ref<ImageTexture> small_icon; - small_icon.instance(); + small_icon.instantiate(); small_icon->create_from_image(im); MenuButton *mb = memnew(MenuButton); mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::_run_native), varray(i)); diff --git a/editor/editor_run_script.h b/editor/editor_run_script.h index 83987ecba1..c8412c3c92 100644 --- a/editor/editor_run_script.h +++ b/editor/editor_run_script.h @@ -31,11 +31,11 @@ #ifndef EDITOR_RUN_SCRIPT_H #define EDITOR_RUN_SCRIPT_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "editor_plugin.h" class EditorNode; -class EditorScript : public Reference { - GDCLASS(EditorScript, Reference); +class EditorScript : public RefCounted { + GDCLASS(EditorScript, RefCounted); EditorNode *editor; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index ce8c49279f..080563f375 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -35,13 +35,13 @@ #include "core/io/certs_compressed.gen.h" #include "core/io/compression.h" #include "core/io/config_file.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_memory.h" #include "core/io/ip.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" #include "core/io/translation_loader_po.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/version.h" @@ -79,7 +79,7 @@ bool EditorSettings::_set_only(const StringName &p_name, const Variant &p_value) Ref<InputEvent> shortcut = arr[i + 1]; Ref<Shortcut> sc; - sc.instance(); + sc.instantiate(); sc->set_shortcut(shortcut); add_shortcut(name, sc); } @@ -240,19 +240,19 @@ void EditorSettings::_get_property_list(List<PropertyInfo> *p_list) const { } for (Set<_EVCSort>::Element *E = vclist.front(); E; E = E->next()) { - int pinfo = 0; + uint32_t pusage = PROPERTY_USAGE_NONE; if (E->get().save || !optimize_save) { - pinfo |= PROPERTY_USAGE_STORAGE; + pusage |= PROPERTY_USAGE_STORAGE; } if (!E->get().name.begins_with("_") && !E->get().name.begins_with("projects/")) { - pinfo |= PROPERTY_USAGE_EDITOR; + pusage |= PROPERTY_USAGE_EDITOR; } else { - pinfo |= PROPERTY_USAGE_STORAGE; //hiddens must always be saved + pusage |= PROPERTY_USAGE_STORAGE; //hiddens must always be saved } PropertyInfo pi(E->get().type, E->get().name); - pi.usage = pinfo; + pi.usage = pusage; if (hints.has(E->get().name)) { pi = hints[E->get().name]; } @@ -373,28 +373,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Editor _initial_set("interface/editor/display_scale", 0); // Display what the Auto display scale setting effectively corresponds to. - // The code below is adapted in `editor/editor_node.cpp` and `editor/project_manager.cpp`. - // Make sure to update those when modifying the code below. -#ifdef OSX_ENABLED - float scale = DisplayServer::get_singleton()->screen_get_max_scale(); -#else - const int screen = DisplayServer::get_singleton()->window_get_current_screen(); - float scale; - if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) { - // hiDPI display. - scale = 2.0; - } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) { - // Likely a hiDPI display, but we aren't certain due to the returned DPI. - // Use an intermediate scale to handle this situation. - scale = 1.5; - } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) { - // Small loDPI display. Use a smaller display scale so that editor elements fit more easily. - // Icons won't look great, but this is better than having editor elements overflow from its window. - scale = 0.75; - } else { - scale = 1.0; - } -#endif + float scale = get_auto_display_scale(); hints["interface/editor/display_scale"] = PropertyInfo(Variant::INT, "interface/editor/display_scale", PROPERTY_HINT_ENUM, vformat("Auto (%d%%),75%%,100%%,125%%,150%%,175%%,200%%,Custom", Math::round(scale * 100)), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/custom_display_scale", 1.0f); hints["interface/editor/custom_display_scale"] = PropertyInfo(Variant::FLOAT, "interface/editor/custom_display_scale", PROPERTY_HINT_RANGE, "0.5,3,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); @@ -421,8 +400,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); - _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS - hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 100000); // 10 FPS + // Allow an unfocused FPS limit as low as 1 FPS for those who really need low power usage + // (but don't need to preview particles or shaders while the editor is unfocused). + // With very low FPS limits, the editor can take a small while to become usable after being focused again, + // so this should be used at the user's discretion. + hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,1000000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); _initial_set("interface/editor/single_window_mode", false); @@ -648,6 +631,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/3d/navigation/zoom_style", 0); hints["editors/3d/navigation/zoom_style"] = PropertyInfo(Variant::INT, "editors/3d/navigation/zoom_style", PROPERTY_HINT_ENUM, "Vertical, Horizontal"); + _initial_set("editors/3d/navigation/emulate_numpad", false); _initial_set("editors/3d/navigation/emulate_3_button_mouse", false); _initial_set("editors/3d/navigation/orbit_modifier", 0); hints["editors/3d/navigation/orbit_modifier"] = PropertyInfo(Variant::INT, "editors/3d/navigation/orbit_modifier", PROPERTY_HINT_ENUM, "None,Shift,Alt,Meta,Ctrl"); @@ -689,11 +673,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/2d/guides_color", Color(0.6, 0.0, 0.8)); _initial_set("editors/2d/smart_snapping_line_color", Color(0.9, 0.1, 0.1)); _initial_set("editors/2d/bone_width", 5); - _initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9)); - _initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.9)); - _initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.9)); - _initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.9)); - _initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35)); + _initial_set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.7)); + _initial_set("editors/2d/bone_color2", Color(0.6, 0.6, 0.6, 0.7)); + _initial_set("editors/2d/bone_selected_color", Color(0.9, 0.45, 0.45, 0.7)); + _initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.7)); + _initial_set("editors/2d/bone_outline_color", Color(0.35, 0.35, 0.35, 0.5)); _initial_set("editors/2d/bone_outline_size", 2); _initial_set("editors/2d/viewport_border_color", Color(0.4, 0.4, 1.0, 0.4)); _initial_set("editors/2d/constrain_editor_view", true); @@ -768,8 +752,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { for (int i = 0; i < list.size(); i++) { String name = list[i].replace("/", "::"); set("projects/" + name, list[i]); - }; - }; + } + } if (p_extra_config->has_section("presets")) { List<String> keys; @@ -779,9 +763,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { String key = E->get(); Variant val = p_extra_config->get_value("presets", key); set(key, val); - }; - }; - }; + } + } + } } void EditorSettings::_load_godot2_text_editor_theme() { @@ -871,9 +855,8 @@ static void _create_script_templates(const String &p_path) { Dictionary templates = _get_builtin_script_templates(); List<Variant> keys; templates.get_key_list(&keys); - FileAccess *file = FileAccess::create(FileAccess::ACCESS_FILESYSTEM); - - DirAccess *dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + FileAccessRef file = FileAccess::create(FileAccess::ACCESS_FILESYSTEM); + DirAccessRef dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); dir->change_dir(p_path); for (int i = 0; i < keys.size(); i++) { if (!dir->file_exists(keys[i])) { @@ -883,9 +866,6 @@ static void _create_script_templates(const String &p_path) { file->close(); } } - - memdelete(dir); - memdelete(file); } // PUBLIC METHODS @@ -895,103 +875,48 @@ EditorSettings *EditorSettings::get_singleton() { } void EditorSettings::create() { + // IMPORTANT: create() *must* create a valid EditorSettings singleton, + // as the rest of the engine code will assume it. As such, it should never + // return (incl. via ERR_FAIL) without initializing the singleton member. + if (singleton.ptr()) { - return; //pointless + ERR_PRINT("Can't recreate EditorSettings as it already exists."); + return; } + ClassDB::register_class<EditorSettings>(); // Otherwise it can't be unserialized. + + String config_file_path; Ref<ConfigFile> extra_config = memnew(ConfigFile); + if (!EditorPaths::get_singleton()) { + ERR_PRINT("Bug (please report): EditorPaths haven't been initialized, EditorSettings cannot be created properly."); + goto fail; + } + if (EditorPaths::get_singleton()->is_self_contained()) { Error err = extra_config->load(EditorPaths::get_singleton()->get_self_contained_file()); if (err != OK) { - ERR_PRINT("Can't load extra config from path :" + EditorPaths::get_singleton()->get_self_contained_file()); + ERR_PRINT("Can't load extra config from path: " + EditorPaths::get_singleton()->get_self_contained_file()); } } - DirAccess *dir = nullptr; - - ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized - - String config_file_path; - if (EditorPaths::get_singleton()->are_paths_valid()) { - // Validate/create data dir and subdirectories + _create_script_templates(EditorPaths::get_singleton()->get_config_dir().plus_file("script_templates")); - String data_dir = EditorPaths::get_singleton()->get_data_dir(); - - dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - if (dir->change_dir(data_dir) != OK) { - dir->make_dir_recursive(data_dir); - if (dir->change_dir(data_dir) != OK) { - ERR_PRINT("Cannot create data directory!"); - memdelete(dir); - goto fail; - } - } - - if (dir->change_dir("templates") != OK) { - dir->make_dir("templates"); - } else { - dir->change_dir(".."); - } - - // Validate/create config dir and subdirectories - - if (dir->change_dir(EditorPaths::get_singleton()->get_config_dir()) != OK) { - dir->make_dir_recursive(EditorPaths::get_singleton()->get_config_dir()); - if (dir->change_dir(EditorPaths::get_singleton()->get_config_dir()) != OK) { - ERR_PRINT("Cannot create config directory!"); - memdelete(dir); - goto fail; - } - } - - if (dir->change_dir("text_editor_themes") != OK) { - dir->make_dir("text_editor_themes"); - } else { - dir->change_dir(".."); - } - - if (dir->change_dir("script_templates") != OK) { - dir->make_dir("script_templates"); - } else { - dir->change_dir(".."); - } - - if (dir->change_dir("feature_profiles") != OK) { - dir->make_dir("feature_profiles"); - } else { - dir->change_dir(".."); - } - - _create_script_templates(dir->get_current_dir().plus_file("script_templates")); - - { - // Validate/create project-specific editor settings dir. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (da->change_dir(EditorSettings::PROJECT_EDITOR_SETTINGS_PATH) != OK) { - Error err = da->make_dir_recursive(EditorSettings::PROJECT_EDITOR_SETTINGS_PATH); - if (err || da->change_dir(EditorSettings::PROJECT_EDITOR_SETTINGS_PATH) != OK) { - ERR_FAIL_MSG("Failed to create '" + EditorSettings::PROJECT_EDITOR_SETTINGS_PATH + "' folder."); - } - } - } - - // Validate editor config file + // Validate editor config file. + DirAccessRef dir = DirAccess::open(EditorPaths::get_singleton()->get_config_dir()); String config_file_name = "editor_settings-" + itos(VERSION_MAJOR) + ".tres"; config_file_path = EditorPaths::get_singleton()->get_config_dir().plus_file(config_file_name); if (!dir->file_exists(config_file_name)) { - memdelete(dir); goto fail; } - memdelete(dir); - singleton = ResourceLoader::load(config_file_path, "EditorSettings"); if (singleton.is_null()) { - WARN_PRINT("Could not open config file."); + ERR_PRINT("Could not load editor settings from path: " + config_file_path); goto fail; } @@ -1009,7 +934,6 @@ void EditorSettings::create() { } fail: - // patch init projects String exe_path = OS::get_singleton()->get_executable_path().get_base_dir(); @@ -1017,9 +941,9 @@ fail: Vector<String> list = extra_config->get_value("init_projects", "list"); for (int i = 0; i < list.size(); i++) { list.write[i] = exe_path.plus_file(list[i]); - }; + } extra_config->set_value("init_projects", "list", list); - }; + } singleton = Ref<EditorSettings>(memnew(EditorSettings)); singleton->save_changed_setting = true; @@ -1251,16 +1175,15 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) { hints[p_hint.name] = p_hint; } -// Data directories +// Editor data and config directories +// EditorPaths::create() is responsible for the creation of these directories. String EditorSettings::get_templates_dir() const { return EditorPaths::get_singleton()->get_data_dir().plus_file("templates"); } -// Config directories - String EditorSettings::get_project_settings_dir() const { - return EditorSettings::PROJECT_EDITOR_SETTINGS_PATH; + return EditorPaths::get_singleton()->get_project_data_dir().plus_file("editor"); } String EditorSettings::get_text_editor_themes_dir() const { @@ -1275,8 +1198,6 @@ String EditorSettings::get_project_script_templates_dir() const { return ProjectSettings::get_singleton()->get("editor/script/templates_search_path"); } -// Cache directory - String EditorSettings::get_feature_profiles_dir() const { return EditorPaths::get_singleton()->get_config_dir().plus_file("feature_profiles"); } @@ -1508,6 +1429,29 @@ String EditorSettings::get_editor_layouts_config() const { return EditorPaths::get_singleton()->get_config_dir().plus_file("editor_layouts.cfg"); } +float EditorSettings::get_auto_display_scale() const { +#ifdef OSX_ENABLED + return DisplayServer::get_singleton()->screen_get_max_scale(); +#else + const int screen = DisplayServer::get_singleton()->window_get_current_screen(); + // Use the smallest dimension to use a correct display scale on portait displays. + const int smallest_dimension = MIN(DisplayServer::get_singleton()->screen_get_size(screen).x, DisplayServer::get_singleton()->screen_get_size(screen).y); + if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && smallest_dimension >= 1400) { + // hiDPI display. + return 2.0; + } else if (smallest_dimension >= 1700) { + // Likely a hiDPI display, but we aren't certain due to the returned DPI. + // Use an intermediate scale to handle this situation. + return 1.5; + } else if (smallest_dimension <= 800) { + // Small loDPI display. Use a smaller display scale so that editor elements fit more easily. + // Icons won't look great, but this is better than having editor elements overflow from its window. + return 0.75; + } + return 1.0; +#endif +} + // Shortcuts void EditorSettings::add_shortcut(const String &p_name, Ref<Shortcut> &p_shortcut) { @@ -1533,7 +1477,7 @@ Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const { Ref<Shortcut> sc; const Map<String, List<Ref<InputEvent>>>::Element *builtin_override = builtin_action_overrides.find(p_name); if (builtin_override) { - sc.instance(); + sc.instantiate(); sc->set_shortcut(builtin_override->get().front()->get()); sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name)); } @@ -1542,7 +1486,7 @@ Ref<Shortcut> EditorSettings::get_shortcut(const String &p_name) const { if (sc.is_null()) { const OrderedHashMap<String, List<Ref<InputEvent>>>::ConstElement builtin_default = InputMap::get_singleton()->get_builtins().find(p_name); if (builtin_default) { - sc.instance(); + sc.instantiate(); sc->set_shortcut(builtin_default.get().front()->get()); sc->set_name(InputMap::get_singleton()->get_builtin_display_name(p_name)); } @@ -1585,7 +1529,7 @@ Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p Ref<InputEventKey> ie; if (p_keycode) { - ie.instance(); + ie.instantiate(); ie->set_unicode(p_keycode & KEY_CODE_MASK); ie->set_keycode(p_keycode & KEY_CODE_MASK); @@ -1597,7 +1541,7 @@ Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p if (!EditorSettings::get_singleton()) { Ref<Shortcut> sc; - sc.instance(); + sc.instantiate(); sc->set_name(p_name); sc->set_shortcut(ie); sc->set_meta("original", ie); @@ -1611,7 +1555,7 @@ Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, uint32_t p return sc; } - sc.instance(); + sc.instantiate(); sc->set_name(p_name); sc->set_shortcut(ie); sc->set_meta("original", ie); //to compare against changes @@ -1642,7 +1586,7 @@ void EditorSettings::set_builtin_action_override(const String &p_name, const Arr // Check equality of each event. for (List<Ref<InputEvent>>::Element *E = builtin_events.front(); E; E = E->next()) { - if (!E->get()->shortcut_match(p_events[event_idx])) { + if (!E->get()->is_match(p_events[event_idx])) { same_as_builtin = false; break; } diff --git a/editor/editor_settings.h b/editor/editor_settings.h index 4c361403a9..3a28c18b27 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -47,7 +47,6 @@ class EditorSettings : public Resource { _THREAD_SAFE_CLASS_ public: - inline static const String PROJECT_EDITOR_SETTINGS_PATH = "res://.godot/editor"; struct Plugin { EditorPlugin *instance = nullptr; String path; @@ -175,6 +174,7 @@ public: Vector<String> get_script_templates(const String &p_extension, const String &p_custom_path = String()); String get_editor_layouts_config() const; + float get_auto_display_scale() const; void add_shortcut(const String &p_name, Ref<Shortcut> &p_shortcut); bool is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const; diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 657dcfa760..aa4a394d30 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -206,24 +206,34 @@ void EditorSpinSlider::_notification(int p_what) { // EditorSpinSliders with a label have more space on the left, so add an // higher margin to match the location where the text begins. // The margin values below were determined by empirical testing. - stylebox->set_default_margin(SIDE_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE); + if (is_layout_rtl()) { + stylebox->set_default_margin(SIDE_LEFT, 0); + stylebox->set_default_margin(SIDE_RIGHT, (get_label() != String() ? 23 : 16) * EDSCALE); + } else { + stylebox->set_default_margin(SIDE_LEFT, (get_label() != String() ? 23 : 16) * EDSCALE); + stylebox->set_default_margin(SIDE_RIGHT, 0); + } value_input->add_theme_style_override("normal", stylebox); } if (p_what == NOTIFICATION_DRAW) { updown_offset = -1; + RID ci = get_canvas_item(); + bool rtl = is_layout_rtl(); + Vector2 size = get_size(); + Ref<StyleBox> sb = get_theme_stylebox("normal", "LineEdit"); if (!flat) { - draw_style_box(sb, Rect2(Vector2(), get_size())); + draw_style_box(sb, Rect2(Vector2(), size)); } Ref<Font> font = get_theme_font("font", "LineEdit"); int font_size = get_theme_font_size("font_size", "LineEdit"); int sep_base = 4 * EDSCALE; int sep = sep_base + sb->get_offset().x; //make it have the same margin on both sides, looks better - int string_width = font->get_string_size(label, font_size).width; - int number_width = get_size().width - sb->get_minimum_size().width - string_width - sep; + int label_width = font->get_string_size(label, font_size).width; + int number_width = size.width - sb->get_minimum_size().width - label_width - sep; Ref<Texture2D> updown = get_theme_icon("updown", "SpinBox"); @@ -233,7 +243,7 @@ void EditorSpinSlider::_notification(int p_what) { String numstr = get_text_value(); - int vofs = (get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size); + int vofs = (size.height - font->get_height(font_size)) / 2 + font->get_ascent(font_size); Color fc = get_theme_color("font_color", "LineEdit"); Color lc; @@ -245,22 +255,59 @@ void EditorSpinSlider::_notification(int p_what) { if (flat && label != String()) { Color label_bg_color = get_theme_color("dark_color_3", "Editor"); - draw_rect(Rect2(Vector2(), Vector2(sb->get_offset().x * 2 + string_width, get_size().height)), label_bg_color); + if (rtl) { + draw_rect(Rect2(Vector2(size.width - (sb->get_offset().x * 2 + label_width), 0), Vector2(sb->get_offset().x * 2 + label_width, size.height)), label_bg_color); + } else { + draw_rect(Rect2(Vector2(), Vector2(sb->get_offset().x * 2 + label_width, size.height)), label_bg_color); + } } if (has_focus()) { Ref<StyleBox> focus = get_theme_stylebox("focus", "LineEdit"); - draw_style_box(focus, Rect2(Vector2(), get_size())); + draw_style_box(focus, Rect2(Vector2(), size)); } - draw_string(font, Vector2(Math::round(sb->get_offset().x), vofs), label, HALIGN_LEFT, -1, font_size, lc * Color(1, 1, 1, 0.5)); + if (rtl) { + draw_string(font, Vector2(Math::round(size.width - sb->get_offset().x - label_width), vofs), label, HALIGN_RIGHT, -1, font_size, lc * Color(1, 1, 1, 0.5)); + } else { + draw_string(font, Vector2(Math::round(sb->get_offset().x), vofs), label, HALIGN_LEFT, -1, font_size, lc * Color(1, 1, 1, 0.5)); + } - draw_string(font, Vector2(Math::round(sb->get_offset().x + string_width + sep), vofs), numstr, HALIGN_LEFT, number_width, font_size, fc); + int suffix_start = numstr.length(); + RID num_rid = TS->create_shaped_text(); + TS->shaped_text_add_string(num_rid, numstr + U"\u2009" + suffix, font->get_rids(), font_size); + + float text_start = rtl ? Math::round(sb->get_offset().x) : Math::round(sb->get_offset().x + label_width + sep); + Vector2 text_ofs = rtl ? Vector2(text_start + (number_width - TS->shaped_text_get_width(num_rid)), vofs) : Vector2(text_start, vofs); + const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(num_rid); + int v_size = visual.size(); + const TextServer::Glyph *glyphs = visual.ptr(); + for (int i = 0; i < v_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (text_ofs.x >= text_start && (text_ofs.x + glyphs[i].advance) <= (text_start + number_width)) { + Color color = fc; + if (glyphs[i].start >= suffix_start) { + color.a *= 0.4; + } + if (glyphs[i].font_rid != RID()) { + TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, text_ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, color); + } else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { + TS->draw_hex_code_box(ci, glyphs[i].font_size, text_ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, color); + } + } + text_ofs.x += glyphs[i].advance; + } + } + TS->free(num_rid); if (get_step() == 1) { Ref<Texture2D> updown2 = get_theme_icon("updown", "SpinBox"); - int updown_vofs = (get_size().height - updown2->get_height()) / 2; - updown_offset = get_size().width - sb->get_margin(SIDE_RIGHT) - updown2->get_width(); + int updown_vofs = (size.height - updown2->get_height()) / 2; + if (rtl) { + updown_offset = sb->get_margin(SIDE_LEFT); + } else { + updown_offset = size.width - sb->get_margin(SIDE_RIGHT) - updown2->get_width(); + } Color c(1, 1, 1); if (hover_updown) { c *= Color(1.2, 1.2, 1.2); @@ -271,9 +318,9 @@ void EditorSpinSlider::_notification(int p_what) { } } else if (!hide_slider) { int grabber_w = 4 * EDSCALE; - int width = get_size().width - sb->get_minimum_size().width - grabber_w; + int width = size.width - sb->get_minimum_size().width - grabber_w; int ofs = sb->get_offset().x; - int svofs = (get_size().height + vofs) / 2 - 1; + int svofs = (size.height + vofs) / 2 - 1; Color c = fc; c.a = 0.2; @@ -365,6 +412,15 @@ String EditorSpinSlider::get_label() const { return label; } +void EditorSpinSlider::set_suffix(const String &p_suffix) { + suffix = p_suffix; + update(); +} + +String EditorSpinSlider::get_suffix() const { + return suffix; +} + void EditorSpinSlider::_evaluate_input_text() { // Replace comma with dot to support it as decimal separator (GH-6028). // This prevents using functions like `pow()`, but using functions @@ -373,7 +429,7 @@ void EditorSpinSlider::_evaluate_input_text() { const String text = TS->parse_number(value_input->get_text().replace(",", ".")); Ref<Expression> expr; - expr.instance(); + expr.instantiate(); Error err = expr->parse(text); if (err != OK) { return; @@ -386,8 +442,8 @@ void EditorSpinSlider::_evaluate_input_text() { set_value(v); } -//text_entered signal -void EditorSpinSlider::_value_input_entered(const String &p_text) { +//text_submitted signal +void EditorSpinSlider::_value_input_submitted(const String &p_text) { value_input_just_closed = true; value_input_popup->hide(); } @@ -468,6 +524,9 @@ void EditorSpinSlider::_bind_methods() { ClassDB::bind_method(D_METHOD("set_label", "label"), &EditorSpinSlider::set_label); ClassDB::bind_method(D_METHOD("get_label"), &EditorSpinSlider::get_label); + ClassDB::bind_method(D_METHOD("set_suffix", "suffix"), &EditorSpinSlider::set_suffix); + ClassDB::bind_method(D_METHOD("get_suffix"), &EditorSpinSlider::get_suffix); + ClassDB::bind_method(D_METHOD("set_read_only", "read_only"), &EditorSpinSlider::set_read_only); ClassDB::bind_method(D_METHOD("is_read_only"), &EditorSpinSlider::is_read_only); @@ -477,6 +536,7 @@ void EditorSpinSlider::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &EditorSpinSlider::_gui_input); ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); } @@ -510,7 +570,7 @@ EditorSpinSlider::EditorSpinSlider() { value_input_popup->set_wrap_controls(true); value_input->set_anchors_and_offsets_preset(PRESET_WIDE); value_input_popup->connect("popup_hide", callable_mp(this, &EditorSpinSlider::_value_input_closed)); - value_input->connect("text_entered", callable_mp(this, &EditorSpinSlider::_value_input_entered)); + value_input->connect("text_submitted", callable_mp(this, &EditorSpinSlider::_value_input_submitted)); value_input->connect("focus_exited", callable_mp(this, &EditorSpinSlider::_value_focus_exited)); value_input_just_closed = false; hide_slider = false; diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index 248a13f7b6..c30ff30390 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -39,6 +39,7 @@ class EditorSpinSlider : public Range { GDCLASS(EditorSpinSlider, Range); String label; + String suffix; int updown_offset; bool hover_updown; bool mouse_hover; @@ -68,7 +69,7 @@ class EditorSpinSlider : public Range { void _grabber_gui_input(const Ref<InputEvent> &p_event); void _value_input_closed(); - void _value_input_entered(const String &); + void _value_input_submitted(const String &); void _value_focus_exited(); bool hide_slider; bool flat; @@ -93,6 +94,9 @@ public: void set_label(const String &p_label); String get_label() const; + void set_suffix(const String &p_suffix); + String get_suffix() const; + void set_hide_slider(bool p_hide); bool is_hiding_slider() const; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 64f7500e8c..131a77e52f 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -766,12 +766,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("sub_inspector_bg" + itos(i), "Editor", sub_inspector_bg); Ref<StyleBoxFlat> bg_color; - bg_color.instance(); + bg_color.instantiate(); bg_color->set_bg_color(si_base_color * Color(0.7, 0.7, 0.7, 0.8)); bg_color->set_border_width_all(0); Ref<StyleBoxFlat> bg_color_selected; - bg_color_selected.instance(); + bg_color_selected.instantiate(); bg_color_selected->set_border_width_all(0); bg_color_selected->set_bg_color(si_base_color * Color(0.8, 0.8, 0.8, 0.8)); @@ -960,14 +960,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_content_panel->set_border_color(dark_color_2); theme->set_stylebox("panel", "TabContainer", style_content_panel); - // this is the stylebox used in 3d and 2d viewports (no borders) - Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate(); - style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2); - style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); - style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2); - style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2); - theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp); - // These styleboxes can be used on tabs against the base color background (e.g. nested tabs). Ref<StyleBoxFlat> style_tab_selected_odd = style_tab_selected->duplicate(); style_tab_selected_odd->set_bg_color(disabled_bg_color); @@ -977,6 +969,22 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_content_panel_odd->set_bg_color(disabled_bg_color); theme->set_stylebox("panel_odd", "TabContainer", style_content_panel_odd); + // This stylebox is used in 3d and 2d viewports (no borders). + Ref<StyleBoxFlat> style_content_panel_vp = style_content_panel->duplicate(); + style_content_panel_vp->set_default_margin(SIDE_LEFT, border_width * 2); + style_content_panel_vp->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE); + style_content_panel_vp->set_default_margin(SIDE_RIGHT, border_width * 2); + style_content_panel_vp->set_default_margin(SIDE_BOTTOM, border_width * 2); + theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp); + + // This stylebox is used by preview tabs in the Theme Editor. + Ref<StyleBoxFlat> style_theme_preview_tab = style_tab_selected_odd->duplicate(); + style_theme_preview_tab->set_expand_margin_size(SIDE_BOTTOM, 5 * EDSCALE); + theme->set_stylebox("ThemeEditorPreviewFG", "EditorStyles", style_theme_preview_tab); + Ref<StyleBoxFlat> style_theme_preview_bg_tab = style_tab_unselected->duplicate(); + style_theme_preview_bg_tab->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE); + theme->set_stylebox("ThemeEditorPreviewBG", "EditorStyles", style_theme_preview_bg_tab); + // Separators theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width))); theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width), 0, 0, true)); @@ -1346,6 +1354,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_info_3d_viewport->set_border_width_all(0); theme->set_stylebox("Information3dViewport", "EditorStyles", style_info_3d_viewport); + // Theme editor. + theme->set_color("preview_picker_overlay_color", "ThemeEditor", Color(0.1, 0.1, 0.1, 0.25)); + Color theme_preview_picker_bg_color = accent_color; + theme_preview_picker_bg_color.a = 0.2; + Ref<StyleBoxFlat> theme_preview_picker_sb = make_flat_stylebox(theme_preview_picker_bg_color, 0, 0, 0, 0); + theme_preview_picker_sb->set_border_color(accent_color); + theme_preview_picker_sb->set_border_width_all(1.0 * EDSCALE); + theme->set_stylebox("preview_picker_overlay", "ThemeEditor", theme_preview_picker_sb); + // adaptive script theme constants // for comments and elements with lower relevance const Color dim_color = Color(font_color.r, font_color.g, font_color.b, 0.5); diff --git a/editor/editor_translation_parser.cpp b/editor/editor_translation_parser.cpp index 49d5cf1fd3..27d428e682 100644 --- a/editor/editor_translation_parser.cpp +++ b/editor/editor_translation_parser.cpp @@ -31,8 +31,8 @@ #include "editor_translation_parser.h" #include "core/error/error_macros.h" +#include "core/io/file_access.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/templates/set.h" EditorTranslationParser *EditorTranslationParser::singleton = nullptr; @@ -42,10 +42,10 @@ Error EditorTranslationParserPlugin::parse_file(const String &p_path, Vector<Str return ERR_UNAVAILABLE; } - if (get_script_instance()->has_method("parse_file")) { + if (get_script_instance()->has_method("_parse_file")) { Array ids; Array ids_ctx_plural; - get_script_instance()->call("parse_file", p_path, ids, ids_ctx_plural); + get_script_instance()->call("_parse_file", p_path, ids, ids_ctx_plural); // Add user's extracted translatable messages. for (int i = 0; i < ids.size(); i++) { @@ -75,8 +75,8 @@ void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_ex return; } - if (get_script_instance()->has_method("get_recognized_extensions")) { - Array extensions = get_script_instance()->call("get_recognized_extensions"); + if (get_script_instance()->has_method("_get_recognized_extensions")) { + Array extensions = get_script_instance()->call("_get_recognized_extensions"); for (int i = 0; i < extensions.size(); i++) { r_extensions->push_back(extensions[i]); } @@ -86,8 +86,8 @@ void EditorTranslationParserPlugin::get_recognized_extensions(List<String> *r_ex } void EditorTranslationParserPlugin::_bind_methods() { - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::NIL, "parse_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::ARRAY, "msgids"), PropertyInfo(Variant::ARRAY, "msgids_context_plural"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_recognized_extensions")); + BIND_VMETHOD(MethodInfo(Variant::NIL, "_parse_file", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::ARRAY, "msgids"), PropertyInfo(Variant::ARRAY, "msgids_context_plural"))); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_recognized_extensions")); } ///////////////////////// diff --git a/editor/editor_translation_parser.h b/editor/editor_translation_parser.h index 4f8f3537f2..7013bbb8c4 100644 --- a/editor/editor_translation_parser.h +++ b/editor/editor_translation_parser.h @@ -32,10 +32,10 @@ #define EDITOR_TRANSLATION_PARSER_H #include "core/error/error_list.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class EditorTranslationParserPlugin : public Reference { - GDCLASS(EditorTranslationParserPlugin, Reference); +class EditorTranslationParserPlugin : public RefCounted { + GDCLASS(EditorTranslationParserPlugin, RefCounted); protected: static void _bind_methods(); diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h index af952eaffc..52ab6d68ee 100644 --- a/editor/editor_vcs_interface.h +++ b/editor/editor_vcs_interface.h @@ -46,16 +46,16 @@ protected: static void _bind_methods(); // Implemented by addons as end points for the proxy functions - bool _initialize(String p_project_root_path); - bool _is_vcs_initialized(); - Dictionary _get_modified_files_data(); - void _stage_file(String p_file_path); - void _unstage_file(String p_file_path); - void _commit(String p_msg); - Array _get_file_diff(String p_file_path); - bool _shut_down(); - String _get_project_name(); - String _get_vcs_name(); + virtual bool _initialize(String p_project_root_path); + virtual bool _is_vcs_initialized(); + virtual Dictionary _get_modified_files_data(); + virtual void _stage_file(String p_file_path); + virtual void _unstage_file(String p_file_path); + virtual void _commit(String p_msg); + virtual Array _get_file_diff(String p_file_path); + virtual bool _shut_down(); + virtual String _get_project_name(); + virtual String _get_vcs_name(); public: static EditorVCSInterface *get_singleton(); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 6e0ae403a2..dd4ce74406 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -31,9 +31,9 @@ #include "export_template_manager.h" #include "core/input/input.h" +#include "core/io/dir_access.h" #include "core/io/json.h" #include "core/io/zip_io.h" -#include "core/os/dir_access.h" #include "core/os/keyboard.h" #include "core/version.h" #include "editor_node.h" @@ -41,141 +41,334 @@ #include "progress_dialog.h" #include "scene/gui/link_button.h" -void ExportTemplateManager::_update_template_list() { - while (current_hb->get_child_count()) { - memdelete(current_hb->get_child(0)); - } - - while (installed_vb->get_child_count()) { - memdelete(installed_vb->get_child(0)); - } +void ExportTemplateManager::_update_template_status() { + // Fetch installed templates from the file system. + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir(); - DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = d->change_dir(EditorSettings::get_singleton()->get_templates_dir()); + Error err = da->change_dir(templates_dir); + ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'."); Set<String> templates; - d->list_dir_begin(); + da->list_dir_begin(); if (err == OK) { - String c = d->get_next(); + String c = da->get_next(); while (c != String()) { - if (d->current_is_dir() && !c.begins_with(".")) { + if (da->current_is_dir() && !c.begins_with(".")) { templates.insert(c); } - c = d->get_next(); + c = da->get_next(); } } - d->list_dir_end(); - - memdelete(d); + da->list_dir_end(); + memdelete(da); + // Update the state of the current version. String current_version = VERSION_FULL_CONFIG; - // Downloadable export templates are only available for stable and official alpha/beta/RC builds - // (which always have a number following their status, e.g. "alpha1"). - // Therefore, don't display download-related features when using a development version - // (whose builds aren't numbered). - const bool downloads_available = - String(VERSION_STATUS) != String("dev") && - String(VERSION_STATUS) != String("alpha") && - String(VERSION_STATUS) != String("beta") && - String(VERSION_STATUS) != String("rc"); - - Label *current = memnew(Label); - current->set_h_size_flags(Control::SIZE_EXPAND_FILL); - current_hb->add_child(current); + current_value->set_text(current_version); if (templates.has(current_version)) { - current->add_theme_color_override("font_color", current->get_theme_color("success_color", "Editor")); - - // Only display a redownload button if it can be downloaded in the first place - if (downloads_available) { - Button *redownload = memnew(Button); - redownload->set_text(TTR("Redownload")); - current_hb->add_child(redownload); - redownload->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_template), varray(current_version)); - } + current_missing_label->hide(); + current_installed_label->show(); - Button *uninstall = memnew(Button); - uninstall->set_text(TTR("Uninstall")); - current_hb->add_child(uninstall); - current->set_text(current_version + " " + TTR("(Installed)")); - uninstall->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(current_version)); + current_installed_hb->show(); + current_version_exists = true; + } else { + current_installed_label->hide(); + current_missing_label->show(); + current_installed_hb->hide(); + current_version_exists = false; + } + + if (is_downloading_templates) { + install_options_vb->hide(); + download_progress_hb->show(); } else { - current->add_theme_color_override("font_color", current->get_theme_color("error_color", "Editor")); - Button *redownload = memnew(Button); - redownload->set_text(TTR("Download")); + download_progress_hb->hide(); + install_options_vb->show(); - if (!downloads_available) { - redownload->set_disabled(true); - redownload->set_tooltip(TTR("Official export templates aren't available for development builds.")); + if (templates.has(current_version)) { + current_installed_path->set_text(templates_dir.plus_file(current_version)); } - - redownload->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_template), varray(current_version)); - current_hb->add_child(redownload); - current->set_text(current_version + " " + TTR("(Missing)")); } + // Update the list of other installed versions. + installed_table->clear(); + TreeItem *installed_root = installed_table->create_item(); + for (Set<String>::Element *E = templates.back(); E; E = E->prev()) { - String text = E->get(); - if (text == current_version) { + String version_string = E->get(); + if (version_string == current_version) { continue; } - HBoxContainer *hbc = memnew(HBoxContainer); - Label *version = memnew(Label); - version->set_modulate(current->get_theme_color("disabled_font_color", "Editor")); - version->set_text(text); - version->set_h_size_flags(Control::SIZE_EXPAND_FILL); - hbc->add_child(version); + TreeItem *ti = installed_table->create_item(installed_root); + ti->set_text(0, version_string); - Button *uninstall = memnew(Button); + ti->add_button(0, get_theme_icon("Folder", "EditorIcons"), OPEN_TEMPLATE_FOLDER, false, TTR("Open the folder containing these templates.")); + ti->add_button(0, get_theme_icon("Remove", "EditorIcons"), UNINSTALL_TEMPLATE, false, TTR("Uninstall these templates.")); + } +} + +void ExportTemplateManager::_download_current() { + if (is_downloading_templates) { + return; + } + is_downloading_templates = true; - uninstall->set_text(TTR("Uninstall")); - hbc->add_child(uninstall); - uninstall->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(E->get())); + install_options_vb->hide(); + download_progress_hb->show(); - installed_vb->add_child(hbc); + if (mirrors_available) { + String mirror_url = _get_selected_mirror(); + if (mirror_url.is_empty()) { + _set_current_progress_status(TTR("There are no mirrors available."), true); + return; + } + + _download_template(mirror_url, true); + } else if (!mirrors_available && !is_refreshing_mirrors) { + _set_current_progress_status(TTR("Retrieving the mirror list...")); + _refresh_mirrors(); } } -void ExportTemplateManager::_download_template(const String &p_version) { - while (template_list->get_child_count()) { - memdelete(template_list->get_child(0)); - } - template_downloader->popup_centered(); - template_list_state->set_text(TTR("Retrieving mirrors, please wait...")); - template_download_progress->set_max(100); - template_download_progress->set_value(0); - request_mirror->request("https://godotengine.org/mirrorlist/" + p_version + ".json"); - template_list_state->show(); - template_download_progress->show(); +void ExportTemplateManager::_download_template(const String &p_url, bool p_skip_check) { + if (!p_skip_check && is_downloading_templates) { + return; + } + is_downloading_templates = true; + + install_options_vb->hide(); + download_progress_hb->show(); + _set_current_progress_status(TTR("Starting the download...")); + + download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz")); + download_templates->set_use_threads(true); + + Error err = download_templates->request(p_url); + if (err != OK) { + _set_current_progress_status(TTR("Error requesting URL:") + " " + p_url, true); + return; + } + + set_process(true); + _set_current_progress_status(TTR("Connecting to the mirror...")); } -void ExportTemplateManager::_uninstall_template(const String &p_version) { - remove_confirm->set_text(vformat(TTR("Remove template version '%s'?"), p_version)); - remove_confirm->popup_centered(); - to_remove = p_version; +void ExportTemplateManager::_download_template_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { + switch (p_status) { + case HTTPRequest::RESULT_CANT_RESOLVE: { + _set_current_progress_status(TTR("Can't resolve the requested address."), true); + } break; + case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED: + case HTTPRequest::RESULT_CONNECTION_ERROR: + case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: + case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR: + case HTTPRequest::RESULT_CANT_CONNECT: { + _set_current_progress_status(TTR("Can't connect to the mirror."), true); + } break; + case HTTPRequest::RESULT_NO_RESPONSE: { + _set_current_progress_status(TTR("No response from the mirror."), true); + } break; + case HTTPRequest::RESULT_REQUEST_FAILED: { + _set_current_progress_status(TTR("Request failed."), true); + } break; + case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: { + _set_current_progress_status(TTR("Request ended up in a redirect loop."), true); + } break; + default: { + if (p_code != 200) { + _set_current_progress_status(TTR("Request failed:") + " " + itos(p_code), true); + } else { + _set_current_progress_status(TTR("Download complete; extracting templates...")); + String path = download_templates->get_download_file(); + + is_downloading_templates = false; + bool ret = _install_file_selected(path, true); + if (ret) { + // Clean up downloaded file. + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error err = da->remove(path); + if (err != OK) { + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove temporary file:") + "\n" + path + "\n"); + } + } else { + EditorNode::get_singleton()->add_io_error(vformat(TTR("Templates installation failed.\nThe problematic templates archives can be found at '%s'."), path)); + } + } + } break; + } + + set_process(false); } -void ExportTemplateManager::_uninstall_template_confirm() { - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir(); - Error err = da->change_dir(templates_dir); - ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'."); - err = da->change_dir(to_remove); - ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(to_remove) + "'."); +void ExportTemplateManager::_cancel_template_download() { + if (!is_downloading_templates) { + return; + } - err = da->erase_contents_recursive(); - ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(to_remove) + "'."); + download_templates->cancel_request(); + download_progress_hb->hide(); + install_options_vb->show(); + is_downloading_templates = false; +} - da->change_dir(".."); - err = da->remove(to_remove); - ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(to_remove) + "'."); +void ExportTemplateManager::_refresh_mirrors() { + if (is_refreshing_mirrors) { + return; + } + is_refreshing_mirrors = true; + + String current_version = VERSION_FULL_CONFIG; + const String mirrors_metadata_url = "https://godotengine.org/mirrorlist/" + current_version + ".json"; + request_mirrors->request(mirrors_metadata_url); +} + +void ExportTemplateManager::_refresh_mirrors_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { + if (p_status != HTTPRequest::RESULT_SUCCESS || p_code != 200) { + EditorNode::get_singleton()->show_warning(TTR("Error getting the list of mirrors.")); + is_refreshing_mirrors = false; + if (is_downloading_templates) { + _cancel_template_download(); + } + return; + } + + String response_json; + { + const uint8_t *r = p_data.ptr(); + response_json.parse_utf8((const char *)r, p_data.size()); + } + + JSON json; + Error err = json.parse(response_json); + if (err != OK) { + EditorNode::get_singleton()->show_warning(TTR("Error parsing JSON with the list of mirrors. Please report this issue!")); + is_refreshing_mirrors = false; + if (is_downloading_templates) { + _cancel_template_download(); + } + return; + } + + mirrors_list->clear(); + mirrors_list->add_item(TTR("Best available mirror"), 0); + + mirrors_available = false; + + Dictionary data = json.get_data(); + if (data.has("mirrors")) { + Array mirrors = data["mirrors"]; + + for (int i = 0; i < mirrors.size(); i++) { + Dictionary m = mirrors[i]; + ERR_CONTINUE(!m.has("url") || !m.has("name")); + + mirrors_list->add_item(m["name"]); + mirrors_list->set_item_metadata(i + 1, m["url"]); + + mirrors_available = true; + } + } + if (!mirrors_available) { + EditorNode::get_singleton()->show_warning(TTR("No download links found for this version. Direct download is only available for official releases.")); + if (is_downloading_templates) { + _cancel_template_download(); + } + } + + is_refreshing_mirrors = false; + + if (is_downloading_templates) { + String mirror_url = _get_selected_mirror(); + if (mirror_url.is_empty()) { + _set_current_progress_status(TTR("There are no mirrors available."), true); + return; + } + + _download_template(mirror_url, true); + } +} + +bool ExportTemplateManager::_humanize_http_status(HTTPRequest *p_request, String *r_status, int *r_downloaded_bytes, int *r_total_bytes) { + *r_status = ""; + *r_downloaded_bytes = -1; + *r_total_bytes = -1; + bool success = true; + + switch (p_request->get_http_client_status()) { + case HTTPClient::STATUS_DISCONNECTED: + *r_status = TTR("Disconnected"); + success = false; + break; + case HTTPClient::STATUS_RESOLVING: + *r_status = TTR("Resolving"); + break; + case HTTPClient::STATUS_CANT_RESOLVE: + *r_status = TTR("Can't Resolve"); + success = false; + break; + case HTTPClient::STATUS_CONNECTING: + *r_status = TTR("Connecting..."); + break; + case HTTPClient::STATUS_CANT_CONNECT: + *r_status = TTR("Can't Connect"); + success = false; + break; + case HTTPClient::STATUS_CONNECTED: + *r_status = TTR("Connected"); + break; + case HTTPClient::STATUS_REQUESTING: + *r_status = TTR("Requesting..."); + break; + case HTTPClient::STATUS_BODY: + *r_status = TTR("Downloading"); + *r_downloaded_bytes = p_request->get_downloaded_bytes(); + *r_total_bytes = p_request->get_body_size(); + + if (p_request->get_body_size() > 0) { + *r_status += " " + String::humanize_size(p_request->get_downloaded_bytes()) + "/" + String::humanize_size(p_request->get_body_size()); + } else { + *r_status += " " + String::humanize_size(p_request->get_downloaded_bytes()); + } + break; + case HTTPClient::STATUS_CONNECTION_ERROR: + *r_status = TTR("Connection Error"); + success = false; + break; + case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: + *r_status = TTR("SSL Handshake Error"); + success = false; + break; + } + + return success; +} + +void ExportTemplateManager::_set_current_progress_status(const String &p_status, bool p_error) { + download_progress_bar->hide(); + download_progress_label->set_text(p_status); + + if (p_error) { + download_progress_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); + } else { + download_progress_label->add_theme_color_override("font_color", get_theme_color("font_color", "Label")); + } +} + +void ExportTemplateManager::_set_current_progress_value(float p_value, const String &p_status) { + download_progress_bar->show(); + download_progress_bar->set_value(p_value); + download_progress_label->set_text(p_status); +} - _update_template_list(); +void ExportTemplateManager::_install_file() { + install_file_dialog->popup_file_dialog(); } -bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_progress) { +bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_skip_progress) { // unzClose() will take care of closing the file stored in the unzFile, // so we don't need to `memdelete(fa)` in this method. FileAccess *fa = nullptr; @@ -183,12 +376,13 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ unzFile pkg = unzOpen2(p_file.utf8().get_data(), &io); if (!pkg) { - EditorNode::get_singleton()->show_warning(TTR("Can't open export templates zip.")); + EditorNode::get_singleton()->show_warning(TTR("Can't open the export templates file.")); return false; } int ret = unzGoToFirstFile(pkg); - int fc = 0; //count them and find version + // Count them and find version. + int fc = 0; String version; String contents_dir; @@ -198,12 +392,11 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); String file = fname; - if (file.ends_with("version.txt")) { Vector<uint8_t> data; data.resize(info.uncompressed_size); - //read + // Read. unzOpenCurrentFile(pkg); ret = unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); @@ -215,7 +408,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ // Version number should be of the form major.minor[.patch].status[.module_config] // so it can in theory have 3 or more slices. if (data_str.get_slice_count(".") < 3) { - EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside templates: %s."), data_str)); + EditorNode::get_singleton()->show_warning(vformat(TTR("Invalid version.txt format inside the export templates file: %s."), data_str)); unzClose(pkg); return false; } @@ -232,32 +425,29 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ } if (version == String()) { - EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside templates.")); + EditorNode::get_singleton()->show_warning(TTR("No version.txt found inside the export templates file.")); unzClose(pkg); return false; } - String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); - DirAccessRef d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + String template_path = EditorSettings::get_singleton()->get_templates_dir().plus_file(version); Error err = d->make_dir_recursive(template_path); if (err != OK) { - EditorNode::get_singleton()->show_warning(TTR("Error creating path for templates:") + "\n" + template_path); + EditorNode::get_singleton()->show_warning(TTR("Error creating path for extracting templates:") + "\n" + template_path); unzClose(pkg); return false; } - ret = unzGoToFirstFile(pkg); - EditorProgress *p = nullptr; - if (p_use_progress) { + if (!p_skip_progress) { p = memnew(EditorProgress("ltask", TTR("Extracting Export Templates"), fc)); } fc = 0; - + ret = unzGoToFirstFile(pkg); while (ret == UNZ_OK) { - //get filename + // Get filename. unz_file_info info; char fname[16384]; unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); @@ -274,7 +464,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ Vector<uint8_t> data; data.resize(info.uncompressed_size); - //read + // Read unzOpenCurrentFile(pkg); unzReadCurrentFile(pkg, data.ptrw(), data.size()); unzCloseCurrentFile(pkg); @@ -322,216 +512,116 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (p) { memdelete(p); } - unzClose(pkg); - _update_template_list(); + _update_template_status(); return true; } -void ExportTemplateManager::popup_manager() { - _update_template_list(); - popup_centered(Size2(400, 400) * EDSCALE); -} - -void ExportTemplateManager::ok_pressed() { - template_open->popup_file_dialog(); +void ExportTemplateManager::_uninstall_template(const String &p_version) { + uninstall_confirm->set_text(vformat(TTR("Remove templates for the version '%s'?"), p_version)); + uninstall_confirm->popup_centered(); + uninstall_version = p_version; } -void ExportTemplateManager::_http_download_mirror_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { - if (p_status != HTTPRequest::RESULT_SUCCESS || p_code != 200) { - EditorNode::get_singleton()->show_warning(TTR("Error getting the list of mirrors.")); - return; - } +void ExportTemplateManager::_uninstall_template_confirmed() { + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir(); - String mirror_str; - { - const uint8_t *r = p_data.ptr(); - mirror_str.parse_utf8((const char *)r, p_data.size()); - } + Error err = da->change_dir(templates_dir); + ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir + "'."); + err = da->change_dir(uninstall_version); + ERR_FAIL_COND_MSG(err != OK, "Could not access templates directory at '" + templates_dir.plus_file(uninstall_version) + "'."); - template_list_state->hide(); - template_download_progress->hide(); + err = da->erase_contents_recursive(); + ERR_FAIL_COND_MSG(err != OK, "Could not remove all templates in '" + templates_dir.plus_file(uninstall_version) + "'."); - Variant r; - String errs; - int errline; - Error err = JSON::parse(mirror_str, r, errs, errline); - if (err != OK) { - EditorNode::get_singleton()->show_warning(TTR("Error parsing JSON of mirror list. Please report this issue!")); - return; - } + da->change_dir(".."); + err = da->remove(uninstall_version); + ERR_FAIL_COND_MSG(err != OK, "Could not remove templates directory at '" + templates_dir.plus_file(uninstall_version) + "'."); - bool mirrors_found = false; + _update_template_status(); +} - Dictionary d = r; - if (d.has("mirrors")) { - Array mirrors = d["mirrors"]; - for (int i = 0; i < mirrors.size(); i++) { - Dictionary m = mirrors[i]; - ERR_CONTINUE(!m.has("url") || !m.has("name")); - LinkButton *lb = memnew(LinkButton); - lb->set_text(m["name"]); - lb->connect("pressed", callable_mp(this, &ExportTemplateManager::_begin_template_download), varray(m["url"])); - template_list->add_child(lb); - mirrors_found = true; - } +String ExportTemplateManager::_get_selected_mirror() const { + if (mirrors_list->get_item_count() == 1) { + return ""; } - if (!mirrors_found) { - EditorNode::get_singleton()->show_warning(TTR("No download links found for this version. Direct download is only available for official releases.")); - return; + int selected = mirrors_list->get_selected_id(); + if (selected == 0) { + // This is a special "best available" value; so pick the first available mirror from the rest of the list. + selected = 1; } + + return mirrors_list->get_item_metadata(selected); } -void ExportTemplateManager::_http_download_templates_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data) { - switch (p_status) { - case HTTPRequest::RESULT_CANT_RESOLVE: { - template_list_state->set_text(TTR("Can't resolve.")); - } break; - case HTTPRequest::RESULT_BODY_SIZE_LIMIT_EXCEEDED: - case HTTPRequest::RESULT_CONNECTION_ERROR: - case HTTPRequest::RESULT_CHUNKED_BODY_SIZE_MISMATCH: - case HTTPRequest::RESULT_SSL_HANDSHAKE_ERROR: - case HTTPRequest::RESULT_CANT_CONNECT: { - template_list_state->set_text(TTR("Can't connect.")); - } break; - case HTTPRequest::RESULT_NO_RESPONSE: { - template_list_state->set_text(TTR("No response.")); - } break; - case HTTPRequest::RESULT_REQUEST_FAILED: { - template_list_state->set_text(TTR("Request Failed.")); - } break; - case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: { - template_list_state->set_text(TTR("Redirect Loop.")); +void ExportTemplateManager::_mirror_options_button_cbk(int p_id) { + switch (p_id) { + case VISIT_WEB_MIRROR: { + String mirror_url = _get_selected_mirror(); + if (mirror_url.is_empty()) { + EditorNode::get_singleton()->show_warning(TTR("There are no mirrors available.")); + return; + } + + OS::get_singleton()->shell_open(mirror_url); } break; - default: { - if (p_code != 200) { - template_list_state->set_text(TTR("Failed:") + " " + itos(p_code)); - } else { - String path = download_templates->get_download_file(); - template_list_state->set_text(TTR("Download Complete.")); - template_downloader->hide(); - bool ret = _install_from_file(path, false); - if (ret) { - // Clean up downloaded file. - DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = da->remove(path); - if (err != OK) { - EditorNode::get_singleton()->add_io_error(TTR("Cannot remove temporary file:") + "\n" + path + "\n"); - } - } else { - EditorNode::get_singleton()->add_io_error(vformat(TTR("Templates installation failed.\nThe problematic templates archives can be found at '%s'."), path)); - } + + case COPY_MIRROR_URL: { + String mirror_url = _get_selected_mirror(); + if (mirror_url.is_empty()) { + EditorNode::get_singleton()->show_warning(TTR("There are no mirrors available.")); + return; } + + DisplayServer::get_singleton()->clipboard_set(mirror_url); } break; } - - set_process(false); } -void ExportTemplateManager::_begin_template_download(const String &p_url) { - if (Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - OS::get_singleton()->shell_open(p_url); +void ExportTemplateManager::_installed_table_button_cbk(Object *p_item, int p_column, int p_id) { + TreeItem *ti = Object::cast_to<TreeItem>(p_item); + if (!ti) { return; } - for (int i = 0; i < template_list->get_child_count(); i++) { - BaseButton *b = Object::cast_to<BaseButton>(template_list->get_child(0)); - if (b) { - b->set_disabled(true); - } - } - - download_data.clear(); - download_templates->set_download_file(EditorPaths::get_singleton()->get_cache_dir().plus_file("tmp_templates.tpz")); - download_templates->set_use_threads(true); + switch (p_id) { + case OPEN_TEMPLATE_FOLDER: { + String version_string = ti->get_text(0); + _open_template_folder(version_string); + } break; - Error err = download_templates->request(p_url); - if (err != OK) { - EditorNode::get_singleton()->show_warning(TTR("Error requesting URL:") + " " + p_url); - return; + case UNINSTALL_TEMPLATE: { + String version_string = ti->get_text(0); + _uninstall_template(version_string); + } break; } +} - set_process(true); - - template_list_state->show(); - template_download_progress->set_max(100); - template_download_progress->set_value(0); - template_download_progress->show(); - template_list_state->set_text(TTR("Connecting to Mirror...")); +void ExportTemplateManager::_open_template_folder(const String &p_version) { + const String &templates_dir = EditorSettings::get_singleton()->get_templates_dir(); + OS::get_singleton()->shell_open("file://" + templates_dir.plus_file(p_version)); } -void ExportTemplateManager::_window_template_downloader_closed() { - download_templates->cancel_request(); +void ExportTemplateManager::popup_manager() { + _update_template_status(); + _refresh_mirrors(); + popup_centered(Size2(720, 280) * EDSCALE); } -void ExportTemplateManager::_notification(int p_what) { - if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { - if (!is_visible()) { - set_process(false); - } +void ExportTemplateManager::ok_pressed() { + if (!is_downloading_templates) { + hide(); + return; } - if (p_what == NOTIFICATION_PROCESS) { - update_countdown -= get_process_delta_time(); - if (update_countdown > 0) { - return; - } - update_countdown = 0.5; - String status; - bool errored = false; - - switch (download_templates->get_http_client_status()) { - case HTTPClient::STATUS_DISCONNECTED: - status = TTR("Disconnected"); - errored = true; - break; - case HTTPClient::STATUS_RESOLVING: - status = TTR("Resolving"); - break; - case HTTPClient::STATUS_CANT_RESOLVE: - status = TTR("Can't Resolve"); - errored = true; - break; - case HTTPClient::STATUS_CONNECTING: - status = TTR("Connecting..."); - break; - case HTTPClient::STATUS_CANT_CONNECT: - status = TTR("Can't Connect"); - errored = true; - break; - case HTTPClient::STATUS_CONNECTED: - status = TTR("Connected"); - break; - case HTTPClient::STATUS_REQUESTING: - status = TTR("Requesting..."); - break; - case HTTPClient::STATUS_BODY: - status = TTR("Downloading"); - if (download_templates->get_body_size() > 0) { - status += " " + String::humanize_size(download_templates->get_downloaded_bytes()) + "/" + String::humanize_size(download_templates->get_body_size()); - template_download_progress->set_max(download_templates->get_body_size()); - template_download_progress->set_value(download_templates->get_downloaded_bytes()); - } else { - status += " " + String::humanize_size(download_templates->get_downloaded_bytes()); - } - break; - case HTTPClient::STATUS_CONNECTION_ERROR: - status = TTR("Connection Error"); - errored = true; - break; - case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: - status = TTR("SSL Handshake Error"); - errored = true; - break; - } + hide_dialog_accept->popup_centered(); +} - template_list_state->set_text(status); - if (errored) { - set_process(false); - } - } +void ExportTemplateManager::_hide_dialog() { + hide(); } bool ExportTemplateManager::can_install_android_template() { @@ -643,72 +733,246 @@ Error ExportTemplateManager::install_android_template() { return OK; } -void ExportTemplateManager::_bind_methods() { -} +void ExportTemplateManager::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + current_value->add_theme_font_override("font", get_theme_font("main", "EditorFonts")); + current_missing_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); + current_installed_label->add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor")); + + mirror_options_button->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons")); + } break; -ExportTemplateManager::ExportTemplateManager() { - VBoxContainer *main_vb = memnew(VBoxContainer); - add_child(main_vb); + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + set_process(false); + } else if (is_visible() && is_downloading_templates) { + set_process(true); + } + } break; - current_hb = memnew(HBoxContainer); - main_vb->add_margin_child(TTR("Current Version:"), current_hb, false); + case NOTIFICATION_PROCESS: { + update_countdown -= get_process_delta_time(); + if (update_countdown > 0) { + return; + } + update_countdown = 0.5; - installed_scroll = memnew(ScrollContainer); - main_vb->add_margin_child(TTR("Other Installed Versions:"), installed_scroll, true); + String status; + int downloaded_bytes; + int total_bytes; + bool success = _humanize_http_status(download_templates, &status, &downloaded_bytes, &total_bytes); - installed_vb = memnew(VBoxContainer); - installed_scroll->add_child(installed_vb); - installed_scroll->set_enable_v_scroll(true); - installed_scroll->set_enable_h_scroll(false); - installed_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (downloaded_bytes >= 0) { + if (total_bytes > 0) { + _set_current_progress_value(float(downloaded_bytes) / total_bytes, status); + } else { + _set_current_progress_value(0, status); + } + } else { + _set_current_progress_status(status); + } - get_cancel_button()->set_text(TTR("Close")); - get_ok_button()->set_text(TTR("Install From File")); + if (!success) { + set_process(false); + } + } break; - remove_confirm = memnew(ConfirmationDialog); - remove_confirm->set_title(TTR("Remove Template")); - add_child(remove_confirm); - remove_confirm->connect("confirmed", callable_mp(this, &ExportTemplateManager::_uninstall_template_confirm)); + case NOTIFICATION_WM_CLOSE_REQUEST: { + // This won't stop the window from closing, but will show the alert if the download is active. + ok_pressed(); + } break; + } +} - template_open = memnew(FileDialog); - template_open->set_title(TTR("Select Template File")); - template_open->add_filter("*.tpz ; " + TTR("Godot Export Templates")); - template_open->set_access(FileDialog::ACCESS_FILESYSTEM); - template_open->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE); - template_open->connect("file_selected", callable_mp(this, &ExportTemplateManager::_install_from_file), varray(true)); - add_child(template_open); +void ExportTemplateManager::_bind_methods() { +} +ExportTemplateManager::ExportTemplateManager() { set_title(TTR("Export Template Manager")); set_hide_on_ok(false); + get_ok_button()->set_text(TTR("Close")); + + // Downloadable export templates are only available for stable and official alpha/beta/RC builds + // (which always have a number following their status, e.g. "alpha1"). + // Therefore, don't display download-related features when using a development version + // (whose builds aren't numbered). + downloads_available = + String(VERSION_STATUS) != String("dev") && + String(VERSION_STATUS) != String("alpha") && + String(VERSION_STATUS) != String("beta") && + String(VERSION_STATUS) != String("rc"); + + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); + + // Current version controls. + HBoxContainer *current_hb = memnew(HBoxContainer); + main_vb->add_child(current_hb); + + Label *current_label = memnew(Label); + current_label->set_text(TTR("Current Version:")); + current_hb->add_child(current_label); + + current_value = memnew(Label); + current_hb->add_child(current_value); + + // Current version statuses. + // Status: Current version is missing. + current_missing_label = memnew(Label); + current_missing_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + current_missing_label->set_align(Label::ALIGN_RIGHT); + current_missing_label->set_text(TTR("Export templates are missing. Download them or install from a file.")); + current_hb->add_child(current_missing_label); + + // Status: Current version is installed. + current_installed_label = memnew(Label); + current_installed_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + current_installed_label->set_align(Label::ALIGN_RIGHT); + current_installed_label->set_text(TTR("Export templates are installed and ready to be used.")); + current_hb->add_child(current_installed_label); + current_installed_label->hide(); + + // Currently installed template. + current_installed_hb = memnew(HBoxContainer); + main_vb->add_child(current_installed_hb); + + current_installed_path = memnew(LineEdit); + current_installed_path->set_editable(false); + current_installed_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + current_installed_hb->add_child(current_installed_path); + + current_open_button = memnew(Button); + current_open_button->set_text(TTR("Open Folder")); + current_open_button->set_tooltip(TTR("Open the folder containing installed templates for the current version.")); + current_installed_hb->add_child(current_open_button); + current_open_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_open_template_folder), varray(VERSION_FULL_CONFIG)); + + current_uninstall_button = memnew(Button); + current_uninstall_button->set_text(TTR("Uninstall")); + current_uninstall_button->set_tooltip(TTR("Uninstall templates for the current version.")); + current_installed_hb->add_child(current_uninstall_button); + current_uninstall_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_uninstall_template), varray(VERSION_FULL_CONFIG)); + + main_vb->add_child(memnew(HSeparator)); + + // Download and install section. + HBoxContainer *install_templates_hb = memnew(HBoxContainer); + main_vb->add_child(install_templates_hb); + + // Download and install buttons are available. + install_options_vb = memnew(VBoxContainer); + install_options_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + install_templates_hb->add_child(install_options_vb); + + HBoxContainer *download_install_hb = memnew(HBoxContainer); + install_options_vb->add_child(download_install_hb); + + Label *mirrors_label = memnew(Label); + mirrors_label->set_text(TTR("Download from:")); + download_install_hb->add_child(mirrors_label); + + mirrors_list = memnew(OptionButton); + mirrors_list->set_custom_minimum_size(Size2(280, 0) * EDSCALE); + download_install_hb->add_child(mirrors_list); + mirrors_list->add_item(TTR("Best available mirror"), 0); + + request_mirrors = memnew(HTTPRequest); + mirrors_list->add_child(request_mirrors); + request_mirrors->connect("request_completed", callable_mp(this, &ExportTemplateManager::_refresh_mirrors_completed)); + + mirror_options_button = memnew(MenuButton); + mirror_options_button->get_popup()->add_item("Open in Web Browser", VISIT_WEB_MIRROR); + mirror_options_button->get_popup()->add_item("Copy Mirror URL", COPY_MIRROR_URL); + download_install_hb->add_child(mirror_options_button); + mirror_options_button->get_popup()->connect("id_pressed", callable_mp(this, &ExportTemplateManager::_mirror_options_button_cbk)); + + download_install_hb->add_spacer(); + + Button *download_current_button = memnew(Button); + download_current_button->set_text(TTR("Download and Install")); + download_current_button->set_tooltip(TTR("Download and install templates for the current version from the best possible mirror.")); + download_install_hb->add_child(download_current_button); + download_current_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_download_current)); + + // Update downloads buttons to prevent unsupported downloads. + if (!downloads_available) { + download_current_button->set_disabled(true); + download_current_button->set_tooltip(TTR("Official export templates aren't available for development builds.")); + } - request_mirror = memnew(HTTPRequest); - add_child(request_mirror); - request_mirror->connect("request_completed", callable_mp(this, &ExportTemplateManager::_http_download_mirror_completed)); + HBoxContainer *install_file_hb = memnew(HBoxContainer); + install_file_hb->set_alignment(BoxContainer::ALIGN_END); + install_options_vb->add_child(install_file_hb); + + install_file_button = memnew(Button); + install_file_button->set_text(TTR("Install from File")); + install_file_button->set_tooltip(TTR("Install templates from a local file.")); + install_file_hb->add_child(install_file_button); + install_file_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_install_file)); + + // Templates are being downloaded; buttons unavailable. + download_progress_hb = memnew(HBoxContainer); + download_progress_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); + install_templates_hb->add_child(download_progress_hb); + download_progress_hb->hide(); + + download_progress_bar = memnew(ProgressBar); + download_progress_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); + download_progress_bar->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + download_progress_bar->set_min(0); + download_progress_bar->set_max(1); + download_progress_bar->set_value(0); + download_progress_bar->set_step(0.01); + download_progress_hb->add_child(download_progress_bar); + + download_progress_label = memnew(Label); + download_progress_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + download_progress_hb->add_child(download_progress_label); + + Button *download_cancel_button = memnew(Button); + download_cancel_button->set_text(TTR("Cancel")); + download_cancel_button->set_tooltip(TTR("Cancel the download of the templates.")); + download_progress_hb->add_child(download_cancel_button); + download_cancel_button->connect("pressed", callable_mp(this, &ExportTemplateManager::_cancel_template_download)); download_templates = memnew(HTTPRequest); - add_child(download_templates); - download_templates->connect("request_completed", callable_mp(this, &ExportTemplateManager::_http_download_templates_completed)); - - template_downloader = memnew(AcceptDialog); - template_downloader->set_title(TTR("Download Templates")); - template_downloader->get_ok_button()->set_text(TTR("Close")); - template_downloader->set_exclusive(true); - add_child(template_downloader); - template_downloader->connect("cancelled", callable_mp(this, &ExportTemplateManager::_window_template_downloader_closed)); - - VBoxContainer *vbc = memnew(VBoxContainer); - template_downloader->add_child(vbc); - ScrollContainer *sc = memnew(ScrollContainer); - sc->set_custom_minimum_size(Size2(400, 200) * EDSCALE); - vbc->add_margin_child(TTR("Select mirror from list: (Shift+Click: Open in Browser)"), sc); - template_list = memnew(VBoxContainer); - sc->add_child(template_list); - sc->set_enable_v_scroll(true); - sc->set_enable_h_scroll(false); - template_list_state = memnew(Label); - vbc->add_child(template_list_state); - template_download_progress = memnew(ProgressBar); - vbc->add_child(template_download_progress); - - update_countdown = 0; + install_templates_hb->add_child(download_templates); + download_templates->connect("request_completed", callable_mp(this, &ExportTemplateManager::_download_template_completed)); + + main_vb->add_child(memnew(HSeparator)); + + // Other installed templates table. + HBoxContainer *installed_versions_hb = memnew(HBoxContainer); + main_vb->add_child(installed_versions_hb); + Label *installed_label = memnew(Label); + installed_label->set_text(TTR("Other Installed Versions:")); + installed_versions_hb->add_child(installed_label); + + installed_table = memnew(Tree); + installed_table->set_hide_root(true); + installed_table->set_custom_minimum_size(Size2(0, 100) * EDSCALE); + installed_table->set_v_size_flags(Control::SIZE_EXPAND_FILL); + main_vb->add_child(installed_table); + installed_table->connect("button_pressed", callable_mp(this, &ExportTemplateManager::_installed_table_button_cbk)); + + // Dialogs. + uninstall_confirm = memnew(ConfirmationDialog); + uninstall_confirm->set_title(TTR("Uninstall Template")); + add_child(uninstall_confirm); + uninstall_confirm->connect("confirmed", callable_mp(this, &ExportTemplateManager::_uninstall_template_confirmed)); + + install_file_dialog = memnew(FileDialog); + install_file_dialog->set_title(TTR("Select Template File")); + install_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM); + install_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE); + install_file_dialog->add_filter("*.tpz ; " + TTR("Godot Export Templates")); + install_file_dialog->connect("file_selected", callable_mp(this, &ExportTemplateManager::_install_file_selected), varray(false)); + add_child(install_file_dialog); + + hide_dialog_accept = memnew(AcceptDialog); + hide_dialog_accept->set_text(TTR("The templates will continue to download.\nYou may experience a short editor freeze when they finish.")); + add_child(hide_dialog_accept); + hide_dialog_accept->connect("confirmed", callable_mp(this, &ExportTemplateManager::_hide_dialog)); } diff --git a/editor/export_template_manager.h b/editor/export_template_manager.h index 3de74e17d8..f145c6c0f5 100644 --- a/editor/export_template_manager.h +++ b/editor/export_template_manager.h @@ -34,50 +34,87 @@ #include "editor/editor_settings.h" #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/menu_button.h" #include "scene/gui/progress_bar.h" #include "scene/gui/scroll_container.h" #include "scene/main/http_request.h" class ExportTemplateVersion; -class ExportTemplateManager : public ConfirmationDialog { - GDCLASS(ExportTemplateManager, ConfirmationDialog); +class ExportTemplateManager : public AcceptDialog { + GDCLASS(ExportTemplateManager, AcceptDialog); + + bool current_version_exists = false; + bool downloads_available = true; + bool mirrors_available = false; + bool is_refreshing_mirrors = false; + bool is_downloading_templates = false; + float update_countdown = 0; + + Label *current_value; + Label *current_missing_label; + Label *current_installed_label; + + HBoxContainer *current_installed_hb; + LineEdit *current_installed_path; + Button *current_open_button; + Button *current_uninstall_button; + + VBoxContainer *install_options_vb; + OptionButton *mirrors_list; + + enum MirrorAction { + VISIT_WEB_MIRROR, + COPY_MIRROR_URL, + }; + + MenuButton *mirror_options_button; + HBoxContainer *download_progress_hb; + ProgressBar *download_progress_bar; + Label *download_progress_label; + HTTPRequest *download_templates; + Button *install_file_button; + HTTPRequest *request_mirrors; - AcceptDialog *template_downloader; - VBoxContainer *template_list; - Label *template_list_state; - ProgressBar *template_download_progress; + enum TemplatesAction { + OPEN_TEMPLATE_FOLDER, + UNINSTALL_TEMPLATE, + }; - ScrollContainer *installed_scroll; - VBoxContainer *installed_vb; - HBoxContainer *current_hb; - FileDialog *template_open; + Tree *installed_table; - ConfirmationDialog *remove_confirm; - String to_remove; + ConfirmationDialog *uninstall_confirm; + String uninstall_version; + FileDialog *install_file_dialog; + AcceptDialog *hide_dialog_accept; - HTTPRequest *request_mirror; - HTTPRequest *download_templates; + void _update_template_status(); - Vector<uint8_t> download_data; + void _download_current(); + void _download_template(const String &p_url, bool p_skip_check = false); + void _download_template_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); + void _cancel_template_download(); + void _refresh_mirrors(); + void _refresh_mirrors_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); - float update_countdown; + bool _humanize_http_status(HTTPRequest *p_request, String *r_status, int *r_downloaded_bytes, int *r_total_bytes); + void _set_current_progress_status(const String &p_status, bool p_error = false); + void _set_current_progress_value(float p_value, const String &p_status); - void _update_template_list(); + void _install_file(); + bool _install_file_selected(const String &p_file, bool p_skip_progress = false); - void _download_template(const String &p_version); void _uninstall_template(const String &p_version); - void _uninstall_template_confirm(); + void _uninstall_template_confirmed(); - virtual void ok_pressed() override; - bool _install_from_file(const String &p_file, bool p_use_progress = true); + String _get_selected_mirror() const; + void _mirror_options_button_cbk(int p_id); + void _installed_table_button_cbk(Object *p_item, int p_column, int p_id); - void _http_download_mirror_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); - void _http_download_templates_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); + void _open_template_folder(const String &p_version); - void _begin_template_download(const String &p_url); - - void _window_template_downloader_closed(); + virtual void ok_pressed() override; + void _hide_dialog(); protected: void _notification(int p_what); diff --git a/editor/fileserver/editor_file_server.cpp b/editor/fileserver/editor_file_server.cpp index 654915e3e5..8f019a95fd 100644 --- a/editor/fileserver/editor_file_server.cpp +++ b/editor/fileserver/editor_file_server.cpp @@ -312,7 +312,7 @@ void EditorFileServer::stop() { } EditorFileServer::EditorFileServer() { - server.instance(); + server.instantiate(); quit = false; active = false; cmd = CMD_NONE; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index ce98f699ae..3dc854d6bd 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -31,9 +31,9 @@ #include "filesystem_dock.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/templates/list.h" @@ -365,7 +365,7 @@ void FileSystemDock::_notification(int p_what) { file_list_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_file_list_rmb_option)); tree_popup->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option)); - current_path->connect("text_entered", callable_mp(this, &FileSystemDock::_navigate_to_path), make_binds(false)); + current_path->connect("text_submitted", callable_mp(this, &FileSystemDock::_navigate_to_path), make_binds(false)); always_show_folders = bool(EditorSettings::get_singleton()->get("docks/filesystem/always_show_folders")); @@ -815,7 +815,8 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { if (searched_string.length() > 0) { // Display the search results. - _search(EditorFileSystem::get_singleton()->get_filesystem(), &file_list, 128); + // Limit the number of results displayed to avoid an infinite loop. + _search(EditorFileSystem::get_singleton()->get_filesystem(), &file_list, 10000); } else { if (display_mode == DISPLAY_MODE_TREE_ONLY || always_show_folders) { // Display folders in the list. @@ -945,7 +946,7 @@ void FileSystemDock::_select_file(const String &p_path, bool p_select_in_favorit } else if (fpath != "Favorites") { if (FileAccess::exists(fpath + ".import")) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(fpath + ".import"); if (err == OK) { if (config->has_section_key("remap", "importer")) { @@ -1985,20 +1986,6 @@ void FileSystemDock::_resource_created() { editor->save_resource_as(RES(r), fpath); } -void FileSystemDock::_focus_current_search_box() { - LineEdit *current_search_box = nullptr; - if (display_mode == DISPLAY_MODE_TREE_ONLY) { - current_search_box = tree_search_box; - } else if (display_mode == DISPLAY_MODE_SPLIT) { - current_search_box = file_list_search_box; - } - - if (current_search_box) { - current_search_box->grab_focus(); - current_search_box->select_all(); - } -} - void FileSystemDock::_search_changed(const String &p_text, const Control *p_from) { if (searched_string.length() == 0) { // Register the uncollapsed paths before they change. @@ -2040,7 +2027,17 @@ void FileSystemDock::fix_dependencies(const String &p_for_file) { } void FileSystemDock::focus_on_filter() { - file_list_search_box->grab_focus(); + LineEdit *current_search_box = nullptr; + if (display_mode == DISPLAY_MODE_TREE_ONLY) { + current_search_box = tree_search_box; + } else if (display_mode == DISPLAY_MODE_SPLIT) { + current_search_box = file_list_search_box; + } + + if (current_search_box) { + current_search_box->grab_focus(); + current_search_box->select_all(); + } } void FileSystemDock::set_file_list_display_mode(FileListDisplayMode p_mode) { @@ -2590,7 +2587,7 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) { } else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) { _tree_rmb_option(FILE_RENAME); } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) { - _focus_current_search_box(); + focus_on_filter(); } else { return; } @@ -2611,7 +2608,7 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) { } else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) { _file_list_rmb_option(FILE_RENAME); } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) { - _focus_current_search_box(); + focus_on_filter(); } else { return; } @@ -2675,7 +2672,7 @@ void FileSystemDock::_update_import_dock() { for (int i = 0; i < efiles.size(); i++) { String fpath = efiles[i]; Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); Error err = cf->load(fpath + ".import"); if (err != OK) { imports.clear(); @@ -2751,9 +2748,9 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done); ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file); - ClassDB::bind_method(D_METHOD("get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw); ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path); ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock); @@ -2777,22 +2774,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { // `KEY_MASK_CMD | KEY_C` conflicts with other editor shortcuts. ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_C); ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KEY_MASK_CMD | KEY_D); - -#if defined(WINDOWS_ENABLED) - // TRANSLATORS: This string is only used on Windows, as it refers to the system trash - // as "Recycle Bin" instead of "Trash". Make sure to use the translation of "Recycle Bin" - // recommended by Microsoft for the target language. - ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Recycle Bin"), KEY_DELETE); -#elif defined(OSX_ENABLED) - // TRANSLATORS: This string is only used on macOS, as it refers to the system trash - // as "Bin" instead of "Trash". Make sure to use the translation of "Bin" - // recommended by Apple for the target language. - ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Bin"), KEY_DELETE); -#else - // TRANSLATORS: This string is only used on platforms other than Windows and macOS. - ED_SHORTCUT("filesystem_dock/delete", TTR("Move to Trash"), KEY_DELETE); -#endif - + ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), KEY_DELETE); ED_SHORTCUT("filesystem_dock/rename", TTR("Rename..."), KEY_F2); VBoxContainer *top_vbc = memnew(VBoxContainer); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 8783c402cd..21a7abe622 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -43,7 +43,7 @@ #include "scene/gui/tree.h" #include "scene/main/timer.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/thread.h" #include "create_dialog.h" @@ -253,7 +253,6 @@ private: void _toggle_split_mode(bool p_active); - void _focus_current_search_box(); void _search_changed(const String &p_text, const Control *p_from); MenuButton *_create_file_menu_button(); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index d9b956ed08..cb8de09a9a 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -30,7 +30,7 @@ #include "find_in_files.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" #include "editor_node.h" #include "editor_scale.h" @@ -311,7 +311,7 @@ FindInFilesDialog::FindInFilesDialog() { _search_text_line_edit = memnew(LineEdit); _search_text_line_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); _search_text_line_edit->connect("text_changed", callable_mp(this, &FindInFilesDialog::_on_search_text_modified)); - _search_text_line_edit->connect("text_entered", callable_mp(this, &FindInFilesDialog::_on_search_text_entered)); + _search_text_line_edit->connect("text_submitted", callable_mp(this, &FindInFilesDialog::_on_search_text_submitted)); gc->add_child(_search_text_line_edit); _replace_label = memnew(Label); @@ -321,7 +321,7 @@ FindInFilesDialog::FindInFilesDialog() { _replace_text_line_edit = memnew(LineEdit); _replace_text_line_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); - _replace_text_line_edit->connect("text_entered", callable_mp(this, &FindInFilesDialog::_on_replace_text_entered)); + _replace_text_line_edit->connect("text_submitted", callable_mp(this, &FindInFilesDialog::_on_replace_text_submitted)); _replace_text_line_edit->hide(); gc->add_child(_replace_text_line_edit); @@ -503,7 +503,7 @@ void FindInFilesDialog::_on_search_text_modified(String text) { _replace_button->set_disabled(get_search_text().is_empty()); } -void FindInFilesDialog::_on_search_text_entered(String text) { +void FindInFilesDialog::_on_search_text_submitted(String text) { // This allows to trigger a global search without leaving the keyboard if (!_find_button->is_disabled()) { if (_mode == SEARCH_MODE) { @@ -518,7 +518,7 @@ void FindInFilesDialog::_on_search_text_entered(String text) { } } -void FindInFilesDialog::_on_replace_text_entered(String text) { +void FindInFilesDialog::_on_replace_text_submitted(String text) { // This allows to trigger a global search without leaving the keyboard if (!_replace_button->is_disabled()) { if (_mode == REPLACE_MODE) { @@ -638,7 +638,7 @@ void FindInFilesPanel::set_with_replace(bool with_replace) { // Results show checkboxes on their left so they can be opted out _results_display->set_columns(2); _results_display->set_column_expand(0, false); - _results_display->set_column_min_width(0, 48 * EDSCALE); + _results_display->set_column_custom_minimum_width(0, 48 * EDSCALE); } else { // Results are single-cell items diff --git a/editor/find_in_files.h b/editor/find_in_files.h index b9d60a8d4f..488f14a922 100644 --- a/editor/find_in_files.h +++ b/editor/find_in_files.h @@ -128,8 +128,8 @@ private: void _on_folder_button_pressed(); void _on_folder_selected(String path); void _on_search_text_modified(String text); - void _on_search_text_entered(String text); - void _on_replace_text_entered(String text); + void _on_search_text_submitted(String text); + void _on_replace_text_submitted(String text); FindInFilesMode _mode; LineEdit *_search_text_line_edit; diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index d8e5a05c5d..1b11ec4451 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -446,7 +446,7 @@ GroupDialog::GroupDialog() { add_group_text = memnew(LineEdit); chbc->add_child(add_group_text); add_group_text->set_h_size_flags(Control::SIZE_EXPAND_FILL); - add_group_text->connect("text_entered", callable_mp(this, &GroupDialog::_add_group_pressed)); + add_group_text->connect("text_submitted", callable_mp(this, &GroupDialog::_add_group_pressed)); Button *add_group_button = memnew(Button); add_group_button->set_text(TTR("Add")); @@ -689,7 +689,7 @@ GroupsEditor::GroupsEditor() { group_name = memnew(LineEdit); group_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); hbc->add_child(group_name); - group_name->connect("text_entered", callable_mp(this, &GroupsEditor::_add_group)); + group_name->connect("text_submitted", callable_mp(this, &GroupsEditor::_add_group)); add = memnew(Button); add->set_text(TTR("Add")); diff --git a/editor/icons/2D.svg b/editor/icons/2D.svg index afb9f4b45f..fdd2e473e3 100644 --- a/editor/icons/2D.svg +++ b/editor/icons/2D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.9844 1.002a1.0001 1.0001 0 0 0 -.69141.29102l-2 2a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l.29297-.29297v8.5859h8.5859l-.29297.29297a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 0-1.4141l-2-2a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l.29297.29297h-6.5859v-6.5859l.29297.29297a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-2-2a1.0001 1.0001 0 0 0 -.72266-.29102z" fill="#e0e0e0"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.984375 15a1 1 0 0 1 -.6914062-.291316l-2-2a1 1 0 0 1 0-1.414062 1 1 0 0 1 1.4140624 0l.2929688.292968v-8.5859371h8.585938l-.292969-.292969a1 1 0 0 1 0-1.414062 1 1 0 0 1 1.414062 0l2 2a1 1 0 0 1 0 1.414062l-2 2.0000002a1 1 0 0 1 -.720703.2910157 1 1 0 0 1 -.693359-.2910157 1 1 0 0 1 0-1.4140622l.292969-.292969h-6.585938v6.5859371l.2929688-.292968a1 1 0 0 1 1.4140624 0 1 1 0 0 1 0 1.414062l-2 2a1 1 0 0 1 -.7226562.291316z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/CenterView.svg b/editor/icons/CenterView.svg new file mode 100644 index 0000000000..c2a918fe81 --- /dev/null +++ b/editor/icons/CenterView.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><circle cx="4" cy="12" fill="none" r="2"/><g fill="#e0e0e0"><path d="m7.3333333 6c-.7386666 0-1.3333333.5946667-1.3333333 1.3333333v1.3333334c0 .7386663.5946667 1.3333333 1.3333333 1.3333333h1.3333334c.7386666 0 1.3333333-.594667 1.3333333-1.3333333v-1.3333334c0-.7386666-.5946667-1.3333333-1.3333333-1.3333333z" stroke-width=".666667"/><g stroke-width=".830398"><path d="m2.9918978 5.5000002c-.7478701.0001968-1.1170118.9026572-.5810669 1.4205652l.2441488.2424178h-2.15497967v1.6548989h2.15497967l-.2441488.242418c-.8159014.77992.3929613 1.9802119 1.178451 1.1700959l1.6667154-1.6548989c.3253369-.3231472.3253369-.8469488 0-1.170096l-1.6667154-1.6548989c-.1568986-.1601378-.3723426-.2504824-.5973507-.2504937z"/><path d="m13.008102 10.5c.74787-.000197 1.117012-.9026571.581067-1.4205651l-.244149-.242418h2.15498v-1.6548988h-2.15498l.244149-.2424179c.815901-.7799207-.392961-1.9802122-1.178451-1.1700961l-1.666715 1.6548987c-.325337.3231474-.325337.846949 0 1.1700961l1.666715 1.6548991c.156899.160138.372343.250482.597351.250494z"/><path d="m5.5000001 13.008102c.000197.74787.902657 1.117012 1.420565.581067l.242418-.244149v2.15498h1.654899v-2.15498l.242418.244149c.77992.815901 1.9802119-.392961 1.1700959-1.178451l-1.6548989-1.666715c-.323147-.325337-.846949-.325337-1.170096 0l-1.654899 1.666715c-.160138.156899-.250482.372343-.250494.597351z"/><path d="m10.5 2.9918983c-.000197-.7478701-.9026571-1.1170121-1.4205651-.581067l-.242418.244149v-2.1549801h-1.6548989v2.1549801l-.242418-.2441491c-.77992-.815901-1.9802121.3929611-1.170096 1.1784512l1.654899 1.6667148c.3231469.325337.8469489.325337 1.1700959 0l1.6548991-1.6667148c.160138-.156899.250482-.3723431.250494-.597351z"/></g></g></svg> diff --git a/editor/icons/KinematicBody2D.svg b/editor/icons/CharacterBody2D.svg index b71fda9650..b71fda9650 100644 --- a/editor/icons/KinematicBody2D.svg +++ b/editor/icons/CharacterBody2D.svg diff --git a/editor/icons/KinematicBody3D.svg b/editor/icons/CharacterBody3D.svg index d0def4f14a..d0def4f14a 100644 --- a/editor/icons/KinematicBody3D.svg +++ b/editor/icons/CharacterBody3D.svg diff --git a/editor/icons/ImmediateMesh.svg b/editor/icons/ImmediateMesh.svg new file mode 100644 index 0000000000..9521530876 --- /dev/null +++ b/editor/icons/ImmediateMesh.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 14.999999 14.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2v2h5v-2zm5 2v3h2v-3zm2-2v2h5v-2zm-2 7v3h2v-3zm-5 3v2h5v-2zm7 0v2h5v-2z" fill="#ffca5f" transform="scale(.93749994)"/></svg> diff --git a/editor/icons/BakedLightmap.svg b/editor/icons/LightmapGI.svg index 78f0a64a7b..78f0a64a7b 100644 --- a/editor/icons/BakedLightmap.svg +++ b/editor/icons/LightmapGI.svg diff --git a/editor/icons/BakedLightmapData.svg b/editor/icons/LightmapGIData.svg index f5dcfb618b..f5dcfb618b 100644 --- a/editor/icons/BakedLightmapData.svg +++ b/editor/icons/LightmapGIData.svg diff --git a/editor/icons/ORMMaterial3D.svg b/editor/icons/ORMMaterial3D.svg index 3d6db6910d..e09208155d 100644 --- a/editor/icons/ORMMaterial3D.svg +++ b/editor/icons/ORMMaterial3D.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5.0534707 10.652714q0 .729229-.4538398 1.253141-.4538403.516832-1.0868283.516832h-1.1943162q-.6389592 0-1.1047425-.509753-.47175502-.509751-.47175502-1.26022v-5.5223119q0-.7575473.47175502-1.2672998.4717549-.5097517 1.1047425-.5097517h1.1943162q.6270165 0 1.0868283.516832.4538398.5168313.4538398 1.2602195zm-1.0808559-.233636v-5.0550395q0-.5734707-.3344086-.8141867-.1074887-.0849591-.2567782-.0778788h-.9912826q-.2567779 0-.4120391.2690357-.1552611.2690357-.1552611.6230298v5.0550395q0 .559311.3164938.807108.1074885.08496.2508064.08496h.9912826q.2746925 0 .4359254-.276116.1552614-.276115.1552614-.61595z" fill="#f00"/><path d="m9.9872948 12.451006h-1.0427362l-1.4698137-3.9222572h-.7931457v3.9222572h-1.0094573v-9.076416h2.739956q.5435541 0 .9318066.4601926.3882524.4601933.3882524 1.1540217v2.1239667q0 1.0053443-.6766682 1.3168588-.2107668.099119-.4659043.099119zm-1.2590481-5.64267v-1.5858953q0-.4743524-.2884169-.6867495-.088743-.070798-.2052192-.063719h-1.5530114v2.9452329h1.7194053q.2828702-.00708.3161488-.389394.011093-.1132781.011093-.2194752z" fill="#008000"/><path d="m10.201004 3.7285848q0-.4106342.529158-.3681546.126777.014161.209458.014161v.00708h.115753l1.692202 4.9205216 1.697714-4.9205216h.06063v-.00708h.463013q.198434 0 .297651.212397.03307.063719.03307.1415978v8.694102h-1.01422v-5.6001914l-1.058314 3.2284284h-.953584l-1.058315-2.9310723v5.3028353h-1.014218z" fill="#00f"/></svg> +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 3.1191406-3.7636719 1.8808594 3.7636719 1.8828125 3.763672-1.8828125z" fill="#80ff45"/><path d="m3 6.6191406v2.3808594 1.382812l1.234375.617188 2.765625 1.382812v-1.382812-2-.3808594l-3.2382812-1.6191406z" fill="#ff4545"/><path d="m13 6.6191406-.761719.3808594-3.238281 1.6191406v3.7636714l2.765625-1.382812 1.234375-.617188v-1.382812z" fill="#45d7ff"/></svg> diff --git a/editor/icons/Quat.svg b/editor/icons/Quaternion.svg index cf29160ff4..cf29160ff4 100644 --- a/editor/icons/Quat.svg +++ b/editor/icons/Quaternion.svg diff --git a/editor/icons/RectangleAddRemove.svg b/editor/icons/RectangleAddRemove.svg deleted file mode 100644 index 87e2155a0d..0000000000 --- a/editor/icons/RectangleAddRemove.svg +++ /dev/null @@ -1 +0,0 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 2c-.5522619.0000552-.9999448.4477381-1 1v10c.0000552.552262.4477381.999945 1 1h6v-2h-5v-8h10v1h2v-2c-.000055-.5522619-.447738-.9999448-1-1zm9.25 4v2.25h-2.25v1.5h2.25v2.25h1.5v-2.25h2.25v-1.5h-2.25v-2.25zm-2.25 7.5v1.5h6v-1.5z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/TileChecked.svg b/editor/icons/TileChecked.svg new file mode 100644 index 0000000000..33b99a0e4c --- /dev/null +++ b/editor/icons/TileChecked.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#808080" stroke-width="1.16667"/><path d="m11.500773 3.7343508-5.6117507 5.6117502-1.7045017-1.6814543-1.4992276 1.4992276 3.2037293 3.1806817 7.1109777-7.1109775z" fill="#fff" stroke-width="1.06023"/></svg> diff --git a/editor/icons/TileUnchecked.svg b/editor/icons/TileUnchecked.svg new file mode 100644 index 0000000000..cd8db4ee19 --- /dev/null +++ b/editor/icons/TileUnchecked.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 15.999999" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3.3333333 1c-1.2887 0-2.3333333 1.0446683-2.3333333 2.3333333v9.3333337c0 1.2887 1.0446683 2.333333 2.3333333 2.333333h9.3333337c1.2887 0 2.333333-1.044668 2.333333-2.333333v-9.3333337c0-1.2887-1.044668-2.3333333-2.333333-2.3333333z" fill="#808080" stroke-width="1.16667"/></svg> diff --git a/editor/icons/Transform.svg b/editor/icons/Transform3D.svg index a940120702..a940120702 100644 --- a/editor/icons/Transform.svg +++ b/editor/icons/Transform3D.svg diff --git a/editor/icons/VisibilityEnabler2D.svg b/editor/icons/VisibleOnScreenEnabler2D.svg index 989675f44f..989675f44f 100644 --- a/editor/icons/VisibilityEnabler2D.svg +++ b/editor/icons/VisibleOnScreenEnabler2D.svg diff --git a/editor/icons/VisibilityEnabler3D.svg b/editor/icons/VisibleOnScreenEnabler3D.svg index 6923bcb46b..6923bcb46b 100644 --- a/editor/icons/VisibilityEnabler3D.svg +++ b/editor/icons/VisibleOnScreenEnabler3D.svg diff --git a/editor/icons/VisibilityNotifier2D.svg b/editor/icons/VisibleOnScreenNotifier2D.svg index 13df19be56..13df19be56 100644 --- a/editor/icons/VisibilityNotifier2D.svg +++ b/editor/icons/VisibleOnScreenNotifier2D.svg diff --git a/editor/icons/VisibilityNotifier3D.svg b/editor/icons/VisibleOnScreenNotifier3D.svg index 2fdf784701..2fdf784701 100644 --- a/editor/icons/VisibilityNotifier3D.svg +++ b/editor/icons/VisibleOnScreenNotifier3D.svg diff --git a/editor/icons/GIProbe.svg b/editor/icons/VoxelGI.svg index f5e1025260..f5e1025260 100644 --- a/editor/icons/GIProbe.svg +++ b/editor/icons/VoxelGI.svg diff --git a/editor/icons/GIProbeData.svg b/editor/icons/VoxelGIData.svg index 5975115f4c..5975115f4c 100644 --- a/editor/icons/GIProbeData.svg +++ b/editor/icons/VoxelGIData.svg diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp index e38034dd8c..aa9700716d 100644 --- a/editor/import/collada.cpp +++ b/editor/import/collada.cpp @@ -50,8 +50,8 @@ String Collada::Effect::get_texture_path(const String &p_source, Collada &state) return state.state.image_map[image].path; } -Transform Collada::get_root_transform() const { - Transform unit_scale_transform; +Transform3D Collada::get_root_transform() const { + Transform3D unit_scale_transform; #ifndef COLLADA_IMPORT_SCALE_SCENE unit_scale_transform.scale(Vector3(state.unit_scale, state.unit_scale, state.unit_scale)); #endif @@ -74,8 +74,8 @@ static String _uri_to_id(const String &p_uri) { /** HELPER FUNCTIONS **/ -Transform Collada::fix_transform(const Transform &p_transform) { - Transform tr = p_transform; +Transform3D Collada::fix_transform(const Transform3D &p_transform) { + Transform3D tr = p_transform; #ifndef NO_UP_AXIS_SWAP @@ -102,8 +102,8 @@ Transform Collada::fix_transform(const Transform &p_transform) { //return state.matrix_fix * p_transform; } -static Transform _read_transform_from_array(const Vector<float> &array, int ofs = 0) { - Transform tr; +static Transform3D _read_transform_from_array(const Vector<float> &array, int ofs = 0) { + Transform3D tr; // i wonder why collada matrices are transposed, given that's opposed to opengl.. tr.basis.elements[0][0] = array[0 + ofs]; tr.basis.elements[0][1] = array[1 + ofs]; @@ -122,11 +122,11 @@ static Transform _read_transform_from_array(const Vector<float> &array, int ofs /* STRUCTURES */ -Transform Collada::Node::compute_transform(Collada &state) const { - Transform xform; +Transform3D Collada::Node::compute_transform(Collada &state) const { + Transform3D xform; for (int i = 0; i < xform_list.size(); i++) { - Transform xform_step; + Transform3D xform_step; const XForm &xf = xform_list[i]; switch (xf.op) { case XForm::OP_ROTATE: { @@ -165,11 +165,11 @@ Transform Collada::Node::compute_transform(Collada &state) const { return xform; } -Transform Collada::Node::get_transform() const { +Transform3D Collada::Node::get_transform() const { return default_transform; } -Transform Collada::Node::get_global_transform() const { +Transform3D Collada::Node::get_global_transform() const { if (parent) { return parent->get_global_transform() * default_transform; } else { @@ -201,14 +201,14 @@ Vector<float> Collada::AnimationTrack::get_value_at_time(float p_time) const { if (keys[i].data.size() == 16) { //interpolate a matrix - Transform src = _read_transform_from_array(keys[i - 1].data); - Transform dst = _read_transform_from_array(keys[i].data); + Transform3D src = _read_transform_from_array(keys[i - 1].data); + Transform3D dst = _read_transform_from_array(keys[i].data); - Transform interp = c < 0.001 ? src : src.interpolate_with(dst, c); + Transform3D interp = c < 0.001 ? src : src.interpolate_with(dst, c); Vector<float> ret; ret.resize(16); - Transform tr; + Transform3D tr; // i wonder why collada matrices are transposed, given that's opposed to opengl.. ret.write[0] = interp.basis.elements[0][0]; ret.write[1] = interp.basis.elements[0][1]; @@ -410,10 +410,9 @@ Vector<String> Collada::_read_string_array(XMLParser &parser) { return array; } -Transform Collada::_read_transform(XMLParser &parser) { - if (parser.is_empty()) { - return Transform(); - } +Transform3D Collada::_read_transform(XMLParser &parser) { + if (parser.is_empty()) + return Transform3D(); Vector<String> array; while (parser.read() == OK) { @@ -429,7 +428,7 @@ Transform Collada::_read_transform(XMLParser &parser) { } } - ERR_FAIL_COND_V(array.size() != 16, Transform()); + ERR_FAIL_COND_V(array.size() != 16, Transform3D()); Vector<float> farr; farr.resize(16); for (int i = 0; i < 16; i++) { @@ -1197,7 +1196,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { /* STORE REST MATRICES */ - Vector<Transform> rests; + Vector<Transform3D> rests; ERR_FAIL_COND(!skindata.joints.sources.has("JOINT")); ERR_FAIL_COND(!skindata.joints.sources.has("INV_BIND_MATRIX")); @@ -1214,7 +1213,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) { for (int i = 0; i < joint_source.sarray.size(); i++) { String name = joint_source.sarray[i]; - Transform xform = _read_transform_from_array(ibm_source.array, i * 16); //<- this is a mistake, it must be applied to vertices + Transform3D xform = _read_transform_from_array(ibm_source.array, i * 16); //<- this is a mistake, it must be applied to vertices xform.affine_invert(); // inverse for rest, because it's an inverse #ifdef COLLADA_IMPORT_SCALE_SCENE xform.origin *= state.unit_scale; @@ -2096,7 +2095,7 @@ void Collada::_merge_skeletons2(VisualScene *p_vscene) { NodeSkeleton *skeleton = nullptr; - for (Map<String, Transform>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) { + for (Map<String, Transform3D>::Element *F = cd.bone_rest_map.front(); F; F = F->next()) { String name; if (!state.sid_to_node_map.has(F->key())) { @@ -2240,11 +2239,11 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L //this should be correct ERR_FAIL_COND_V(!state.skin_controller_data_map.has(ng->source), false); SkinControllerData &skin = state.skin_controller_data_map[ng->source]; - Transform skel_inv = sk->get_global_transform().affine_inverse(); + Transform3D skel_inv = sk->get_global_transform().affine_inverse(); p_node->default_transform = skel_inv * (skin.bind_shape /* p_node->get_global_transform()*/); // i honestly have no idea what to do with a previous model xform.. most exporters ignore it //make rests relative to the skeleton (they seem to be always relative to world) - for (Map<String, Transform>::Element *E = skin.bone_rest_map.front(); E; E = E->next()) { + for (Map<String, Transform3D>::Element *E = skin.bone_rest_map.front(); E; E = E->next()) { E->get() = skel_inv * E->get(); //make the bone rest local to the skeleton state.bone_rest_map[E->key()] = E->get(); // make it remember where the bone is globally, now that it's relative } @@ -2252,7 +2251,7 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L //but most exporters seem to work only if i do this.. //p_node->default_transform = p_node->get_global_transform(); - //p_node->default_transform=Transform(); //this seems to be correct, because bind shape makes the object local to the skeleton + //p_node->default_transform=Transform3D(); //this seems to be correct, because bind shape makes the object local to the skeleton p_node->ignore_anim = true; // collada may animate this later, if it does, then this is not supported (redo your original asset and don't animate the base mesh) p_node->parent = sk; //sk->children.push_back(0,p_node); //avoid INFINITE loop diff --git a/editor/import/collada.h b/editor/import/collada.h index 2c3f0a3006..5e38637504 100644 --- a/editor/import/collada.h +++ b/editor/import/collada.h @@ -182,7 +182,7 @@ public: String base; bool use_idrefs = false; - Transform bind_shape; + Transform3D bind_shape; struct Source { Vector<String> sarray; //maybe for names @@ -210,7 +210,7 @@ public: int count = 0; } weights; - Map<String, Transform> bone_rest_map; + Map<String, Transform3D> bone_rest_map; SkinControllerData() {} }; @@ -342,15 +342,15 @@ public: String empty_draw_type; bool noname = false; Vector<XForm> xform_list; - Transform default_transform; - Transform post_transform; + Transform3D default_transform; + Transform3D post_transform; Vector<Node *> children; Node *parent = nullptr; - Transform compute_transform(Collada &state) const; - Transform get_global_transform() const; - Transform get_transform() const; + Transform3D compute_transform(Collada &state) const; + Transform3D get_global_transform() const; + Transform3D get_transform() const; bool ignore_anim = false; @@ -497,7 +497,7 @@ public: Map<String, String> sid_to_node_map; //Map<String,NodeJoint*> bone_map; - Map<String, Transform> bone_rest_map; + Map<String, Transform3D> bone_rest_map; String local_path; String root_visual_scene; @@ -517,9 +517,9 @@ public: Collada(); - Transform fix_transform(const Transform &p_transform); + Transform3D fix_transform(const Transform3D &p_transform); - Transform get_root_transform() const; + Transform3D get_root_transform() const; int get_uv_channel(String p_name); @@ -557,7 +557,7 @@ private: // private stuff Variant _parse_param(XMLParser &parser); Vector<float> _read_float_array(XMLParser &parser); Vector<String> _read_string_array(XMLParser &parser); - Transform _read_transform(XMLParser &parser); + Transform3D _read_transform(XMLParser &parser); String _read_empty_draw_type(XMLParser &parser); void _joint_set_owner(Collada::Node *p_node, NodeSkeleton *p_owner); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index d3183e5a8d..ddf89f077b 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -87,7 +87,7 @@ struct ColladaImport { Error _create_scene(Collada::Node *p_node, Node3D *p_parent); Error _create_resources(Collada::Node *p_node, bool p_use_compression); Error _create_material(const String &p_target); - Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); + Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false); void _fix_param_animation_tracks(); void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks); @@ -300,7 +300,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { nm.node = node; node_map[p_node->id] = nm; node_name_map[node->get_name()] = p_node->id; - Transform xf = p_node->default_transform; + Transform3D xf = p_node->default_transform; xf = collada.fix_transform(xf) * p_node->post_transform; node->set_transform(xf); @@ -457,7 +457,7 @@ Error ColladaImport::_create_material(const String &p_target) { return OK; } -Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { +Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { bool local_xform_mirror = p_local_xform.basis.determinant() < 0; if (p_morph_data) { @@ -811,7 +811,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor if (has_weights) { //if skeleton, localize - Transform local_xform = p_local_xform; + Transform3D local_xform = p_local_xform; for (int i = 0; i < vertex_array.size(); i++) { vertex_array.write[i].vertex = local_xform.xform(vertex_array[i].vertex); vertex_array.write[i].normal = local_xform.basis.xform(vertex_array[i].normal).normalized(); @@ -850,7 +850,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImpor } Ref<SurfaceTool> surftool; - surftool.instance(); + surftool.instantiate(); surftool->begin(Mesh::PRIMITIVE_TRIANGLES); for (int k = 0; k < vertex_array.size(); k++) { @@ -1037,7 +1037,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres Collada::SkinControllerData *skin = nullptr; Collada::MorphControllerData *morph = nullptr; String meshid; - Transform apply_xform; + Transform3D apply_xform; Vector<int> bone_remap; Vector<Ref<EditorSceneImporterMesh>> morphs; @@ -1073,9 +1073,9 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres if (apply_mesh_xform_to_vertices) { apply_xform = collada.fix_transform(p_node->default_transform); - node->set_transform(Transform()); + node->set_transform(Transform3D()); } else { - apply_xform = Transform(); + apply_xform = Transform3D(); } ERR_FAIL_COND_V(!skin->weights.sources.has("JOINT"), ERR_INVALID_DATA); @@ -1461,7 +1461,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones continue; } - animation->add_track(Animation::TYPE_TRANSFORM); + animation->add_track(Animation::TYPE_TRANSFORM3D); int track = animation->get_track_count() - 1; animation->track_set_path(track, path); animation->track_set_imported(track, true); //helps merging later @@ -1530,7 +1530,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } } - Transform xform = cn->compute_transform(collada); + Transform3D xform = cn->compute_transform(collada); xform = collada.fix_transform(xform) * cn->post_transform; if (nm.bone >= 0) { @@ -1544,8 +1544,8 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } Vector3 s = xform.basis.get_scale(); - bool singular_matrix = Math::is_equal_approx(s.x, 0.0f) || Math::is_equal_approx(s.y, 0.0f) || Math::is_equal_approx(s.z, 0.0f); - Quat q = singular_matrix ? Quat() : xform.basis.get_rotation_quat(); + bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z); + Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion(); Vector3 l = xform.origin; animation->transform_track_insert_key(track, snapshots[i], l, q, s); @@ -1584,19 +1584,19 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones continue; } - animation->add_track(Animation::TYPE_TRANSFORM); + animation->add_track(Animation::TYPE_TRANSFORM3D); int track = animation->get_track_count() - 1; animation->track_set_path(track, path); animation->track_set_imported(track, true); //helps merging later - Transform xform = cn->compute_transform(collada); + Transform3D xform = cn->compute_transform(collada); xform = collada.fix_transform(xform) * cn->post_transform; xform = sk->get_bone_rest(nm.bone).affine_inverse() * xform; Vector3 s = xform.basis.get_scale(); - bool singular_matrix = Math::is_equal_approx(s.x, 0.0f) || Math::is_equal_approx(s.y, 0.0f) || Math::is_equal_approx(s.z, 0.0f); - Quat q = singular_matrix ? Quat() : xform.basis.get_rotation_quat(); + bool singular_matrix = Math::is_zero_approx(s.x) || Math::is_zero_approx(s.y) || Math::is_zero_approx(s.z); + Quaternion q = singular_matrix ? Quaternion() : xform.basis.get_rotation_quaternion(); Vector3 l = xform.origin; animation->transform_track_insert_key(track, 0, l, q, s); diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp index 44aff874eb..8660289c40 100644 --- a/editor/import/editor_import_plugin.cpp +++ b/editor/import/editor_import_plugin.cpp @@ -35,63 +35,63 @@ EditorImportPlugin::EditorImportPlugin() { } String EditorImportPlugin::get_importer_name() const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_importer_name")), ""); - return get_script_instance()->call("get_importer_name"); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_importer_name")), ""); + return get_script_instance()->call("_get_importer_name"); } String EditorImportPlugin::get_visible_name() const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_visible_name")), ""); - return get_script_instance()->call("get_visible_name"); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_visible_name")), ""); + return get_script_instance()->call("_get_visible_name"); } void EditorImportPlugin::get_recognized_extensions(List<String> *p_extensions) const { - ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("get_recognized_extensions"))); - Array extensions = get_script_instance()->call("get_recognized_extensions"); + ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("_get_recognized_extensions"))); + Array extensions = get_script_instance()->call("_get_recognized_extensions"); for (int i = 0; i < extensions.size(); i++) { p_extensions->push_back(extensions[i]); } } String EditorImportPlugin::get_preset_name(int p_idx) const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_preset_name")), ""); - return get_script_instance()->call("get_preset_name", p_idx); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_preset_name")), ""); + return get_script_instance()->call("_get_preset_name", p_idx); } int EditorImportPlugin::get_preset_count() const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_preset_count")), 0); - return get_script_instance()->call("get_preset_count"); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_preset_count")), 0); + return get_script_instance()->call("_get_preset_count"); } String EditorImportPlugin::get_save_extension() const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_save_extension")), ""); - return get_script_instance()->call("get_save_extension"); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_save_extension")), ""); + return get_script_instance()->call("_get_save_extension"); } String EditorImportPlugin::get_resource_type() const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_resource_type")), ""); - return get_script_instance()->call("get_resource_type"); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_resource_type")), ""); + return get_script_instance()->call("_get_resource_type"); } float EditorImportPlugin::get_priority() const { - if (!(get_script_instance() && get_script_instance()->has_method("get_priority"))) { + if (!(get_script_instance() && get_script_instance()->has_method("_get_priority"))) { return ResourceImporter::get_priority(); } - return get_script_instance()->call("get_priority"); + return get_script_instance()->call("_get_priority"); } int EditorImportPlugin::get_import_order() const { - if (!(get_script_instance() && get_script_instance()->has_method("get_import_order"))) { + if (!(get_script_instance() && get_script_instance()->has_method("_get_import_order"))) { return ResourceImporter::get_import_order(); } - return get_script_instance()->call("get_import_order"); + return get_script_instance()->call("_get_import_order"); } void EditorImportPlugin::get_import_options(List<ResourceImporter::ImportOption> *r_options, int p_preset) const { - ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("get_import_options"))); + ERR_FAIL_COND(!(get_script_instance() && get_script_instance()->has_method("_get_import_options"))); Array needed; needed.push_back("name"); needed.push_back("default_value"); - Array options = get_script_instance()->call("get_import_options", p_preset); + Array options = get_script_instance()->call("_get_import_options", p_preset); for (int i = 0; i < options.size(); i++) { Dictionary d = options[i]; ERR_FAIL_COND(!d.has_all(needed)); @@ -119,18 +119,18 @@ void EditorImportPlugin::get_import_options(List<ResourceImporter::ImportOption> } bool EditorImportPlugin::get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("get_option_visibility")), true); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_get_option_visibility")), true); Dictionary d; Map<StringName, Variant>::Element *E = p_options.front(); while (E) { d[E->key()] = E->get(); E = E->next(); } - return get_script_instance()->call("get_option_visibility", p_option, d); + return get_script_instance()->call("_get_option_visibility", p_option, d); } Error EditorImportPlugin::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { - ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("import")), ERR_UNAVAILABLE); + ERR_FAIL_COND_V(!(get_script_instance() && get_script_instance()->has_method("_import")), ERR_UNAVAILABLE); Dictionary options; Array platform_variants, gen_files; @@ -139,7 +139,7 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa options[E->key()] = E->get(); E = E->next(); } - Error err = (Error)get_script_instance()->call("import", p_source_file, p_save_path, options, platform_variants, gen_files).operator int64_t(); + Error err = (Error)get_script_instance()->call("_import", p_source_file, p_save_path, options, platform_variants, gen_files).operator int64_t(); for (int i = 0; i < platform_variants.size(); i++) { r_platform_variants->push_back(platform_variants[i]); @@ -151,16 +151,16 @@ Error EditorImportPlugin::import(const String &p_source_file, const String &p_sa } void EditorImportPlugin::_bind_methods() { - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_importer_name")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_visible_name")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_preset_count")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_preset_name", PropertyInfo(Variant::INT, "preset"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_recognized_extensions")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::ARRAY, "get_import_options", PropertyInfo(Variant::INT, "preset"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_save_extension")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::STRING, "get_resource_type")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::FLOAT, "get_priority")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "get_import_order")); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::BOOL, "get_option_visibility", PropertyInfo(Variant::STRING, "option"), PropertyInfo(Variant::DICTIONARY, "options"))); - ClassDB::add_virtual_method(get_class_static(), MethodInfo(Variant::INT, "import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "platform_variants"), PropertyInfo(Variant::ARRAY, "gen_files"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_importer_name")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_visible_name")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_preset_count")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_preset_name", PropertyInfo(Variant::INT, "preset"))); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_recognized_extensions")); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_import_options", PropertyInfo(Variant::INT, "preset"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_save_extension")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_resource_type")); + BIND_VMETHOD(MethodInfo(Variant::FLOAT, "_get_priority")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_import_order")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_get_option_visibility", PropertyInfo(Variant::STRING, "option"), PropertyInfo(Variant::DICTIONARY, "options"))); + BIND_VMETHOD(MethodInfo(Variant::INT, "_import", PropertyInfo(Variant::STRING, "source_file"), PropertyInfo(Variant::STRING, "save_path"), PropertyInfo(Variant::DICTIONARY, "options"), PropertyInfo(Variant::ARRAY, "platform_variants"), PropertyInfo(Variant::ARRAY, "gen_files"))); } diff --git a/editor/import/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp index ffef759c07..7fd9230284 100644 --- a/editor/import/resource_importer_bitmask.cpp +++ b/editor/import/resource_importer_bitmask.cpp @@ -78,7 +78,7 @@ Error ResourceImporterBitMap::import(const String &p_source_file, const String & int create_from = p_options["create_from"]; float threshold = p_options["threshold"]; Ref<Image> image; - image.instance(); + image.instantiate(); Error err = ImageLoader::load_image(p_source_file, image); if (err != OK) { return err; @@ -88,7 +88,7 @@ Error ResourceImporterBitMap::import(const String &p_source_file, const String & int h = image->get_height(); Ref<BitMap> bitmap; - bitmap.instance(); + bitmap.instantiate(); bitmap->create(Size2(w, h)); for (int i = 0; i < h; i++) { diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index 4a4d9d8f06..07647d8b6a 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -30,8 +30,8 @@ #include "resource_importer_csv_translation.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "core/string/optimized_translation.h" #include "core/string/translation.h" @@ -104,7 +104,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const locales.push_back(locale); Ref<Translation> translation; - translation.instance(); + translation.instantiate(); translation->set_locale(locale); translations.push_back(translation); } diff --git a/editor/import/resource_importer_image.cpp b/editor/import/resource_importer_image.cpp index c5b2a8dc3a..2dea359188 100644 --- a/editor/import/resource_importer_image.cpp +++ b/editor/import/resource_importer_image.cpp @@ -30,9 +30,9 @@ #include "resource_importer_image.h" +#include "core/io/file_access.h" #include "core/io/image_loader.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "scene/resources/texture.h" String ResourceImporterImage::get_importer_name() const { diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index 6d2215c379..2ac8b8bd7d 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -186,7 +186,7 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons for (int i = 0; i < mm_d; i++) { Ref<Image> mm; - mm.instance(); + mm.instantiate(); mm->create(mm_w, mm_h, false, p_images[0]->get_format()); Vector3 pos; pos.z = float(i) * float(d) / float(mm_d) + 0.5; @@ -328,7 +328,7 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const } Ref<Image> image; - image.instance(); + image.instantiate(); Error err = ImageLoader::load_image(p_source_file, image, nullptr, false, 1.0); if (err != OK) { return err; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index dd62c72d8a..01603c0a6a 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -30,8 +30,8 @@ #include "resource_importer_obj.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "editor/import/scene_importer_mesh.h" #include "editor/import/scene_importer_mesh_node_3d.h" #include "scene/3d/mesh_instance_3d.h" @@ -57,7 +57,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand //vertex current_name = l.replace("newmtl", "").strip_edges(); - current.instance(); + current.instantiate(); current->set_name(current_name); material_map[current_name] = current; } else if (l.begins_with("Ka ")) { @@ -126,7 +126,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand String p = l.replace("map_Kd", "").replace("\\", "/").strip_edges(); String path; - if (p.is_abs_path()) { + if (p.is_absolute_path()) { path = p; } else { path = base_path.plus_file(p); @@ -146,7 +146,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand String p = l.replace("map_Ks", "").replace("\\", "/").strip_edges(); String path; - if (p.is_abs_path()) { + if (p.is_absolute_path()) { path = p; } else { path = base_path.plus_file(p); @@ -166,7 +166,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Stand String p = l.replace("map_Ns", "").replace("\\", "/").strip_edges(); String path; - if (p.is_abs_path()) { + if (p.is_absolute_path()) { path = p; } else { path = base_path.plus_file(p); @@ -207,7 +207,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); bool generate_tangents = p_generate_tangents; Vector3 scale_mesh = p_scale_mesh; @@ -378,7 +378,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ if (!p_single_mesh) { mesh->set_name(name); r_meshes.push_back(mesh); - mesh.instance(); + mesh.instantiate(); current_group = ""; current_material = ""; } @@ -440,7 +440,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in for (List<Ref<Mesh>>::Element *E = meshes.front(); E; E = E->next()) { Ref<EditorSceneImporterMesh> mesh; - mesh.instance(); + mesh.instantiate(); Ref<Mesh> m = E->get(); for (int i = 0; i < m->get_surface_count(); i++) { mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i)); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 96002400f3..c14b948dae 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -120,13 +120,13 @@ void EditorSceneImporter::_bind_methods() { ///////////////////////////////// void EditorScenePostImport::_bind_methods() { - BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene"))); + BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_post_import", PropertyInfo(Variant::OBJECT, "scene"))); ClassDB::bind_method(D_METHOD("get_source_file"), &EditorScenePostImport::get_source_file); } Node *EditorScenePostImport::post_import(Node *p_scene) { if (get_script_instance()) { - return get_script_instance()->call("post_import", p_scene); + return get_script_instance()->call("_post_import", p_scene); } return p_scene; @@ -433,7 +433,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E p_node->replace_by(rigid_body); rigid_body->set_transform(mi->get_transform()); p_node = rigid_body; - mi->set_transform(Transform()); + mi->set_transform(Transform3D()); rigid_body->add_child(mi); mi->set_owner(rigid_body->get_owner()); @@ -632,7 +632,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< p_node->replace_by(rigid_body); rigid_body->set_transform(mi->get_transform()); p_node = rigid_body; - mi->set_transform(Transform()); + mi->set_transform(Transform3D()); rigid_body->add_child(mi); mi->set_owner(rigid_body->get_owner()); base = rigid_body; @@ -856,8 +856,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ new_anim->track_set_path(dtrack, default_anim->track_get_path(j)); if (kt > (from + 0.01) && k > 0) { - if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) { - Quat q; + if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) { + Quaternion q; Vector3 p; Vector3 s; default_anim->transform_track_interpolate(j, from, &p, &q, &s); @@ -870,8 +870,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ } } - if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) { - Quat q; + if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) { + Quaternion q; Vector3 p; Vector3 s; default_anim->transform_track_get_key(j, k, &p, &q, &s); @@ -884,8 +884,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ } if (dtrack != -1 && kt >= to) { - if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) { - Quat q; + if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) { + Quaternion q; Vector3 p; Vector3 s; default_anim->transform_track_interpolate(j, to, &p, &q, &s); @@ -902,8 +902,8 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_ new_anim->add_track(default_anim->track_get_type(j)); dtrack = new_anim->get_track_count() - 1; new_anim->track_set_path(dtrack, default_anim->track_get_path(j)); - if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM) { - Quat q; + if (default_anim->track_get_type(j) == Animation::TYPE_TRANSFORM3D) { + Quaternion q; Vector3 p; Vector3 s; default_anim->transform_track_interpolate(j, from, &p, &q, &s); @@ -1209,11 +1209,11 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m } if (bake_lightmaps) { - Transform xf; + Transform3D xf; Node3D *n = src_mesh_node; while (n) { xf = n->get_transform() * xf; - n = n->get_parent_spatial(); + n = n->get_parent_node_3d(); } Vector<uint8_t> lightmap_cache; @@ -1422,7 +1422,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } if (root_type != "Node3D") { - Node *base_node = Object::cast_to<Node>(ClassDB::instance(root_type)); + Node *base_node = Object::cast_to<Node>(ClassDB::instantiate(root_type)); if (base_node) { scene->replace_by(base_node); @@ -1508,7 +1508,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p if (!scene) { EditorNode::add_io_error( TTR("Error running post-import script:") + " " + post_import_script_path + "\n" + - TTR("Did you return a Node-derived object in the `post_import()` method?")); + TTR("Did you return a Node-derived object in the `_post_import()` method?")); return err; } } @@ -1557,7 +1557,7 @@ Node *EditorSceneImporterESCN::import_scene(const String &p_path, uint32_t p_fla Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error); ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'."); - Node *scene = ps->instance(); + Node *scene = ps->instantiate(); ERR_FAIL_COND_V(!scene, nullptr); return scene; diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 8cb84abce2..c6e5836a23 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -42,8 +42,8 @@ class Material; class AnimationPlayer; class EditorSceneImporterMesh; -class EditorSceneImporter : public Reference { - GDCLASS(EditorSceneImporter, Reference); +class EditorSceneImporter : public RefCounted { + GDCLASS(EditorSceneImporter, RefCounted); protected: static void _bind_methods(); @@ -69,8 +69,8 @@ public: EditorSceneImporter() {} }; -class EditorScenePostImport : public Reference { - GDCLASS(EditorScenePostImport, Reference); +class EditorScenePostImport : public RefCounted { + GDCLASS(EditorScenePostImport, RefCounted); String source_file; diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp index f4d20a6296..4d92490675 100644 --- a/editor/import/resource_importer_shader_file.cpp +++ b/editor/import/resource_importer_shader_file.cpp @@ -30,9 +30,9 @@ #include "resource_importer_shader_file.h" +#include "core/io/file_access.h" #include "core/io/marshalls.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "editor/editor_node.h" #include "editor/plugins/shader_file_editor_plugin.h" #include "servers/rendering/rendering_device_binds.h" @@ -99,7 +99,7 @@ Error ResourceImporterShaderFile::import(const String &p_source_file, const Stri String file_txt = file->get_as_utf8_string(); Ref<RDShaderFile> shader_file; - shader_file.instance(); + shader_file.instantiate(); String base_path = p_source_file.get_base_dir(); err = shader_file->parse_versions_from_text(file_txt, "", _include_function, &base_path); diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index de8031af35..daf7b15794 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -88,7 +88,7 @@ void ResourceImporterTexture::update_imports() { for (Map<StringName, MakeInfo>::Element *E = make_flags.front(); E; E = E->next()) { Ref<ConfigFile> cf; - cf.instance(); + cf.instantiate(); String src_path = String(E->key()) + ".import"; Error err = cf->load(src_path); @@ -208,7 +208,7 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options, r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "roughness/src_normal", PROPERTY_HINT_FILE, "*.bmp,*.dds,*.exr,*.jpeg,*.jpg,*.hdr,*.png,*.svg,*.svgz,*.tga,*.webp"), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/fix_alpha_border"), p_preset != PRESET_3D)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/premult_alpha"), false)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/invert_color"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/normal_map_invert_y"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "process/HDR_as_SRGB"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "process/size_limit", PROPERTY_HINT_RANGE, "0,4096,1"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "detect_3d/compress_to", PROPERTY_HINT_ENUM, "Disabled,VRAM Compressed,Basis Universal"), (p_preset == PRESET_DETECT) ? 1 : 0)); @@ -218,14 +218,21 @@ void ResourceImporterTexture::get_import_options(List<ImportOption> *r_options, void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image> &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality) { switch (p_compress_mode) { case COMPRESS_LOSSLESS: { - f->store_32(StreamTexture2D::DATA_FORMAT_LOSSLESS); + bool lossless_force_png = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/force_png"); + bool use_webp = !lossless_force_png && p_image->get_width() <= 16383 && p_image->get_height() <= 16383; // WebP has a size limit + f->store_32(use_webp ? StreamTexture2D::DATA_FORMAT_WEBP : StreamTexture2D::DATA_FORMAT_PNG); f->store_16(p_image->get_width()); f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); f->store_32(p_image->get_format()); for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) { - Vector<uint8_t> data = Image::lossless_packer(p_image->get_image_from_mipmap(i)); + Vector<uint8_t> data; + if (use_webp) { + data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i)); + } else { + data = Image::png_packer(p_image->get_image_from_mipmap(i)); + } int data_len = data.size(); f->store_32(data_len); @@ -235,14 +242,14 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image } break; case COMPRESS_LOSSY: { - f->store_32(StreamTexture2D::DATA_FORMAT_LOSSY); + f->store_32(StreamTexture2D::DATA_FORMAT_WEBP); f->store_16(p_image->get_width()); f->store_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); f->store_32(p_image->get_format()); for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) { - Vector<uint8_t> data = Image::lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality); + Vector<uint8_t> data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality); int data_len = data.size(); f->store_32(data_len); @@ -301,6 +308,7 @@ void ResourceImporterTexture::save_to_stex_format(FileAccess *f, const Ref<Image void ResourceImporterTexture::_save_stex(const Ref<Image> &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref<Image> &p_normal, Image::RoughnessChannel p_roughness_channel) { FileAccess *f = FileAccess::open(p_to_path, FileAccess::WRITE); + ERR_FAIL_NULL(f); f->store_8('G'); f->store_8('S'); f->store_8('T'); @@ -388,7 +396,7 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String uint32_t mipmap_limit = int(mipmaps ? int(p_options["mipmaps/limit"]) : int(-1)); bool fix_alpha_border = p_options["process/fix_alpha_border"]; bool premult_alpha = p_options["process/premult_alpha"]; - bool invert_color = p_options["process/invert_color"]; + bool normal_map_invert_y = p_options["process/normal_map_invert_y"]; bool stream = p_options["compress/streamed"]; int size_limit = p_options["process/size_limit"]; bool hdr_as_srgb = p_options["process/HDR_as_SRGB"]; @@ -403,13 +411,13 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String Image::RoughnessChannel roughness_channel = Image::ROUGHNESS_CHANNEL_R; if (mipmaps && roughness > 1 && FileAccess::exists(normal_map)) { - normal_image.instance(); + normal_image.instantiate(); if (ImageLoader::load_image(normal_map, normal_image) == OK) { roughness_channel = Image::RoughnessChannel(roughness - 2); } } Ref<Image> image; - image.instance(); + image.instantiate(); Error err = ImageLoader::load_image(p_source_file, image, nullptr, hdr_as_srgb, scale); if (err != OK) { return err; @@ -444,13 +452,18 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String image->premultiply_alpha(); } - if (invert_color) { - int height = image->get_height(); - int width = image->get_width(); + if (normal_map_invert_y) { + // Inverting the green channel can be used to flip a normal map's direction. + // There's no standard when it comes to normal map Y direction, so this is + // sometimes needed when using a normal map exported from another program. + // See <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details#Common_Swizzle_Coordinates>. + const int height = image->get_height(); + const int width = image->get_width(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { - image->set_pixel(i, j, image->get_pixel(i, j).inverted()); + const Color color = image->get_pixel(i, j); + image->set_pixel(i, j, Color(color.r, 1 - color.g, color.b)); } } } diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index 0d551a965c..41220009cd 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -31,9 +31,9 @@ #ifndef RESOURCEIMPORTTEXTURE_H #define RESOURCEIMPORTTEXTURE_H +#include "core/io/file_access.h" #include "core/io/image.h" #include "core/io/resource_importer.h" -#include "core/os/file_access.h" #include "scene/resources/texture.h" #include "servers/rendering_server.h" diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index 4c3ae59951..dec1466da1 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -31,10 +31,10 @@ #include "resource_importer_texture_atlas.h" #include "atlas_import_failed.xpm" +#include "core/io/file_access.h" #include "core/io/image_loader.h" #include "core/io/resource_saver.h" #include "core/math/geometry_2d.h" -#include "core/os/file_access.h" #include "editor/editor_atlas_packer.h" #include "scene/resources/mesh.h" #include "scene/resources/texture.h" @@ -87,7 +87,7 @@ Error ResourceImporterTextureAtlas::import(const String &p_source_file, const St //it's a simple hack Ref<Image> broken = memnew(Image((const char **)atlas_import_failed_xpm)); Ref<ImageTexture> broken_texture; - broken_texture.instance(); + broken_texture.instantiate(); broken_texture->create_from_image(broken); String target_file = p_save_path + ".tex"; @@ -201,7 +201,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file const Map<StringName, Variant> &options = E->get(); Ref<Image> image; - image.instance(); + image.instantiate(); Error err = ImageLoader::load_image(source, image); ERR_CONTINUE(err != OK); @@ -240,7 +240,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file pack_data.is_mesh = true; Ref<BitMap> bit_map; - bit_map.instance(); + bit_map.instantiate(); bit_map->create_from_image_alpha(image); Vector<Vector<Vector2>> polygons = bit_map->clip_opaque_to_polygons(Rect2(0, 0, image->get_width(), image->get_height())); @@ -272,7 +272,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file //blit the atlas Ref<Image> new_atlas; - new_atlas.instance(); + new_atlas.instantiate(); new_atlas->create(atlas_width, atlas_height, false, Image::FORMAT_RGBA8); for (int i = 0; i < pack_data_files.size(); i++) { @@ -303,7 +303,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file cache.reference_ptr(resptr); } else { Ref<ImageTexture> res_cache; - res_cache.instance(); + res_cache.instantiate(); res_cache->create_from_image(new_atlas); res_cache->set_path(p_group_file); cache = res_cache; @@ -321,7 +321,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file //region Ref<AtlasTexture> atlas_texture; - atlas_texture.instance(); + atlas_texture.instantiate(); atlas_texture->set_atlas(cache); atlas_texture->set_region(Rect2(offset, pack_data.region.size)); atlas_texture->set_margin(Rect2(pack_data.region.position, Size2(pack_data.image->get_width(), pack_data.image->get_height()) - pack_data.region.size)); @@ -329,7 +329,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file texture = atlas_texture; } else { Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); for (int i = 0; i < pack_data.chart_pieces.size(); i++) { const EditorAtlasPacker::Chart &chart = charts[pack_data.chart_pieces[i]]; @@ -375,7 +375,7 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file } Ref<MeshTexture> mesh_texture; - mesh_texture.instance(); + mesh_texture.instantiate(); mesh_texture->set_base_texture(cache); mesh_texture->set_image_size(pack_data.image->get_size()); mesh_texture->set_mesh(mesh); diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index bcc55b330b..2db1db9e51 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -30,9 +30,9 @@ #include "resource_importer_wav.h" +#include "core/io/file_access.h" #include "core/io/marshalls.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "scene/resources/audio_stream_sample.h" const float TRIM_DB_LIMIT = -50; @@ -78,7 +78,7 @@ void ResourceImporterWAV::get_import_options(List<ImportOption> *r_options, int r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/8_bit"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/mono"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force/max_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); - r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "force/max_rate_hz", PROPERTY_HINT_EXP_RANGE, "11025,192000,1"), 44100)); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "force/max_rate_hz", PROPERTY_HINT_RANGE, "11025,192000,1,exp"), 44100)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/trim"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/normalize"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "edit/loop"), false)); @@ -508,7 +508,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s } Ref<AudioStreamSample> sample; - sample.instance(); + sample.instantiate(); sample->set_data(dst_data); sample->set_format(dst_format); sample->set_mix_rate(rate); diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 488c124c28..f9f47ec4f4 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -317,7 +317,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) { if (mesh_node && mesh_node->get_mesh().is_valid()) { _fill_mesh(scene_tree, mesh_node->get_mesh(), item); - Transform accum_xform; + Transform3D accum_xform; Node3D *base = mesh_node; while (base) { accum_xform = base->get_transform() * accum_xform; @@ -379,7 +379,7 @@ void SceneImportSettings::_update_camera() { camera->set_orthogonal(camera_size * zoom, 0.0001, camera_size * 2); - Transform xf; + Transform3D xf; xf.basis = Basis(Vector3(0, 1, 0), rot_y) * Basis(Vector3(1, 0, 0), rot_x); xf.origin = center; xf.translate(0, 0, camera_size); @@ -435,7 +435,7 @@ void SceneImportSettings::open_settings(const String &p_path) { base_subresource_settings.clear(); Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(p_path + ".import"); if (err == OK) { List<String> keys; @@ -493,7 +493,7 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) { Ref<Mesh> base_mesh = mi->get_mesh(); if (base_mesh.is_valid()) { AABB aabb = base_mesh->get_aabb(); - Transform aabb_xf; + Transform3D aabb_xf; aabb_xf.basis.scale(aabb.size); aabb_xf.origin = aabb.position; @@ -1099,18 +1099,18 @@ SceneImportSettings::SceneImportSettings() { camera->make_current(); light = memnew(DirectionalLight3D); - light->set_transform(Transform().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0))); + light->set_transform(Transform3D().looking_at(Vector3(-1, -2, -0.6), Vector3(0, 1, 0))); base_viewport->add_child(light); light->set_shadow(true); { Ref<StandardMaterial3D> selection_mat; - selection_mat.instance(); + selection_mat.instantiate(); selection_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); selection_mat->set_albedo(Color(1, 0.8, 1.0)); Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->begin(Mesh::PRIMITIVE_LINES); AABB base_aabb; @@ -1126,7 +1126,7 @@ SceneImportSettings::SceneImportSettings() { st->add_vertex(b.lerp(a, 0.2)); } - selection_mesh.instance(); + selection_mesh.instantiate(); st->commit(selection_mesh); selection_mesh->surface_set_material(0, selection_mat); @@ -1141,7 +1141,7 @@ SceneImportSettings::SceneImportSettings() { base_viewport->add_child(mesh_preview); mesh_preview->hide(); - material_preview.instance(); + material_preview.instantiate(); } inspector = memnew(EditorInspector); @@ -1163,13 +1163,13 @@ SceneImportSettings::SceneImportSettings() { external_path_tree->set_columns(3); external_path_tree->set_column_titles_visible(true); external_path_tree->set_column_expand(0, true); - external_path_tree->set_column_min_width(0, 100 * EDSCALE); + external_path_tree->set_column_custom_minimum_width(0, 100 * EDSCALE); external_path_tree->set_column_title(0, TTR("Resource")); external_path_tree->set_column_expand(1, true); - external_path_tree->set_column_min_width(1, 100 * EDSCALE); + external_path_tree->set_column_custom_minimum_width(1, 100 * EDSCALE); external_path_tree->set_column_title(1, TTR("Path")); external_path_tree->set_column_expand(2, false); - external_path_tree->set_column_min_width(2, 200 * EDSCALE); + external_path_tree->set_column_custom_minimum_width(2, 200 * EDSCALE); external_path_tree->set_column_title(2, TTR("Status")); save_path = memnew(EditorFileDialog); save_path->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_DIR); diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp index fa1a027a8d..f8e93df382 100644 --- a/editor/import/scene_importer_mesh.cpp +++ b/editor/import/scene_importer_mesh.cpp @@ -215,6 +215,7 @@ void EditorSceneImporterMesh::generate_lods() { int index_target = indices.size() * threshold; float max_mesh_error_percentage = 1e0f; float mesh_error = 0.0f; + float scale = SurfaceTool::simplify_scale_func((const float *)vertices_ptr, vertex_count, sizeof(Vector3)); while (index_target > min_indices) { Vector<int> new_indices; new_indices.resize(indices.size()); @@ -223,8 +224,8 @@ void EditorSceneImporterMesh::generate_lods() { break; } Surface::LOD lod; - lod.distance = mesh_error; - if (Math::is_equal_approx(mesh_error, 0.0f)) { + lod.distance = mesh_error * scale; + if (Math::is_zero_approx(mesh_error)) { break; } if (new_len <= 0) { @@ -251,7 +252,7 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<Mesh> &p_base) { mesh = p_base; } if (mesh.is_null()) { - mesh.instance(); + mesh.instantiate(); } mesh->set_name(get_name()); if (has_meta("import_id")) { @@ -320,7 +321,7 @@ void EditorSceneImporterMesh::create_shadow_mesh() { } } - shadow_mesh.instance(); + shadow_mesh.instantiate(); for (int i = 0; i < surfaces.size(); i++) { LocalVector<int> vertex_remap; @@ -505,7 +506,7 @@ Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose() const { const Vector<Face3> faces = get_faces(); - Vector<Vector<Face3>> decomposed = Mesh::convex_composition_function(faces); + Vector<Vector<Face3>> decomposed = Mesh::convex_composition_function(faces, -1); Vector<Ref<Shape3D>> ret; @@ -528,7 +529,7 @@ Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose() const { } Ref<ConvexPolygonShape3D> shape; - shape.instance(); + shape.instantiate(); shape->set_points(convex_points); ret.push_back(shape); } @@ -587,7 +588,7 @@ Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() { } Ref<NavigationMesh> nm; - nm.instance(); + nm.instantiate(); nm->set_vertices(vertices); Vector<int> v3; @@ -612,7 +613,7 @@ struct EditorSceneImporterMeshLightmapSurface { String name; }; -Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) { +Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) { ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes."); @@ -628,7 +629,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform &p_base_tr Basis basis = p_base_transform.get_basis(); Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length()); - Transform transform; + Transform3D transform; transform.scale(scale); Basis normal_basis = transform.basis.inverse().transposed(); @@ -733,7 +734,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform &p_base_tr for (int i = 0; i < lightmap_surfaces.size(); i++) { Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->begin(Mesh::PRIMITIVE_TRIANGLES); st->set_material(lightmap_surfaces[i].material); st->set_meta("name", lightmap_surfaces[i].name); diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h index c00339a620..2488de7ed0 100644 --- a/editor/import/scene_importer_mesh.h +++ b/editor/import/scene_importer_mesh.h @@ -106,7 +106,7 @@ public: Vector<Ref<Shape3D>> convex_decompose() const; Ref<Shape3D> create_trimesh_shape() const; Ref<NavigationMesh> create_navigation_mesh(); - Error lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache); + Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache); void set_lightmap_size_hint(const Size2i &p_size); Size2i get_lightmap_size_hint() const; diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 17c51f0f85..6fa9864830 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -91,7 +91,7 @@ public: void ImportDock::set_edit_path(const String &p_path) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(p_path + ".import"); if (err != OK) { clear(); @@ -182,7 +182,7 @@ void ImportDock::set_edit_multiple_paths(const Vector<String> &p_paths) { for (int i = 0; i < p_paths.size(); i++) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(p_paths[i] + ".import"); ERR_CONTINUE(err != OK); @@ -328,7 +328,7 @@ void ImportDock::_importer_selected(int i_idx) { Ref<ConfigFile> config; if (params->paths.size()) { - config.instance(); + config.instantiate(); Error err = config->load(params->paths[0] + ".import"); if (err != OK) { config.unref(); @@ -440,7 +440,7 @@ void ImportDock::_reimport_attempt() { } for (int i = 0; i < params->paths.size(); i++) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(params->paths[i] + ".import"); ERR_CONTINUE(err != OK); @@ -477,7 +477,7 @@ void ImportDock::_advanced_options() { void ImportDock::_reimport() { for (int i = 0; i < params->paths.size(); i++) { Ref<ConfigFile> config; - config.instance(); + config.instantiate(); Error err = config->load(params->paths[i] + ".import"); ERR_CONTINUE(err != OK); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 6265dfc2e4..e8c01d0e0c 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -42,6 +42,14 @@ void InspectorDock::_menu_option(int p_option) { case COLLAPSE_ALL: { _menu_collapseall(); } break; + + case RESOURCE_SAVE: { + _save_resource(false); + } break; + case RESOURCE_SAVE_AS: { + _save_resource(true); + } break; + case RESOURCE_MAKE_BUILT_IN: { _unref_resource(); } break; @@ -52,13 +60,6 @@ void InspectorDock::_menu_option(int p_option) { _paste_resource(); } break; - case RESOURCE_SAVE: { - _save_resource(false); - } break; - case RESOURCE_SAVE_AS: { - _save_resource(true); - } break; - case OBJECT_REQUEST_HELP: { if (current) { editor->set_visible_editor(EditorNode::EDITOR_SCRIPT); @@ -313,7 +314,7 @@ void InspectorDock::_property_keyed(const String &p_keyed, const Variant &p_valu AnimationPlayerEditor::singleton->get_track_editor()->insert_value_key(p_keyed, p_value, p_advance); } -void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform &p_key) { +void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform3D &p_key) { Node3D *s = Object::cast_to<Node3D>(sp); if (!s) { return; @@ -335,9 +336,16 @@ void InspectorDock::_notification(int p_what) { case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { set_theme(editor->get_gui_base()->get_theme()); + resource_new_button->set_icon(get_theme_icon("New", "EditorIcons")); resource_load_button->set_icon(get_theme_icon("Load", "EditorIcons")); resource_save_button->set_icon(get_theme_icon("Save", "EditorIcons")); + resource_extra_button->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons")); + + PopupMenu *resource_extra_popup = resource_extra_button->get_popup(); + resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_EDIT_CLIPBOARD), get_theme_icon("ActionPaste", "EditorIcons")); + resource_extra_popup->set_item_icon(resource_extra_popup->get_item_index(RESOURCE_COPY), get_theme_icon("ActionCopy", "EditorIcons")); + if (is_layout_rtl()) { backward_button->set_icon(get_theme_icon("Forward", "EditorIcons")); forward_button->set_icon(get_theme_icon("Back", "EditorIcons")); @@ -345,6 +353,7 @@ void InspectorDock::_notification(int p_what) { backward_button->set_icon(get_theme_icon("Back", "EditorIcons")); forward_button->set_icon(get_theme_icon("Forward", "EditorIcons")); } + history_menu->set_icon(get_theme_icon("History", "EditorIcons")); object_menu->set_icon(get_theme_icon("Tools", "EditorIcons")); warning->set_icon(get_theme_icon("NodeWarning", "EditorIcons")); @@ -403,12 +412,7 @@ void InspectorDock::update(Object *p_object) { object_menu->set_disabled(true); warning->hide(); search->set_editable(false); - - editor_path->set_disabled(true); - editor_path->set_text(""); - editor_path->set_tooltip(""); - editor_path->set_icon(nullptr); - + editor_path->clear_path(); return; } @@ -417,35 +421,28 @@ void InspectorDock::update(Object *p_object) { object_menu->set_disabled(false); search->set_editable(true); - editor_path->set_disabled(false); + editor_path->enable_path(); + resource_save_button->set_disabled(!is_resource); + open_docs_button->set_visible(is_resource || is_node); + + PopupMenu *resource_extra_popup = resource_extra_button->get_popup(); + resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_COPY), !is_resource); + resource_extra_popup->set_item_disabled(resource_extra_popup->get_item_index(RESOURCE_MAKE_BUILT_IN), !is_resource); PopupMenu *p = object_menu->get_popup(); p->clear(); - p->add_shortcut(ED_SHORTCUT("property_editor/expand_all", TTR("Expand All Properties")), EXPAND_ALL); - p->add_shortcut(ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse All Properties")), COLLAPSE_ALL); - p->add_separator(); - if (is_resource) { - p->add_item(TTR("Save"), RESOURCE_SAVE); - p->add_item(TTR("Save As..."), RESOURCE_SAVE_AS); - p->add_separator(); - } - p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS); - p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS); + p->add_icon_shortcut(get_theme_icon("GuiTreeArrowDown", "EditorIcons"), ED_SHORTCUT("property_editor/expand_all", TTR("Expand All")), EXPAND_ALL); + p->add_icon_shortcut(get_theme_icon("GuiTreeArrowRight", "EditorIcons"), ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse All")), COLLAPSE_ALL); p->add_separator(); - p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource Clipboard")), RESOURCE_EDIT_CLIPBOARD); - if (is_resource) { - p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY); - p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_MAKE_BUILT_IN); - } + p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Properties")), OBJECT_COPY_PARAMS); + p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Properties")), OBJECT_PASTE_PARAMS); if (is_resource || is_node) { p->add_separator(); p->add_shortcut(ED_SHORTCUT("property_editor/make_subresources_unique", TTR("Make Sub-Resources Unique")), OBJECT_UNIQUE_RESOURCES); - p->add_separator(); - p->add_icon_shortcut(get_theme_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP); } List<MethodInfo> methods; @@ -525,6 +522,17 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { resource_save_button->set_focus_mode(Control::FOCUS_NONE); resource_save_button->set_disabled(true); + resource_extra_button = memnew(MenuButton); + resource_extra_button->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons")); + general_options_hb->add_child(resource_extra_button); + resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon("ActionPaste", "EditorIcons"), ED_SHORTCUT("property_editor/paste_resource", TTR("Edit Resource from Clipboard")), RESOURCE_EDIT_CLIPBOARD); + resource_extra_button->get_popup()->add_icon_shortcut(get_theme_icon("ActionCopy", "EditorIcons"), ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY); + resource_extra_button->get_popup()->set_item_disabled(1, true); + resource_extra_button->get_popup()->add_separator(); + resource_extra_button->get_popup()->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Resource Built-In")), RESOURCE_MAKE_BUILT_IN); + resource_extra_button->get_popup()->set_item_disabled(3, true); + resource_extra_button->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); + general_options_hb->add_spacer(); backward_button = memnew(Button); @@ -558,31 +566,42 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { history_menu->connect("about_to_popup", callable_mp(this, &InspectorDock::_prepare_history)); history_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_select_history)); - HBoxContainer *node_info_hb = memnew(HBoxContainer); - add_child(node_info_hb); - + HBoxContainer *subresource_hb = memnew(HBoxContainer); + add_child(subresource_hb); editor_path = memnew(EditorPath(editor->get_editor_history())); editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); - node_info_hb->add_child(editor_path); + subresource_hb->add_child(editor_path); - object_menu = memnew(MenuButton); - object_menu->set_shortcut_context(this); - object_menu->set_icon(get_theme_icon("Tools", "EditorIcons")); - node_info_hb->add_child(object_menu); - object_menu->set_tooltip(TTR("Object properties.")); - object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); + open_docs_button = memnew(Button); + open_docs_button->set_flat(true); + open_docs_button->set_visible(false); + open_docs_button->set_tooltip(TTR("Open documentation for this object.")); + open_docs_button->set_icon(get_theme_icon("HelpSearch", "EditorIcons")); + open_docs_button->set_shortcut(ED_SHORTCUT("property_editor/open_help", TTR("Open Documentation"))); + subresource_hb->add_child(open_docs_button); + open_docs_button->connect("pressed", callable_mp(this, &InspectorDock::_menu_option), varray(OBJECT_REQUEST_HELP)); new_resource_dialog = memnew(CreateDialog); editor->get_gui_base()->add_child(new_resource_dialog); new_resource_dialog->set_base_type("Resource"); new_resource_dialog->connect("create", callable_mp(this, &InspectorDock::_resource_created)); + HBoxContainer *property_tools_hb = memnew(HBoxContainer); + add_child(property_tools_hb); + search = memnew(LineEdit); search->set_h_size_flags(Control::SIZE_EXPAND_FILL); search->set_placeholder(TTR("Filter properties")); search->set_right_icon(get_theme_icon("Search", "EditorIcons")); search->set_clear_button_enabled(true); - add_child(search); + property_tools_hb->add_child(search); + + object_menu = memnew(MenuButton); + object_menu->set_shortcut_context(this); + object_menu->set_icon(get_theme_icon("Tools", "EditorIcons")); + property_tools_hb->add_child(object_menu); + object_menu->set_tooltip(TTR("Manage object properties.")); + object_menu->get_popup()->connect("id_pressed", callable_mp(this, &InspectorDock::_menu_option)); warning = memnew(Button); add_child(warning); diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h index 6a3f8c679c..d50785d95c 100644 --- a/editor/inspector_dock.h +++ b/editor/inspector_dock.h @@ -81,9 +81,11 @@ class InspectorDock : public VBoxContainer { Button *resource_new_button; Button *resource_load_button; MenuButton *resource_save_button; + MenuButton *resource_extra_button; MenuButton *history_menu; LineEdit *search; + Button *open_docs_button; MenuButton *object_menu; EditorPath *editor_path; @@ -112,7 +114,7 @@ class InspectorDock : public VBoxContainer { void _prepare_history(); void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance); - void _transform_keyed(Object *sp, const String &p_sub, const Transform &p_key); + void _transform_keyed(Object *sp, const String &p_sub, const Transform3D &p_key); protected: static void _bind_methods(); diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp index 161f1dde0d..208d4437d3 100644 --- a/editor/localization_editor.cpp +++ b/editor/localization_editor.cpp @@ -728,8 +728,10 @@ LocalizationEditor::LocalizationEditor() { translation_remap_options->set_column_title(1, TTR("Locale")); translation_remap_options->set_column_titles_visible(true); translation_remap_options->set_column_expand(0, true); + translation_remap_options->set_column_clip_content(0, true); translation_remap_options->set_column_expand(1, false); - translation_remap_options->set_column_min_width(1, 200); + translation_remap_options->set_column_clip_content(1, true); + translation_remap_options->set_column_custom_minimum_width(1, 200); translation_remap_options->connect("item_edited", callable_mp(this, &LocalizationEditor::_translation_res_option_changed)); translation_remap_options->connect("button_pressed", callable_mp(this, &LocalizationEditor::_translation_res_option_delete)); tmc->add_child(translation_remap_options); diff --git a/editor/multi_node_edit.h b/editor/multi_node_edit.h index 0544eb2d50..2efecb9f65 100644 --- a/editor/multi_node_edit.h +++ b/editor/multi_node_edit.h @@ -33,8 +33,8 @@ #include "scene/main/node.h" -class MultiNodeEdit : public Reference { - GDCLASS(MultiNodeEdit, Reference); +class MultiNodeEdit : public RefCounted { + GDCLASS(MultiNodeEdit, RefCounted); List<NodePath> nodes; struct PLData { diff --git a/editor/node_3d_editor_gizmos.cpp b/editor/node_3d_editor_gizmos.cpp index cc261ea868..2a399f4b03 100644 --- a/editor/node_3d_editor_gizmos.cpp +++ b/editor/node_3d_editor_gizmos.cpp @@ -34,15 +34,14 @@ #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" #include "scene/3d/audio_stream_player_3d.h" -#include "scene/3d/baked_lightmap.h" #include "scene/3d/collision_polygon_3d.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/cpu_particles_3d.h" #include "scene/3d/decal.h" -#include "scene/3d/gi_probe.h" #include "scene/3d/gpu_particles_3d.h" #include "scene/3d/gpu_particles_collision_3d.h" #include "scene/3d/light_3d.h" +#include "scene/3d/lightmap_gi.h" #include "scene/3d/lightmap_probe.h" #include "scene/3d/listener_3d.h" #include "scene/3d/mesh_instance_3d.h" @@ -56,7 +55,8 @@ #include "scene/3d/spring_arm_3d.h" #include "scene/3d/sprite_3d.h" #include "scene/3d/vehicle_body_3d.h" -#include "scene/3d/visibility_notifier_3d.h" +#include "scene/3d/visible_on_screen_notifier_3d.h" +#include "scene/3d/voxel_gi.h" #include "scene/resources/box_shape_3d.h" #include "scene/resources/capsule_shape_3d.h" #include "scene/resources/concave_polygon_shape_3d.h" @@ -104,8 +104,8 @@ void EditorNode3DGizmo::clear() { } void EditorNode3DGizmo::redraw() { - if (get_script_instance() && get_script_instance()->has_method("redraw")) { - get_script_instance()->call("redraw"); + if (get_script_instance() && get_script_instance()->has_method("_redraw")) { + get_script_instance()->call("_redraw"); return; } @@ -114,8 +114,8 @@ void EditorNode3DGizmo::redraw() { } String EditorNode3DGizmo::get_handle_name(int p_idx) const { - if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) { - return get_script_instance()->call("get_handle_name", p_idx); + if (get_script_instance() && get_script_instance()->has_method("_get_handle_name")) { + return get_script_instance()->call("_get_handle_name", p_idx); } ERR_FAIL_COND_V(!gizmo_plugin, ""); @@ -123,8 +123,8 @@ String EditorNode3DGizmo::get_handle_name(int p_idx) const { } bool EditorNode3DGizmo::is_handle_highlighted(int p_idx) const { - if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) { - return get_script_instance()->call("is_handle_highlighted", p_idx); + if (get_script_instance() && get_script_instance()->has_method("_is_handle_highlighted")) { + return get_script_instance()->call("_is_handle_highlighted", p_idx); } ERR_FAIL_COND_V(!gizmo_plugin, false); @@ -132,8 +132,8 @@ bool EditorNode3DGizmo::is_handle_highlighted(int p_idx) const { } Variant EditorNode3DGizmo::get_handle_value(int p_idx) { - if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) { - return get_script_instance()->call("get_handle_value", p_idx); + if (get_script_instance() && get_script_instance()->has_method("_get_handle_value")) { + return get_script_instance()->call("_get_handle_value", p_idx); } ERR_FAIL_COND_V(!gizmo_plugin, Variant()); @@ -141,8 +141,8 @@ Variant EditorNode3DGizmo::get_handle_value(int p_idx) { } void EditorNode3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_point) { - if (get_script_instance() && get_script_instance()->has_method("set_handle")) { - get_script_instance()->call("set_handle", p_idx, p_camera, p_point); + if (get_script_instance() && get_script_instance()->has_method("_set_handle")) { + get_script_instance()->call("_set_handle", p_idx, p_camera, p_point); return; } @@ -151,8 +151,8 @@ void EditorNode3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 & } void EditorNode3DGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) { - if (get_script_instance() && get_script_instance()->has_method("commit_handle")) { - get_script_instance()->call("commit_handle", p_idx, p_restore, p_cancel); + if (get_script_instance() && get_script_instance()->has_method("_commit_handle")) { + get_script_instance()->call("_commit_handle", p_idx, p_restore, p_cancel); return; } @@ -455,7 +455,7 @@ bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector int vc = collision_segments.size(); const Vector3 *vptr = collision_segments.ptr(); - Transform t = spatial_node->get_global_transform(); + Transform3D t = spatial_node->get_global_transform(); bool any_out = false; for (int j = 0; j < fc; j++) { @@ -477,12 +477,12 @@ bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector } if (collision_mesh.is_valid()) { - Transform t = spatial_node->get_global_transform(); + Transform3D t = spatial_node->get_global_transform(); Vector3 mesh_scale = t.get_basis().get_scale(); t.orthonormalize(); - Transform it = t.affine_inverse(); + Transform3D it = t.affine_inverse(); Vector<Plane> transformed_frustum; @@ -508,7 +508,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, } if (r_gizmo_handle && !hidden) { - Transform t = spatial_node->get_global_transform(); + Transform3D t = spatial_node->get_global_transform(); if (billboard_handle) { t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1)); } @@ -560,7 +560,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, } if (selectable_icon_size > 0.0f) { - Transform t = spatial_node->get_global_transform(); + Transform3D t = spatial_node->get_global_transform(); Vector3 camera_position = p_camera->get_camera_transform().origin; if (camera_position.distance_squared_to(t.origin) > 0.01) { t.set_look_at(t.origin, camera_position); @@ -576,7 +576,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, Point2 center = p_camera->unproject_position(t.origin); - Transform orig_camera_transform = p_camera->get_camera_transform(); + Transform3D orig_camera_transform = p_camera->get_camera_transform(); if (orig_camera_transform.origin.distance_squared_to(t.origin) > 0.01 && ABS(orig_camera_transform.basis.get_axis(Vector3::AXIS_Z).dot(Vector3(0, 1, 0))) < 0.99) { @@ -600,8 +600,6 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, r_normal = -p_camera->project_ray_normal(p_point); return true; } - - return false; } if (collision_segments.size()) { @@ -609,7 +607,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, int vc = collision_segments.size(); const Vector3 *vptr = collision_segments.ptr(); - Transform t = spatial_node->get_global_transform(); + Transform3D t = spatial_node->get_global_transform(); if (billboard_handle) { t.set_look_at(t.origin, t.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1)); } @@ -652,18 +650,16 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, r_normal = -p_camera->project_ray_normal(p_point); return true; } - - return false; } if (collision_mesh.is_valid()) { - Transform gt = spatial_node->get_global_transform(); + Transform3D gt = spatial_node->get_global_transform(); if (billboard_handle) { gt.set_look_at(gt.origin, gt.origin - p_camera->get_transform().basis.get_axis(2), p_camera->get_transform().basis.get_axis(1)); } - Transform ai = gt.affine_inverse(); + Transform3D ai = gt.affine_inverse(); Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point)); Vector3 ray_dir = ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized(); Vector3 rpos, rnorm; @@ -739,16 +735,16 @@ void EditorNode3DGizmo::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &EditorNode3DGizmo::clear); ClassDB::bind_method(D_METHOD("set_hidden", "hidden"), &EditorNode3DGizmo::set_hidden); - BIND_VMETHOD(MethodInfo("redraw")); - BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", PropertyInfo(Variant::INT, "index"))); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", PropertyInfo(Variant::INT, "index"))); + BIND_VMETHOD(MethodInfo("_redraw")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_handle_name", PropertyInfo(Variant::INT, "index"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_handle_highlighted", PropertyInfo(Variant::INT, "index"))); - MethodInfo hvget(Variant::NIL, "get_handle_value", PropertyInfo(Variant::INT, "index")); + MethodInfo hvget(Variant::NIL, "_get_handle_value", PropertyInfo(Variant::INT, "index")); hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; BIND_VMETHOD(hvget); - BIND_VMETHOD(MethodInfo("set_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point"))); - MethodInfo cm = MethodInfo("commit_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel")); + BIND_VMETHOD(MethodInfo("_set_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point"))); + MethodInfo cm = MethodInfo("_commit_handle", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel")); cm.default_arguments.push_back(false); BIND_VMETHOD(cm); } @@ -759,7 +755,7 @@ EditorNode3DGizmo::EditorNode3DGizmo() { hidden = false; base = nullptr; selected = false; - instanced = false; + instantiated = false; spatial_node = nullptr; gizmo_plugin = nullptr; selectable_icon_size = -1.0f; @@ -826,7 +822,7 @@ Variant Light3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_i return Variant(); } -static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform &p_arc_xform) { +static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vector3 &p_to, float p_arc_radius, const Transform3D &p_arc_xform) { //bleh, discrete is simpler static const int arc_test_points = 64; float min_d = 1e20; @@ -855,8 +851,8 @@ static float _find_closest_angle_to_half_pi_arc(const Vector3 &p_from, const Vec void Light3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { Light3D *light = Object::cast_to<Light3D>(p_gizmo->get_spatial_node()); - Transform gt = light->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = light->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -1084,8 +1080,8 @@ Variant AudioStreamPlayer3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gi void AudioStreamPlayer3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_spatial_node()); - Transform gt = player->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = player->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -1230,8 +1226,8 @@ Variant Camera3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_ void Camera3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { Camera3D *camera = Object::cast_to<Camera3D>(p_gizmo->get_spatial_node()); - Transform gt = camera->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = camera->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -1239,7 +1235,7 @@ void Camera3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Came Vector3 s[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) }; if (camera->get_projection() == Camera3D::PROJECTION_PERSPECTIVE) { - Transform gt2 = camera->get_global_transform(); + Transform3D gt2 = camera->get_global_transform(); float a = _find_closest_angle_to_half_pi_arc(s[0], s[1], 1.0, gt2); camera->set("fov", CLAMP(a * 2.0, 1, 179)); } else { @@ -1418,7 +1414,7 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { lines.push_back(cam_pos); } - Transform local = camera->get_global_transform().affine_inverse(); + Transform3D local = camera->get_global_transform().affine_inverse(); for (int i = 0; i < lines.size(); i++) { lines.write[i] = local.xform(lines[i]); } @@ -1541,19 +1537,46 @@ Position3DGizmoPlugin::Position3DGizmoPlugin() { cursor_points = Vector<Vector3>(); Vector<Color> cursor_colors; - float cs = 0.25; + const float cs = 0.25; + // Add more points to create a "hard stop" in the color gradient. cursor_points.push_back(Vector3(+cs, 0, 0)); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3()); cursor_points.push_back(Vector3(-cs, 0, 0)); + cursor_points.push_back(Vector3(0, +cs, 0)); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3()); cursor_points.push_back(Vector3(0, -cs, 0)); + cursor_points.push_back(Vector3(0, 0, +cs)); + cursor_points.push_back(Vector3()); + cursor_points.push_back(Vector3()); cursor_points.push_back(Vector3(0, 0, -cs)); - cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_x_color", "Editor")); - cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_x_color", "Editor")); - cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_y_color", "Editor")); - cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_y_color", "Editor")); - cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_z_color", "Editor")); - cursor_colors.push_back(EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_z_color", "Editor")); + + // Use the axis color which is brighter for the positive axis. + // Use a darkened axis color for the negative axis. + // This makes it possible to see in which direction the Position3D node is rotated + // (which can be important depending on how it's used). + const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_x_color", "Editor"); + cursor_colors.push_back(color_x); + cursor_colors.push_back(color_x); + // FIXME: Use less strong darkening factor once GH-48573 is fixed. + // The current darkening factor compensates for lines being too bright in the 3D editor. + cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75)); + cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75)); + + const Color color_y = EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_y_color", "Editor"); + cursor_colors.push_back(color_y); + cursor_colors.push_back(color_y); + cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75)); + cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75)); + + const Color color_z = EditorNode::get_singleton()->get_gui_base()->get_theme_color("axis_z_color", "Editor"); + cursor_colors.push_back(color_z); + cursor_colors.push_back(color_z); + cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75)); + cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75)); Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D); mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); @@ -1617,7 +1640,7 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { surface_tool->begin(Mesh::PRIMITIVE_LINES); surface_tool->set_material(material); - Vector<Transform> grests; + Vector<Transform3D> grests; grests.resize(skel->get_bone_count()); Vector<int> bones; @@ -1731,59 +1754,10 @@ void Skeleton3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { surface_tool->set_color(bonecolor); surface_tool->add_vertex(points[(j + 1) % 4]); } - - /* - bones[0]=parent; - surface_tool->add_bones(bones); - surface_tool->add_weights(weights); - surface_tool->add_color(Color(0.4,1,0.4,0.4)); - surface_tool->add_vertex(v0); - bones[0]=i; - surface_tool->add_bones(bones); - surface_tool->add_weights(weights); - surface_tool->add_color(Color(0.4,1,0.4,0.4)); - surface_tool->add_vertex(v1); -*/ } else { grests.write[i] = skel->get_bone_rest(i); bones.write[0] = i; } - /* - Transform t = grests[i]; - t.orthonormalize(); - - for (int i=0;i<6;i++) { - - - Vector3 face_points[4]; - - for (int j=0;j<4;j++) { - float v[3]; - v[0]=1.0; - v[1]=1-2*((j>>1)&1); - v[2]=v[1]*(1-2*(j&1)); - - for (int k=0;k<3;k++) { - if (i<3) - face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1); - else - face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1); - } - } - - for(int j=0;j<4;j++) { - surface_tool->add_bones(bones); - surface_tool->add_weights(weights); - surface_tool->add_color(Color(1.0,0.4,0.4,0.4)); - surface_tool->add_vertex(t.xform(face_points[j]*0.04)); - surface_tool->add_bones(bones); - surface_tool->add_weights(weights); - surface_tool->add_color(Color(1.0,0.4,0.4,0.4)); - surface_tool->add_vertex(t.xform(face_points[(j+1)%4]*0.04)); - } - - } - */ } Ref<ArrayMesh> m = surface_tool->commit(); @@ -2149,7 +2123,7 @@ bool SoftBody3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_giz /////////// -VisibilityNotifier3DGizmoPlugin::VisibilityNotifier3DGizmoPlugin() { +VisibleOnScreenNotifier3DGizmoPlugin::VisibleOnScreenNotifier3DGizmoPlugin() { Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7)); create_material("visibility_notifier_material", gizmo_color); gizmo_color.a = 0.1; @@ -2157,19 +2131,19 @@ VisibilityNotifier3DGizmoPlugin::VisibilityNotifier3DGizmoPlugin() { create_handle_material("handles"); } -bool VisibilityNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to<VisibilityNotifier3D>(p_spatial) != nullptr; +bool VisibleOnScreenNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to<VisibleOnScreenNotifier3D>(p_spatial) != nullptr; } -String VisibilityNotifier3DGizmoPlugin::get_gizmo_name() const { - return "VisibilityNotifier3D"; +String VisibleOnScreenNotifier3DGizmoPlugin::get_gizmo_name() const { + return "VisibleOnScreenNotifier3D"; } -int VisibilityNotifier3DGizmoPlugin::get_priority() const { +int VisibleOnScreenNotifier3DGizmoPlugin::get_priority() const { return -1; } -String VisibilityNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { +String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { switch (p_idx) { case 0: return "Size X"; @@ -2188,17 +2162,17 @@ String VisibilityNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo return ""; } -Variant VisibilityNotifier3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { - VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node()); +Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { + VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node()); return notifier->get_aabb(); } -void VisibilityNotifier3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { - VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node()); +void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { + VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node()); - Transform gt = notifier->get_global_transform(); + Transform3D gt = notifier->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gi = gt.affine_inverse(); bool move = p_idx >= 3; p_idx = p_idx % 3; @@ -2245,8 +2219,8 @@ void VisibilityNotifier3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int } } -void VisibilityNotifier3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { - VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node()); +void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node()); if (p_cancel) { notifier->set_aabb(p_restore); @@ -2260,8 +2234,8 @@ void VisibilityNotifier3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, ur->commit_action(); } -void VisibilityNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - VisibilityNotifier3D *notifier = Object::cast_to<VisibilityNotifier3D>(p_gizmo->get_spatial_node()); +void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_spatial_node()); p_gizmo->clear(); @@ -2388,8 +2362,8 @@ Variant GPUParticles3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, void GPUParticles3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_spatial_node()); - Transform gt = particles->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = particles->get_global_transform(); + Transform3D gi = gt.affine_inverse(); bool move = p_idx >= 3; p_idx = p_idx % 3; @@ -2555,8 +2529,8 @@ Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(EditorNode3DGizmo * void GPUParticlesCollision3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { Node3D *sn = p_gizmo->get_spatial_node(); - Transform gt = sn->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = sn->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -2814,9 +2788,9 @@ Variant ReflectionProbeGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, void ReflectionProbeGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_spatial_node()); - Transform gt = probe->get_global_transform(); + Transform3D gt = probe->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gi = gt.affine_inverse(); if (p_idx < 3) { Vector3 extents = probe->get_extents(); @@ -2993,9 +2967,9 @@ Variant DecalGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx void DecalGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { Decal *decal = Object::cast_to<Decal>(p_gizmo->get_spatial_node()); - Transform gt = decal->get_global_transform(); + Transform3D gt = decal->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gi = gt.affine_inverse(); Vector3 extents = decal->get_extents(); @@ -3086,35 +3060,35 @@ void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } /////////////////////////////// -GIProbeGizmoPlugin::GIProbeGizmoPlugin() { - Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); +VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() { + Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6)); - create_material("gi_probe_material", gizmo_color); + create_material("voxel_gi_material", gizmo_color); // This gizmo draws a lot of lines. Use a low opacity to make it not too intrusive. gizmo_color.a = 0.1; - create_material("gi_probe_internal_material", gizmo_color); + create_material("voxel_gi_internal_material", gizmo_color); gizmo_color.a = 0.05; - create_material("gi_probe_solid_material", gizmo_color); + create_material("voxel_gi_solid_material", gizmo_color); - create_icon_material("gi_probe_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoGIProbe", "EditorIcons")); + create_icon_material("voxel_gi_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoVoxelGI", "EditorIcons")); create_handle_material("handles"); } -bool GIProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to<GIProbe>(p_spatial) != nullptr; +bool VoxelGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to<VoxelGI>(p_spatial) != nullptr; } -String GIProbeGizmoPlugin::get_gizmo_name() const { - return "GIProbe"; +String VoxelGIGizmoPlugin::get_gizmo_name() const { + return "VoxelGI"; } -int GIProbeGizmoPlugin::get_priority() const { +int VoxelGIGizmoPlugin::get_priority() const { return -1; } -String GIProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { +String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { switch (p_idx) { case 0: return "Extents X"; @@ -3127,16 +3101,16 @@ String GIProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int return ""; } -Variant GIProbeGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { - GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); +Variant VoxelGIGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { + VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node()); return probe->get_extents(); } -void GIProbeGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { - GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); +void VoxelGIGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { + VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node()); - Transform gt = probe->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = probe->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 extents = probe->get_extents(); @@ -3163,8 +3137,8 @@ void GIProbeGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camer probe->set_extents(extents); } -void GIProbeGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { - GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); +void VoxelGIGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { + VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node()); Vector3 restore = p_restore; @@ -3180,19 +3154,19 @@ void GIProbeGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, co ur->commit_action(); } -void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - GIProbe *probe = Object::cast_to<GIProbe>(p_gizmo->get_spatial_node()); +void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { + VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_spatial_node()); - Ref<Material> material = get_material("gi_probe_material", p_gizmo); - Ref<Material> icon = get_material("gi_probe_icon", p_gizmo); - Ref<Material> material_internal = get_material("gi_probe_internal_material", p_gizmo); + Ref<Material> material = get_material("voxel_gi_material", p_gizmo); + Ref<Material> icon = get_material("voxel_gi_icon", p_gizmo); + Ref<Material> material_internal = get_material("voxel_gi_internal_material", p_gizmo); p_gizmo->clear(); Vector<Vector3> lines; Vector3 extents = probe->get_extents(); - static const int subdivs[GIProbe::SUBDIV_MAX] = { 64, 128, 256, 512 }; + static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 }; AABB aabb = AABB(-extents, extents * 2); int subdiv = subdivs[probe->get_subdiv()]; @@ -3256,7 +3230,7 @@ void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } if (p_gizmo->is_selected()) { - Ref<Material> solid_material = get_material("gi_probe_solid_material", p_gizmo); + Ref<Material> solid_material = get_material("voxel_gi_solid_material", p_gizmo); p_gizmo->add_solid_box(solid_material, aabb.get_size()); } @@ -3266,7 +3240,7 @@ void GIProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { //// -BakedLightmapGizmoPlugin::BakedLightmapGizmoPlugin() { +LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() { Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightmap_lines", Color(0.5, 0.6, 1)); gizmo_color.a = 0.1; @@ -3280,39 +3254,39 @@ BakedLightmapGizmoPlugin::BakedLightmapGizmoPlugin() { add_material("lightmap_probe_material", mat); - create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoBakedLightmap", "EditorIcons")); + create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_theme_icon("GizmoLightmapGI", "EditorIcons")); } -String BakedLightmapGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { +String LightmapGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { return ""; } -Variant BakedLightmapGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { +Variant LightmapGIGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { return Variant(); } -void BakedLightmapGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { +void LightmapGIGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { } -void BakedLightmapGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { +void LightmapGIGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { } -bool BakedLightmapGizmoPlugin::has_gizmo(Node3D *p_spatial) { - return Object::cast_to<BakedLightmap>(p_spatial) != nullptr; +bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) { + return Object::cast_to<LightmapGI>(p_spatial) != nullptr; } -String BakedLightmapGizmoPlugin::get_gizmo_name() const { - return "BakedLightmap"; +String LightmapGIGizmoPlugin::get_gizmo_name() const { + return "LightmapGI"; } -int BakedLightmapGizmoPlugin::get_priority() const { +int LightmapGIGizmoPlugin::get_priority() const { return -1; } -void BakedLightmapGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { +void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Ref<Material> icon = get_material("baked_indirect_light_icon", p_gizmo); - BakedLightmap *baker = Object::cast_to<BakedLightmap>(p_gizmo->get_spatial_node()); - Ref<BakedLightmapData> data = baker->get_light_data(); + LightmapGI *baker = Object::cast_to<LightmapGI>(p_gizmo->get_spatial_node()); + Ref<LightmapGIData> data = baker->get_light_data(); p_gizmo->add_unscaled_billboard(icon, 0.05); @@ -3449,7 +3423,7 @@ void BakedLightmapGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { array[RS::ARRAY_COLOR] = colors; Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, array, Array(), Dictionary(), 0); //no compression mesh->surface_set_material(0, material_probes); @@ -3583,7 +3557,7 @@ void CollisionObject3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { co->get_shape_owners(&owners); for (List<uint32_t>::Element *E = owners.front(); E; E = E->next()) { uint32_t owner_id = E->get(); - Transform xform = co->shape_owner_get_transform(owner_id); + Transform3D xform = co->shape_owner_get_transform(owner_id); Object *owner = co->shape_owner_get_owner(owner_id); // Exclude CollisionShape3D and CollisionPolygon3D as they have their gizmo. if (!Object::cast_to<CollisionShape3D>(owner) && !Object::cast_to<CollisionPolygon3D>(owner)) { @@ -3701,8 +3675,8 @@ void CollisionShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_i return; } - Transform gt = cs->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = cs->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -4369,7 +4343,7 @@ void NavigationRegion3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { #define BODY_A_RADIUS 0.25 #define BODY_B_RADIUS 0.27 -Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Transform &p_body_transform) { +Basis JointGizmosDrawer::look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { const Vector3 &p_eye(p_joint_transform.origin); const Vector3 &p_target(p_body_transform.origin); @@ -4394,7 +4368,7 @@ Basis JointGizmosDrawer::look_body(const Transform &p_joint_transform, const Tra return base; } -Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform) { +Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform) { switch (p_axis) { case Vector3::AXIS_X: return look_body_toward_x(joint_transform, body_transform); @@ -4407,7 +4381,7 @@ Basis JointGizmosDrawer::look_body_toward(Vector3::Axis p_axis, const Transform } } -Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform) { +Basis JointGizmosDrawer::look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { const Vector3 &p_eye(p_joint_transform.origin); const Vector3 &p_target(p_body_transform.origin); @@ -4438,7 +4412,7 @@ Basis JointGizmosDrawer::look_body_toward_x(const Transform &p_joint_transform, return base; } -Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform) { +Basis JointGizmosDrawer::look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { const Vector3 &p_eye(p_joint_transform.origin); const Vector3 &p_target(p_body_transform.origin); @@ -4469,7 +4443,7 @@ Basis JointGizmosDrawer::look_body_toward_y(const Transform &p_joint_transform, return base; } -Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform) { +Basis JointGizmosDrawer::look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform) { const Vector3 &p_eye(p_joint_transform.origin); const Vector3 &p_target(p_body_transform.origin); @@ -4500,7 +4474,7 @@ Basis JointGizmosDrawer::look_body_toward_z(const Transform &p_joint_transform, return base; } -void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) { +void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse) { if (p_limit_lower == p_limit_upper) { r_points.push_back(p_offset.translated(Vector3()).origin); r_points.push_back(p_offset.translated(p_base.xform(Vector3(0.5, 0, 0))).origin); @@ -4562,7 +4536,7 @@ void JointGizmosDrawer::draw_circle(Vector3::Axis p_axis, real_t p_radius, const } } -void JointGizmosDrawer::draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) { +void JointGizmosDrawer::draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points) { float r = 1.0; float w = r * Math::sin(p_swing); float d = r * Math::cos(p_swing); @@ -4666,7 +4640,7 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Vector<Vector3> body_b_points; if (Object::cast_to<PinJoint3D>(joint)) { - CreatePinJointGizmo(Transform(), points); + CreatePinJointGizmo(Transform3D(), points); p_gizmo->add_collision_segments(points); p_gizmo->add_lines(points, common_material); } @@ -4674,10 +4648,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { HingeJoint3D *hinge = Object::cast_to<HingeJoint3D>(joint); if (hinge) { CreateHingeJointGizmo( - Transform(), + Transform3D(), hinge->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), hinge->get_param(HingeJoint3D::PARAM_LIMIT_LOWER), hinge->get_param(HingeJoint3D::PARAM_LIMIT_UPPER), hinge->get_flag(HingeJoint3D::FLAG_USE_LIMIT), @@ -4697,10 +4671,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { SliderJoint3D *slider = Object::cast_to<SliderJoint3D>(joint); if (slider) { CreateSliderJointGizmo( - Transform(), + Transform3D(), slider->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_LOWER), slider->get_param(SliderJoint3D::PARAM_ANGULAR_LIMIT_UPPER), slider->get_param(SliderJoint3D::PARAM_LINEAR_LIMIT_LOWER), @@ -4721,10 +4695,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { ConeTwistJoint3D *cone = Object::cast_to<ConeTwistJoint3D>(joint); if (cone) { CreateConeTwistJointGizmo( - Transform(), + Transform3D(), cone->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), cone->get_param(ConeTwistJoint3D::PARAM_SWING_SPAN), cone->get_param(ConeTwistJoint3D::PARAM_TWIST_SPAN), node_body_a ? &body_a_points : nullptr, @@ -4740,10 +4714,10 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Generic6DOFJoint3D *gen = Object::cast_to<Generic6DOFJoint3D>(joint); if (gen) { CreateGeneric6DOFJointGizmo( - Transform(), + Transform3D(), gen->get_global_transform(), - node_body_a ? node_body_a->get_global_transform() : Transform(), - node_body_b ? node_body_b->get_global_transform() : Transform(), + node_body_a ? node_body_a->get_global_transform() : Transform3D(), + node_body_b ? node_body_b->get_global_transform() : Transform3D(), gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_LOWER_LIMIT), gen->get_param_x(Generic6DOFJoint3D::PARAM_ANGULAR_UPPER_LIMIT), @@ -4780,7 +4754,7 @@ void Joint3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { } } -void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points) { +void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform3D &p_offset, Vector<Vector3> &r_cursor_points) { float cs = 0.25; r_cursor_points.push_back(p_offset.translated(Vector3(+cs, 0, 0)).origin); @@ -4791,7 +4765,7 @@ void Joint3DGizmoPlugin::CreatePinJointGizmo(const Transform &p_offset, Vector<V r_cursor_points.push_back(p_offset.translated(Vector3(0, 0, -cs)).origin); } -void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { r_common_points.push_back(p_offset.translated(Vector3(0, 0, 0.5)).origin); r_common_points.push_back(p_offset.translated(Vector3(0, 0, -0.5)).origin); @@ -4821,7 +4795,7 @@ void Joint3DGizmoPlugin::CreateHingeJointGizmo(const Transform &p_offset, const } } -void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { p_linear_limit_lower = -p_linear_limit_lower; p_linear_limit_upper = -p_linear_limit_upper; @@ -4880,7 +4854,7 @@ void Joint3DGizmoPlugin::CreateSliderJointGizmo(const Transform &p_offset, const } } -void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { +void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points) { if (r_body_a_points) { JointGizmosDrawer::draw_cone( p_offset, @@ -4901,10 +4875,10 @@ void Joint3DGizmoPlugin::CreateConeTwistJointGizmo(const Transform &p_offset, co } void Joint3DGizmoPlugin::CreateGeneric6DOFJointGizmo( - const Transform &p_offset, - const Transform &p_trs_joint, - const Transform &p_trs_body_a, - const Transform &p_trs_body_b, + const Transform3D &p_offset, + const Transform3D &p_trs_joint, + const Transform3D &p_trs_body_a, + const Transform3D &p_trs_body_b, real_t p_angular_limit_lower_x, real_t p_angular_limit_upper_x, real_t p_linear_limit_lower_x, diff --git a/editor/node_3d_editor_gizmos.h b/editor/node_3d_editor_gizmos.h index 95344176ad..6f071859ec 100644 --- a/editor/node_3d_editor_gizmos.h +++ b/editor/node_3d_editor_gizmos.h @@ -218,8 +218,8 @@ public: SoftBody3DGizmoPlugin(); }; -class VisibilityNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(VisibilityNotifier3DGizmoPlugin, EditorNode3DGizmoPlugin); +class VisibleOnScreenNotifier3DGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(VisibleOnScreenNotifier3DGizmoPlugin, EditorNode3DGizmoPlugin); public: bool has_gizmo(Node3D *p_spatial) override; @@ -232,7 +232,7 @@ public: void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override; void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) override; - VisibilityNotifier3DGizmoPlugin(); + VisibleOnScreenNotifier3DGizmoPlugin(); }; class CPUParticles3DGizmoPlugin : public EditorNode3DGizmoPlugin { @@ -316,8 +316,8 @@ public: DecalGizmoPlugin(); }; -class GIProbeGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(GIProbeGizmoPlugin, EditorNode3DGizmoPlugin); +class VoxelGIGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(VoxelGIGizmoPlugin, EditorNode3DGizmoPlugin); public: bool has_gizmo(Node3D *p_spatial) override; @@ -330,11 +330,11 @@ public: void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override; void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) override; - GIProbeGizmoPlugin(); + VoxelGIGizmoPlugin(); }; -class BakedLightmapGizmoPlugin : public EditorNode3DGizmoPlugin { - GDCLASS(BakedLightmapGizmoPlugin, EditorNode3DGizmoPlugin); +class LightmapGIGizmoPlugin : public EditorNode3DGizmoPlugin { + GDCLASS(LightmapGIGizmoPlugin, EditorNode3DGizmoPlugin); public: bool has_gizmo(Node3D *p_spatial) override; @@ -347,7 +347,7 @@ public: void set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) override; void commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel = false) override; - BakedLightmapGizmoPlugin(); + LightmapGIGizmoPlugin(); }; class LightmapProbeGizmoPlugin : public EditorNode3DGizmoPlugin { @@ -428,17 +428,17 @@ public: class JointGizmosDrawer { public: - static Basis look_body(const Transform &p_joint_transform, const Transform &p_body_transform); - static Basis look_body_toward(Vector3::Axis p_axis, const Transform &joint_transform, const Transform &body_transform); - static Basis look_body_toward_x(const Transform &p_joint_transform, const Transform &p_body_transform); - static Basis look_body_toward_y(const Transform &p_joint_transform, const Transform &p_body_transform); + static Basis look_body(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); + static Basis look_body_toward(Vector3::Axis p_axis, const Transform3D &joint_transform, const Transform3D &body_transform); + static Basis look_body_toward_x(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); + static Basis look_body_toward_y(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); /// Special function just used for physics joints, it returns a basis constrained toward Joint Z axis /// with axis X and Y that are looking toward the body and oriented toward up - static Basis look_body_toward_z(const Transform &p_joint_transform, const Transform &p_body_transform); + static Basis look_body_toward_z(const Transform3D &p_joint_transform, const Transform3D &p_body_transform); // Draw circle around p_axis - static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse = false); - static void draw_cone(const Transform &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points); + static void draw_circle(Vector3::Axis p_axis, real_t p_radius, const Transform3D &p_offset, const Basis &p_base, real_t p_limit_lower, real_t p_limit_upper, Vector<Vector3> &r_points, bool p_inverse = false); + static void draw_cone(const Transform3D &p_offset, const Basis &p_base, real_t p_swing, real_t p_twist, Vector<Vector3> &r_points); }; class Joint3DGizmoPlugin : public EditorNode3DGizmoPlugin { @@ -455,15 +455,15 @@ public: int get_priority() const override; void redraw(EditorNode3DGizmo *p_gizmo) override; - static void CreatePinJointGizmo(const Transform &p_offset, Vector<Vector3> &r_cursor_points); - static void CreateHingeJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - static void CreateSliderJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); - static void CreateConeTwistJointGizmo(const Transform &p_offset, const Transform &p_trs_joint, const Transform &p_trs_body_a, const Transform &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreatePinJointGizmo(const Transform3D &p_offset, Vector<Vector3> &r_cursor_points); + static void CreateHingeJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_limit_lower, real_t p_limit_upper, bool p_use_limit, Vector<Vector3> &r_common_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateSliderJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_angular_limit_lower, real_t p_angular_limit_upper, real_t p_linear_limit_lower, real_t p_linear_limit_upper, Vector<Vector3> &r_points, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); + static void CreateConeTwistJointGizmo(const Transform3D &p_offset, const Transform3D &p_trs_joint, const Transform3D &p_trs_body_a, const Transform3D &p_trs_body_b, real_t p_swing, real_t p_twist, Vector<Vector3> *r_body_a_points, Vector<Vector3> *r_body_b_points); static void CreateGeneric6DOFJointGizmo( - const Transform &p_offset, - const Transform &p_trs_joint, - const Transform &p_trs_body_a, - const Transform &p_trs_body_b, + const Transform3D &p_offset, + const Transform3D &p_trs_joint, + const Transform3D &p_trs_body_a, + const Transform3D &p_trs_body_b, real_t p_angular_limit_lower_x, real_t p_angular_limit_upper_x, real_t p_linear_limit_lower_x, diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp index 7dda61f0bf..f55d77d782 100644 --- a/editor/plugin_config_dialog.cpp +++ b/editor/plugin_config_dialog.cpp @@ -30,7 +30,7 @@ #include "plugin_config_dialog.h" #include "core/io/config_file.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/editor_scale.h" diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index f7c0ebcfaf..b6dd9474d3 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -386,7 +386,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { } else { String type = menu->get_item_metadata(p_index); - Object *obj = ClassDB::instance(type); + Object *obj = ClassDB::instantiate(type); ERR_FAIL_COND(!obj); AnimationNode *an = Object::cast_to<AnimationNode>(obj); ERR_FAIL_COND(!an); @@ -413,7 +413,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) { void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) { Ref<AnimationNodeAnimation> anim; - anim.instance(); + anim.instantiate(); anim->set_animation(animations_to_add[p_index]); @@ -594,7 +594,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() { add_child(top_hb); Ref<ButtonGroup> bg; - bg.instance(); + bg.instantiate(); tool_blend = memnew(Button); tool_blend->set_flat(true); diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index e719df53d5..359df95bce 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -308,7 +308,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { } else { String type = menu->get_item_metadata(p_index); - Object *obj = ClassDB::instance(type); + Object *obj = ClassDB::instantiate(type); ERR_FAIL_COND(!obj); AnimationNode *an = Object::cast_to<AnimationNode>(obj); ERR_FAIL_COND(!an); @@ -335,7 +335,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) { void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) { Ref<AnimationNodeAnimation> anim; - anim.instance(); + anim.instantiate(); anim->set_animation(animations_to_add[p_index]); @@ -818,7 +818,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() { add_child(top_hb); Ref<ButtonGroup> bg; - bg.instance(); + bg.instantiate(); tool_blend = memnew(Button); tool_blend->set_flat(true); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 78c30df04b..dcde89f177 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -139,7 +139,7 @@ void AnimationNodeBlendTreeEditor::_update_graph() { name->set_expand_to_text_length_enabled(true); node->add_child(name); node->set_slot(0, false, 0, Color(), true, 0, get_theme_color("font_color", "Label")); - name->connect("text_entered", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode), CONNECT_DEFERRED); + name->connect("text_submitted", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed), varray(agnode), CONNECT_DEFERRED); name->connect("focus_exited", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_renamed_focus_out), varray(name, agnode), CONNECT_DEFERRED); base = 1; node->set_show_close_button(true); @@ -288,14 +288,14 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { ERR_FAIL_COND(!anode.is_valid()); base_name = anode->get_class(); } else if (add_options[p_idx].type != String()) { - AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(add_options[p_idx].type)); + AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(add_options[p_idx].type)); ERR_FAIL_COND(!an); anode = Ref<AnimationNode>(an); base_name = add_options[p_idx].name; } else { ERR_FAIL_COND(add_options[p_idx].script.is_null()); String base_type = add_options[p_idx].script->get_instance_base_type(); - AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instance(base_type)); + AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(base_type)); ERR_FAIL_COND(!an); anode = Ref<AnimationNode>(an); anode->set_script(add_options[p_idx].script); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index bd88d96a66..2b92943f7e 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -121,11 +121,11 @@ void AnimationPlayerEditor::_notification(int p_what) { Ref<Image> reset_img = reset_icon->get_image(); Ref<Image> autoplay_reset_img; Size2 icon_size = Size2(autoplay_img->get_width(), autoplay_img->get_height()); - autoplay_reset_img.instance(); + autoplay_reset_img.instantiate(); autoplay_reset_img->create(icon_size.x * 2, icon_size.y, false, autoplay_img->get_format()); autoplay_reset_img->blit_rect(autoplay_img, Rect2(Point2(), icon_size), Point2()); autoplay_reset_img->blit_rect(reset_img, Rect2(Point2(), icon_size), Point2(icon_size.x, 0)); - autoplay_reset_icon.instance(); + autoplay_reset_icon.instantiate(); autoplay_reset_icon->create_from_image(autoplay_reset_img); } stop->set_icon(get_theme_icon("Stop", "EditorIcons")); @@ -569,8 +569,10 @@ void AnimationPlayerEditor::_animation_blend() { blend_editor.dialog->popup_centered(Size2(400, 400) * EDSCALE); blend_editor.tree->set_hide_root(true); - blend_editor.tree->set_column_min_width(0, 10); - blend_editor.tree->set_column_min_width(1, 3); + blend_editor.tree->set_column_expand_ratio(0, 10); + blend_editor.tree->set_column_clip_content(0, true); + blend_editor.tree->set_column_expand_ratio(1, 3); + blend_editor.tree->set_column_clip_content(1, true); List<StringName> anims; player->get_animation_list(&anims); @@ -1694,7 +1696,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor, AnimationPlay file->connect("file_selected", callable_mp(this, &AnimationPlayerEditor::_dialog_action)); frame->connect("value_changed", callable_mp(this, &AnimationPlayerEditor::_seek_value_changed), make_binds(true, false)); - scale->connect("text_entered", callable_mp(this, &AnimationPlayerEditor::_scale_changed)); + scale->connect("text_submitted", callable_mp(this, &AnimationPlayerEditor::_scale_changed)); renaming = false; last_active = false; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index c915276d3a..94e526922d 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -257,7 +257,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv } else { Ref<AnimationNodeStateMachineTransition> tr; - tr.instance(); + tr.instantiate(); tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(transition_mode->get_selected())); updating = true; @@ -423,7 +423,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { } else { String type = menu->get_item_metadata(p_index); - Object *obj = ClassDB::instance(type); + Object *obj = ClassDB::instantiate(type); ERR_FAIL_COND(!obj); AnimationNode *an = Object::cast_to<AnimationNode>(obj); ERR_FAIL_COND(!an); @@ -462,7 +462,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) { void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) { Ref<AnimationNodeAnimation> anim; - anim.instance(); + anim.instantiate(); anim->set_animation(animations_to_add[p_index]); @@ -1213,7 +1213,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { add_child(top_hb); Ref<ButtonGroup> bg; - bg.instance(); + bg.instantiate(); tool_select = memnew(Button); tool_select->set_flat(true); @@ -1329,7 +1329,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { name_edit = memnew(LineEdit); name_edit_popup->add_child(name_edit); name_edit->set_anchors_and_offsets_preset(PRESET_WIDE); - name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); + name_edit->connect("text_submitted", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out)); open_file = memnew(EditorFileDialog); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index c33b06ff32..e90665f84d 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -76,7 +76,7 @@ void AnimationTreeEditor::_update_path() { } Ref<ButtonGroup> group; - group.instance(); + group.instantiate(); Button *b = memnew(Button); b->set_text("Root"); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 93bb170128..cd61ebd418 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -86,7 +86,7 @@ void EditorAssetLibraryItem::_bind_methods() { EditorAssetLibraryItem::EditorAssetLibraryItem() { Ref<StyleBoxEmpty> border; - border.instance(); + border.instantiate(); border->set_default_margin(SIDE_LEFT, 5 * EDSCALE); border->set_default_margin(SIDE_RIGHT, 5 * EDSCALE); border->set_default_margin(SIDE_BOTTOM, 5 * EDSCALE); @@ -155,7 +155,7 @@ void EditorAssetLibraryItemDescription::set_image(int p_type, int p_index, const thumbnail->blend_rect(overlay, overlay->get_used_rect(), overlay_pos); Ref<ImageTexture> tex; - tex.instance(); + tex.instantiate(); tex->create_from_image(thumbnail); preview_images[i].button->set_icon(tex); @@ -761,7 +761,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PackedB } Ref<ImageTexture> tex; - tex.instance(); + tex.instantiate(); tex->create_from_image(image); obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, tex); @@ -1098,11 +1098,9 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const Dictionary d; { - Variant js; - String errs; - int errl; - JSON::parse(str, js, errs, errl); - d = js; + JSON json; + json.parse(str); + d = json.get_data(); } RequestType requested = requesting; @@ -1437,7 +1435,7 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { library_scroll_bg->add_child(library_scroll); Ref<StyleBoxEmpty> border2; - border2.instance(); + border2.instantiate(); border2->set_default_margin(SIDE_LEFT, 15 * EDSCALE); border2->set_default_margin(SIDE_RIGHT, 35 * EDSCALE); border2->set_default_margin(SIDE_BOTTOM, 15 * EDSCALE); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index 11eae9e041..c6ca1ecd4f 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -282,7 +282,7 @@ class EditorAssetLibrary : public PanelContainer { void _search(int p_page = 0); void _rerun_search(int p_ignore); void _search_text_changed(const String &p_text = ""); - void _search_text_entered(const String &p_text = ""); + void _search_text_submitted(const String &p_text = ""); void _api_request(const String &p_request, RequestType p_request_type, const String &p_arguments = ""); void _http_request_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); void _http_download_completed(int p_status, int p_code, const PackedStringArray &headers, const PackedByteArray &p_data); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 2be586733b..7282475ddf 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -666,93 +666,6 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel } } -void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) { - Point2 screen_pos = transform.xform(p_pos); - - for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); - - Vector<Vector2> bone_shape; - if (!_get_bone_shape(&bone_shape, nullptr, E)) { - continue; - } - - // Check if the point is inside the Polygon2D - if (Geometry2D::is_point_in_polygon(screen_pos, bone_shape)) { - // Check if the item is already in the list - bool duplicate = false; - for (int i = 0; i < r_items.size(); i++) { - if (r_items[i].item == from_node) { - duplicate = true; - break; - } - } - if (duplicate) { - continue; - } - - // Else, add it - _SelectResult res; - res.item = from_node; - res.z_index = from_node ? from_node->get_z_index() : 0; - res.has_z = from_node; - r_items.push_back(res); - } - } -} - -bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone) { - int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width"); - int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size"); - - Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().from)); - Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().to)); - - if (!from_node) { - return false; - } - if (!from_node->is_inside_tree()) { - return false; //may have been removed - } - - if (!to_node && bone->get().length == 0) { - return false; - } - - Vector2 from = transform.xform(from_node->get_global_position()); - Vector2 to; - - if (to_node) { - to = transform.xform(to_node->get_global_position()); - } else { - to = transform.xform(from_node->get_global_transform().xform(Vector2(bone->get().length, 0))); - } - - Vector2 rel = to - from; - Vector2 relt = rel.orthogonal().normalized() * bone_width; - Vector2 reln = rel.normalized(); - Vector2 reltn = relt.normalized(); - - if (shape) { - shape->clear(); - shape->push_back(from); - shape->push_back(from + rel * 0.2 + relt); - shape->push_back(to); - shape->push_back(from + rel * 0.2 - relt); - } - - if (outline_shape) { - outline_shape->clear(); - outline_shape->push_back(from + (-reln - reltn) * bone_outline_width); - outline_shape->push_back(from + (-reln + reltn) * bone_outline_width); - outline_shape->push_back(from + rel * 0.2 + relt + reltn * bone_outline_width); - outline_shape->push_back(to + (reln + reltn) * bone_outline_width); - outline_shape->push_back(to + (reln - reltn) * bone_outline_width); - outline_shape->push_back(from + rel * 0.2 - relt - reltn * bone_outline_width); - } - return true; -} - void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { if (!p_node) { return; @@ -886,50 +799,6 @@ Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 return output; } -void CanvasItemEditor::_save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state) { - if (p_bones_length) { - *p_bones_length = List<float>(); - } - if (p_bones_state) { - *p_bones_state = List<Dictionary>(); - } - - const Node2D *bone = Object::cast_to<Node2D>(p_canvas_item); - if (bone && bone->has_meta("_edit_bone_")) { - // Check if we have an IK chain - List<const Node2D *> bone_ik_list; - bool ik_found = false; - bone = Object::cast_to<Node2D>(bone->get_parent()); - while (bone) { - bone_ik_list.push_back(bone); - if (bone->has_meta("_edit_ik_")) { - ik_found = true; - break; - } else if (!bone->has_meta("_edit_bone_")) { - break; - } - bone = Object::cast_to<Node2D>(bone->get_parent()); - } - - //Save the bone state and length if we have an IK chain - if (ik_found) { - bone = Object::cast_to<Node2D>(p_canvas_item); - Transform2D bone_xform = bone->get_global_transform(); - for (List<const Node2D *>::Element *bone_E = bone_ik_list.front(); bone_E; bone_E = bone_E->next()) { - bone_xform = bone_xform * bone->get_transform().affine_inverse(); - const Node2D *parent_bone = bone_E->get(); - if (p_bones_length) { - p_bones_length->push_back(parent_bone->get_global_transform().get_origin().distance_to(bone->get_global_position())); - } - if (p_bones_state) { - p_bones_state->push_back(parent_bone->_edit_get_state()); - } - bone = parent_bone; - } - } - } -} - void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones) { for (List<CanvasItem *>::Element *E = p_canvas_items.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); @@ -942,31 +811,15 @@ void CanvasItemEditor::_save_canvas_item_state(List<CanvasItem *> p_canvas_items } else { se->pre_drag_rect = Rect2(); } - - // If we have a bone, save the state of all nodes in the IK chain - _save_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_length), &(se->pre_drag_bones_undo_state)); } } } -void CanvasItemEditor::_restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state) { - CanvasItem *canvas_item = p_canvas_item; - for (const List<Dictionary>::Element *E = p_bones_state->front(); E; E = E->next()) { - canvas_item = Object::cast_to<CanvasItem>(canvas_item->get_parent()); - canvas_item->_edit_set_state(E->get()); - } -} - void CanvasItemEditor::_restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones) { for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); - if (se) { - canvas_item->_edit_set_state(se->undo_state); - if (restore_bones) { - _restore_canvas_item_ik_chain(canvas_item, &(se->pre_drag_bones_undo_state)); - } - } + canvas_item->_edit_set_state(se->undo_state); } } @@ -1388,7 +1241,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event, bo Ref<InputEventPanGesture> pan_gesture = p_event; if (pan_gesture.is_valid() && !p_already_accepted) { - // If control key pressed, then zoom instead of pan + // If ctrl key pressed, then zoom instead of pan. if (pan_gesture->is_ctrl_pressed()) { const float factor = pan_gesture->get_delta().y; @@ -1497,76 +1350,6 @@ bool CanvasItemEditor::_gui_input_pivot(const Ref<InputEvent> &p_event) { return false; } -void CanvasItemEditor::_solve_IK(Node2D *leaf_node, Point2 target_position) { - CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(leaf_node); - if (se) { - int nb_bones = se->pre_drag_bones_undo_state.size(); - if (nb_bones > 0) { - // Build the node list - Point2 leaf_pos = target_position; - - List<Node2D *> joints_list; - List<Point2> joints_pos; - Node2D *joint = leaf_node; - Transform2D joint_transform = leaf_node->get_global_transform_with_canvas(); - for (int i = 0; i < nb_bones + 1; i++) { - joints_list.push_back(joint); - joints_pos.push_back(joint_transform.get_origin()); - joint_transform = joint_transform * joint->get_transform().affine_inverse(); - joint = Object::cast_to<Node2D>(joint->get_parent()); - } - Point2 root_pos = joints_list.back()->get()->get_global_transform_with_canvas().get_origin(); - - // Restraints the node to a maximum distance is necessary - float total_len = 0; - for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) { - total_len += E->get(); - } - if ((root_pos.distance_to(leaf_pos)) > total_len) { - Vector2 rel = leaf_pos - root_pos; - rel = rel.normalized() * total_len; - leaf_pos = root_pos + rel; - } - joints_pos[0] = leaf_pos; - - // Run the solver - int solver_iterations = 64; - float solver_k = 0.3; - - // Build the position list - for (int i = 0; i < solver_iterations; i++) { - // Handle the leaf joint - int node_id = 0; - for (List<float>::Element *E = se->pre_drag_bones_length.front(); E; E = E->next()) { - Vector2 direction = (joints_pos[node_id + 1] - joints_pos[node_id]).normalized(); - int len = E->get(); - if (E == se->pre_drag_bones_length.front()) { - joints_pos[1] = joints_pos[1].lerp(joints_pos[0] + len * direction, solver_k); - } else if (E == se->pre_drag_bones_length.back()) { - joints_pos[node_id] = joints_pos[node_id].lerp(joints_pos[node_id + 1] - len * direction, solver_k); - } else { - Vector2 center = (joints_pos[node_id + 1] + joints_pos[node_id]) / 2.0; - joints_pos[node_id] = joints_pos[node_id].lerp(center - (direction * len) / 2.0, solver_k); - joints_pos[node_id + 1] = joints_pos[node_id + 1].lerp(center + (direction * len) / 2.0, solver_k); - } - node_id++; - } - } - - // Set the position - for (int node_id = joints_list.size() - 1; node_id > 0; node_id--) { - Point2 current = (joints_list[node_id - 1]->get_global_position() - joints_list[node_id]->get_global_position()).normalized(); - Point2 target = (joints_pos[node_id - 1] - joints_list[node_id]->get_global_position()).normalized(); - float rot = current.angle_to(target); - if (joints_list[node_id]->get_global_transform().basis_determinant() < 0) { - rot = -rot; - } - joints_list[node_id]->rotate(rot); - } - } - } -} - bool CanvasItemEditor::_gui_input_rotate(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> b = p_event; Ref<InputEventMouseMotion> m = p_event; @@ -2208,14 +1991,6 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { if (drag_type == DRAG_MOVE || drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y) { // Move the nodes if (m.is_valid()) { - // Save the ik chain for reapplying before IK solve - Vector<List<Dictionary>> all_bones_ik_states; - for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { - List<Dictionary> bones_ik_states; - _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states); - all_bones_ik_states.push_back(bones_ik_states); - } - _restore_canvas_item_state(drag_selection, true); drag_to = transform.affine_inverse().xform(m->get_position()); @@ -2244,25 +2019,12 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } } - bool force_no_IK = m->is_alt_pressed(); int index = 0; for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); - CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); - if (se) { - Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); - - Node2D *node2d = Object::cast_to<Node2D>(canvas_item); - if (node2d && se->pre_drag_bones_undo_state.size() > 0 && !force_no_IK) { - real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index])); - real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation); - _solve_IK(node2d, new_pos); - } else { - canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); - } - } + Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); + + canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); index++; } return true; @@ -2325,14 +2087,6 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { } if (drag_selection.size() > 0) { - // Save the ik chain for reapplying before IK solve - Vector<List<Dictionary>> all_bones_ik_states; - for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { - List<Dictionary> bones_ik_states; - _save_canvas_item_ik_chain(E->get(), nullptr, &bones_ik_states); - all_bones_ik_states.push_back(bones_ik_states); - } - _restore_canvas_item_state(drag_selection, true); bool move_local_base = k->is_alt_pressed(); @@ -2384,21 +2138,9 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) { int index = 0; for (List<CanvasItem *>::Element *E = drag_selection.front(); E; E = E->next()) { CanvasItem *canvas_item = E->get(); - CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item); - if (se) { - Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); - - Node2D *node2d = Object::cast_to<Node2D>(canvas_item); - if (node2d && se->pre_drag_bones_undo_state.size() > 0) { - real_t initial_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - _restore_canvas_item_ik_chain(node2d, &(all_bones_ik_states[index])); - real_t final_leaf_node_rotation = node2d->get_global_transform_with_canvas().get_rotation(); - node2d->rotate(initial_leaf_node_rotation - final_leaf_node_rotation); - _solve_IK(node2d, new_pos); - } else { - canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); - } - } + Transform2D xform = canvas_item->get_global_transform_with_canvas().affine_inverse() * canvas_item->get_transform(); + + canvas_item->_edit_set_position(canvas_item->_edit_get_position() + xform.xform(new_pos) - xform.xform(previous_pos)); index++; } } @@ -2524,18 +2266,12 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Find the item to select CanvasItem *canvas_item = nullptr; - // Retrieve the bones Vector<_SelectResult> selection = Vector<_SelectResult>(); - _get_bones_at_pos(click, selection); + // Retrieve the canvas items + selection = Vector<_SelectResult>(); + _get_canvas_items_at_pos(click, selection); if (!selection.is_empty()) { canvas_item = selection[0].item; - } else { - // Retrieve the canvas items - selection = Vector<_SelectResult>(); - _get_canvas_items_at_pos(click, selection); - if (!selection.is_empty()) { - canvas_item = selection[0].item; - } } if (!canvas_item) { @@ -2556,22 +2292,38 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Start dragging if (still_selected) { // Drag the node(s) if requested - List<CanvasItem *> selection2 = _get_edited_canvas_items(); + drag_start_origin = click; + drag_type = DRAG_QUEUED; + } + // Select the item + return true; + } + } + } - drag_selection.clear(); - for (int i = 0; i < selection2.size(); i++) { - if (_is_node_movable(selection2[i], true)) { - drag_selection.push_back(selection2[i]); - } - } + if (drag_type == DRAG_QUEUED) { + if (b.is_valid() && !b->is_pressed()) { + drag_type = DRAG_NONE; + return true; + } + if (m.is_valid()) { + Point2 click = transform.affine_inverse().xform(m->get_position()); + bool movement_threshold_passed = drag_start_origin.distance_to(click) > 10 * EDSCALE; + if (m.is_valid() && movement_threshold_passed) { + List<CanvasItem *> selection2 = _get_edited_canvas_items(); - if (selection2.size() > 0) { - drag_type = DRAG_MOVE; - drag_from = click; - _save_canvas_item_state(drag_selection); + drag_selection.clear(); + for (int i = 0; i < selection2.size(); i++) { + if (_is_node_movable(selection2[i], true)) { + drag_selection.push_back(selection2[i]); } } - // Select the item + + if (selection2.size() > 0) { + drag_type = DRAG_MOVE; + drag_from = click; + _save_canvas_item_state(drag_selection); + } return true; } } @@ -3734,65 +3486,6 @@ void CanvasItemEditor::_draw_axis() { } } -void CanvasItemEditor::_draw_bones() { - RID ci = viewport->get_canvas_item(); - - if (skeleton_show_bones) { - Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); - Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); - Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); - Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); - Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); - - for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Vector<Vector2> bone_shape; - Vector<Vector2> bone_shape_outline; - if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E)) { - continue; - } - - Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); - if (!from_node->is_visible_in_tree()) { - continue; - } - - Vector<Color> colors; - if (from_node->has_meta("_edit_ik_")) { - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - colors.push_back(bone_ik_color); - } else { - colors.push_back(bone_color1); - colors.push_back(bone_color2); - colors.push_back(bone_color1); - colors.push_back(bone_color2); - } - - Vector<Color> outline_colors; - - if (editor_selection->is_selected(from_node)) { - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - outline_colors.push_back(bone_selected_color); - } else { - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - outline_colors.push_back(bone_outline_color); - } - - RenderingServer::get_singleton()->canvas_item_add_polygon(ci, bone_shape_outline, outline_colors); - RenderingServer::get_singleton()->canvas_item_add_primitive(ci, bone_shape, colors, Vector<Vector2>(), RID()); - } - } -} - void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { ERR_FAIL_COND(!p_node); @@ -3908,72 +3601,6 @@ void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p } } -bool CanvasItemEditor::_build_bones_list(Node *p_node) { - ERR_FAIL_COND_V(!p_node, false); - - bool has_child_bones = false; - - for (int i = 0; i < p_node->get_child_count(); i++) { - if (_build_bones_list(p_node->get_child(i))) { - has_child_bones = true; - } - } - - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(p_node); - Node *scene = editor->get_edited_scene(); - if (!canvas_item || !canvas_item->is_visible() || (canvas_item != scene && canvas_item->get_owner() != scene && canvas_item != scene->get_deepest_editable_node(canvas_item))) { - return false; - } - - Node *parent = canvas_item->get_parent(); - - if (Object::cast_to<Bone2D>(canvas_item)) { - if (Object::cast_to<Bone2D>(parent)) { - // Add as bone->parent relationship - BoneKey bk; - bk.from = parent->get_instance_id(); - bk.to = canvas_item->get_instance_id(); - if (!bone_list.has(bk)) { - BoneList b; - b.length = 0; - bone_list[bk] = b; - } - - bone_list[bk].last_pass = bone_last_frame; - } - - if (!has_child_bones) { - // Add a last bone if the Bone2D has no Bone2D child - BoneKey bk; - bk.from = canvas_item->get_instance_id(); - bk.to = ObjectID(); - if (!bone_list.has(bk)) { - BoneList b; - b.length = 0; - bone_list[bk] = b; - } - bone_list[bk].last_pass = bone_last_frame; - } - - return true; - } - - if (canvas_item->has_meta("_edit_bone_")) { - // Add a "custom bone" - BoneKey bk; - bk.from = parent->get_instance_id(); - bk.to = canvas_item->get_instance_id(); - if (!bone_list.has(bk)) { - BoneList b; - b.length = 0; - bone_list[bk] = b; - } - bone_list[bk].last_pass = bone_last_frame; - } - - return false; -} - void CanvasItemEditor::_draw_viewport() { // Update the transform transform = Transform2D(); @@ -4033,7 +3660,6 @@ void CanvasItemEditor::_draw_viewport() { force_over_plugin_list->forward_canvas_force_draw_over_viewport(viewport); } - _draw_bones(); if (show_rulers) { _draw_rulers(); } @@ -4159,8 +3785,8 @@ void CanvasItemEditor::_notification(int p_what) { } Bone2D *bone = Object::cast_to<Bone2D>(b); - if (bone && bone->get_default_length() != E->get().length) { - E->get().length = bone->get_default_length(); + if (bone && bone->get_length() != E->get().length) { + E->get().length = bone->get_length(); viewport->update(); } } @@ -4175,18 +3801,11 @@ void CanvasItemEditor::_notification(int p_what) { AnimationPlayerEditor::singleton->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed)); _keying_changed(); - get_tree()->connect("node_added", callable_mp(this, &CanvasItemEditor::_tree_changed), varray()); - get_tree()->connect("node_removed", callable_mp(this, &CanvasItemEditor::_tree_changed), varray()); } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { select_sb->set_texture(get_theme_icon("EditorRect2D", "EditorIcons")); } - if (p_what == NOTIFICATION_EXIT_TREE) { - get_tree()->disconnect("node_added", callable_mp(this, &CanvasItemEditor::_tree_changed)); - get_tree()->disconnect("node_removed", callable_mp(this, &CanvasItemEditor::_tree_changed)); - } - if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); list_select_button->set_icon(get_theme_icon("ListSelect", "EditorIcons")); @@ -4321,46 +3940,6 @@ void CanvasItemEditor::edit(CanvasItem *p_canvas_item) { } } -void CanvasItemEditor::_queue_update_bone_list() { - if (bone_list_dirty) { - return; - } - - call_deferred("_update_bone_list"); - bone_list_dirty = true; -} - -void CanvasItemEditor::_update_bone_list() { - bone_last_frame++; - - if (editor->get_edited_scene()) { - _build_bones_list(editor->get_edited_scene()); - } - - List<Map<BoneKey, BoneList>::Element *> bone_to_erase; - for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - if (E->get().last_pass != bone_last_frame) { - bone_to_erase.push_back(E); - continue; - } - - Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E->key().from)); - if (!node || !node->is_inside_tree() || (node != get_tree()->get_edited_scene_root() && !get_tree()->get_edited_scene_root()->is_a_parent_of(node))) { - bone_to_erase.push_back(E); - continue; - } - } - while (bone_to_erase.size()) { - bone_list.erase(bone_to_erase.front()->get()); - bone_to_erase.pop_front(); - } - bone_list_dirty = false; -} - -void CanvasItemEditor::_tree_changed(Node *) { - _queue_update_bone_list(); -} - void CanvasItemEditor::_update_scrollbars() { updating_scroll = true; @@ -4376,8 +3955,6 @@ void CanvasItemEditor::_update_scrollbars() { Size2 screen_rect = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); Rect2 local_rect = Rect2(Point2(), viewport->get_size() - Size2(vmin.width, hmin.height)); - _queue_update_bone_list(); - // Calculate scrollable area. Rect2 canvas_item_rect = Rect2(Point2(), screen_rect); if (editor->is_inside_tree() && editor->get_edited_scene()) { @@ -4665,7 +4242,7 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "position", n2d->get_position(), p_on_existing); } if (key_rot && p_rotation) { - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation_degrees", Math::rad2deg(n2d->get_rotation()), p_on_existing); + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "rotation", n2d->get_rotation(), p_on_existing); } if (key_scale && p_scale) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(n2d, "scale", n2d->get_scale(), p_on_existing); @@ -4697,7 +4274,7 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "position", F->get()->get_position(), p_on_existing); } if (key_rot) { - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation_degrees", Math::rad2deg(F->get()->get_rotation()), p_on_existing); + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "rotation", F->get()->get_rotation(), p_on_existing); } if (key_scale) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(F->get(), "scale", F->get()->get_scale(), p_on_existing); @@ -4713,7 +4290,7 @@ void CanvasItemEditor::_insert_animation_keys(bool p_location, bool p_rotation, AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_position", ctrl->get_position(), p_on_existing); } if (key_rot) { - AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation_degrees(), p_on_existing); + AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_rotation", ctrl->get_rotation(), p_on_existing); } if (key_scale) { AnimationPlayerEditor::singleton->get_track_editor()->insert_node_value_key(ctrl, "rect_size", ctrl->get_size(), p_on_existing); @@ -4740,11 +4317,11 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) { void CanvasItemEditor::_update_override_camera_button(bool p_game_running) { if (p_game_running) { override_camera_button->set_disabled(false); - override_camera_button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera.")); + override_camera_button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera.")); } else { override_camera_button->set_disabled(true); override_camera_button->set_pressed(false); - override_camera_button->set_tooltip(TTR("Game Camera Override\nNo game instance running.")); + override_camera_button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature.")); } } @@ -4837,10 +4414,19 @@ void CanvasItemEditor::_popup_callback(int p_op) { snap_dialog->popup_centered(Size2(220, 160) * EDSCALE); } break; case SKELETON_SHOW_BONES: { - skeleton_show_bones = !skeleton_show_bones; - int idx = skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES); - skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones); - viewport->update(); + List<Node *> selection = editor_selection->get_selected_node_list(); + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { + // Add children nodes so they are processed + for (int child = 0; child < E->get()->get_child_count(); child++) { + selection.push_back(E->get()->get_child(child)); + } + + Bone2D *bone_2d = Object::cast_to<Bone2D>(E->get()); + if (!bone_2d || !bone_2d->is_inside_tree()) { + continue; + } + bone_2d->_editor_set_show_bone_gizmo(!bone_2d->_editor_get_show_bone_gizmo()); + } } break; case SHOW_HELPERS: { show_helpers = !show_helpers; @@ -5189,107 +4775,45 @@ void CanvasItemEditor::_popup_callback(int p_op) { } break; case SKELETON_MAKE_BONES: { Map<Node *, Object *> &selection = editor_selection->get_selection(); + Node *editor_root = EditorNode::get_singleton()->get_edited_scene()->get_tree()->get_edited_scene_root(); - undo_redo->create_action(TTR("Create Custom Bone(s) from Node(s)")); + undo_redo->create_action(TTR("Create Custom Bone2D(s) from Node(s)")); for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { Node2D *n2d = Object::cast_to<Node2D>(E->key()); - if (!n2d) { - continue; - } - if (!n2d->is_visible_in_tree()) { - continue; - } - if (!n2d->get_parent_item()) { - continue; - } - if (n2d->has_meta("_edit_bone_") && n2d->get_meta("_edit_bone_")) { - continue; - } - - undo_redo->add_do_method(n2d, "set_meta", "_edit_bone_", true); - undo_redo->add_undo_method(n2d, "remove_meta", "_edit_bone_"); - } - undo_redo->add_do_method(this, "_queue_update_bone_list"); - undo_redo->add_undo_method(this, "_queue_update_bone_list"); - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); - undo_redo->commit_action(); - } break; - case SKELETON_CLEAR_BONES: { - Map<Node *, Object *> &selection = editor_selection->get_selection(); + Bone2D *new_bone = memnew(Bone2D); + String new_bone_name = n2d->get_name(); + new_bone_name += "Bone2D"; + new_bone->set_name(new_bone_name); + new_bone->set_transform(n2d->get_transform()); - undo_redo->create_action(TTR("Clear Bones")); - for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - Node2D *n2d = Object::cast_to<Node2D>(E->key()); - if (!n2d) { - continue; - } - if (!n2d->is_visible_in_tree()) { - continue; - } - if (!n2d->has_meta("_edit_bone_")) { + Node *n2d_parent = n2d->get_parent(); + if (!n2d_parent) { continue; } - undo_redo->add_do_method(n2d, "remove_meta", "_edit_bone_"); - undo_redo->add_undo_method(n2d, "set_meta", "_edit_bone_", n2d->get_meta("_edit_bone_")); - } - undo_redo->add_do_method(this, "_queue_update_bone_list"); - undo_redo->add_undo_method(this, "_queue_update_bone_list"); - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); - undo_redo->commit_action(); - - } break; - case SKELETON_SET_IK_CHAIN: { - List<Node *> selection = editor_selection->get_selected_node_list(); + undo_redo->add_do_method(n2d_parent, "add_child", new_bone); + undo_redo->add_do_method(n2d_parent, "remove_child", n2d); + undo_redo->add_do_method(new_bone, "add_child", n2d); + undo_redo->add_do_method(n2d, "set_transform", Transform2D()); + undo_redo->add_do_method(this, "_set_owner_for_node_and_children", new_bone, editor_root); - undo_redo->create_action(TTR("Make IK Chain")); - for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *canvas_item = Object::cast_to<CanvasItem>(E->get()); - if (!canvas_item || !canvas_item->is_visible_in_tree()) { - continue; - } - if (canvas_item->get_viewport() != EditorNode::get_singleton()->get_scene_root()) { - continue; - } - if (canvas_item->has_meta("_edit_ik_") && canvas_item->get_meta("_edit_ik_")) { - continue; - } - - undo_redo->add_do_method(canvas_item, "set_meta", "_edit_ik_", true); - undo_redo->add_undo_method(canvas_item, "remove_meta", "_edit_ik_"); + undo_redo->add_undo_method(new_bone, "remove_child", n2d); + undo_redo->add_undo_method(n2d_parent, "add_child", n2d); + undo_redo->add_undo_method(n2d, "set_transform", new_bone->get_transform()); + undo_redo->add_undo_method(new_bone, "queue_free"); + undo_redo->add_undo_method(this, "_set_owner_for_node_and_children", n2d, editor_root); } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); undo_redo->commit_action(); } break; - case SKELETON_CLEAR_IK_CHAIN: { - Map<Node *, Object *> &selection = editor_selection->get_selection(); - - undo_redo->create_action(TTR("Clear IK Chain")); - for (Map<Node *, Object *>::Element *E = selection.front(); E; E = E->next()) { - CanvasItem *n2d = Object::cast_to<CanvasItem>(E->key()); - if (!n2d) { - continue; - } - if (!n2d->is_visible_in_tree()) { - continue; - } - if (!n2d->has_meta("_edit_ik_")) { - continue; - } - - undo_redo->add_do_method(n2d, "remove_meta", "_edit_ik_"); - undo_redo->add_undo_method(n2d, "set_meta", "_edit_ik_", n2d->get_meta("_edit_ik_")); - } - undo_redo->add_do_method(viewport, "update"); - undo_redo->add_undo_method(viewport, "update"); - undo_redo->commit_action(); + } +} - } break; +void CanvasItemEditor::_set_owner_for_node_and_children(Node *p_node, Node *p_owner) { + p_node->set_owner(p_owner); + for (int i = 0; i < p_node->get_child_count(); i++) { + _set_owner_for_node_and_children(p_node->get_child(i), p_owner); } } @@ -5358,14 +4882,12 @@ void CanvasItemEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button); ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data); ClassDB::bind_method("_unhandled_key_input", &CanvasItemEditor::_unhandled_key_input); - ClassDB::bind_method("_queue_update_bone_list", &CanvasItemEditor::_update_bone_list); - ClassDB::bind_method("_update_bone_list", &CanvasItemEditor::_update_bone_list); - ClassDB::bind_method("_reset_create_position", &CanvasItemEditor::_reset_create_position); - ClassDB::bind_method(D_METHOD("get_state"), &CanvasItemEditor::get_state); ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state); ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport); ClassDB::bind_method(D_METHOD("_zoom_on_position"), &CanvasItemEditor::_zoom_on_position); + ClassDB::bind_method("_set_owner_for_node_and_children", &CanvasItemEditor::_set_owner_for_node_and_children); + ADD_SIGNAL(MethodInfo("item_lock_status_changed")); ADD_SIGNAL(MethodInfo("item_group_status_changed")); } @@ -5402,7 +4924,6 @@ Dictionary CanvasItemEditor::get_state() const { state["snap_scale"] = snap_scale; state["snap_relative"] = snap_relative; state["snap_pixel"] = snap_pixel; - state["skeleton_show_bones"] = skeleton_show_bones; return state; } @@ -5570,12 +5091,6 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) { snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel); } - if (state.has("skeleton_show_bones")) { - skeleton_show_bones = state["skeleton_show_bones"]; - int idx = skeleton_menu->get_popup()->get_item_index(SKELETON_SHOW_BONES); - skeleton_menu->get_popup()->set_item_checked(idx, skeleton_show_bones); - } - if (update_scrollbars) { _update_scrollbars(); } @@ -5658,8 +5173,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { selected_from_canvas = false; anchors_mode = false; - skeleton_show_bones = true; - drag_type = DRAG_NONE; drag_from = Vector2(); drag_to = Vector2(); @@ -5675,7 +5188,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { bone_last_frame = 0; - bone_list_dirty = false; tool = TOOL_SELECT; undo_redo = p_editor->get_undo_redo(); editor = p_editor; @@ -5911,24 +5423,32 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { lock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(LOCK_SELECTED)); lock_button->set_tooltip(TTR("Lock the selected object in place (can't be moved).")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KEY_MASK_CMD | KEY_L)); unlock_button = memnew(Button); unlock_button->set_flat(true); hb->add_child(unlock_button); unlock_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNLOCK_SELECTED)); unlock_button->set_tooltip(TTR("Unlock the selected object (can be moved).")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_L)); group_button = memnew(Button); group_button->set_flat(true); hb->add_child(group_button); group_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(GROUP_SELECTED)); group_button->set_tooltip(TTR("Makes sure the object's children are not selectable.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KEY_MASK_CMD | KEY_G)); ungroup_button = memnew(Button); ungroup_button->set_flat(true); hb->add_child(ungroup_button); ungroup_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(UNGROUP_SELECTED)); ungroup_button->set_tooltip(TTR("Restores the object's children's ability to be selected.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G)); hb->add_child(memnew(VSeparator)); @@ -5940,13 +5460,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p = skeleton_menu->get_popup(); p->set_hide_on_checkable_item_selection(false); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_set_ik_chain", TTR("Make IK Chain")), SKELETON_SET_IK_CHAIN); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_ik_chain", TTR("Clear IK Chain")), SKELETON_CLEAR_IK_CHAIN); + p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_show_bones", TTR("Show Bones")), SKELETON_SHOW_BONES); p->add_separator(); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Custom Bone(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_clear_bones", TTR("Clear Custom Bones")), SKELETON_CLEAR_BONES); + p->add_shortcut(ED_SHORTCUT("canvas_item_editor/skeleton_make_bones", TTR("Make Bone2D Node(s) from Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_B), SKELETON_MAKE_BONES); p->connect("id_pressed", callable_mp(this, &CanvasItemEditor::_popup_callback)); hb->add_child(memnew(VSeparator)); @@ -5970,7 +5486,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p = view_menu->get_popup(); p->set_hide_on_checkable_item_selection(false); - p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Always Show Grid"), KEY_MASK_CTRL | KEY_G), SHOW_GRID); + p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_grid", TTR("Always Show Grid"), KEY_NUMBERSIGN), SHOW_GRID); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_helpers", TTR("Show Helpers"), KEY_H), SHOW_HELPERS); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_rulers", TTR("Show Rulers")), SHOW_RULERS); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/show_guides", TTR("Show Guides"), KEY_Y), SHOW_GUIDES); @@ -6115,12 +5631,12 @@ void CanvasItemEditorPlugin::make_visible(bool p_visible) { if (p_visible) { canvas_item_editor->show(); canvas_item_editor->set_physics_process(true); - RenderingServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), false); + RenderingServer::get_singleton()->viewport_set_disable_2d(editor->get_scene_root()->get_viewport_rid(), false); } else { canvas_item_editor->hide(); canvas_item_editor->set_physics_process(false); - RenderingServer::get_singleton()->viewport_set_hide_canvas(editor->get_scene_root()->get_viewport_rid(), true); + RenderingServer::get_singleton()->viewport_set_disable_2d(editor->get_scene_root()->get_viewport_rid(), true); } } @@ -6190,7 +5706,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons label_desc->show(); } else { if (scene.is_valid()) { - Node *instance = scene->instance(); + Node *instance = scene->instantiate(); if (instance) { preview_node->add_child(instance); } @@ -6303,26 +5819,26 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons return false; } - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { // error on instancing + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { // error on instancing return false; } if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing - if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) { - memdelete(instanced_scene); + if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instantiated_scene)) { + memdelete(instantiated_scene); return false; } } - instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path)); + instantiated_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path)); - editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene); - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(instanced_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene); + editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(instantiated_scene); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); - String new_name = parent->validate_child_name(instanced_scene); + String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name); editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); @@ -6333,11 +5849,11 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons target_pos = canvas_item_editor->snap_point(target_pos); target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos); // Preserve instance position of the original scene. - CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instanced_scene); + CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene); if (instance_ci) { target_pos += instance_ci->_edit_get_position(); } - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_position", target_pos); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_position", target_pos); } return true; @@ -6420,7 +5936,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian if (d.has("type")) { if (String(d["type"]) == "files") { Vector<String> files = d["files"]; - bool can_instance = false; + bool can_instantiate = false; for (int i = 0; i < files.size(); i++) { // check if dragged files contain resource or scene can be created at least once RES res = ResourceLoader::load(files[i]); if (res.is_null()) { @@ -6429,11 +5945,11 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian String type = res->get_class(); if (type == "PackedScene") { Ref<PackedScene> sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { continue; } - memdelete(instanced_scene); + memdelete(instantiated_scene); } else if (type == "Texture2D" || type == "ImageTexture" || type == "ViewportTexture" || @@ -6448,10 +5964,10 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian } else { continue; } - can_instance = true; + can_instantiate = true; break; } - if (can_instance) { + if (can_instantiate) { if (!preview_node->get_parent()) { // create preview only once _create_preview(files); } @@ -6459,7 +5975,7 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x); label->set_text(vformat(TTR("Adding %s..."), default_type)); } - return can_instance; + return can_instantiate; } } label->hide(); @@ -6584,7 +6100,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte vbc->add_child(btn_group); btn_group->set_h_size_flags(0); - button_group.instance(); + button_group.instantiate(); for (int i = 0; i < types.size(); i++) { CheckBox *check = memnew(CheckBox); btn_group->add_child(check); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 21ef3f88df..7b64d0cb5d 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -187,10 +187,7 @@ private: VIEW_FRAME_TO_SELECTION, PREVIEW_CANVAS_SCALE, SKELETON_MAKE_BONES, - SKELETON_CLEAR_BONES, - SKELETON_SHOW_BONES, - SKELETON_SET_IK_CHAIN, - SKELETON_CLEAR_IK_CHAIN + SKELETON_SHOW_BONES }; enum DragType { @@ -209,6 +206,7 @@ private: DRAG_ANCHOR_BOTTOM_RIGHT, DRAG_ANCHOR_BOTTOM_LEFT, DRAG_ANCHOR_ALL, + DRAG_QUEUED, DRAG_MOVE, DRAG_MOVE_X, DRAG_MOVE_Y, @@ -223,7 +221,6 @@ private: DRAG_KEY_MOVE }; - EditorSelection *editor_selection; bool selection_menu_additive_selection; Tool tool; @@ -277,7 +274,6 @@ private: bool snap_scale; bool snap_relative; bool snap_pixel; - bool skeleton_show_bones; bool key_pos; bool key_rot; bool key_scale; @@ -384,6 +380,7 @@ private: Control *top_ruler; Control *left_ruler; + Point2 drag_start_origin; DragType drag_type; Point2 drag_from; Point2 drag_to; @@ -412,7 +409,6 @@ private: bool _is_node_movable(const Node *p_node, bool p_popup_warning = false); void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, bool p_allow_locked = false); - void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items); void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append); @@ -423,9 +419,7 @@ private: void _add_canvas_item(CanvasItem *p_canvas_item); - void _save_canvas_item_ik_chain(const CanvasItem *p_canvas_item, List<float> *p_bones_length, List<Dictionary> *p_bones_state); void _save_canvas_item_state(List<CanvasItem *> p_canvas_items, bool save_bones = false); - void _restore_canvas_item_ik_chain(CanvasItem *p_canvas_item, const List<Dictionary> *p_bones_state); void _restore_canvas_item_state(List<CanvasItem *> p_canvas_items, bool restore_bones = false); void _commit_canvas_item_state(List<CanvasItem *> p_canvas_items, String action_name, bool commit_bones = false); @@ -445,8 +439,6 @@ private: void _reset_create_position(); UndoRedo *undo_redo; - bool _build_bones_list(Node *p_node); - bool _get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone); List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); @@ -476,7 +468,6 @@ private: void _draw_control_helpers(Control *control); void _draw_selection(); void _draw_axis(); - void _draw_bones(); void _draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _draw_hover(); @@ -503,8 +494,6 @@ private: void _focus_selection(int p_op); - void _solve_IK(Node2D *leaf_node, Point2 target_position); - SnapTarget snap_target[2]; Transform2D snap_transform; void _snap_if_closer_float( @@ -546,14 +535,11 @@ private: HSplitContainer *palette_split; VSplitContainer *bottom_split; - bool bone_list_dirty; - void _queue_update_bone_list(); - void _update_bone_list(); - void _tree_changed(Node *); - void _popup_warning_temporarily(Control *p_control, const float p_duration); void _popup_warning_depop(Control *p_control); + void _set_owner_for_node_and_children(Node *p_node, Node *p_owner); + friend class CanvasItemEditorPlugin; protected: @@ -641,6 +627,8 @@ public: bool is_anchors_mode_enabled() { return anchors_mode; }; + EditorSelection *editor_selection; + CanvasItemEditor(EditorNode *p_editor); }; diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp index 252e5c68a0..6f90d278bd 100644 --- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp @@ -32,8 +32,8 @@ #include "canvas_item_editor_plugin.h" #include "core/input/input.h" +#include "core/io/file_access.h" #include "core/math/geometry_2d.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "editor/editor_settings.h" #include "node_3d_editor_plugin.h" @@ -108,8 +108,8 @@ bool CollisionPolygon3DEditor::forward_spatial_gui_input(Camera3D *p_camera, con return false; } - Transform gt = node->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = node->get_global_transform(); + Transform3D gi = gt.affine_inverse(); float depth = _get_depth() * 0.5; Vector3 n = gt.basis.get_axis(2).normalized(); Plane p(gt.origin + n * depth, n); @@ -358,9 +358,9 @@ void CollisionPolygon3DEditor::_polygon_draw() { float depth = _get_depth() * 0.5; - imgeom->clear(); + imesh->clear_surfaces(); imgeom->set_material_override(line_material); - imgeom->begin(Mesh::PRIMITIVE_LINES, Ref<Texture2D>()); + imesh->surface_begin(Mesh::PRIMITIVE_LINES); Rect2 rect; @@ -382,10 +382,10 @@ void CollisionPolygon3DEditor::_polygon_draw() { Vector3 point = Vector3(p.x, p.y, depth); Vector3 next_point = Vector3(p2.x, p2.y, depth); - imgeom->set_color(Color(1, 0.3, 0.1, 0.8)); - imgeom->add_vertex(point); - imgeom->set_color(Color(1, 0.3, 0.1, 0.8)); - imgeom->add_vertex(next_point); + imesh->surface_set_color(Color(1, 0.3, 0.1, 0.8)); + imesh->surface_add_vertex(point); + imesh->surface_set_color(Color(1, 0.3, 0.1, 0.8)); + imesh->surface_add_vertex(next_point); //Color col=Color(1,0.3,0.1,0.8); //vpc->draw_line(point,next_point,col,2); @@ -402,45 +402,43 @@ void CollisionPolygon3DEditor::_polygon_draw() { r.size.y = rect.size.y; r.size.z = 0; - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(0.3, 0, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(0.0, 0.3, 0)); - - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0) - Vector3(0.3, 0, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(r.size.x, 0, 0) + Vector3(0, 0.3, 0)); - - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0) - Vector3(0, 0.3, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + Vector3(0, r.size.y, 0) + Vector3(0.3, 0, 0)); - - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + r.size); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + r.size - Vector3(0.3, 0, 0)); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + r.size); - imgeom->set_color(Color(0.8, 0.8, 0.8, 0.2)); - imgeom->add_vertex(r.position + r.size - Vector3(0.0, 0.3, 0)); - - imgeom->end(); - - m->clear_surfaces(); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(0.3, 0, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(0.0, 0.3, 0)); + + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0) - Vector3(0.3, 0, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(r.size.x, 0, 0) + Vector3(0, 0.3, 0)); + + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0) - Vector3(0, 0.3, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + Vector3(0, r.size.y, 0) + Vector3(0.3, 0, 0)); + + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + r.size); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + r.size - Vector3(0.3, 0, 0)); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + r.size); + imesh->surface_set_color(Color(0.8, 0.8, 0.8, 0.2)); + imesh->surface_add_vertex(r.position + r.size - Vector3(0.0, 0.3, 0)); + + imesh->surface_end(); if (poly.size() == 0) { return; @@ -515,8 +513,10 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) { mode = MODE_EDIT; wip_active = false; - imgeom = memnew(ImmediateGeometry3D); - imgeom->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001))); + imgeom = memnew(MeshInstance3D); + imesh.instantiate(); + imgeom->set_mesh(imesh); + imgeom->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001))); line_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); @@ -537,9 +537,9 @@ CollisionPolygon3DEditor::CollisionPolygon3DEditor(EditorNode *p_editor) { pointsm = memnew(MeshInstance3D); imgeom->add_child(pointsm); - m.instance(); + m.instantiate(); pointsm->set_mesh(m); - pointsm->set_transform(Transform(Basis(), Vector3(0, 0, 0.00001))); + pointsm->set_transform(Transform3D(Basis(), Vector3(0, 0, 0.00001))); snap_ignore = false; } diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.h b/editor/plugins/collision_polygon_3d_editor_plugin.h index c66518e3e5..5db0f7308a 100644 --- a/editor/plugins/collision_polygon_3d_editor_plugin.h +++ b/editor/plugins/collision_polygon_3d_editor_plugin.h @@ -34,8 +34,8 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "scene/3d/collision_polygon_3d.h" -#include "scene/3d/immediate_geometry_3d.h" #include "scene/3d/mesh_instance_3d.h" +#include "scene/resources/immediate_mesh.h" class CanvasItemEditor; @@ -60,7 +60,8 @@ class CollisionPolygon3DEditor : public HBoxContainer { EditorNode *editor; Panel *panel; Node3D *node; - ImmediateGeometry3D *imgeom; + Ref<ImmediateMesh> imesh; + MeshInstance3D *imgeom; MeshInstance3D *pointsm; Ref<ArrayMesh> m; diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 3403aeceba..6a56cd31d1 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -74,7 +74,7 @@ void CPUParticles2DEditorPlugin::_menu_callback(int p_idx) { void CPUParticles2DEditorPlugin::_generate_emission_mask() { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = ImageLoader::load_image(source_emission_file, img); ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'."); diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 7a38fd2bd5..706243fe25 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -127,6 +127,8 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) { case MOUSE_BUTTON_LEFT: _dragging = true; break; + default: + break; } } @@ -776,7 +778,7 @@ void EditorInspectorPluginCurve::parse_begin(Object *p_object) { CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginCurve> curve_plugin; - curve_plugin.instance(); + curve_plugin.instantiate(); EditorInspector::add_inspector_plugin(curve_plugin); get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); @@ -798,7 +800,7 @@ Ref<Texture2D> CurvePreviewGenerator::generate(const Ref<Resource> &p_from, cons int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; Ref<Image> img_ref; - img_ref.instance(); + img_ref.instantiate(); Image &im = **img_ref; im.create(thumbnail_size, thumbnail_size / 2, false, Image::FORMAT_RGBA8); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 2d79e4f3e3..a233d66d82 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -174,7 +174,7 @@ Ref<Texture2D> EditorImagePreviewPlugin::generate(const RES &p_from, const Size2 post_process_preview(img); Ref<ImageTexture> ptex; - ptex.instance(); + ptex.instantiate(); ptex->create_from_image(img); return ptex; @@ -219,7 +219,7 @@ Ref<Texture2D> EditorBitmapPreviewPlugin::generate(const RES &p_from, const Size } Ref<Image> img; - img.instance(); + img.instantiate(); img->create(bm->get_size().width, bm->get_size().height, false, Image::FORMAT_L8, data); if (img->is_compressed()) { @@ -278,7 +278,7 @@ Ref<Texture2D> EditorPackedScenePreviewPlugin::generate_from_path(const String & } Ref<Image> img; - img.instance(); + img.instantiate(); Error err = img->load(path); if (err == OK) { Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); @@ -359,12 +359,12 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { camera = RS::get_singleton()->camera_create(); RS::get_singleton()->viewport_attach_camera(viewport, camera); - RS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3))); + RS::get_singleton()->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 0, 3))); RS::get_singleton()->camera_set_perspective(camera, 45, 0.1, 10); light = RS::get_singleton()->directional_light_create(); light_instance = RS::get_singleton()->instance_create2(light, scenario); - RS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); light2 = RS::get_singleton()->directional_light_create(); RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); @@ -372,7 +372,7 @@ EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() { light_instance2 = RS::get_singleton()->instance_create2(light2, scenario); - RS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + RS::get_singleton()->instance_set_transform(light_instance2, Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); sphere = RS::get_singleton()->mesh_create(); sphere_instance = RS::get_singleton()->instance_create2(sphere, scenario); @@ -501,7 +501,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const RES &p_from, const Size int line = 0; int col = 0; Ref<Image> img; - img.instance(); + img.instantiate(); int thumbnail_size = MAX(p_size.x, p_size.y); img->create(thumbnail_size, thumbnail_size, false, Image::FORMAT_RGBA8); @@ -688,7 +688,7 @@ Ref<Texture2D> EditorAudioStreamPreviewPlugin::generate(const RES &p_from, const Ref<ImageTexture> ptex = Ref<ImageTexture>(memnew(ImageTexture)); Ref<Image> image; - image.instance(); + image.instantiate(); image->create(w, h, false, Image::FORMAT_RGB8, img); ptex->create_from_image(image); return ptex; @@ -720,7 +720,7 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 AABB aabb = mesh->get_aabb(); Vector3 ofs = aabb.position + aabb.size * 0.5; aabb.position -= ofs; - Transform xform; + Transform3D xform; xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI * 0.125); xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI * 0.125) * xform.basis; AABB rot_aabb = xform.xform(aabb); @@ -780,20 +780,20 @@ EditorMeshPreviewPlugin::EditorMeshPreviewPlugin() { camera = RS::get_singleton()->camera_create(); RS::get_singleton()->viewport_attach_camera(viewport, camera); - RS::get_singleton()->camera_set_transform(camera, Transform(Basis(), Vector3(0, 0, 3))); + RS::get_singleton()->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 0, 3))); //RS::get_singleton()->camera_set_perspective(camera,45,0.1,10); RS::get_singleton()->camera_set_orthogonal(camera, 1.0, 0.01, 1000.0); light = RS::get_singleton()->directional_light_create(); light_instance = RS::get_singleton()->instance_create2(light, scenario); - RS::get_singleton()->instance_set_transform(light_instance, Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + RS::get_singleton()->instance_set_transform(light_instance, Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); light2 = RS::get_singleton()->directional_light_create(); RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); //RS::get_singleton()->light_set_color(light2, RS::LIGHT_COLOR_SPECULAR, Color(0.0, 0.0, 0.0)); light_instance2 = RS::get_singleton()->instance_create2(light2, scenario); - RS::get_singleton()->instance_set_transform(light_instance2, Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + RS::get_singleton()->instance_set_transform(light_instance2, Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); //sphere = RS::get_singleton()->mesh_create(); mesh_instance = RS::get_singleton()->instance_create(); @@ -832,7 +832,7 @@ struct FSample { }; static FSample _samples[] = { - { "hani", U"漢語" }, + { "hani", U"æ¼¢å—" }, { "armn", U"Ô±Õ¢" }, { "copt", U"Αα" }, { "cyrl", U"Ðб" }, @@ -881,7 +881,7 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, if (res->is_class("Font")) { sampled_font = res->duplicate(); } else if (res->is_class("FontData")) { - sampled_font.instance(); + sampled_font.instantiate(); sampled_font->add_data(res->duplicate()); } diff --git a/editor/plugins/font_editor_plugin.cpp b/editor/plugins/font_editor_plugin.cpp index fa58eb5480..e385a84087 100644 --- a/editor/plugins/font_editor_plugin.cpp +++ b/editor/plugins/font_editor_plugin.cpp @@ -56,7 +56,7 @@ struct FSample { }; static FSample _samples[] = { - { "hani", U"漢語" }, + { "hani", U"æ¼¢å—" }, { "armn", U"Ô±Õ¢" }, { "copt", U"Αα" }, { "cyrl", U"Ðб" }, @@ -119,7 +119,7 @@ void FontDataPreview::set_data(const Ref<FontData> &p_data) { } FontDataPreview::FontDataPreview() { - line.instance(); + line.instantiate(); } /*************************************************************************/ @@ -290,7 +290,7 @@ void EditorInspectorPluginFont::parse_begin(Object *p_object) { add_custom_control(editor); } -bool EditorInspectorPluginFont::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorPluginFont::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if (p_path.begins_with("language_support_override/") && p_object->is_class("FontData")) { String lang = p_path.replace("language_support_override/", ""); @@ -326,6 +326,6 @@ bool EditorInspectorPluginFont::parse_property(Object *p_object, Variant::Type p FontEditorPlugin::FontEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginFont> fd_plugin; - fd_plugin.instance(); + fd_plugin.instantiate(); EditorInspector::add_inspector_plugin(fd_plugin); } diff --git a/editor/plugins/font_editor_plugin.h b/editor/plugins/font_editor_plugin.h index 04e6c1dac7..71464003a0 100644 --- a/editor/plugins/font_editor_plugin.h +++ b/editor/plugins/font_editor_plugin.h @@ -94,7 +94,7 @@ class EditorInspectorPluginFont : public EditorInspectorPlugin { public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; }; /*************************************************************************/ diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index b447304a3f..37f900280b 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -146,7 +146,7 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } Ref<Image> img; - img.instance(); + img.instantiate(); Error err = ImageLoader::load_image(source_emission_file, img); ERR_FAIL_COND_MSG(err != OK, "Error loading image '" + source_emission_file + "'."); @@ -270,11 +270,11 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } } - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGF, texdata); Ref<ImageTexture> imgt; - imgt.instance(); + imgt.instantiate(); imgt->create_from_image(img); pm->set_emission_point_texture(imgt); @@ -291,10 +291,10 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } } - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8, colordata); - imgt.instance(); + imgt.instantiate(); imgt->create_from_image(img); pm->set_emission_color_texture(imgt); } @@ -314,10 +314,10 @@ void GPUParticles2DEditorPlugin::_generate_emission_mask() { } } - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGF, normdata); - imgt.instance(); + imgt.instantiate(); imgt->create_from_image(img); pm->set_emission_normal_texture(imgt); diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index 89d6aaa5f9..571bcf9c4a 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -177,7 +177,7 @@ void GPUParticles3DEditorBase::_node_selected(const NodePath &p_path) { return; } - Transform geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform(); + Transform3D geom_xform = base_node->get_global_transform().affine_inverse() * vi->get_global_transform(); int gc = geometry.size(); Face3 *w = geometry.ptrw(); @@ -359,7 +359,7 @@ void GPUParticles3DEditor::_generate_emission_points() { Ref<Image> image = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img)); Ref<ImageTexture> tex; - tex.instance(); + tex.instantiate(); Ref<ParticlesMaterial> material = node->get_process_material(); ERR_FAIL_COND(material.is_null()); @@ -387,7 +387,7 @@ void GPUParticles3DEditor::_generate_emission_points() { Ref<Image> image2 = memnew(Image(w, h, false, Image::FORMAT_RGBF, point_img2)); Ref<ImageTexture> tex2; - tex2.instance(); + tex2.instantiate(); material->set_emission_normal_texture(tex2); } else { diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp index 8c4928b7cb..a2dee4a1dc 100644 --- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp @@ -137,7 +137,7 @@ void GPUParticlesCollisionSDFEditorPlugin::_sdf_save_path_and_bake(const String Ref<ConfigFile> config; - config.instance(); + config.instantiate(); if (FileAccess::exists(p_path + ".import")) { config->load(p_path + ".import"); } diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 46fa00f730..355bdb69d8 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -92,6 +92,6 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) { GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginGradient> plugin; - plugin.instance(); + plugin.instantiate(); add_inspector_plugin(plugin); } diff --git a/editor/plugins/input_event_editor_plugin.cpp b/editor/plugins/input_event_editor_plugin.cpp new file mode 100644 index 0000000000..f1aa10844b --- /dev/null +++ b/editor/plugins/input_event_editor_plugin.cpp @@ -0,0 +1,122 @@ +/*************************************************************************/ +/* input_event_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "input_event_editor_plugin.h" + +void InputEventConfigContainer::_bind_methods() { +} + +void InputEventConfigContainer::_configure_pressed() { + config_dialog->popup_and_configure(input_event); +} + +void InputEventConfigContainer::_event_changed() { + input_event_text->set_text(input_event->as_text()); +} + +void InputEventConfigContainer::_config_dialog_confirmed() { + Ref<InputEvent> ie = config_dialog->get_event(); + input_event->copy_from(ie); + _event_changed(); +} + +Size2 InputEventConfigContainer::get_minimum_size() const { + // Don't bother with a minimum x size for the control - we don't want the inspector + // to jump in size if a long text is placed in the label (e.g. Joypad Axis description) + return Size2(0, HBoxContainer::get_minimum_size().y); +} + +void InputEventConfigContainer::set_event(const Ref<InputEvent> &p_event) { + Ref<InputEventKey> k = p_event; + Ref<InputEventMouseButton> m = p_event; + Ref<InputEventJoypadButton> jb = p_event; + Ref<InputEventJoypadMotion> jm = p_event; + + if (k.is_valid()) { + config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_KEY); + } else if (m.is_valid()) { + config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_MOUSE_BUTTON); + } else if (jb.is_valid()) { + config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_JOY_BUTTON); + } else if (jm.is_valid()) { + config_dialog->set_allowed_input_types(InputEventConfigurationDialog::InputType::INPUT_JOY_MOTION); + } + + input_event = p_event; + _event_changed(); + input_event->connect("changed", callable_mp(this, &InputEventConfigContainer::_event_changed)); +} + +InputEventConfigContainer::InputEventConfigContainer() { + MarginContainer *mc = memnew(MarginContainer); + mc->add_theme_constant_override("margin_left", 10); + mc->add_theme_constant_override("margin_right", 10); + mc->add_theme_constant_override("margin_top", 10); + mc->add_theme_constant_override("margin_bottom", 10); + add_child(mc); + + HBoxContainer *hb = memnew(HBoxContainer); + mc->add_child(hb); + + open_config_button = memnew(Button); + open_config_button->set_text("Configure"); + open_config_button->connect("pressed", callable_mp(this, &InputEventConfigContainer::_configure_pressed)); + hb->add_child(open_config_button); + + input_event_text = memnew(Label); + hb->add_child(input_event_text); + + config_dialog = memnew(InputEventConfigurationDialog); + config_dialog->connect("confirmed", callable_mp(this, &InputEventConfigContainer::_config_dialog_confirmed)); + add_child(config_dialog); +} + +bool EditorInspectorPluginInputEvent::can_handle(Object *p_object) { + Ref<InputEventKey> k = Ref<InputEventKey>(p_object); + Ref<InputEventMouseButton> m = Ref<InputEventMouseButton>(p_object); + Ref<InputEventJoypadButton> jb = Ref<InputEventJoypadButton>(p_object); + Ref<InputEventJoypadMotion> jm = Ref<InputEventJoypadMotion>(p_object); + + return k.is_valid() || m.is_valid() || jb.is_valid() || jm.is_valid(); +} + +void EditorInspectorPluginInputEvent::parse_begin(Object *p_object) { + Ref<InputEvent> ie = Ref<InputEvent>(p_object); + + InputEventConfigContainer *picker_controls = memnew(InputEventConfigContainer); + picker_controls->set_event(ie); + add_custom_control(picker_controls); +} + +InputEventEditorPlugin::InputEventEditorPlugin(EditorNode *p_node) { + Ref<EditorInspectorPluginInputEvent> plugin; + plugin.instantiate(); + add_inspector_plugin(plugin); +} diff --git a/editor/plugins/input_event_editor_plugin.h b/editor/plugins/input_event_editor_plugin.h new file mode 100644 index 0000000000..bc8293c9e5 --- /dev/null +++ b/editor/plugins/input_event_editor_plugin.h @@ -0,0 +1,79 @@ +/*************************************************************************/ +/* input_event_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef INPUT_EVENT_EDITOR_PLUGIN_H +#define INPUT_EVENT_EDITOR_PLUGIN_H + +#include "editor/action_map_editor.h" +#include "editor/editor_inspector.h" +#include "editor/editor_node.h" + +class InputEventConfigContainer : public HBoxContainer { + GDCLASS(InputEventConfigContainer, HBoxContainer); + + Label *input_event_text; + Button *open_config_button; + + Ref<InputEvent> input_event; + InputEventConfigurationDialog *config_dialog; + + void _config_dialog_confirmed(); + void _configure_pressed(); + + void _event_changed(); + +protected: + static void _bind_methods(); + +public: + virtual Size2 get_minimum_size() const override; + void set_event(const Ref<InputEvent> &p_event); + + InputEventConfigContainer(); +}; + +class EditorInspectorPluginInputEvent : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginInputEvent, EditorInspectorPlugin); + +public: + virtual bool can_handle(Object *p_object) override; + virtual void parse_begin(Object *p_object) override; +}; + +class InputEventEditorPlugin : public EditorPlugin { + GDCLASS(InputEventEditorPlugin, EditorPlugin); + +public: + virtual String get_name() const override { return "InputEvent"; } + + InputEventEditorPlugin(EditorNode *p_node); +}; + +#endif // INPUT_EVENT_EDITOR_PLUGIN_H diff --git a/editor/plugins/baked_lightmap_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp index 470b61bf40..484fdabfe1 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.cpp +++ b/editor/plugins/lightmap_gi_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* baked_lightmap_editor_plugin.cpp */ +/* lightmap_gi_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "baked_lightmap_editor_plugin.h" +#include "lightmap_gi_editor_plugin.h" -void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) { +void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) { if (lightmap) { - BakedLightmap::BakeError err; + LightmapGI::BakeError err; if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) { err = lightmap->bake(lightmap, p_file, bake_func_step); } else { @@ -42,7 +42,7 @@ void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) { bake_func_end(); switch (err) { - case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH: { + case LightmapGI::BAKE_ERROR_NO_SAVE_PATH: { String scene_path = lightmap->get_filename(); if (scene_path == String()) { scene_path = lightmap->get_owner()->get_filename(); @@ -57,10 +57,10 @@ void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) { file_dialog->popup_file_dialog(); } break; - case BakedLightmap::BAKE_ERROR_NO_MESHES: + case LightmapGI::BAKE_ERROR_NO_MESHES: EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on.")); break; - case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE: + case LightmapGI::BAKE_ERROR_CANT_CREATE_IMAGE: EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable.")); break; default: { @@ -69,12 +69,12 @@ void BakedLightmapEditorPlugin::_bake_select_file(const String &p_file) { } } -void BakedLightmapEditorPlugin::_bake() { +void LightmapGIEditorPlugin::_bake() { _bake_select_file(""); } -void BakedLightmapEditorPlugin::edit(Object *p_object) { - BakedLightmap *s = Object::cast_to<BakedLightmap>(p_object); +void LightmapGIEditorPlugin::edit(Object *p_object) { + LightmapGI *s = Object::cast_to<LightmapGI>(p_object); if (!s) { return; } @@ -82,11 +82,11 @@ void BakedLightmapEditorPlugin::edit(Object *p_object) { lightmap = s; } -bool BakedLightmapEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("BakedLightmap"); +bool LightmapGIEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("LightmapGI"); } -void BakedLightmapEditorPlugin::make_visible(bool p_visible) { +void LightmapGIEditorPlugin::make_visible(bool p_visible) { if (p_visible) { bake->show(); } else { @@ -94,9 +94,9 @@ void BakedLightmapEditorPlugin::make_visible(bool p_visible) { } } -EditorProgress *BakedLightmapEditorPlugin::tmp_progress = nullptr; +EditorProgress *LightmapGIEditorPlugin::tmp_progress = nullptr; -bool BakedLightmapEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) { +bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) { if (!tmp_progress) { tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, false)); ERR_FAIL_COND_V(tmp_progress == nullptr, false); @@ -104,18 +104,18 @@ bool BakedLightmapEditorPlugin::bake_func_step(float p_progress, const String &p return tmp_progress->step(p_description, p_progress * 1000, p_refresh); } -void BakedLightmapEditorPlugin::bake_func_end() { +void LightmapGIEditorPlugin::bake_func_end() { if (tmp_progress != nullptr) { memdelete(tmp_progress); tmp_progress = nullptr; } } -void BakedLightmapEditorPlugin::_bind_methods() { - ClassDB::bind_method("_bake", &BakedLightmapEditorPlugin::_bake); +void LightmapGIEditorPlugin::_bind_methods() { + ClassDB::bind_method("_bake", &LightmapGIEditorPlugin::_bake); } -BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) { +LightmapGIEditorPlugin::LightmapGIEditorPlugin(EditorNode *p_node) { editor = p_node; bake = memnew(Button); bake->set_flat(true); @@ -130,9 +130,9 @@ BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) { file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->add_filter("*.lmbake ; LightMap Bake"); file_dialog->set_title(TTR("Select lightmap bake file:")); - file_dialog->connect("file_selected", callable_mp(this, &BakedLightmapEditorPlugin::_bake_select_file)); + file_dialog->connect("file_selected", callable_mp(this, &LightmapGIEditorPlugin::_bake_select_file)); bake->add_child(file_dialog); } -BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() { +LightmapGIEditorPlugin::~LightmapGIEditorPlugin() { } diff --git a/editor/plugins/baked_lightmap_editor_plugin.h b/editor/plugins/lightmap_gi_editor_plugin.h index d291c377d9..12d080d6be 100644 --- a/editor/plugins/baked_lightmap_editor_plugin.h +++ b/editor/plugins/lightmap_gi_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* baked_lightmap_editor_plugin.h */ +/* lightmap_gi_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,13 +33,13 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/baked_lightmap.h" +#include "scene/3d/lightmap_gi.h" #include "scene/resources/material.h" -class BakedLightmapEditorPlugin : public EditorPlugin { - GDCLASS(BakedLightmapEditorPlugin, EditorPlugin); +class LightmapGIEditorPlugin : public EditorPlugin { + GDCLASS(LightmapGIEditorPlugin, EditorPlugin); - BakedLightmap *lightmap; + LightmapGI *lightmap; Button *bake; EditorNode *editor; @@ -56,14 +56,14 @@ protected: static void _bind_methods(); public: - virtual String get_name() const override { return "BakedLightmap"; } + virtual String get_name() const override { return "LightmapGI"; } bool has_main_screen() const override { return false; } virtual void edit(Object *p_object) override; virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; - BakedLightmapEditorPlugin(EditorNode *p_node); - ~BakedLightmapEditorPlugin(); + LightmapGIEditorPlugin(EditorNode *p_node); + ~LightmapGIEditorPlugin(); }; #endif diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp index ad99ad7808..17a634ee14 100644 --- a/editor/plugins/material_editor_plugin.cpp +++ b/editor/plugins/material_editor_plugin.cpp @@ -111,7 +111,7 @@ MaterialEditor::MaterialEditor() { vc->set_anchors_and_offsets_preset(PRESET_WIDE); viewport = memnew(SubViewport); Ref<World3D> world_3d; - world_3d.instance(); + world_3d.instantiate(); viewport->set_world_3d(world_3d); //use own world vc->add_child(viewport); viewport->set_disable_input(true); @@ -119,17 +119,17 @@ MaterialEditor::MaterialEditor() { viewport->set_msaa(Viewport::MSAA_4X); camera = memnew(Camera3D); - camera->set_transform(Transform(Basis(), Vector3(0, 0, 3))); + camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 3))); camera->set_perspective(45, 0.1, 10); camera->make_current(); viewport->add_child(camera); light1 = memnew(DirectionalLight3D); - light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); viewport->add_child(light1); light2 = memnew(DirectionalLight3D); - light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + light2->set_transform(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); light2->set_color(Color(0.7, 0.7, 0.7)); viewport->add_child(light2); @@ -139,16 +139,16 @@ MaterialEditor::MaterialEditor() { box_instance = memnew(MeshInstance3D); viewport->add_child(box_instance); - Transform box_xform; + Transform3D box_xform; box_xform.basis.rotate(Vector3(1, 0, 0), Math::deg2rad(25.0)); box_xform.basis = box_xform.basis * Basis().rotated(Vector3(0, 1, 0), Math::deg2rad(-25.0)); box_xform.basis.scale(Vector3(0.8, 0.8, 0.8)); box_xform.origin.y = 0.2; box_instance->set_transform(box_xform); - sphere_mesh.instance(); + sphere_mesh.instantiate(); sphere_instance->set_mesh(sphere_mesh); - box_mesh.instance(); + box_mesh.instantiate(); box_instance->set_mesh(box_mesh); set_custom_minimum_size(Size2(1, 150) * EDSCALE); @@ -223,7 +223,7 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) { } EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() { - env.instance(); + env.instantiate(); Ref<Sky> sky = memnew(Sky()); env->set_sky(sky); env->set_background(Environment::BG_COLOR); @@ -233,7 +233,7 @@ EditorInspectorPluginMaterial::EditorInspectorPluginMaterial() { MaterialEditorPlugin::MaterialEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginMaterial> plugin; - plugin.instance(); + plugin.instantiate(); add_inspector_plugin(plugin); } @@ -251,10 +251,10 @@ Ref<Resource> StandardMaterial3DConversionPlugin::convert(const Ref<Resource> &p ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; - smat.instance(); + smat.instantiate(); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); @@ -295,10 +295,10 @@ Ref<Resource> ParticlesMaterialConversionPlugin::convert(const Ref<Resource> &p_ ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; - smat.instance(); + smat.instantiate(); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); @@ -332,10 +332,10 @@ Ref<Resource> CanvasItemMaterialConversionPlugin::convert(const Ref<Resource> &p ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; - smat.instance(); + smat.instantiate(); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); @@ -369,10 +369,10 @@ Ref<Resource> ProceduralSkyMaterialConversionPlugin::convert(const Ref<Resource> ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; - smat.instance(); + smat.instantiate(); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); @@ -406,10 +406,10 @@ Ref<Resource> PanoramaSkyMaterialConversionPlugin::convert(const Ref<Resource> & ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; - smat.instance(); + smat.instantiate(); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); @@ -443,10 +443,10 @@ Ref<Resource> PhysicalSkyMaterialConversionPlugin::convert(const Ref<Resource> & ERR_FAIL_COND_V(!mat.is_valid(), Ref<Resource>()); Ref<ShaderMaterial> smat; - smat.instance(); + smat.instantiate(); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = RS::get_singleton()->shader_get_code(mat->get_shader_rid()); diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 9d29c31522..fcc6b84efb 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -65,7 +65,7 @@ void MeshEditor::_notification(int p_what) { } void MeshEditor::_update_rotation() { - Transform t; + Transform3D t; t.basis.rotate(Vector3(0, 1, 0), -rot_y); t.basis.rotate(Vector3(1, 0, 0), -rot_x); rotation->set_transform(t); @@ -85,7 +85,7 @@ void MeshEditor::edit(Ref<Mesh> p_mesh) { if (m != 0) { m = 1.0 / m; m *= 0.5; - Transform xform; + Transform3D xform; xform.basis.scale(Vector3(m, m, m)); xform.origin = -xform.basis.xform(ofs); //-ofs*m; //xform.origin.z -= aabb.get_longest_axis_size() * 2; @@ -110,23 +110,23 @@ void MeshEditor::_bind_methods() { MeshEditor::MeshEditor() { viewport = memnew(SubViewport); Ref<World3D> world_3d; - world_3d.instance(); + world_3d.instantiate(); viewport->set_world_3d(world_3d); //use own world add_child(viewport); viewport->set_disable_input(true); viewport->set_msaa(Viewport::MSAA_2X); set_stretch(true); camera = memnew(Camera3D); - camera->set_transform(Transform(Basis(), Vector3(0, 0, 1.1))); + camera->set_transform(Transform3D(Basis(), Vector3(0, 0, 1.1))); camera->set_perspective(45, 0.1, 10); viewport->add_child(camera); light1 = memnew(DirectionalLight3D); - light1->set_transform(Transform().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); + light1->set_transform(Transform3D().looking_at(Vector3(-1, -1, -1), Vector3(0, 1, 0))); viewport->add_child(light1); light2 = memnew(DirectionalLight3D); - light2->set_transform(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); + light2->set_transform(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, 1))); light2->set_color(Color(0.7, 0.7, 0.7)); viewport->add_child(light2); @@ -182,6 +182,6 @@ void EditorInspectorPluginMesh::parse_begin(Object *p_object) { MeshEditorPlugin::MeshEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginMesh> plugin; - plugin.instance(); + plugin.instantiate(); add_inspector_plugin(plugin); } diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 0d2b2ea2f5..7434accc1a 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -153,14 +153,18 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->add_undo_method(node->get_parent(), "remove_child", cshape); ur->commit_action(); } break; - case MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE: { + + case MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE: + case MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE: { if (node == get_tree()->get_edited_scene_root()) { err_dialog->set_text(TTR("Can't create a single convex collision shape for the scene root.")); err_dialog->popup_centered(); return; } - Ref<Shape3D> shape = mesh->create_convex_shape(); + bool simplify = (p_option == MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE); + + Ref<Shape3D> shape = mesh->create_convex_shape(true, simplify); if (shape.is_null()) { err_dialog->set_text(TTR("Couldn't create a single convex collision shape.")); @@ -169,7 +173,11 @@ void MeshInstance3DEditor::_menu_option(int p_option) { } UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); - ur->create_action(TTR("Create Single Convex Shape")); + if (simplify) { + ur->create_action(TTR("Create Simplified Convex Shape")); + } else { + ur->create_action(TTR("Create Single Convex Shape")); + } CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(shape); @@ -186,6 +194,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->commit_action(); } break; + case MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES: { if (node == get_tree()->get_edited_scene_root()) { err_dialog->set_text(TTR("Can't create multiple convex collision shapes for the scene root.")); @@ -441,8 +450,10 @@ MeshInstance3DEditor::MeshInstance3DEditor() { options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is the most accurate (but slowest) option for collision detection.")); options->get_popup()->add_item(TTR("Create Single Convex Collision Sibling"), MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE); options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a single convex collision shape.\nThis is the fastest (but least accurate) option for collision detection.")); + options->get_popup()->add_item(TTR("Create Simplified Convex Collision Sibling"), MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a simplified convex collision shape.\nThis is similar to single collision shape, but can result in a simpler geometry in some cases, at the cost of accuracy.")); options->get_popup()->add_item(TTR("Create Multiple Convex Collision Siblings"), MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES); - options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between the two above options.")); + options->get_popup()->set_item_tooltip(options->get_popup()->get_item_count() - 1, TTR("Creates a polygon-based collision shape.\nThis is a performance middle-ground between a single convex collision and a polygon-based collision.")); options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH); options->get_popup()->add_separator(); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h index 69f494de7f..98b667c978 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.h +++ b/editor/plugins/mesh_instance_3d_editor_plugin.h @@ -43,6 +43,7 @@ class MeshInstance3DEditor : public Control { MENU_OPTION_CREATE_STATIC_TRIMESH_BODY, MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE, MENU_OPTION_CREATE_SINGLE_CONVEX_COLLISION_SHAPE, + MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE, MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES, MENU_OPTION_CREATE_NAVMESH, MENU_OPTION_CREATE_OUTLINE_MESH, diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 6f1f243444..5d1d29cbc8 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -127,7 +127,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, continue; } - //Transform shape_transform = sb->shape_owner_get_transform(E->get()); + //Transform3D shape_transform = sb->shape_owner_get_transform(E->get()); //shape_transform.set_origin(shape_transform.get_origin() - phys_offset); @@ -147,7 +147,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, p_library->set_item_shapes(id, collisions); Ref<NavigationMesh> navmesh; - Transform navmesh_transform; + Transform3D navmesh_transform; for (int j = 0; j < mi->get_child_count(); j++) { Node *child2 = mi->get_child(j); if (!Object::cast_to<NavigationRegion3D>(child2)) { @@ -170,7 +170,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, if (true) { Vector<Ref<Mesh>> meshes; - Vector<Transform> transforms; + Vector<Transform3D> transforms; Vector<int> ids = p_library->get_item_list(); for (int i = 0; i < ids.size(); i++) { if (mesh_instances.find(ids[i])) { @@ -193,7 +193,7 @@ void MeshLibraryEditor::_import_scene(Node *p_scene, Ref<MeshLibrary> p_library, void MeshLibraryEditor::_import_scene_cbk(const String &p_str) { Ref<PackedScene> ps = ResourceLoader::load(p_str, "PackedScene"); ERR_FAIL_COND(ps.is_null()); - Node *scene = ps->instance(); + Node *scene = ps->instantiate(); ERR_FAIL_COND_MSG(!scene, "Cannot create an instance from PackedScene '" + p_str + "'."); diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index 19c6dcf402..48b885930f 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -111,7 +111,7 @@ void MultiMeshEditor::_populate() { return; } - Transform geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform(); + Transform3D geom_xform = node->get_global_transform().affine_inverse() * ss_instance->get_global_transform(); Vector<Face3> geometry = ss_instance->get_faces(VisualInstance3D::FACES_SOLID); @@ -167,7 +167,7 @@ void MultiMeshEditor::_populate() { float _scale = populate_scale->get_value(); int axis = populate_axis->get_selected(); - Transform axis_xform; + Transform3D axis_xform; if (axis == Vector3::AXIS_Z) { axis_xform.rotate(Vector3(1, 0, 0), -Math_PI * 0.5); } @@ -191,7 +191,7 @@ void MultiMeshEditor::_populate() { Vector3 normal = face.get_plane().normal; Vector3 op_axis = (face.vertex[0] - face.vertex[1]).normalized(); - Transform xform; + Transform3D xform; xform.set_look_at(pos, pos + op_axis, normal); xform = xform * axis_xform; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ba39ce3aed..72a63539b3 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "core/config/project_settings.h" #include "core/input/input.h" #include "core/math/camera_matrix.h" +#include "core/math/math_funcs.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" #include "core/templates/sort_array.h" @@ -344,7 +345,7 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { equal = false; } - if (!equal || p_interp_delta == 0 || is_freelook_active() || is_orthogonal != orthogonal) { + if (!equal || p_interp_delta == 0 || is_orthogonal != orthogonal) { camera->set_global_transform(to_camera_transform(camera_cursor)); if (orthogonal) { @@ -361,8 +362,8 @@ void Node3DEditorViewport::_update_camera(float p_interp_delta) { } } -Transform Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const { - Transform camera_transform; +Transform3D Node3DEditorViewport::to_camera_transform(const Cursor &p_cursor) const { + Transform3D camera_transform; camera_transform.translate(p_cursor.pos); camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot); camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot); @@ -410,7 +411,7 @@ float Node3DEditorViewport::get_fov() const { return CLAMP(spatial_editor->get_fov(), MIN_FOV, MAX_FOV); } -Transform Node3DEditorViewport::_get_camera_transform() const { +Transform3D Node3DEditorViewport::_get_camera_transform() const { return camera->get_global_transform(); } @@ -466,22 +467,31 @@ void Node3DEditorViewport::_select_clicked(bool p_append, bool p_single, bool p_ } void Node3DEditorViewport::_select(Node *p_node, bool p_append, bool p_single) { - if (!p_append) { - editor_selection->clear(); - } - - if (editor_selection->is_selected(p_node)) { - //erase - editor_selection->remove_node(p_node); + // Add or remove a single node from the selection + if (p_append && p_single) { + if (editor_selection->is_selected(p_node)) { + // Already in the selection, remove it from the selected nodes + editor_selection->remove_node(p_node); + } else { + // Add the item to the selection + editor_selection->add_node(p_node); + } + } else if (p_append && !p_single) { + // Add the item to the selection + editor_selection->add_node(p_node); } else { + // No append; single select + editor_selection->clear(); editor_selection->add_node(p_node); - } - - if (p_single) { + // Reselect if (Engine::get_singleton()->is_editor_hint()) { editor->call("edit_node", p_node); } } + + if (editor_selection->get_selected_node_list().size() == 1) { + editor->push_item(editor_selection->get_selected_node_list()[0]); + } } ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos, bool p_append, bool &r_includes_current, int *r_gizmo_handle, bool p_alt_select) { @@ -631,7 +641,7 @@ Vector3 Node3DEditorViewport::_get_screen_to_space(const Vector3 &p_vector3) { } Vector2 screen_he = cm.get_viewport_half_extents(); - Transform camera_transform; + Transform3D camera_transform; camera_transform.translate(cursor.pos); camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot); camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot); @@ -829,7 +839,7 @@ bool Node3DEditorViewport::_gizmo_select(const Vector2 &p_screenpos, bool p_high Vector3 ray_pos = _get_ray_pos(Vector2(p_screenpos.x, p_screenpos.y)); Vector3 ray = _get_ray(Vector2(p_screenpos.x, p_screenpos.y)); - Transform gt = spatial_editor->get_gizmo_transform(); + Transform3D gt = spatial_editor->get_gizmo_transform(); float gs = gizmo_scale; if (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) { @@ -1244,6 +1254,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } _edit.mouse_pos = b->get_position(); + _edit.original_mouse_pos = b->get_position(); _edit.snap = spatial_editor->is_snap_enabled(); _edit.mode = TRANSFORM_NONE; @@ -1396,6 +1407,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } } break; + default: + break; } } @@ -1450,7 +1463,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed()) { nav_mode = NAVIGATION_ORBIT; } else { - if (clicked.is_valid()) { + bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 10 * EDSCALE; + if (clicked.is_valid() && movement_threshold_passed) { if (!clicked_includes_current) { _select_clicked(clicked_wants_append, true); // Processing was deferred. @@ -1579,10 +1593,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { continue; } - Transform original = se->original; - Transform original_local = se->original_local; - Transform base = Transform(Basis(), _edit.center); - Transform t; + Transform3D original = se->original; + Transform3D original_local = se->original_local; + Transform3D base = Transform3D(Basis(), _edit.center); + Transform3D t; Vector3 local_scale; if (local_coords) { @@ -1608,7 +1622,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { motion.snap(Vector3(snap, snap, snap)); } - Transform r; + Transform3D r; r.basis.scale(motion + Vector3(1, 1, 1)); t = base * (r * (base.inverse() * original)); @@ -1701,8 +1715,8 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { continue; } - Transform original = se->original; - Transform t; + Transform3D original = se->original; + Transform3D t; if (local_coords) { if (_edit.snap || spatial_editor->is_snap_enabled()) { @@ -1797,10 +1811,10 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { continue; } - Transform t; + Transform3D t; if (local_coords) { - Transform original_local = se->original_local; + Transform3D original_local = se->original_local; Basis rot = Basis(axis, angle); t.basis = original_local.get_basis().orthonormalized() * rot; @@ -1811,9 +1825,9 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { sp->set_scale(original_local.basis.get_scale()); // re-apply original scale } else { - Transform original = se->original; - Transform r; - Transform base = Transform(Basis(), _edit.center); + Transform3D original = se->original; + Transform3D r; + Transform3D base = Transform3D(Basis(), _edit.center); r.basis.rotate(plane.normal, angle); t = base * r * base.inverse() * original; @@ -1962,6 +1976,13 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) { return; } + if (EditorSettings::get_singleton()->get("editors/3d/navigation/emulate_numpad")) { + const uint32_t code = k->get_keycode(); + if (code >= KEY_0 && code <= KEY_9) { + k->set_keycode(code - KEY_0 + KEY_KP_0); + } + } + if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) { if (_edit.mode != TRANSFORM_NONE) { _edit.snap = !_edit.snap; @@ -2057,7 +2078,7 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const pan_speed *= pan_speed_modifier; } - Transform camera_transform; + Transform3D camera_transform; camera_transform.translate(cursor.pos); camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot); @@ -2145,7 +2166,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const const bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y_axis"); // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag". - const Transform prev_camera_transform = to_camera_transform(cursor); + const Transform3D prev_camera_transform = to_camera_transform(cursor); if (invert_y_axis) { cursor.x_rot -= p_relative.y * radians_per_pixel; @@ -2158,7 +2179,7 @@ void Node3DEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const cursor.y_rot += p_relative.x * radians_per_pixel; // Look is like the opposite of Orbit: the focus point rotates around the camera - Transform camera_transform = to_camera_transform(cursor); + Transform3D camera_transform = to_camera_transform(cursor); Vector3 pos = camera_transform.xform(Vector3(0, 0, 0)); Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0)); Vector3 diff = prev_pos - pos; @@ -2444,7 +2465,7 @@ void Node3DEditorViewport::_notification(int p_what) { continue; } - Transform t = sp->get_global_gizmo_transform(); + Transform3D t = sp->get_global_gizmo_transform(); VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(sp); AABB new_aabb = vi ? vi->get_aabb() : _calculate_spatial_bounds(sp); @@ -2499,25 +2520,21 @@ void Node3DEditorViewport::_notification(int p_what) { } if (show_info) { + const String viewport_size = vformat(String::utf8("%d × %d"), viewport->get_size().x, viewport->get_size().y); String text; - text += "X: " + rtos(current_camera->get_translation().x).pad_decimals(1) + "\n"; - text += "Y: " + rtos(current_camera->get_translation().y).pad_decimals(1) + "\n"; - text += "Z: " + rtos(current_camera->get_translation().z).pad_decimals(1) + "\n"; - text += TTR("Pitch") + ": " + itos(Math::round(current_camera->get_rotation_degrees().x)) + "\n"; - text += TTR("Yaw") + ": " + itos(Math::round(current_camera->get_rotation_degrees().y)) + "\n\n"; - - text += TTR("Size") + - vformat( - ": %dx%d (%.1fMP)\n", - viewport->get_size().x, - viewport->get_size().y, - viewport->get_size().x * viewport->get_size().y * 0.000'001); - text += TTR("Objects Drawn") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_OBJECTS_IN_FRAME)) + "\n"; - text += TTR("Material Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_MATERIAL_CHANGES_IN_FRAME)) + "\n"; - text += TTR("Shader Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SHADER_CHANGES_IN_FRAME)) + "\n"; - text += TTR("Surface Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SURFACE_CHANGES_IN_FRAME)) + "\n"; - text += TTR("Draw Calls") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)) + "\n"; - text += TTR("Vertices") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_VERTICES_IN_FRAME)); + text += vformat(TTR("X: %s\n"), rtos(current_camera->get_position().x).pad_decimals(1)); + text += vformat(TTR("Y: %s\n"), rtos(current_camera->get_position().y).pad_decimals(1)); + text += vformat(TTR("Z: %s\n"), rtos(current_camera->get_position().z).pad_decimals(1)); + text += "\n"; + text += vformat( + TTR("Size: %s (%.1fMP)\n"), + viewport_size, + viewport->get_size().x * viewport->get_size().y * 0.000001); + + text += "\n"; + text += vformat(TTR("Objects: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_OBJECTS_IN_FRAME)); + text += vformat(TTR("Primitives: %d\n"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_PRIMITIVES_IN_FRAME)); + text += vformat(TTR("Draw Calls: %d"), viewport->get_render_info(Viewport::RENDER_INFO_TYPE_VISIBLE, Viewport::RENDER_INFO_DRAW_CALLS_IN_FRAME)); info_label->set_text(text); } @@ -2878,7 +2895,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { break; } - Transform camera_transform = camera->get_global_transform(); + Transform3D camera_transform = camera->get_global_transform(); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -2895,7 +2912,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { continue; } - Transform xform; + Transform3D xform; if (orthogonal) { xform = sp->get_global_transform(); xform.basis.set_euler(camera_transform.basis.get_euler()); @@ -2915,7 +2932,7 @@ void Node3DEditorViewport::_menu_option(int p_option) { break; } - Transform camera_transform = camera->get_global_transform(); + Transform3D camera_transform = camera->get_global_transform(); List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -3060,9 +3077,9 @@ void Node3DEditorViewport::_menu_option(int p_option) { case VIEW_DISPLAY_NORMAL_BUFFER: case VIEW_DISPLAY_DEBUG_SHADOW_ATLAS: case VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS: - case VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO: - case VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING: - case VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION: + case VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO: + case VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING: + case VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION: case VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE: case VIEW_DISPLAY_DEBUG_SSAO: case VIEW_DISPLAY_DEBUG_PSSM_SPLITS: @@ -3086,9 +3103,9 @@ void Node3DEditorViewport::_menu_option(int p_option) { VIEW_DISPLAY_WIREFRAME, VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, - VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO, - VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING, - VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION, + VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO, + VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING, + VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION, VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, VIEW_DISPLAY_DEBUG_SSAO, VIEW_DISPLAY_DEBUG_GI_BUFFER, @@ -3114,9 +3131,9 @@ void Node3DEditorViewport::_menu_option(int p_option) { Viewport::DEBUG_DRAW_WIREFRAME, Viewport::DEBUG_DRAW_SHADOW_ATLAS, Viewport::DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS, - Viewport::DEBUG_DRAW_GI_PROBE_ALBEDO, - Viewport::DEBUG_DRAW_GI_PROBE_LIGHTING, - Viewport::DEBUG_DRAW_GI_PROBE_EMISSION, + Viewport::DEBUG_DRAW_VOXEL_GI_ALBEDO, + Viewport::DEBUG_DRAW_VOXEL_GI_LIGHTING, + Viewport::DEBUG_DRAW_VOXEL_GI_EMISSION, Viewport::DEBUG_DRAW_SCENE_LUMINANCE, Viewport::DEBUG_DRAW_SSAO, Viewport::DEBUG_DRAW_GI_BUFFER, @@ -3249,14 +3266,12 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { if (!preview) { preview_camera->hide(); } - view_menu->set_disabled(false); surface->update(); } else { previewing = preview; previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace - view_menu->set_disabled(true); surface->update(); } } @@ -3315,9 +3330,9 @@ void Node3DEditorViewport::update_transform_gizmo_view() { return; } - Transform xform = spatial_editor->get_gizmo_transform(); + Transform3D xform = spatial_editor->get_gizmo_transform(); - Transform camera_xform = camera->get_transform(); + Transform3D camera_xform = camera->get_transform(); if (xform.origin.distance_squared_to(camera_xform.origin) < 0.01) { for (int i = 0; i < 3; i++) { @@ -3503,7 +3518,6 @@ void Node3DEditorViewport::set_state(const Dictionary &p_state) { previewing = Object::cast_to<Camera3D>(pv); previewing->connect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); RS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), previewing->get_camera()); //replace - view_menu->set_disabled(true); surface->update(); preview_camera->set_pressed(true); preview_camera->show(); @@ -3551,8 +3565,8 @@ Dictionary Node3DEditorViewport::get_state() const { void Node3DEditorViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred. - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &Node3DEditorViewport::drop_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &Node3DEditorViewport::drop_data_fw); ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport"))); ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport"))); @@ -3711,7 +3725,7 @@ void Node3DEditorViewport::_create_preview(const Vector<String> &files) const { preview_node->add_child(mesh_instance); } else { if (scene.is_valid()) { - Node *instance = scene->instance(); + Node *instance = scene->instantiate(); if (instance) { preview_node->add_child(instance); } @@ -3756,51 +3770,51 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res)); - Node *instanced_scene = nullptr; + Node *instantiated_scene = nullptr; if (mesh != nullptr || scene != nullptr) { if (mesh != nullptr) { MeshInstance3D *mesh_instance = memnew(MeshInstance3D); mesh_instance->set_mesh(mesh); mesh_instance->set_name(path.get_file().get_basename()); - instanced_scene = mesh_instance; + instantiated_scene = mesh_instance; } else { if (!scene.is_valid()) { // invalid scene return false; } else { - instanced_scene = scene->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); + instantiated_scene = scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); } } } - if (instanced_scene == nullptr) { + if (instantiated_scene == nullptr) { return false; } if (editor->get_edited_scene()->get_filename() != "") { // cyclical instancing - if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instanced_scene)) { - memdelete(instanced_scene); + if (_cyclical_dependency_exists(editor->get_edited_scene()->get_filename(), instantiated_scene)) { + memdelete(instantiated_scene); return false; } } if (scene != nullptr) { - instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path)); + instantiated_scene->set_filename(ProjectSettings::get_singleton()->localize_path(path)); } - editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene); - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", editor->get_edited_scene()); - editor_data->get_undo_redo().add_do_reference(instanced_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene); + editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", editor->get_edited_scene()); + editor_data->get_undo_redo().add_do_reference(instantiated_scene); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); - String new_name = parent->validate_child_name(instanced_scene); + String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", editor->get_edited_scene()->get_path_to(parent), path, new_name); editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(editor->get_edited_scene()->get_path_to(parent)) + "/" + new_name)); - Node3D *node3d = Object::cast_to<Node3D>(instanced_scene); + Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene); if (node3d) { - Transform global_transform; + Transform3D global_transform; Node3D *parent_node3d = Object::cast_to<Node3D>(parent); if (parent_node3d) { global_transform = parent_node3d->get_global_gizmo_transform(); @@ -3809,7 +3823,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po global_transform.origin = spatial_editor->snap_point(_get_instance_position(p_point)); global_transform.basis *= node3d->get_transform().basis; - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_global_transform", global_transform); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_global_transform", global_transform); } return true; @@ -3852,7 +3866,7 @@ void Node3DEditorViewport::_perform_drop_data() { } bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { - bool can_instance = false; + bool can_instantiate = false; if (!preview_node->is_inside_tree()) { Dictionary d = p_data; @@ -3874,11 +3888,11 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant String type = res->get_class(); if (type == "PackedScene") { Ref<PackedScene> sdata = ResourceLoader::load(files[i]); - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { continue; } - memdelete(instanced_scene); + memdelete(instantiated_scene); } else if (type == "Mesh" || type == "ArrayMesh" || type == "PrimitiveMesh") { Ref<Mesh> mesh = ResourceLoader::load(files[i]); if (!mesh.is_valid()) { @@ -3887,24 +3901,24 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant } else { continue; } - can_instance = true; + can_instantiate = true; break; } } - if (can_instance) { + if (can_instantiate) { _create_preview(files); } } } else { - can_instance = true; + can_instantiate = true; } - if (can_instance) { - Transform global_transform = Transform(Basis(), _get_instance_position(p_point)); + if (can_instantiate) { + Transform3D global_transform = Transform3D(Basis(), _get_instance_position(p_point)); preview_node->set_global_transform(global_transform); } - return can_instance; + return can_instantiate; } void Node3DEditorViewport::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { @@ -4036,9 +4050,9 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito display_submenu->add_separator(); display_submenu->add_radio_check_item(TTR("Decal Atlas"), VIEW_DISPLAY_DEBUG_DECAL_ATLAS); display_submenu->add_separator(); - display_submenu->add_radio_check_item(TTR("GIProbe Lighting"), VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING); - display_submenu->add_radio_check_item(TTR("GIProbe Albedo"), VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO); - display_submenu->add_radio_check_item(TTR("GIProbe Emission"), VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION); + display_submenu->add_radio_check_item(TTR("VoxelGI Lighting"), VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING); + display_submenu->add_radio_check_item(TTR("VoxelGI Albedo"), VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO); + display_submenu->add_radio_check_item(TTR("VoxelGI Emission"), VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION); display_submenu->add_separator(); display_submenu->add_radio_check_item(TTR("SDFGI Cascades"), VIEW_DISPLAY_DEBUG_SDFGI); display_submenu->add_radio_check_item(TTR("SDFGI Probes"), VIEW_DISPLAY_DEBUG_SDFGI_PROBES); @@ -4574,7 +4588,7 @@ void Node3DEditor::update_transform_gizmo() { continue; } - Transform xf = se->sp->get_global_gizmo_transform(); + Transform3D xf = se->sp->get_global_gizmo_transform(); if (first) { center.position = xf.origin; @@ -4955,7 +4969,7 @@ void Node3DEditor::_snap_update() { } void Node3DEditor::_xform_dialog_action() { - Transform t; + Transform3D t; //translation Vector3 scale; Vector3 rotate; @@ -4988,7 +5002,7 @@ void Node3DEditor::_xform_dialog_action() { bool post = xform_type->get_selected() > 0; - Transform tr = sp->get_global_gizmo_transform(); + Transform3D tr = sp->get_global_gizmo_transform(); if (post) { tr = tr * t; } else { @@ -5056,11 +5070,11 @@ void Node3DEditor::_update_camera_override_button(bool p_game_running) { if (p_game_running) { button->set_disabled(false); - button->set_tooltip(TTR("Game Camera Override\nNo game instance running.")); + button->set_tooltip(TTR("Project Camera Override\nOverrides the running project's camera with the editor viewport camera.")); } else { button->set_disabled(true); button->set_pressed(false); - button->set_tooltip(TTR("Game Camera Override\nOverrides game camera with editor viewport camera.")); + button->set_tooltip(TTR("Project Camera Override\nNo project instance running. Run the project from the editor to use this feature.")); } } @@ -5314,7 +5328,7 @@ void Node3DEditor::_init_indicators() { origin_enabled = true; grid_enabled = true; - indicator_mat.instance(); + indicator_mat.instantiate(); indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); indicator_mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); @@ -5394,7 +5408,7 @@ void Node3DEditor::_init_indicators() { "}"); for (int i = 0; i < 3; i++) { - grid_mat[i].instance(); + grid_mat[i].instantiate(); grid_mat[i]->set_shader(grid_shader); } @@ -5834,7 +5848,7 @@ void Node3DEditor::_init_grid() { return; } Camera3D *camera = get_editor_viewport(0)->camera; - Vector3 camera_position = camera->get_translation(); + Vector3 camera_position = camera->get_position(); if (camera_position == Vector3()) { return; // Camera3D is invalid, don't draw the grid. } @@ -6180,7 +6194,7 @@ void Node3DEditor::snap_selected_nodes_to_floor() { if (ss->intersect_ray(from, to, result, excluded)) { Vector3 position_offset = d["position_offset"]; - Transform new_transform = sp->get_global_transform(); + Transform3D new_transform = sp->get_global_transform(); new_transform.origin.y = result.position.y; new_transform.origin = new_transform.origin - position_offset; @@ -6213,31 +6227,47 @@ void Node3DEditor::_sun_environ_settings_pressed() { sun_environ_popup->popup(); } -void Node3DEditor::_add_sun_to_scene() { +void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) { sun_environ_popup->hide(); + if (!p_already_added_environment && world_env_count == 0 && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + // Prevent infinite feedback loop between the sun and environment methods. + _add_environment_to_scene(true); + } + Node *base = get_tree()->get_edited_scene_root(); if (!base) { - EditorNode::get_singleton()->show_warning(TTR("A root node is needed for this operation")); - return; + // Create a root node so we can add child nodes to it. + EditorNode::get_singleton()->get_scene_tree_dock()->add_root_node(memnew(Node3D)); + base = get_tree()->get_edited_scene_root(); } ERR_FAIL_COND(!base); Node *new_sun = preview_sun->duplicate(); undo_redo->create_action("Add Preview Sun to Scene"); undo_redo->add_do_method(base, "add_child", new_sun); + // Move to the beginning of the scene tree since more "global" nodes + // generally look better when placed at the top. + undo_redo->add_do_method(base, "move_child", new_sun, 0); undo_redo->add_do_method(new_sun, "set_owner", base); undo_redo->add_undo_method(base, "remove_child", new_sun); undo_redo->add_do_reference(new_sun); undo_redo->commit_action(); } -void Node3DEditor::_add_environment_to_scene() { + +void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) { sun_environ_popup->hide(); + if (!p_already_added_sun && directional_light_count == 0 && Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + // Prevent infinite feedback loop between the sun and environment methods. + _add_sun_to_scene(true); + } + Node *base = get_tree()->get_edited_scene_root(); if (!base) { - EditorNode::get_singleton()->show_warning(TTR("A root node is needed for this operation")); - return; + // Create a root node so we can add child nodes to it. + EditorNode::get_singleton()->get_scene_tree_dock()->add_root_node(memnew(Node3D)); + base = get_tree()->get_edited_scene_root(); } ERR_FAIL_COND(!base); @@ -6246,6 +6276,9 @@ void Node3DEditor::_add_environment_to_scene() { undo_redo->create_action("Add Preview Environment to Scene"); undo_redo->add_do_method(base, "add_child", new_env); + // Move to the beginning of the scene tree since more "global" nodes + // generally look better when placed at the top. + undo_redo->add_do_method(base, "move_child", new_env, 0); undo_redo->add_do_method(new_env, "set_owner", base); undo_redo->add_undo_method(base, "remove_child", new_env); undo_redo->add_do_reference(new_env); @@ -6368,7 +6401,7 @@ void Node3DEditor::_request_gizmo(Object *p_obj) { if (!sp) { return; } - if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_a_parent_of(sp)))) { + if (editor->get_edited_scene() && (sp == editor->get_edited_scene() || (sp->get_owner() && editor->get_edited_scene()->is_ancestor_of(sp)))) { Ref<EditorNode3DGizmo> seg; for (int i = 0; i < gizmo_plugins_by_priority.size(); ++i) { @@ -6442,7 +6475,7 @@ void Node3DEditor::_toggle_maximize_view(Object *p_viewport) { } void Node3DEditor::_node_added(Node *p_node) { - if (EditorNode::get_singleton()->get_scene_root()->is_a_parent_of(p_node)) { + if (EditorNode::get_singleton()->get_scene_root()->is_ancestor_of(p_node)) { if (Object::cast_to<WorldEnvironment>(p_node)) { world_env_count++; if (world_env_count == 1) { @@ -6458,7 +6491,7 @@ void Node3DEditor::_node_added(Node *p_node) { } void Node3DEditor::_node_removed(Node *p_node) { - if (EditorNode::get_singleton()->get_scene_root()->is_a_parent_of(p_node)) { + if (EditorNode::get_singleton()->get_scene_root()->is_ancestor_of(p_node)) { if (Object::cast_to<WorldEnvironment>(p_node)) { world_env_count--; if (world_env_count == 0) { @@ -6490,14 +6523,14 @@ void Node3DEditor::_register_all_gizmos() { add_gizmo_plugin(Ref<RayCast3DGizmoPlugin>(memnew(RayCast3DGizmoPlugin))); add_gizmo_plugin(Ref<SpringArm3DGizmoPlugin>(memnew(SpringArm3DGizmoPlugin))); add_gizmo_plugin(Ref<VehicleWheel3DGizmoPlugin>(memnew(VehicleWheel3DGizmoPlugin))); - add_gizmo_plugin(Ref<VisibilityNotifier3DGizmoPlugin>(memnew(VisibilityNotifier3DGizmoPlugin))); + add_gizmo_plugin(Ref<VisibleOnScreenNotifier3DGizmoPlugin>(memnew(VisibleOnScreenNotifier3DGizmoPlugin))); add_gizmo_plugin(Ref<GPUParticles3DGizmoPlugin>(memnew(GPUParticles3DGizmoPlugin))); add_gizmo_plugin(Ref<GPUParticlesCollision3DGizmoPlugin>(memnew(GPUParticlesCollision3DGizmoPlugin))); add_gizmo_plugin(Ref<CPUParticles3DGizmoPlugin>(memnew(CPUParticles3DGizmoPlugin))); add_gizmo_plugin(Ref<ReflectionProbeGizmoPlugin>(memnew(ReflectionProbeGizmoPlugin))); add_gizmo_plugin(Ref<DecalGizmoPlugin>(memnew(DecalGizmoPlugin))); - add_gizmo_plugin(Ref<GIProbeGizmoPlugin>(memnew(GIProbeGizmoPlugin))); - add_gizmo_plugin(Ref<BakedLightmapGizmoPlugin>(memnew(BakedLightmapGizmoPlugin))); + add_gizmo_plugin(Ref<VoxelGIGizmoPlugin>(memnew(VoxelGIGizmoPlugin))); + add_gizmo_plugin(Ref<LightmapGIGizmoPlugin>(memnew(LightmapGIGizmoPlugin))); add_gizmo_plugin(Ref<LightmapProbeGizmoPlugin>(memnew(LightmapProbeGizmoPlugin))); add_gizmo_plugin(Ref<CollisionObject3DGizmoPlugin>(memnew(CollisionObject3DGizmoPlugin))); add_gizmo_plugin(Ref<CollisionShape3DGizmoPlugin>(memnew(CollisionShape3DGizmoPlugin))); @@ -6545,9 +6578,11 @@ void Node3DEditor::clear() { void Node3DEditor::_sun_direction_draw() { sun_direction->draw_rect(Rect2(Vector2(), sun_direction->get_size()), Color(1, 1, 1, 1)); - sun_direction_material->set_shader_param("sun_direction", -preview_sun->get_transform().basis.get_axis(Vector3::AXIS_Z)); - float nrg = sun_energy->get_value(); - sun_direction_material->set_shader_param("sun_color", Vector3(sun_color->get_pick_color().r * nrg, sun_color->get_pick_color().g * nrg, sun_color->get_pick_color().b * nrg)); + Vector3 z_axis = preview_sun->get_transform().basis.get_axis(Vector3::AXIS_Z); + z_axis = get_editor_viewport(0)->camera->get_camera_transform().basis.xform_inv(z_axis); + sun_direction_material->set_shader_param("sun_direction", Vector3(z_axis.x, -z_axis.y, z_axis.z)); + Color color = sun_color->get_pick_color() * sun_energy->get_value(); + sun_direction_material->set_shader_param("sun_color", Vector3(color.r, color.g, color.b)); } void Node3DEditor::_preview_settings_changed() { @@ -6556,8 +6591,8 @@ void Node3DEditor::_preview_settings_changed() { } { // preview sun - Transform t; - t.basis = sun_rotation; + Transform3D t; + t.basis = Basis(Vector3(sun_rotation.x, sun_rotation.y, 0)); preview_sun->set_transform(t); sun_direction->update(); preview_sun->set_param(Light3D::PARAM_ENERGY, sun_energy->get_value()); @@ -6579,11 +6614,20 @@ void Node3DEditor::_preview_settings_changed() { environment->set_tonemapper(environ_tonemap_button->is_pressed() ? Environment::TONE_MAPPER_FILMIC : Environment::TONE_MAPPER_LINEAR); } } + void Node3DEditor::_load_default_preview_settings() { sun_environ_updating = true; - sun_rotation = Basis(Vector3(0, 1, 0), Math_PI * 3.0 / 4) * Basis(Vector3(1, 0, 0), -Math_PI / 4); + // These default rotations place the preview sun at an angular altitude + // of 60 degrees (must be negative) and an azimuth of 30 degrees clockwise + // from north (or 150 CCW from south), from north east, facing south west. + // On any not-tidally-locked planet, a sun would have an angular altitude + // of 60 degrees as the average of all points on the sphere at noon. + // The azimuth choice is arbitrary, but ideally shouldn't be on an axis. + sun_rotation = Vector2(-Math::deg2rad(60.0), Math::deg2rad(150.0)); + sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x)); + sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y)); sun_direction->update(); environ_sky_color->set_pick_color(Color::hex(0x91b2ceff)); environ_ground_color->set_pick_color(Color::hex(0x1f1f21ff)); @@ -6626,6 +6670,9 @@ void Node3DEditor::_update_preview_environment() { } } + sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x)); + sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y)); + bool disable_env = world_env_count > 0 || environ_button->is_pressed(); environ_button->set_disabled(world_env_count > 0); @@ -6654,17 +6701,21 @@ void Node3DEditor::_update_preview_environment() { void Node3DEditor::_sun_direction_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { - float x = -mm->get_relative().y * 0.02 * EDSCALE; - float y = mm->get_relative().x * 0.02 * EDSCALE; - - Basis rot = Basis(Vector3(0, 1, 0), y) * Basis(Vector3(1, 0, 0), x); - - sun_rotation = rot * sun_rotation; - sun_rotation.orthonormalize(); + sun_rotation.x += mm->get_relative().y * (0.02 * EDSCALE); + sun_rotation.y -= mm->get_relative().x * (0.02 * EDSCALE); + sun_rotation.x = CLAMP(sun_rotation.x, -Math_TAU / 4, Math_TAU / 4); + sun_angle_altitude->set_value(-Math::rad2deg(sun_rotation.x)); + sun_angle_azimuth->set_value(180.0 - Math::rad2deg(sun_rotation.y)); _preview_settings_changed(); } } +void Node3DEditor::_sun_direction_angle_set() { + sun_rotation.x = Math::deg2rad(-sun_angle_altitude->get_value()); + sun_rotation.y = Math::deg2rad(180.0 - sun_angle_azimuth->get_value()); + _preview_settings_changed(); +} + Node3DEditor::Node3DEditor(EditorNode *p_editor) { gizmo.visible = true; gizmo.scale = 1.0; @@ -6755,6 +6806,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { button_binds.write[0] = MENU_LOCK_SELECTED; tool_button[TOOL_LOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_LOCK_SELECTED]->set_tooltip(TTR("Lock the selected object in place (can't be moved).")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KEY_MASK_CMD | KEY_L)); tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_UNLOCK_SELECTED]); @@ -6762,6 +6815,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { button_binds.write[0] = MENU_UNLOCK_SELECTED; tool_button[TOOL_UNLOCK_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip(TTR("Unlock the selected object (can be moved).")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_L)); tool_button[TOOL_GROUP_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_GROUP_SELECTED]); @@ -6769,6 +6824,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { button_binds.write[0] = MENU_GROUP_SELECTED; tool_button[TOOL_GROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_GROUP_SELECTED]->set_tooltip(TTR("Makes sure the object's children are not selectable.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KEY_MASK_CMD | KEY_G)); tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button); hbc_menu->add_child(tool_button[TOOL_UNGROUP_SELECTED]); @@ -6776,6 +6833,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { button_binds.write[0] = MENU_UNGROUP_SELECTED; tool_button[TOOL_UNGROUP_SELECTED]->connect("pressed", callable_mp(this, &Node3DEditor::_menu_item_pressed), button_binds); tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip(TTR("Restores the object's children's ability to be selected.")); + // Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused. + tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_G)); hbc_menu->add_child(memnew(VSeparator)); @@ -6894,7 +6953,7 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { p->add_separator(); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN); - p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID); + p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid"), KEY_NUMBERSIGN), MENU_VIEW_GRID); p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS); @@ -7050,8 +7109,6 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { xform_dialog->connect("confirmed", callable_mp(this, &Node3DEditor::_xform_dialog_action)); - scenario_debug = RenderingServer::SCENARIO_DEBUG_DISABLED; - selected = nullptr; set_process_unhandled_key_input(true); @@ -7094,14 +7151,43 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { sun_direction->set_default_cursor_shape(CURSOR_MOVE); String sun_dir_shader_code = "shader_type canvas_item; uniform vec3 sun_direction; uniform vec3 sun_color; void fragment() { vec3 n; n.xy = UV * 2.0 - 1.0; n.z = sqrt(max(0.0, 1.0 - dot(n.xy, n.xy))); COLOR.rgb = dot(n,sun_direction) * sun_color; COLOR.a = 1.0 - smoothstep(0.99,1.0,length(n.xy)); }"; - sun_direction_shader.instance(); + sun_direction_shader.instantiate(); sun_direction_shader->set_code(sun_dir_shader_code); - sun_direction_material.instance(); + sun_direction_material.instantiate(); sun_direction_material->set_shader(sun_direction_shader); sun_direction_material->set_shader_param("sun_direction", Vector3(0, 0, 1)); sun_direction_material->set_shader_param("sun_color", Vector3(1, 1, 1)); sun_direction->set_material(sun_direction_material); + HBoxContainer *sun_angle_hbox = memnew(HBoxContainer); + VBoxContainer *sun_angle_altitude_vbox = memnew(VBoxContainer); + Label *sun_angle_altitude_label = memnew(Label); + sun_angle_altitude_label->set_text(TTR("Angular Altitude")); + sun_angle_altitude_vbox->add_child(sun_angle_altitude_label); + sun_angle_altitude = memnew(EditorSpinSlider); + sun_angle_altitude->set_max(90); + sun_angle_altitude->set_min(-90); + sun_angle_altitude->set_step(0.1); + sun_angle_altitude->connect("value_changed", callable_mp(this, &Node3DEditor::_sun_direction_angle_set).unbind(1)); + sun_angle_altitude_vbox->add_child(sun_angle_altitude); + sun_angle_hbox->add_child(sun_angle_altitude_vbox); + VBoxContainer *sun_angle_azimuth_vbox = memnew(VBoxContainer); + sun_angle_azimuth_vbox->set_custom_minimum_size(Vector2(100, 0)); + Label *sun_angle_azimuth_label = memnew(Label); + sun_angle_azimuth_label->set_text(TTR("Azimuth")); + sun_angle_azimuth_vbox->add_child(sun_angle_azimuth_label); + sun_angle_azimuth = memnew(EditorSpinSlider); + sun_angle_azimuth->set_max(180); + sun_angle_azimuth->set_min(-180); + sun_angle_azimuth->set_step(0.1); + sun_angle_azimuth->set_allow_greater(true); + sun_angle_azimuth->set_allow_lesser(true); + sun_angle_azimuth->connect("value_changed", callable_mp(this, &Node3DEditor::_sun_direction_angle_set).unbind(1)); + sun_angle_azimuth_vbox->add_child(sun_angle_azimuth); + sun_angle_hbox->add_child(sun_angle_azimuth_vbox); + sun_angle_hbox->add_theme_constant_override("separation", 10); + sun_vb->add_child(sun_angle_hbox); + sun_color = memnew(ColorPickerButton); sun_color->set_edit_alpha(false); sun_vb->add_margin_child(TTR("Sun Color"), sun_color); @@ -7120,7 +7206,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { sun_add_to_scene = memnew(Button); sun_add_to_scene->set_text(TTR("Add Sun to Scene")); - sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene)); + sun_add_to_scene->set_tooltip(TTR("Adds a DirectionalLight3D node matching the preview sun settings to the current scene.\nHold Shift while clicking to also add the preview environment to the current scene.")); + sun_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_sun_to_scene), varray(false)); sun_vb->add_spacer(); sun_vb->add_child(sun_add_to_scene); @@ -7184,7 +7271,8 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { environ_add_to_scene = memnew(Button); environ_add_to_scene->set_text(TTR("Add Environment to Scene")); - environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene)); + environ_add_to_scene->set_tooltip(TTR("Adds a WorldEnvironment node matching the preview environment settings to the current scene.\nHold Shift while clicking to also add the preview sun to the current scene.")); + environ_add_to_scene->connect("pressed", callable_mp(this, &Node3DEditor::_add_environment_to_scene), varray(false)); environ_vb->add_spacer(); environ_vb->add_child(environ_add_to_scene); @@ -7198,11 +7286,11 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) { preview_sun->set_shadow(true); preview_sun->set_shadow_mode(DirectionalLight3D::SHADOW_PARALLEL_4_SPLITS); preview_environment = memnew(WorldEnvironment); - environment.instance(); + environment.instantiate(); preview_environment->set_environment(environment); Ref<Sky> sky; - sky.instance(); - sky_material.instance(); + sky.instantiate(); + sky_material.instantiate(); sky->set_material(sky_material); environment->set_sky(sky); environment->set_background(Environment::BG_SKY); @@ -7243,10 +7331,6 @@ void Node3DEditorPlugin::set_state(const Dictionary &p_state) { spatial_editor->set_state(p_state); } -void Node3DEditor::snap_cursor_to_plane(const Plane &p_plane) { - //cursor.pos=p_plane.project(cursor.pos); -} - Vector3 Node3DEditor::snap_point(Vector3 p_target, Vector3 p_start) const { if (is_snap_enabled()) { p_target.x = Math::snap_scalar(0.0, get_translate_snap(), p_target.x); @@ -7289,14 +7373,6 @@ float Node3DEditor::get_scale_snap() const { return snap_value; } -void Node3DEditorPlugin::_bind_methods() { - ClassDB::bind_method("snap_cursor_to_plane", &Node3DEditorPlugin::snap_cursor_to_plane); -} - -void Node3DEditorPlugin::snap_cursor_to_plane(const Plane &p_plane) { - spatial_editor->snap_cursor_to_plane(p_plane); -} - struct _GizmoPluginPriorityComparator { bool operator()(const Ref<EditorNode3DGizmoPlugin> &p_a, const Ref<EditorNode3DGizmoPlugin> &p_b) const { if (p_a->get_priority() == p_b->get_priority()) { @@ -7345,17 +7421,17 @@ Node3DEditorPlugin::~Node3DEditorPlugin() { } void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color &p_color, bool p_billboard, bool p_on_top, bool p_use_vertex_color) { - Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6)); + Color instantiated_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6)); Vector<Ref<StandardMaterial3D>> mats; for (int i = 0; i < 4; i++) { bool selected = i % 2 == 1; - bool instanced = i < 2; + bool instantiated = i < 2; Ref<StandardMaterial3D> material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - Color color = instanced ? instanced_color : p_color; + Color color = instantiated ? instantiated_color : p_color; if (!selected) { color.a *= 0.3; @@ -7387,17 +7463,17 @@ void EditorNode3DGizmoPlugin::create_material(const String &p_name, const Color } void EditorNode3DGizmoPlugin::create_icon_material(const String &p_name, const Ref<Texture2D> &p_texture, bool p_on_top, const Color &p_albedo) { - Color instanced_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instanced", Color(0.7, 0.7, 0.7, 0.6)); + Color instantiated_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/instantiated", Color(0.7, 0.7, 0.7, 0.6)); Vector<Ref<StandardMaterial3D>> icons; for (int i = 0; i < 4; i++) { bool selected = i % 2 == 1; - bool instanced = i < 2; + bool instantiated = i < 2; Ref<StandardMaterial3D> icon = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); - Color color = instanced ? instanced_color : p_albedo; + Color color = instantiated ? instantiated_color : p_albedo; if (!selected) { color.a *= 0.85; @@ -7475,15 +7551,15 @@ Ref<StandardMaterial3D> EditorNode3DGizmoPlugin::get_material(const String &p_na } String EditorNode3DGizmoPlugin::get_gizmo_name() const { - if (get_script_instance() && get_script_instance()->has_method("get_gizmo_name")) { - return get_script_instance()->call("get_gizmo_name"); + if (get_script_instance() && get_script_instance()->has_method("_get_gizmo_name")) { + return get_script_instance()->call("_get_gizmo_name"); } return TTR("Nameless gizmo"); } int EditorNode3DGizmoPlugin::get_priority() const { - if (get_script_instance() && get_script_instance()->has_method("get_priority")) { - return get_script_instance()->call("get_priority"); + if (get_script_instance() && get_script_instance()->has_method("_get_priority")) { + return get_script_instance()->call("_get_priority"); } return 0; } @@ -7510,8 +7586,8 @@ Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::get_gizmo(Node3D *p_spatial) { void EditorNode3DGizmoPlugin::_bind_methods() { #define GIZMO_REF PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "EditorNode3DGizmo") - BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); - BIND_VMETHOD(MethodInfo(GIZMO_REF, "create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); + BIND_VMETHOD(MethodInfo(GIZMO_REF, "_create_gizmo", PropertyInfo(Variant::OBJECT, "spatial", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); ClassDB::bind_method(D_METHOD("create_material", "name", "color", "billboard", "on_top", "use_vertex_color"), &EditorNode3DGizmoPlugin::create_material, DEFVAL(false), DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_icon_material", "name", "texture", "on_top", "color"), &EditorNode3DGizmoPlugin::create_icon_material, DEFVAL(false), DEFVAL(Color(1, 1, 1, 1))); @@ -7520,97 +7596,97 @@ void EditorNode3DGizmoPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material", "name", "gizmo"), &EditorNode3DGizmoPlugin::get_material, DEFVAL(Ref<EditorNode3DGizmo>())); - BIND_VMETHOD(MethodInfo(Variant::STRING, "get_gizmo_name")); - BIND_VMETHOD(MethodInfo(Variant::INT, "get_priority")); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_be_hidden")); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_selectable_when_hidden")); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_gizmo_name")); + BIND_VMETHOD(MethodInfo(Variant::INT, "_get_priority")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_be_hidden")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_selectable_when_hidden")); - BIND_VMETHOD(MethodInfo("redraw", GIZMO_REF)); - BIND_VMETHOD(MethodInfo(Variant::STRING, "get_handle_name", GIZMO_REF, PropertyInfo(Variant::INT, "index"))); + BIND_VMETHOD(MethodInfo("_redraw", GIZMO_REF)); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_handle_name", GIZMO_REF, PropertyInfo(Variant::INT, "index"))); - MethodInfo hvget(Variant::NIL, "get_handle_value", GIZMO_REF, PropertyInfo(Variant::INT, "index")); + MethodInfo hvget(Variant::NIL, "_get_handle_value", GIZMO_REF, PropertyInfo(Variant::INT, "index")); hvget.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; BIND_VMETHOD(hvget); - BIND_VMETHOD(MethodInfo("set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point"))); - MethodInfo cm = MethodInfo("commit_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel")); + BIND_VMETHOD(MethodInfo("_set_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"), PropertyInfo(Variant::VECTOR2, "point"))); + MethodInfo cm = MethodInfo("_commit_handle", GIZMO_REF, PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::NIL, "restore"), PropertyInfo(Variant::BOOL, "cancel")); cm.default_arguments.push_back(false); BIND_VMETHOD(cm); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "is_handle_highlighted", GIZMO_REF, PropertyInfo(Variant::INT, "index"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_is_handle_highlighted", GIZMO_REF, PropertyInfo(Variant::INT, "index"))); #undef GIZMO_REF } bool EditorNode3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { - if (get_script_instance() && get_script_instance()->has_method("has_gizmo")) { - return get_script_instance()->call("has_gizmo", p_spatial); + if (get_script_instance() && get_script_instance()->has_method("_has_gizmo")) { + return get_script_instance()->call("_has_gizmo", p_spatial); } return false; } Ref<EditorNode3DGizmo> EditorNode3DGizmoPlugin::create_gizmo(Node3D *p_spatial) { - if (get_script_instance() && get_script_instance()->has_method("create_gizmo")) { - return get_script_instance()->call("create_gizmo", p_spatial); + if (get_script_instance() && get_script_instance()->has_method("_create_gizmo")) { + return get_script_instance()->call("_create_gizmo", p_spatial); } Ref<EditorNode3DGizmo> ref; if (has_gizmo(p_spatial)) { - ref.instance(); + ref.instantiate(); } return ref; } bool EditorNode3DGizmoPlugin::can_be_hidden() const { - if (get_script_instance() && get_script_instance()->has_method("can_be_hidden")) { - return get_script_instance()->call("can_be_hidden"); + if (get_script_instance() && get_script_instance()->has_method("_can_be_hidden")) { + return get_script_instance()->call("_can_be_hidden"); } return true; } bool EditorNode3DGizmoPlugin::is_selectable_when_hidden() const { - if (get_script_instance() && get_script_instance()->has_method("is_selectable_when_hidden")) { - return get_script_instance()->call("is_selectable_when_hidden"); + if (get_script_instance() && get_script_instance()->has_method("_is_selectable_when_hidden")) { + return get_script_instance()->call("_is_selectable_when_hidden"); } return false; } void EditorNode3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { - if (get_script_instance() && get_script_instance()->has_method("redraw")) { + if (get_script_instance() && get_script_instance()->has_method("_redraw")) { Ref<EditorNode3DGizmo> ref(p_gizmo); - get_script_instance()->call("redraw", ref); + get_script_instance()->call("_redraw", ref); } } String EditorNode3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_idx) const { - if (get_script_instance() && get_script_instance()->has_method("get_handle_name")) { - return get_script_instance()->call("get_handle_name", p_gizmo, p_idx); + if (get_script_instance() && get_script_instance()->has_method("_get_handle_name")) { + return get_script_instance()->call("_get_handle_name", p_gizmo, p_idx); } return ""; } Variant EditorNode3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int p_idx) const { - if (get_script_instance() && get_script_instance()->has_method("get_handle_value")) { - return get_script_instance()->call("get_handle_value", p_gizmo, p_idx); + if (get_script_instance() && get_script_instance()->has_method("_get_handle_value")) { + return get_script_instance()->call("_get_handle_value", p_gizmo, p_idx); } return Variant(); } void EditorNode3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { - if (get_script_instance() && get_script_instance()->has_method("set_handle")) { - get_script_instance()->call("set_handle", p_gizmo, p_idx, p_camera, p_point); + if (get_script_instance() && get_script_instance()->has_method("_set_handle")) { + get_script_instance()->call("_set_handle", p_gizmo, p_idx, p_camera, p_point); } } void EditorNode3DGizmoPlugin::commit_handle(EditorNode3DGizmo *p_gizmo, int p_idx, const Variant &p_restore, bool p_cancel) { - if (get_script_instance() && get_script_instance()->has_method("commit_handle")) { - get_script_instance()->call("commit_handle", p_gizmo, p_idx, p_restore, p_cancel); + if (get_script_instance() && get_script_instance()->has_method("_commit_handle")) { + get_script_instance()->call("_commit_handle", p_gizmo, p_idx, p_restore, p_cancel); } } bool EditorNode3DGizmoPlugin::is_handle_highlighted(const EditorNode3DGizmo *p_gizmo, int p_idx) const { - if (get_script_instance() && get_script_instance()->has_method("is_handle_highlighted")) { - return get_script_instance()->call("is_handle_highlighted", p_gizmo, p_idx); + if (get_script_instance() && get_script_instance()->has_method("_is_handle_highlighted")) { + return get_script_instance()->call("_is_handle_highlighted", p_gizmo, p_idx); } return false; } diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 33f4c32471..a195a0eee0 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -34,7 +34,6 @@ #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/editor_scale.h" -#include "scene/3d/immediate_geometry_3d.h" #include "scene/3d/light_3d.h" #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" @@ -52,7 +51,7 @@ class EditorNode3DGizmo : public Node3DGizmo { GDCLASS(EditorNode3DGizmo, Node3DGizmo); bool selected; - bool instanced; + bool instantiated; public: void set_selected(bool p_selected) { selected = p_selected; } @@ -206,9 +205,9 @@ class Node3DEditorViewport : public Control { VIEW_DISPLAY_NORMAL_BUFFER, VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, - VIEW_DISPLAY_DEBUG_GIPROBE_ALBEDO, - VIEW_DISPLAY_DEBUG_GIPROBE_LIGHTING, - VIEW_DISPLAY_DEBUG_GIPROBE_EMISSION, + VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO, + VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING, + VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION, VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, VIEW_DISPLAY_DEBUG_SSAO, VIEW_DISPLAY_DEBUG_PSSM_SPLITS, @@ -322,7 +321,7 @@ private: Vector3 _get_ray_pos(const Vector2 &p_pos) const; Vector3 _get_ray(const Vector2 &p_pos) const; Point2 _point_to_screen(const Vector3 &p_point); - Transform _get_camera_transform() const; + Transform3D _get_camera_transform() const; int get_selected_count() const; Vector3 _get_camera_position() const; @@ -380,13 +379,14 @@ private: struct EditData { TransformMode mode; TransformPlane plane; - Transform original; + Transform3D original; Vector3 click_ray; Vector3 click_ray_pos; Vector3 center; Vector3 orig_gizmo_pos; int edited_gizmo = 0; Point2 mouse_pos; + Point2 original_mouse_pos; bool snap = false; Ref<EditorNode3DGizmo> gizmo; int gizmo_handle = 0; @@ -432,7 +432,7 @@ private: // void _update_camera(float p_interp_delta); - Transform to_camera_transform(const Cursor &p_cursor) const; + Transform3D to_camera_transform(const Cursor &p_cursor) const; void _draw(); void _surface_mouse_enter(); @@ -505,9 +505,9 @@ class Node3DEditorSelectedItem : public Object { public: AABB aabb; - Transform original; // original location when moving - Transform original_local; - Transform last_xform; // last transform + Transform3D original; // original location when moving + Transform3D original_local; + Transform3D last_xform; // last transform bool last_xform_dirty; Node3D *sp; RID sbox_instance; @@ -600,8 +600,6 @@ private: ToolMode tool_mode; - RenderingServer::ScenarioDebugMode scenario_debug; - RID origin; RID origin_instance; bool origin_enabled; @@ -641,7 +639,7 @@ private: struct Gizmo { bool visible = false; float scale = 0; - Transform transform; + Transform3D transform; } gizmo; enum MenuOption { @@ -763,6 +761,8 @@ private: VBoxContainer *sun_vb; Popup *sun_environ_popup; Control *sun_direction; + EditorSpinSlider *sun_angle_altitude; + EditorSpinSlider *sun_angle_azimuth; ColorPickerButton *sun_color; EditorSpinSlider *sun_energy; EditorSpinSlider *sun_max_distance; @@ -770,8 +770,9 @@ private: void _sun_direction_draw(); void _sun_direction_input(const Ref<InputEvent> &p_event); + void _sun_direction_angle_set(); - Basis sun_rotation; + Vector2 sun_rotation; Ref<Shader> sun_direction_shader; Ref<ShaderMaterial> sun_direction_material; @@ -804,8 +805,8 @@ private: void _preview_settings_changed(); void _sun_environ_settings_pressed(); - void _add_sun_to_scene(); - void _add_environment_to_scene(); + void _add_sun_to_scene(bool p_already_added_environment = false); + void _add_environment_to_scene(bool p_already_added_sun = false); protected: void _notification(int p_what); @@ -816,7 +817,6 @@ protected: public: static Node3DEditor *get_singleton() { return singleton; } - void snap_cursor_to_plane(const Plane &p_plane); Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const; @@ -824,7 +824,7 @@ public: float get_zfar() const { return settings_zfar->get_value(); } float get_fov() const { return settings_fov->get_value(); } - Transform get_gizmo_transform() const { return gizmo.transform; } + Transform3D get_gizmo_transform() const { return gizmo.transform; } bool is_gizmo_visible() const { return gizmo.visible; } ToolMode get_tool_mode() const { return tool_mode; } @@ -889,12 +889,7 @@ class Node3DEditorPlugin : public EditorPlugin { Node3DEditor *spatial_editor; EditorNode *editor; -protected: - static void _bind_methods(); - public: - void snap_cursor_to_plane(const Plane &p_plane); - Node3DEditor *get_spatial_editor() { return spatial_editor; } virtual String get_name() const override { return "3D"; } bool has_main_screen() const override { return true; } diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp index 0821f140b3..b0cafd83be 100644 --- a/editor/plugins/occluder_instance_3d_editor_plugin.cpp +++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp @@ -56,7 +56,7 @@ void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) { } break; case OccluderInstance3D::BAKE_ERROR_NO_MESHES: { - EditorNode::get_singleton()->show_warning(TTR("No meshes to bake.")); + EditorNode::get_singleton()->show_warning(TTR("No meshes to bake.\nMake sure there is at least one MeshInstance3D node in the scene whose visual layers are part of the OccluderInstance3D's Bake Mask property.")); break; } default: { diff --git a/editor/plugins/ot_features_plugin.cpp b/editor/plugins/ot_features_plugin.cpp index ebfdf2c7cd..2ac90762e3 100644 --- a/editor/plugins/ot_features_plugin.cpp +++ b/editor/plugins/ot_features_plugin.cpp @@ -191,7 +191,7 @@ void EditorInspectorPluginOpenTypeFeatures::parse_begin(Object *p_object) { void EditorInspectorPluginOpenTypeFeatures::parse_category(Object *p_object, const String &p_parse_category) { } -bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if (p_path == "opentype_features/_new") { OpenTypeFeaturesAdd *editor = memnew(OpenTypeFeaturesAdd); add_property_editor(p_path, editor); @@ -208,6 +208,6 @@ bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, Var OpenTypeFeaturesEditorPlugin::OpenTypeFeaturesEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginOpenTypeFeatures> ftr_plugin; - ftr_plugin.instance(); + ftr_plugin.instantiate(); EditorInspector::add_inspector_plugin(ftr_plugin); } diff --git a/editor/plugins/ot_features_plugin.h b/editor/plugins/ot_features_plugin.h index 9559a6c0c3..dbafa3bbf6 100644 --- a/editor/plugins/ot_features_plugin.h +++ b/editor/plugins/ot_features_plugin.h @@ -88,7 +88,7 @@ public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; virtual void parse_category(Object *p_object, const String &p_parse_category) override; - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; }; /*************************************************************************/ diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 208abeb87f..838e67b5e7 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -31,7 +31,7 @@ #include "path_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index 8c73294723..82b51f8a06 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -94,8 +94,8 @@ void Path3DGizmo::set_handle(int p_idx, Camera3D *p_camera, const Point2 &p_poin return; } - Transform gt = path->get_global_transform(); - Transform gi = gt.affine_inverse(); + Transform3D gt = path->get_global_transform(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); @@ -302,8 +302,8 @@ bool Path3DEditorPlugin::forward_spatial_gui_input(Camera3D *p_camera, const Ref if (c.is_null()) { return false; } - Transform gt = path->get_global_transform(); - Transform it = gt.affine_inverse(); + Transform3D gt = path->get_global_transform(); + Transform3D it = gt.affine_inverse(); static const int click_dist = 10; //should make global @@ -554,7 +554,7 @@ Path3DEditorPlugin::Path3DEditorPlugin(EditorNode *p_node) { mirror_handle_length = true; Ref<Path3DGizmoPlugin> gizmo_plugin; - gizmo_plugin.instance(); + gizmo_plugin.instantiate(); Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin); sep = memnew(VSeparator); diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 6d82685c05..1a13a028c8 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -32,8 +32,8 @@ #include "canvas_item_editor_plugin.h" #include "core/input/input.h" +#include "core/io/file_access.h" #include "core/math/geometry_2d.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -162,7 +162,7 @@ void Polygon2DEditor::_update_bone_list() { } Ref<ButtonGroup> bg; - bg.instance(); + bg.instantiate(); for (int i = 0; i < node->get_bone_count(); i++) { CheckBox *cb = memnew(CheckBox); NodePath np = node->get_bone_path(i); @@ -1144,7 +1144,7 @@ void Polygon2DEditor::_uv_draw() { if (!found_child) { //draw normally Transform2D bone_xform = node->get_global_transform().affine_inverse() * (skeleton->get_global_transform() * bone->get_skeleton_rest()); - Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_default_length(), 0)); + Transform2D endpoint_xform = bone_xform * Transform2D(0, Vector2(bone->get_length(), 0)); Color color = current ? Color(1, 1, 1) : Color(0.5, 0.5, 0.5); uv_edit_draw->draw_line(mtx.xform(bone_xform.get_origin()), mtx.xform(endpoint_xform.get_origin()), Color(0, 0, 0), Math::round((current ? 5 : 4) * EDSCALE)); @@ -1231,7 +1231,7 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : uv_edit->add_child(uv_main_vb); HBoxContainer *uv_mode_hb = memnew(HBoxContainer); - uv_edit_group.instance(); + uv_edit_group.instantiate(); uv_edit_mode[0] = memnew(Button); uv_mode_hb->add_child(uv_edit_mode[0]); diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index b4b8e82124..488aa8c861 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -339,9 +339,9 @@ void ResourcePreloaderEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library); ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw); } ResourcePreloaderEditor::ResourcePreloaderEditor() { @@ -367,8 +367,10 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { tree = memnew(Tree); tree->connect("button_pressed", callable_mp(this, &ResourcePreloaderEditor::_cell_button_pressed)); tree->set_columns(2); - tree->set_column_min_width(0, 2); - tree->set_column_min_width(1, 3); + tree->set_column_expand_ratio(0, 2); + tree->set_column_clip_content(0, true); + tree->set_column_expand_ratio(1, 3); + tree->set_column_clip_content(1, true); tree->set_column_expand(0, true); tree->set_column_expand(1, true); tree->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 1e6237ced1..120b0bc0bb 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -278,7 +278,7 @@ void EditorInspectorRootMotionPlugin::parse_begin(Object *p_object) { //do none } -bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if (p_path == "root_motion_track" && p_object->is_class("AnimationTree") && p_type == Variant::NODE_PATH) { EditorPropertyRootMotion *editor = memnew(EditorPropertyRootMotion); if (p_hint == PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE && p_hint_text != String()) { diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h index c70fff7db7..1484af62e8 100644 --- a/editor/plugins/root_motion_editor_plugin.h +++ b/editor/plugins/root_motion_editor_plugin.h @@ -65,7 +65,7 @@ class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin { public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; virtual void parse_end() override; }; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 623e4ea66e..498d5b0711 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -32,8 +32,8 @@ #include "core/config/project_settings.h" #include "core/input/input.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "editor/debugger/editor_debugger_node.h" @@ -71,7 +71,7 @@ Array EditorSyntaxHighlighter::_get_supported_languages() const { Ref<EditorSyntaxHighlighter> EditorSyntaxHighlighter::_create() const { Ref<EditorSyntaxHighlighter> syntax_highlighter; - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); if (get_script_instance()) { syntax_highlighter->set_script(get_script_instance()->get_script()); } @@ -201,7 +201,7 @@ void EditorStandardSyntaxHighlighter::_update_cache() { Ref<EditorSyntaxHighlighter> EditorStandardSyntaxHighlighter::_create() const { Ref<EditorStandardSyntaxHighlighter> syntax_highlighter; - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); return syntax_highlighter; } @@ -209,7 +209,7 @@ Ref<EditorSyntaxHighlighter> EditorStandardSyntaxHighlighter::_create() const { Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const { Ref<EditorPlainTextSyntaxHighlighter> syntax_highlighter; - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); return syntax_highlighter; } @@ -230,7 +230,7 @@ void ScriptEditorBase::_bind_methods() { ADD_SIGNAL(MethodInfo("search_in_files_requested", PropertyInfo(Variant::STRING, "text"))); ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text"))); - BIND_VMETHOD(MethodInfo("add_syntax_highlighter", PropertyInfo(Variant::OBJECT, "highlighter"))); + BIND_VMETHOD(MethodInfo("_add_syntax_highlighter", PropertyInfo(Variant::OBJECT, "highlighter"))); } static bool _is_built_in_script(Script *p_script) { @@ -760,6 +760,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { _update_members_overview_visibility(); _update_help_overview_visibility(); _save_layout(); + _update_find_replace_bar(); } void ScriptEditor::_close_current_tab(bool p_save) { @@ -829,6 +830,7 @@ void ScriptEditor::_close_all_tabs() { _close_current_tab(false); } + _update_find_replace_bar(); } void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) { @@ -1629,7 +1631,7 @@ void ScriptEditor::_help_overview_selected(int p_idx) { } void ScriptEditor::_script_selected(int p_idx) { - grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing + grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT); //amazing hack, simply amazing _go_to_tab(script_list->get_item_metadata(p_idx)); grab_focus_block = false; @@ -1646,6 +1648,7 @@ void ScriptEditor::ensure_select_current() { } } } + _update_find_replace_bar(); _update_selected_editor_menu(); } @@ -2451,7 +2454,9 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const script_list->select(script_list->find_metadata(i)); // Save the current script so the changes can be picked up by an external editor. - save_current_script(); + if (!_is_built_in_script(script.ptr())) { // But only if it's not built-in script. + save_current_script(); + } break; } @@ -2515,6 +2520,16 @@ void ScriptEditor::_file_removed(const String &p_removed_file) { } } +void ScriptEditor::_update_find_replace_bar() { + ScriptEditorBase *se = _get_current_editor(); + if (se) { + se->set_find_replace_bar(find_replace_bar); + } else { + find_replace_bar->set_text_edit(nullptr); + find_replace_bar->hide(); + } +} + void ScriptEditor::_autosave_scripts() { save_all_scripts(); } @@ -2766,6 +2781,8 @@ void ScriptEditor::_script_list_gui_input(const Ref<InputEvent> &ev) { case MOUSE_BUTTON_RIGHT: { _make_script_list_context_menu(); } break; + default: + break; } } } @@ -3188,7 +3205,7 @@ void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_numb if (ResourceLoader::exists(fpath)) { RES res = ResourceLoader::load(fpath); - if (fpath.get_extension() == "shader") { + if (fpath.get_extension() == "gdshader") { ShaderEditorPlugin *shader_editor = Object::cast_to<ShaderEditorPlugin>(EditorNode::get_singleton()->get_editor_data().get_editor("Shader")); shader_editor->edit(res.ptr()); shader_editor->make_visible(true); @@ -3271,9 +3288,9 @@ void ScriptEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("register_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::register_syntax_highlighter); ClassDB::bind_method(D_METHOD("unregister_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::unregister_syntax_highlighter); - ClassDB::bind_method(D_METHOD("get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw); ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2); ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script); @@ -3377,11 +3394,19 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { help_overview->set_custom_minimum_size(Size2(0, 60) * EDSCALE); //need to give a bit of limit to avoid it from disappearing help_overview->set_v_size_flags(SIZE_EXPAND_FILL); + VBoxContainer *code_editor_container = memnew(VBoxContainer); + script_split->add_child(code_editor_container); + tab_container = memnew(TabContainer); tab_container->set_tabs_visible(false); tab_container->set_custom_minimum_size(Size2(200, 0) * EDSCALE); - script_split->add_child(tab_container); + code_editor_container->add_child(tab_container); tab_container->set_h_size_flags(SIZE_EXPAND_FILL); + tab_container->set_v_size_flags(SIZE_EXPAND_FILL); + + find_replace_bar = memnew(FindReplaceBar); + code_editor_container->add_child(find_replace_bar); + find_replace_bar->hide(); ED_SHORTCUT("script_editor/window_sort", TTR("Sort")); ED_SHORTCUT("script_editor/window_move_up", TTR("Move Up"), KEY_MASK_SHIFT | KEY_MASK_ALT | KEY_UP); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 9ae63b7c4f..72a649ffbf 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -80,7 +80,7 @@ public: virtual Ref<EditorSyntaxHighlighter> _create() const override; - EditorStandardSyntaxHighlighter() { highlighter.instance(); } + EditorStandardSyntaxHighlighter() { highlighter.instantiate(); } }; class EditorPlainTextSyntaxHighlighter : public EditorSyntaxHighlighter { @@ -162,6 +162,7 @@ public: virtual void set_tooltip_request_func(String p_method, Object *p_obj) = 0; virtual Control *get_edit_menu() = 0; virtual void clear_edit_menu() = 0; + virtual void set_find_replace_bar(FindReplaceBar *p_bar) = 0; virtual Control *get_base_editor() const = 0; @@ -270,6 +271,7 @@ class ScriptEditor : public PanelContainer { ConfirmationDialog *erase_tab_confirm; ScriptCreateDialog *script_create_dialog; Button *scripts_visible; + FindReplaceBar *find_replace_bar; String current_theme; @@ -326,6 +328,7 @@ class ScriptEditor : public PanelContainer { void _show_error_dialog(String p_path); void _close_tab(int p_idx, bool p_save = true, bool p_history_back = true); + void _update_find_replace_bar(); void _close_current_tab(bool p_save = true); void _close_discard_current_tab(const String &p_str); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index a29e51e8fb..cc0fbcc634 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -109,13 +109,11 @@ ConnectionInfoDialog::ConnectionInfoDialog() { //////////////////////////////////////////////////////////////////////////////// Vector<String> ScriptTextEditor::get_functions() { - String errortxt; - int line = -1, col; CodeEdit *te = code_editor->get_text_editor(); String text = te->get_text(); List<String> fnc; - if (script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc)) { + if (script->get_language()->validate(text, script->get_path(), &fnc)) { //if valid rewrite functions to latest functions.clear(); for (List<String>::Element *E = fnc.front(); E; E = E->next()) { @@ -168,7 +166,6 @@ void ScriptTextEditor::enable_editor() { void ScriptTextEditor::_load_theme_settings() { CodeEdit *text_edit = code_editor->get_text_editor(); - text_edit->clear_keywords(); Color updated_marked_line_color = EDITOR_GET("text_editor/highlighting/mark_color"); Color updated_safe_line_number_color = EDITOR_GET("text_editor/highlighting/safe_line_number_color"); @@ -222,47 +219,10 @@ void ScriptTextEditor::_set_theme_for_script() { String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String(); text_edit->add_comment_delimiter(beg, end, end == ""); } +} - /* add keywords for auto completion */ - // singleton autoloads (as types, just as engine singletons are) - Map<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); - for (Map<StringName, ProjectSettings::AutoloadInfo>::Element *E = autoloads.front(); E; E = E->next()) { - const ProjectSettings::AutoloadInfo &info = E->value(); - if (info.is_singleton) { - text_edit->add_keyword(info.name); - } - } - - // engine types - List<StringName> types; - ClassDB::get_class_list(&types); - for (List<StringName>::Element *E = types.front(); E; E = E->next()) { - String n = E->get(); - if (n.begins_with("_")) { - n = n.substr(1, n.length()); - } - text_edit->add_keyword(n); - } - - // user types - List<StringName> global_classes; - ScriptServer::get_global_class_list(&global_classes); - for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) { - text_edit->add_keyword(E->get()); - } - - List<String> keywords; - script->get_language()->get_reserved_words(&keywords); - for (List<String>::Element *E = keywords.front(); E; E = E->next()) { - text_edit->add_keyword(E->get()); - } - - // core types - List<String> core_types; - script->get_language()->get_core_type_words(&core_types); - for (List<String>::Element *E = core_types.front(); E; E = E->next()) { - text_edit->add_keyword(E->get()); - } +void ScriptTextEditor::_show_errors_panel(bool p_show) { + errors_panel->set_visible(p_show); } void ScriptTextEditor::_show_warnings_panel(bool p_show) { @@ -279,6 +239,12 @@ void ScriptTextEditor::_warning_clicked(Variant p_line) { } } +void ScriptTextEditor::_error_clicked(Variant p_line) { + if (p_line.get_type() == Variant::INT) { + code_editor->get_text_editor()->cursor_set_line(p_line.operator int64_t()); + } +} + void ScriptTextEditor::reload_text() { ERR_FAIL_COND(script.is_null()); @@ -429,23 +395,21 @@ Ref<Texture2D> ScriptTextEditor::get_theme_icon() { } void ScriptTextEditor::_validate_script() { - String errortxt; - int line = -1, col; CodeEdit *te = code_editor->get_text_editor(); String text = te->get_text(); List<String> fnc; Set<int> safe_lines; List<ScriptLanguage::Warning> warnings; + List<ScriptLanguage::ScriptError> errors; - if (!script->get_language()->validate(text, line, col, errortxt, script->get_path(), &fnc, &warnings, &safe_lines)) { - String error_text = "error(" + itos(line) + "," + itos(col) + "): " + errortxt; + if (!script->get_language()->validate(text, script->get_path(), &fnc, &errors, &warnings, &safe_lines)) { + String error_text = TTR("Error at ") + "(" + itos(errors[0].line) + "," + itos(errors[0].column) + "): " + errors[0].message; code_editor->set_error(error_text); - code_editor->set_error_pos(line - 1, col - 1); + code_editor->set_error_pos(errors[0].line - 1, errors[0].column - 1); script_is_valid = false; } else { code_editor->set_error(""); - line = -1; if (!script->is_tool()) { script->set_source_code(text); script->update_exports(); @@ -487,7 +451,8 @@ void ScriptTextEditor::_validate_script() { } } - code_editor->set_warning_nb(warning_nb); + code_editor->set_error_count(errors.size()); + code_editor->set_warning_count(warning_nb); // Add script warnings. warnings_panel->push_table(3); @@ -521,23 +486,52 @@ void ScriptTextEditor::_validate_script() { } warnings_panel->pop(); // Table. - line--; + errors_panel->clear(); + errors_panel->push_table(2); + for (List<ScriptLanguage::ScriptError>::Element *E = errors.front(); E; E = E->next()) { + ScriptLanguage::ScriptError err = E->get(); + + errors_panel->push_cell(); + errors_panel->push_meta(err.line - 1); + errors_panel->push_color(warnings_panel->get_theme_color("error_color", "Editor")); + errors_panel->add_text(TTR("Line") + " " + itos(err.line) + ":"); + errors_panel->pop(); // Color. + errors_panel->pop(); // Meta goto. + errors_panel->pop(); // Cell. + + errors_panel->push_cell(); + errors_panel->add_text(err.message); + errors_panel->pop(); // Cell. + } + errors_panel->pop(); // Table + bool highlight_safe = EDITOR_DEF("text_editor/highlighting/highlight_type_safe_lines", true); bool last_is_safe = false; for (int i = 0; i < te->get_line_count(); i++) { - te->set_line_background_color(i, (line == i) ? marked_line_color : Color(0, 0, 0, 0)); + if (errors.is_empty()) { + te->set_line_background_color(i, Color(0, 0, 0, 0)); + } else { + for (List<ScriptLanguage::ScriptError>::Element *E = errors.front(); E; E = E->next()) { + bool error_line = i == E->get().line - 1; + te->set_line_background_color(i, error_line ? marked_line_color : Color(0, 0, 0, 0)); + if (error_line) { + break; + } + } + } + if (highlight_safe) { if (safe_lines.has(i + 1)) { te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); last_is_safe = true; - } else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().is_empty())) { + } else if (last_is_safe && (te->is_in_comment(i) != -1 || te->get_line(i).strip_edges().is_empty())) { te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color); } else { te->set_line_gutter_item_color(i, line_number_gutter, default_line_number_color); last_is_safe = false; } } else { - te->set_line_gutter_item_color(line, 1, default_line_number_color); + te->set_line_gutter_item_color(i, 1, default_line_number_color); } } @@ -1044,7 +1038,7 @@ void ScriptTextEditor::_edit_option(int p_op) { return; } - tx->indent_selected_lines_left(); + tx->unindent_lines(); } break; case EDIT_INDENT_RIGHT: { Ref<Script> scr = script; @@ -1052,16 +1046,16 @@ void ScriptTextEditor::_edit_option(int p_op) { return; } - tx->indent_selected_lines_right(); + tx->indent_lines(); } break; case EDIT_DELETE_LINE: { code_editor->delete_lines(); } break; - case EDIT_CLONE_DOWN: { - code_editor->clone_lines_down(); + case EDIT_DUPLICATE_SELECTION: { + code_editor->duplicate_selection(); } break; case EDIT_TOGGLE_FOLD_LINE: { - tx->toggle_fold_line(tx->cursor_get_line()); + tx->toggle_foldable_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { @@ -1343,9 +1337,9 @@ void ScriptTextEditor::_notification(int p_what) { void ScriptTextEditor::_bind_methods() { ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods); - ClassDB::bind_method("get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &ScriptTextEditor::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &ScriptTextEditor::drop_data_fw); ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &ScriptTextEditor::add_syntax_highlighter); } @@ -1358,6 +1352,10 @@ void ScriptTextEditor::clear_edit_menu() { memdelete(edit_hb); } +void ScriptTextEditor::set_find_replace_bar(FindReplaceBar *p_bar) { + code_editor->set_find_replace_bar(p_bar); +} + void ScriptTextEditor::reload(bool p_soft) { CodeEdit *te = code_editor->get_text_editor(); Ref<Script> scr = script; @@ -1446,6 +1444,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } if (d.has("type") && (String(d["type"]) == "files" || String(d["type"]) == "files_and_dirs")) { + const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; Array files = d["files"]; String text_to_drop; @@ -1456,9 +1455,9 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data } if (preload) { - text_to_drop += "preload(\"" + String(files[i]).c_escape() + "\")"; + text_to_drop += "preload(" + String(files[i]).c_escape().quote(quote_style) + ")"; } else { - text_to_drop += "\"" + String(files[i]).c_escape() + "\""; + text_to_drop += String(files[i]).c_escape().quote(quote_style); } } @@ -1545,7 +1544,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { } bool has_color = (word_at_pos == "Color"); - bool foldable = tx->can_fold(row) || tx->is_folded(row); + bool foldable = tx->can_fold_line(row) || tx->is_line_folded(row); bool open_docs = false; bool goto_definition = false; @@ -1671,6 +1670,7 @@ void ScriptTextEditor::_enable_code_editor() { editor_box->set_v_size_flags(SIZE_EXPAND_FILL); editor_box->add_child(code_editor); + code_editor->connect("show_errors_panel", callable_mp(this, &ScriptTextEditor::_show_errors_panel)); code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script)); code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings)); @@ -1691,6 +1691,13 @@ void ScriptTextEditor::_enable_code_editor() { "normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("main_size", "EditorFonts")); warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked)); + editor_box->add_child(errors_panel); + errors_panel->add_theme_font_override( + "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts")); + errors_panel->add_theme_font_size_override( + "normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size("main_size", "EditorFonts")); + errors_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_error_clicked)); + add_child(context_menu); context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); @@ -1753,7 +1760,7 @@ void ScriptTextEditor::_enable_code_editor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); @@ -1822,6 +1829,14 @@ ScriptTextEditor::ScriptTextEditor() { warnings_panel->set_focus_mode(FOCUS_CLICK); warnings_panel->hide(); + errors_panel = memnew(RichTextLabel); + errors_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); + errors_panel->set_h_size_flags(SIZE_EXPAND_FILL); + errors_panel->set_meta_underline(true); + errors_panel->set_selection_enabled(true); + errors_panel->set_focus_mode(FOCUS_CLICK); + errors_panel->hide(); + update_settings(); code_editor->get_text_editor()->set_code_hint_draw_below(EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line")); @@ -1847,11 +1862,11 @@ ScriptTextEditor::ScriptTextEditor() { highlighter_menu->set_name("highlighter_menu"); Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; - plain_highlighter.instance(); + plain_highlighter.instantiate(); add_syntax_highlighter(plain_highlighter); Ref<EditorStandardSyntaxHighlighter> highlighter; - highlighter.instance(); + highlighter.instantiate(); add_syntax_highlighter(highlighter); set_syntax_highlighter(highlighter); @@ -1882,6 +1897,7 @@ ScriptTextEditor::~ScriptTextEditor() { if (!editor_enabled) { memdelete(code_editor); memdelete(warnings_panel); + memdelete(errors_panel); memdelete(context_menu); memdelete(color_panel); memdelete(edit_hb); @@ -1918,9 +1934,9 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0); ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED - ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C); + ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_C); #else - ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D); + ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D); #endif ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E); ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index f784bbe1f8..e4a13951e4 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -55,6 +55,7 @@ class ScriptTextEditor : public ScriptEditorBase { CodeTextEditor *code_editor = nullptr; RichTextLabel *warnings_panel = nullptr; + RichTextLabel *errors_panel = nullptr; Ref<Script> script; bool script_is_valid = false; @@ -116,7 +117,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_INDENT_RIGHT, EDIT_INDENT_LEFT, EDIT_DELETE_LINE, - EDIT_CLONE_DOWN, + EDIT_DUPLICATE_SELECTION, EDIT_PICK_COLOR, EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, @@ -161,7 +162,9 @@ protected: void _load_theme_settings(); void _set_theme_for_script(); + void _show_errors_panel(bool p_show); void _show_warnings_panel(bool p_show); + void _error_clicked(Variant p_line); void _warning_clicked(Variant p_line); void _notification(int p_what); @@ -233,6 +236,8 @@ public: Control *get_edit_menu() override; virtual void clear_edit_menu() override; + virtual void set_find_replace_bar(FindReplaceBar *p_bar) override; + static void register_editor(); virtual Control *get_base_editor() const override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 3beef78bfc..c1216a9732 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -240,7 +240,7 @@ void ShaderTextEditor::_validate_script() { warnings.sort_custom<WarningsComparator>(); _update_warning_panel(); } else { - set_warning_nb(0); + set_warning_count(0); } emit_signal("script_changed"); } @@ -280,14 +280,14 @@ void ShaderTextEditor::_update_warning_panel() { } warnings_panel->pop(); // Table. - set_warning_nb(warning_count); + set_warning_count(warning_count); } void ShaderTextEditor::_bind_methods() { } ShaderTextEditor::ShaderTextEditor() { - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); get_text_editor()->set_syntax_highlighter(syntax_highlighter); } @@ -323,25 +323,19 @@ void ShaderEditor::_menu_option(int p_option) { if (shader.is_null()) { return; } - - CodeEdit *tx = shader_editor->get_text_editor(); - tx->indent_selected_lines_left(); - + shader_editor->get_text_editor()->unindent_lines(); } break; case EDIT_INDENT_RIGHT: { if (shader.is_null()) { return; } - - CodeEdit *tx = shader_editor->get_text_editor(); - tx->indent_selected_lines_right(); - + shader_editor->get_text_editor()->indent_lines(); } break; case EDIT_DELETE_LINE: { shader_editor->delete_lines(); } break; - case EDIT_CLONE_DOWN: { - shader_editor->clone_lines_down(); + case EDIT_DUPLICATE_SELECTION: { + shader_editor->duplicate_selection(); } break; case EDIT_TOGGLE_COMMENT: { if (shader.is_null()) { @@ -698,7 +692,7 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION); edit_menu->get_popup()->add_separator(); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_text_completion_query"), EDIT_COMPLETE); edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ShaderEditor::_menu_option)); @@ -751,6 +745,11 @@ ShaderEditor::ShaderEditor(EditorNode *p_node) { editor_box->set_v_size_flags(SIZE_EXPAND_FILL); editor_box->add_child(shader_editor); + FindReplaceBar *bar = memnew(FindReplaceBar); + main_container->add_child(bar); + bar->hide(); + shader_editor->set_find_replace_bar(bar); + warnings_panel = memnew(RichTextLabel); warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index d7da73f2ae..77579754d3 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -91,7 +91,7 @@ class ShaderEditor : public PanelContainer { EDIT_INDENT_LEFT, EDIT_INDENT_RIGHT, EDIT_DELETE_LINE, - EDIT_CLONE_DOWN, + EDIT_DUPLICATE_SELECTION, EDIT_TOGGLE_COMMENT, EDIT_COMPLETE, SEARCH_FIND, diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index 47d7f8204b..85ccc5b798 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -272,7 +272,7 @@ ShaderFileEditor::ShaderFileEditor(EditorNode *p_node) { main_vb->add_child(stage_hb); Ref<ButtonGroup> bg; - bg.instance(); + bg.instantiate(); for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { Button *button = memnew(Button(stage_str[i])); button->set_toggle_mode(true); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 404ef62eca..0b04c2e50e 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -95,7 +95,7 @@ void BoneTransformEditor::create_editors() { section->get_vbox()->add_child(transform_section); // Transform/Matrix property - transform_property = memnew(EditorPropertyTransform()); + transform_property = memnew(EditorPropertyTransform3D()); transform_property->setup(-10000, 10000, 0.001f, true); transform_property->set_label("Transform"); transform_property->set_use_folding(true); @@ -171,7 +171,7 @@ void BoneTransformEditor::_value_changed(const double p_value) { return; } - Transform tform = compute_transform_from_vector3s(); + Transform3D tform = compute_transform_from_vector3s(); _change_transform(tform); } @@ -179,30 +179,30 @@ void BoneTransformEditor::_value_changed_vector3(const String p_property_name, c if (updating) { return; } - Transform tform = compute_transform_from_vector3s(); + Transform3D tform = compute_transform_from_vector3s(); _change_transform(tform); } -Transform BoneTransformEditor::compute_transform_from_vector3s() const { +Transform3D BoneTransformEditor::compute_transform_from_vector3s() const { // Convert rotation from degrees to radians. Vector3 prop_rotation = rotation_property->get_vector(); prop_rotation.x = Math::deg2rad(prop_rotation.x); prop_rotation.y = Math::deg2rad(prop_rotation.y); prop_rotation.z = Math::deg2rad(prop_rotation.z); - return Transform( + return Transform3D( Basis(prop_rotation, scale_property->get_vector()), translation_property->get_vector()); } -void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean) { +void BoneTransformEditor::_value_changed_transform(const String p_property_name, const Transform3D p_transform, const StringName p_edited_property_name, const bool p_boolean) { if (updating) { return; } _change_transform(p_transform); } -void BoneTransformEditor::_change_transform(Transform p_new_transform) { +void BoneTransformEditor::_change_transform(Transform3D p_new_transform) { if (property.get_slicec('/', 0) == "bones" && property.get_slicec('/', 2) == "custom_pose") { undo_redo->create_action(TTR("Set Custom Bone Pose Transform"), UndoRedo::MERGE_ENDS); undo_redo->add_undo_method(skeleton, "set_bone_custom_pose", property.get_slicec('/', 1).to_int(), skeleton->get_bone_custom_pose(property.get_slicec('/', 1).to_int())); @@ -235,7 +235,7 @@ void BoneTransformEditor::_update_properties() { updating = true; - Transform tform = skeleton->get(property); + Transform3D tform = skeleton->get(property); _update_transform_properties(tform); } @@ -250,11 +250,11 @@ void BoneTransformEditor::_update_custom_pose_properties() { updating = true; - Transform tform = skeleton->get_bone_custom_pose(property.to_int()); + Transform3D tform = skeleton->get_bone_custom_pose(property.to_int()); _update_transform_properties(tform); } -void BoneTransformEditor::_update_transform_properties(Transform tform) { +void BoneTransformEditor::_update_transform_properties(Transform3D tform) { Basis rotation_basis = tform.get_basis(); Vector3 rotation_radians = rotation_basis.get_rotation_euler(); Vector3 rotation_degrees = Vector3(Math::rad2deg(rotation_radians.x), Math::rad2deg(rotation_radians.y), Math::rad2deg(rotation_radians.z)); @@ -306,7 +306,7 @@ void BoneTransformEditor::_key_button_pressed() { } // Need to normalize the basis before you key it - Transform tform = compute_transform_from_vector3s(); + Transform3D tform = compute_transform_from_vector3s(); tform.orthonormalize(); AnimationPlayerEditor::singleton->get_track_editor()->insert_transform_key(skeleton, name, tform); } @@ -380,7 +380,7 @@ void Skeleton3DEditor::create_physical_skeleton() { } PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos) { - const Transform child_rest = skeleton->get_bone_rest(bone_child_id); + const Transform3D child_rest = skeleton->get_bone_rest(bone_child_id); const real_t half_height(child_rest.origin.length() * 0.5); const real_t radius(half_height * 0.2); @@ -392,15 +392,15 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi CollisionShape3D *bone_shape = memnew(CollisionShape3D); bone_shape->set_shape(bone_shape_capsule); - Transform capsule_transform; + Transform3D capsule_transform; capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0)); bone_shape->set_transform(capsule_transform); - Transform body_transform; + Transform3D body_transform; body_transform.set_look_at(Vector3(0, 0, 0), child_rest.origin); body_transform.origin = body_transform.basis.xform(Vector3(0, 0, -half_height)); - Transform joint_transform; + Transform3D joint_transform; joint_transform.origin = Vector3(0, 0, half_height); PhysicalBone3D *physical_bone = memnew(PhysicalBone3D); @@ -666,9 +666,9 @@ void Skeleton3DEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties); ClassDB::bind_method(D_METHOD("_on_click_option"), &Skeleton3DEditor::_on_click_option); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &Skeleton3DEditor::drop_data_fw); ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone); } @@ -700,7 +700,7 @@ Skeleton3DEditorPlugin::Skeleton3DEditorPlugin(EditorNode *p_node) { editor = p_node; Ref<EditorInspectorPluginSkeleton> skeleton_plugin; - skeleton_plugin.instance(); + skeleton_plugin.instantiate(); skeleton_plugin->editor = editor; EditorInspector::add_inspector_plugin(skeleton_plugin); diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 14c213f7b2..9de52c6fa8 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -41,7 +41,7 @@ class PhysicalBone3D; class Skeleton3DEditorPlugin; class Button; class CheckBox; -class EditorPropertyTransform; +class EditorPropertyTransform3D; class EditorPropertyVector3; class BoneTransformEditor : public VBoxContainer { @@ -53,7 +53,7 @@ class BoneTransformEditor : public VBoxContainer { EditorPropertyVector3 *rotation_property = nullptr; EditorPropertyVector3 *scale_property = nullptr; EditorInspectorSection *transform_section = nullptr; - EditorPropertyTransform *transform_property = nullptr; + EditorPropertyTransform3D *transform_property = nullptr; Rect2 background_rects[5]; @@ -78,11 +78,11 @@ class BoneTransformEditor : public VBoxContainer { // Called when the one of the EditorPropertyVector3 are updated. void _value_changed_vector3(const String p_property_name, const Vector3 p_vector, const StringName p_edited_property_name, const bool p_boolean); // Called when the transform_property is updated. - void _value_changed_transform(const String p_property_name, const Transform p_transform, const StringName p_edited_property_name, const bool p_boolean); + void _value_changed_transform(const String p_property_name, const Transform3D p_transform, const StringName p_edited_property_name, const bool p_boolean); // Changes the transform to the given transform and updates the UI accordingly. - void _change_transform(Transform p_new_transform); + void _change_transform(Transform3D p_new_transform); // Creates a Transform using the EditorPropertyVector3 properties. - Transform compute_transform_from_vector3s() const; + Transform3D compute_transform_from_vector3s() const; void update_enabled_checkbox(); @@ -98,7 +98,7 @@ public: void _update_properties(); void _update_custom_pose_properties(); - void _update_transform_properties(Transform p_transform); + void _update_transform_properties(Transform3D p_transform); // Can/cannot modify the spinner values for the Transform void set_read_only(const bool p_read_only); @@ -127,7 +127,7 @@ class Skeleton3DEditor : public VBoxContainer { struct BoneInfo { PhysicalBone3D *physical_bone = nullptr; - Transform relative_rest; // Relative to skeleton node + Transform3D relative_rest; // Relative to skeleton node }; EditorNode *editor; diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index 4a7f6c0f7e..ef328bcfe2 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -186,7 +186,7 @@ void Sprite2DEditor::_update_mesh_data() { } Ref<BitMap> bm; - bm.instance(); + bm.instantiate(); bm->create_from_image_alpha(image); int shrink = shrink_pixels->get_value(); @@ -322,7 +322,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() { } Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); Array a; a.resize(Mesh::ARRAY_MAX); @@ -435,7 +435,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() { Vector<Vector2> outline = computed_outline_lines[i]; Ref<OccluderPolygon2D> polygon; - polygon.instance(); + polygon.instantiate(); PackedVector2Array a; a.resize(outline.size()); diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 59bc8f9e55..70c7b3072b 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -103,17 +103,16 @@ void SpriteFramesEditor::_sheet_preview_draw() { } void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { - Ref<InputEventMouseButton> mb = p_event; - + const Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { - Size2i size = split_sheet_preview->get_size(); - int h = split_sheet_h->get_value(); - int v = split_sheet_v->get_value(); + const Size2i size = split_sheet_preview->get_size(); + const int h = split_sheet_h->get_value(); + const int v = split_sheet_v->get_value(); - int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1); - int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1); + const int x = CLAMP(int(mb->get_position().x) * h / size.width, 0, h - 1); + const int y = CLAMP(int(mb->get_position().y) * v / size.height, 0, v - 1); - int idx = h * y + x; + const int idx = h * y + x; if (mb->is_shift_pressed() && last_frame_selected >= 0) { //select multiple @@ -124,6 +123,9 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { } for (int i = from; i <= to; i++) { + // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held. + frames_toggled_by_mouse_hover.insert(idx); + if (mb->is_ctrl_pressed()) { frames_selected.erase(i); } else { @@ -131,6 +133,9 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { } } } else { + // Prevent double-toggling the same frame when moving the mouse when the mouse button is still held. + frames_toggled_by_mouse_hover.insert(idx); + if (frames_selected.has(idx)) { frames_selected.erase(idx); } else { @@ -141,6 +146,39 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) { last_frame_selected = idx; split_sheet_preview->update(); } + + if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { + frames_toggled_by_mouse_hover.clear(); + } + + const Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { + // Select by holding down the mouse button on frames. + const Size2i size = split_sheet_preview->get_size(); + const int h = split_sheet_h->get_value(); + const int v = split_sheet_v->get_value(); + + const int x = CLAMP(int(mm->get_position().x) * h / size.width, 0, h - 1); + const int y = CLAMP(int(mm->get_position().y) * v / size.height, 0, v - 1); + + const int idx = h * y + x; + + if (!frames_toggled_by_mouse_hover.has(idx)) { + // Only allow toggling each tile once per mouse hold. + // Otherwise, the selection would constantly "flicker" in and out when moving the mouse cursor. + // The mouse button must be released before it can be toggled again. + frames_toggled_by_mouse_hover.insert(idx); + + if (frames_selected.has(idx)) { + frames_selected.erase(idx); + } else { + frames_selected.insert(idx); + } + + last_frame_selected = idx; + split_sheet_preview->update(); + } + } } void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) { @@ -189,7 +227,7 @@ void SpriteFramesEditor::_sheet_add_frames() { int y = (yp * height) + region_rect.position.y; Ref<AtlasTexture> at; - at.instance(); + at.instantiate(); at->set_atlas(split_sheet_preview->get_texture()); at->set_region(Rect2(x, y, width, height)); @@ -964,9 +1002,9 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da void SpriteFramesEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpriteFramesEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SpriteFramesEditor::drop_data_fw); } SpriteFramesEditor::SpriteFramesEditor() { diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h index 77cdbb4af6..e6c59e3533 100644 --- a/editor/plugins/sprite_frames_editor_plugin.h +++ b/editor/plugins/sprite_frames_editor_plugin.h @@ -87,6 +87,7 @@ class SpriteFramesEditor : public HSplitContainer { Button *split_sheet_zoom_in; EditorFileDialog *file_split_sheet; Set<int> frames_selected; + Set<int> frames_toggled_by_mouse_hover; int last_frame_selected; float scale_ratio; diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index 64df982d5d..91c5e96f08 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -44,7 +44,7 @@ void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) { add_custom_control(preview); } -bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, bool p_wide) { return false; //do not want } @@ -93,6 +93,6 @@ StyleBoxPreview::StyleBoxPreview() { StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginStyleBox> inspector_plugin; - inspector_plugin.instance(); + inspector_plugin.instantiate(); add_inspector_plugin(inspector_plugin); } diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index d4a235cd10..8ca348bd80 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -61,7 +61,7 @@ class EditorInspectorPluginStyleBox : public EditorInspectorPlugin { public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; virtual void parse_end() override; }; diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 1edcbd2cc9..5766646f7d 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -281,6 +281,10 @@ void TextEditor::clear_edit_menu() { memdelete(edit_hb); } +void TextEditor::set_find_replace_bar(FindReplaceBar *p_bar) { + code_editor->set_find_replace_bar(p_bar); +} + void TextEditor::_edit_option(int p_op) { CodeEdit *tx = code_editor->get_text_editor(); @@ -316,19 +320,19 @@ void TextEditor::_edit_option(int p_op) { code_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { - tx->indent_selected_lines_left(); + tx->unindent_lines(); } break; case EDIT_INDENT_RIGHT: { - tx->indent_selected_lines_right(); + tx->indent_lines(); } break; case EDIT_DELETE_LINE: { code_editor->delete_lines(); } break; - case EDIT_CLONE_DOWN: { - code_editor->clone_lines_down(); + case EDIT_DUPLICATE_SELECTION: { + code_editor->duplicate_selection(); } break; case EDIT_TOGGLE_FOLD_LINE: { - tx->toggle_fold_line(tx->cursor_get_line()); + tx->toggle_foldable_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_FOLD_ALL_LINES: { @@ -428,8 +432,8 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); - bool can_fold = tx->can_fold(row); - bool is_folded = tx->is_folded(row); + bool can_fold = tx->can_fold_line(row); + bool is_folded = tx->is_line_folded(row); if (tx->is_right_click_moving_caret()) { if (tx->is_selection_active()) { @@ -459,7 +463,7 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { if (k.is_valid() && k->is_pressed() && k->get_keycode() == KEY_MENU) { CodeEdit *tx = code_editor->get_text_editor(); int line = tx->cursor_get_line(); - _make_context_menu(tx->is_selection_active(), tx->can_fold(line), tx->is_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos())); + _make_context_menu(tx->is_selection_active(), tx->can_fold_line(line), tx->is_line_folded(line), (get_global_transform().inverse() * tx->get_global_transform()).xform(tx->_get_cursor_pixel_pos())); context_menu->grab_focus(); } } @@ -538,7 +542,7 @@ TextEditor::TextEditor() { edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option)); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_undo"), EDIT_UNDO); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("un_redo"), EDIT_REDO); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY); @@ -555,7 +559,7 @@ TextEditor::TextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); - edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/duplicate_selection"), EDIT_DUPLICATE_SELECTION); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); @@ -577,11 +581,11 @@ TextEditor::TextEditor() { highlighter_menu->connect("id_pressed", callable_mp(this, &TextEditor::_change_syntax_highlighter)); Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; - plain_highlighter.instance(); + plain_highlighter.instantiate(); add_syntax_highlighter(plain_highlighter); Ref<EditorStandardSyntaxHighlighter> highlighter; - highlighter.instance(); + highlighter.instantiate(); add_syntax_highlighter(highlighter); set_syntax_highlighter(plain_highlighter); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index abb75cc9d8..86a4910ac0 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -66,7 +66,7 @@ private: EDIT_INDENT_RIGHT, EDIT_INDENT_LEFT, EDIT_DELETE_LINE, - EDIT_CLONE_DOWN, + EDIT_DUPLICATE_SELECTION, EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, @@ -139,6 +139,7 @@ public: virtual Control *get_edit_menu() override; virtual void clear_edit_menu() override; + virtual void set_find_replace_bar(FindReplaceBar *p_bar) override; virtual void validate() override; diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 36297c8a4a..696aa88e23 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -85,9 +85,9 @@ void Texture3DEditor::_make_shaders() { " COLOR = textureLod(tex,vec3(UV,layer),0.0);\n" "}"; - shader.instance(); + shader.instantiate(); shader->set_code(shader_3d); - material.instance(); + material.instantiate(); material->set_shader(shader); } @@ -207,6 +207,6 @@ void EditorInspectorPlugin3DTexture::parse_begin(Object *p_object) { Texture3DEditorPlugin::Texture3DEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPlugin3DTexture> plugin; - plugin.instance(); + plugin.instantiate(); add_inspector_plugin(plugin); } diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index ecf7370834..10b942d9ee 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -160,6 +160,6 @@ void EditorInspectorPluginTexture::parse_begin(Object *p_object) { TextureEditorPlugin::TextureEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginTexture> plugin; - plugin.instance(); + plugin.instantiate(); add_inspector_plugin(plugin); } diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index 89ed98d53e..3f46cd64a2 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -112,7 +112,7 @@ void TextureLayeredEditor::_make_shaders() { " COLOR = textureLod(tex,vec3(UV,layer),0.0);\n" "}"; - shaders[0].instance(); + shaders[0].instantiate(); shaders[0]->set_code(shader_2d_array); String shader_cube = "" @@ -125,7 +125,7 @@ void TextureLayeredEditor::_make_shaders() { " COLOR = textureLod(tex,n,0.0);\n" "}"; - shaders[1].instance(); + shaders[1].instantiate(); shaders[1]->set_code(shader_cube); String shader_cube_array = "" @@ -139,11 +139,11 @@ void TextureLayeredEditor::_make_shaders() { " COLOR = textureLod(tex,vec4(n,layer),0.0);\n" "}"; - shaders[2].instance(); + shaders[2].instantiate(); shaders[2]->set_code(shader_cube_array); for (int i = 0; i < 3; i++) { - materials[i].instance(); + materials[i].instantiate(); materials[i]->set_shader(shaders[i]); } } @@ -271,6 +271,6 @@ void EditorInspectorPluginLayeredTexture::parse_begin(Object *p_object) { TextureLayeredEditorPlugin::TextureLayeredEditorPlugin(EditorNode *p_node) { Ref<EditorInspectorPluginLayeredTexture> plugin; - plugin.instance(); + plugin.instantiate(); add_inspector_plugin(plugin); } diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 9526160674..d0ba68138b 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -863,13 +863,13 @@ Sprite2D *TextureRegionEditor::get_sprite() { void TextureRegionEditor::edit(Object *p_obj) { if (node_sprite) { - node_sprite->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); + node_sprite->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); } if (node_sprite_3d) { - node_sprite_3d->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); + node_sprite_3d->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); } if (node_ninepatch) { - node_ninepatch->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); + node_ninepatch->disconnect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); } if (obj_styleBox.is_valid()) { obj_styleBox->disconnect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); @@ -881,13 +881,22 @@ void TextureRegionEditor::edit(Object *p_obj) { node_sprite = Object::cast_to<Sprite2D>(p_obj); node_sprite_3d = Object::cast_to<Sprite3D>(p_obj); node_ninepatch = Object::cast_to<NinePatchRect>(p_obj); + + bool is_resource = false; if (Object::cast_to<StyleBoxTexture>(p_obj)) { obj_styleBox = Ref<StyleBoxTexture>(Object::cast_to<StyleBoxTexture>(p_obj)); + is_resource = true; } if (Object::cast_to<AtlasTexture>(p_obj)) { atlas_tex = Ref<AtlasTexture>(Object::cast_to<AtlasTexture>(p_obj)); + is_resource = true; + } + + if (is_resource) { + p_obj->connect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); + } else { + p_obj->connect("texture_changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); } - p_obj->connect("changed", callable_mp(this, &TextureRegionEditor::_texture_changed)); _edit_region(); } else { node_sprite = nullptr; @@ -1033,7 +1042,7 @@ TextureRegionEditor::TextureRegionEditor(EditorNode *p_editor) { hb_grid->add_child(sb_step_y); hb_grid->add_child(memnew(VSeparator)); - hb_grid->add_child(memnew(Label(TTR("Sep.:")))); + hb_grid->add_child(memnew(Label(TTR("Separation:")))); sb_sep_x = memnew(SpinBox); sb_sep_x->set_min(0); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index f1c73f99dc..be1aeb309f 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -30,12 +30,10 @@ #include "theme_editor_plugin.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" -#include "core/version.h" +#include "editor/editor_resource_picker.h" #include "editor/editor_scale.h" #include "editor/progress_dialog.h" -#include "scene/gui/progress_bar.h" void ThemeItemImportTree::_update_items_tree() { import_items_tree->clear(); @@ -756,7 +754,9 @@ void ThemeItemImportTree::_import_selected() { return; } - ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size()); + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size() + 2); int idx = 0; for (Map<ThemeItem, ItemCheckedState>::Element *E = selected_items.front(); E; E = E->next()) { @@ -814,6 +814,12 @@ void ThemeItemImportTree::_import_selected() { idx++; } + // Allow changes to be reported now that the operation is finished. + ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Updating the editor"), idx++); + edited_theme->_unfreeze_and_propagate_changes(); + // Make sure the task is not ended before the editor freezes to update the Inspector. + ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Finalizing"), idx++); + ProgressDialog::get_singleton()->end_task("import_theme_items"); emit_signal("items_imported"); } @@ -924,11 +930,14 @@ ThemeItemImportTree::ThemeItemImportTree() { import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import")); import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data")); import_items_tree->set_column_expand(0, true); + import_items_tree->set_column_clip_content(0, true); import_items_tree->set_column_expand(IMPORT_ITEM, false); import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false); - import_items_tree->set_column_min_width(0, 160 * EDSCALE); - import_items_tree->set_column_min_width(IMPORT_ITEM, 80 * EDSCALE); - import_items_tree->set_column_min_width(IMPORT_ITEM_DATA, 80 * EDSCALE); + import_items_tree->set_column_custom_minimum_width(0, 160 * EDSCALE); + import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM, 80 * EDSCALE); + import_items_tree->set_column_custom_minimum_width(IMPORT_ITEM_DATA, 80 * EDSCALE); + import_items_tree->set_column_clip_content(1, true); + import_items_tree->set_column_clip_content(2, true); ScrollContainer *import_bulk_sc = memnew(ScrollContainer); import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE); @@ -1201,7 +1210,7 @@ void ThemeItemEditorDialog::_close_dialog() { } void ThemeItemEditorDialog::_dialog_about_to_show() { - ERR_FAIL_COND(edited_theme.is_null()); + ERR_FAIL_COND_MSG(edited_theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing."); _update_edit_types(); @@ -1458,6 +1467,9 @@ void ThemeItemEditorDialog::_add_theme_type() { edited_theme->add_color_type(edit_add_type_value->get_text()); edited_theme->add_constant_type(edit_add_type_value->get_text()); _update_edit_types(); + + // Force emit a change so that other parts of the editor can update. + edited_theme->emit_changed(); } void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) { @@ -1488,15 +1500,24 @@ void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) { List<StringName> names; + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + edited_theme->get_theme_item_list(p_data_type, p_item_type, &names); for (List<StringName>::Element *E = names.front(); E; E = E->next()) { edited_theme->clear_theme_item(p_data_type, E->get(), p_item_type); } + + // Allow changes to be reported now that the operation is finished. + edited_theme->_unfreeze_and_propagate_changes(); } void ThemeItemEditorDialog::_remove_class_items() { List<StringName> names; + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { Theme::DataType data_type = (Theme::DataType)dt; @@ -1509,12 +1530,18 @@ void ThemeItemEditorDialog::_remove_class_items() { } } + // Allow changes to be reported now that the operation is finished. + edited_theme->_unfreeze_and_propagate_changes(); + _update_edit_item_tree(edited_item_type); } void ThemeItemEditorDialog::_remove_custom_items() { List<StringName> names; + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { Theme::DataType data_type = (Theme::DataType)dt; @@ -1527,12 +1554,18 @@ void ThemeItemEditorDialog::_remove_custom_items() { } } + // Allow changes to be reported now that the operation is finished. + edited_theme->_unfreeze_and_propagate_changes(); + _update_edit_item_tree(edited_item_type); } void ThemeItemEditorDialog::_remove_all_items() { List<StringName> names; + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) { Theme::DataType data_type = (Theme::DataType)dt; @@ -1543,6 +1576,9 @@ void ThemeItemEditorDialog::_remove_all_items() { } } + // Allow changes to be reported now that the operation is finished. + edited_theme->_unfreeze_and_propagate_changes(); + _update_edit_item_tree(edited_item_type); } @@ -1907,268 +1943,1323 @@ ThemeItemEditorDialog::ThemeItemEditorDialog() { confirm_closing_dialog->connect("confirmed", callable_mp(this, &ThemeItemEditorDialog::_close_dialog)); } +VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) { + VBoxContainer *items_tab = memnew(VBoxContainer); + items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE); + data_type_tabs->add_child(items_tab); + data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, ""); + + ScrollContainer *items_sc = memnew(ScrollContainer); + items_sc->set_v_size_flags(SIZE_EXPAND_FILL); + items_sc->set_enable_h_scroll(false); + items_tab->add_child(items_sc); + VBoxContainer *items_list = memnew(VBoxContainer); + items_list->set_h_size_flags(SIZE_EXPAND_FILL); + items_sc->add_child(items_list); + + HBoxContainer *item_add_hb = memnew(HBoxContainer); + items_tab->add_child(item_add_hb); + LineEdit *item_add_edit = memnew(LineEdit); + item_add_edit->set_h_size_flags(SIZE_EXPAND_FILL); + item_add_hb->add_child(item_add_edit); + item_add_edit->connect("text_submitted", callable_mp(this, &ThemeTypeEditor::_item_add_lineedit_cbk), varray(p_data_type, item_add_edit)); + Button *item_add_button = memnew(Button); + item_add_button->set_text(TTR("Add")); + item_add_hb->add_child(item_add_button); + item_add_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_add_cbk), varray(p_data_type, item_add_edit)); + + return items_list; +} + +void ThemeTypeEditor::_update_type_list() { + ERR_FAIL_COND(edited_theme.is_null()); + + if (updating) { + return; + } + updating = true; + + Control *focused = get_focus_owner(); + if (focused) { + if (focusables.has(focused)) { + // If focus is currently on one of the internal property editors, don't update. + updating = false; + return; + } + + Node *focus_parent = focused->get_parent(); + while (focus_parent) { + Control *c = Object::cast_to<Control>(focus_parent); + if (c && focusables.has(c)) { + // If focus is currently on one of the internal property editors, don't update. + updating = false; + return; + } + + focus_parent = focus_parent->get_parent(); + } + } + + List<StringName> theme_types; + edited_theme->get_type_list(&theme_types); + theme_types.sort_custom<StringName::AlphCompare>(); + + theme_type_list->clear(); + + if (theme_types.size() > 0) { + theme_type_list->set_disabled(false); + + bool item_reselected = false; + int e_idx = 0; + for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) { + Ref<Texture2D> item_icon; + if (E->get() == "") { + item_icon = get_theme_icon("NodeDisabled", "EditorIcons"); + } else { + item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled"); + } + theme_type_list->add_icon_item(item_icon, E->get()); + + if (E->get() == edited_type) { + theme_type_list->select(e_idx); + item_reselected = true; + } + e_idx++; + } + + if (!item_reselected) { + theme_type_list->select(0); + _list_type_selected(0); + } else { + _update_type_items(); + } + } else { + theme_type_list->set_disabled(true); + theme_type_list->add_item(TTR("None")); + + edited_type = ""; + _update_type_items(); + } + + updating = false; +} + +void ThemeTypeEditor::_update_type_list_debounced() { + update_debounce_timer->start(); +} + +void ThemeTypeEditor::_update_add_type_options(const String &p_filter) { + add_type_options->clear(); + + List<StringName> names; + Theme::get_default()->get_type_list(&names); + names.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!p_filter.is_subsequence_ofi(String(E->get()))) { + continue; + } + + Ref<Texture2D> item_icon; + if (E->get() == "") { + item_icon = get_theme_icon("NodeDisabled", "EditorIcons"); + } else { + item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled"); + } + + add_type_options->add_item(E->get(), item_icon); + } +} + +OrderedHashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) { + OrderedHashMap<StringName, bool> items; + List<StringName> names; + + if (include_default) { + names.clear(); + (Theme::get_default().operator->()->*get_list_func)(p_type_name, &names); + names.sort_custom<StringName::AlphCompare>(); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + items[E->get()] = false; + } + } + + { + names.clear(); + (edited_theme.operator->()->*get_list_func)(p_type_name, &names); + names.sort_custom<StringName::AlphCompare>(); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + items[E->get()] = true; + } + } + + List<StringName> keys; + for (OrderedHashMap<StringName, bool>::Element E = items.front(); E; E = E.next()) { + keys.push_back(E.key()); + } + keys.sort_custom<StringName::AlphCompare>(); + + OrderedHashMap<StringName, bool> ordered_items; + for (List<StringName>::Element *E = keys.front(); E; E = E->next()) { + ordered_items[E->get()] = items[E->get()]; + } + + return ordered_items; +} + +HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable) { + HBoxContainer *item_control = memnew(HBoxContainer); + + HBoxContainer *item_name_container = memnew(HBoxContainer); + item_name_container->set_h_size_flags(SIZE_EXPAND_FILL); + item_name_container->set_stretch_ratio(2.0); + item_control->add_child(item_name_container); + + Label *item_name = memnew(Label); + item_name->set_h_size_flags(SIZE_EXPAND_FILL); + item_name->set_clip_text(true); + item_name->set_text(p_item_name); + item_name->set_tooltip(p_item_name); + item_name_container->add_child(item_name); + + if (p_editable) { + LineEdit *item_name_edit = memnew(LineEdit); + item_name_edit->set_h_size_flags(SIZE_EXPAND_FILL); + item_name_edit->set_text(p_item_name); + item_name_container->add_child(item_name_edit); + item_name_edit->connect("text_submitted", callable_mp(this, &ThemeTypeEditor::_item_rename_entered), varray(p_data_type, p_item_name, item_name_container)); + item_name_edit->hide(); + + Button *item_rename_button = memnew(Button); + item_rename_button->set_icon(get_theme_icon("Edit", "EditorIcons")); + item_rename_button->set_tooltip(TTR("Rename Item")); + item_rename_button->set_flat(true); + item_name_container->add_child(item_rename_button); + item_rename_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_cbk), varray(p_data_type, p_item_name, item_name_container)); + + Button *item_remove_button = memnew(Button); + item_remove_button->set_icon(get_theme_icon("Remove", "EditorIcons")); + item_remove_button->set_tooltip(TTR("Remove Item")); + item_remove_button->set_flat(true); + item_name_container->add_child(item_remove_button); + item_remove_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_remove_cbk), varray(p_data_type, p_item_name)); + + Button *item_rename_confirm_button = memnew(Button); + item_rename_confirm_button->set_icon(get_theme_icon("ImportCheck", "EditorIcons")); + item_rename_confirm_button->set_tooltip(TTR("Confirm Item Rename")); + item_rename_confirm_button->set_flat(true); + item_name_container->add_child(item_rename_confirm_button); + item_rename_confirm_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_confirmed), varray(p_data_type, p_item_name, item_name_container)); + item_rename_confirm_button->hide(); + + Button *item_rename_cancel_button = memnew(Button); + item_rename_cancel_button->set_icon(get_theme_icon("ImportFail", "EditorIcons")); + item_rename_cancel_button->set_tooltip(TTR("Cancel Item Rename")); + item_rename_cancel_button->set_flat(true); + item_name_container->add_child(item_rename_cancel_button); + item_rename_cancel_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_rename_canceled), varray(p_data_type, p_item_name, item_name_container)); + item_rename_cancel_button->hide(); + } else { + item_name->add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor")); + + Button *item_override_button = memnew(Button); + item_override_button->set_icon(get_theme_icon("Add", "EditorIcons")); + item_override_button->set_tooltip(TTR("Override Item")); + item_override_button->set_flat(true); + item_name_container->add_child(item_override_button); + item_override_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_item_override_cbk), varray(p_data_type, p_item_name)); + } + + return item_control; +} + +void ThemeTypeEditor::_add_focusable(Control *p_control) { + focusables.append(p_control); +} + +void ThemeTypeEditor::_update_type_items() { + bool show_default = show_default_items_button->is_pressed(); + List<StringName> names; + + focusables.clear(); + + // Colors. + { + for (int i = color_items_list->get_child_count() - 1; i >= 0; i--) { + Node *node = color_items_list->get_child(i); + node->queue_delete(); + color_items_list->remove_child(node); + } + + OrderedHashMap<StringName, bool> color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default); + for (OrderedHashMap<StringName, bool>::Element E = color_items.front(); E; E = E.next()) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key(), E.get()); + ColorPickerButton *item_editor = memnew(ColorPickerButton); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_control->add_child(item_editor); + + if (E.get()) { + item_editor->set_pick_color(edited_theme->get_color(E.key(), edited_type)); + item_editor->connect("color_changed", callable_mp(this, &ThemeTypeEditor::_color_item_changed), varray(E.key())); + } else { + item_editor->set_pick_color(Theme::get_default()->get_color(E.key(), edited_type)); + item_editor->set_disabled(true); + } + + _add_focusable(item_editor); + color_items_list->add_child(item_control); + } + } + + // Constants. + { + for (int i = constant_items_list->get_child_count() - 1; i >= 0; i--) { + Node *node = constant_items_list->get_child(i); + node->queue_delete(); + constant_items_list->remove_child(node); + } + + OrderedHashMap<StringName, bool> constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default); + for (OrderedHashMap<StringName, bool>::Element E = constant_items.front(); E; E = E.next()) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key(), E.get()); + SpinBox *item_editor = memnew(SpinBox); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_editor->set_min(-100000); + item_editor->set_max(100000); + item_editor->set_step(1); + item_editor->set_allow_lesser(true); + item_editor->set_allow_greater(true); + item_control->add_child(item_editor); + + if (E.get()) { + item_editor->set_value(edited_theme->get_constant(E.key(), edited_type)); + item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_constant_item_changed), varray(E.key())); + } else { + item_editor->set_value(Theme::get_default()->get_constant(E.key(), edited_type)); + item_editor->set_editable(false); + } + + _add_focusable(item_editor); + constant_items_list->add_child(item_control); + } + } + + // Fonts. + { + for (int i = font_items_list->get_child_count() - 1; i >= 0; i--) { + Node *node = font_items_list->get_child(i); + node->queue_delete(); + font_items_list->remove_child(node); + } + + OrderedHashMap<StringName, bool> font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default); + for (OrderedHashMap<StringName, bool>::Element E = font_items.front(); E; E = E.next()) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key(), E.get()); + EditorResourcePicker *item_editor = memnew(EditorResourcePicker); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_editor->set_base_type("Font"); + item_control->add_child(item_editor); + + if (E.get()) { + if (edited_theme->has_font(E.key(), edited_type)) { + item_editor->set_edited_resource(edited_theme->get_font(E.key(), edited_type)); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_font_item_changed), varray(E.key())); + } else { + if (Theme::get_default()->has_font(E.key(), edited_type)) { + item_editor->set_edited_resource(Theme::get_default()->get_font(E.key(), edited_type)); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->set_editable(false); + } + + _add_focusable(item_editor); + font_items_list->add_child(item_control); + } + } + + // Fonts sizes. + { + for (int i = font_size_items_list->get_child_count() - 1; i >= 0; i--) { + Node *node = font_size_items_list->get_child(i); + node->queue_delete(); + font_size_items_list->remove_child(node); + } + + OrderedHashMap<StringName, bool> font_size_items = _get_type_items(edited_type, &Theme::get_font_size_list, show_default); + for (OrderedHashMap<StringName, bool>::Element E = font_size_items.front(); E; E = E.next()) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT_SIZE, E.key(), E.get()); + SpinBox *item_editor = memnew(SpinBox); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_editor->set_min(-100000); + item_editor->set_max(100000); + item_editor->set_step(1); + item_editor->set_allow_lesser(true); + item_editor->set_allow_greater(true); + item_control->add_child(item_editor); + + if (E.get()) { + item_editor->set_value(edited_theme->get_font_size(E.key(), edited_type)); + item_editor->connect("value_changed", callable_mp(this, &ThemeTypeEditor::_font_size_item_changed), varray(E.key())); + } else { + item_editor->set_value(Theme::get_default()->get_font_size(E.key(), edited_type)); + item_editor->set_editable(false); + } + + _add_focusable(item_editor); + font_size_items_list->add_child(item_control); + } + } + + // Icons. + { + for (int i = icon_items_list->get_child_count() - 1; i >= 0; i--) { + Node *node = icon_items_list->get_child(i); + node->queue_delete(); + icon_items_list->remove_child(node); + } + + OrderedHashMap<StringName, bool> icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default); + for (OrderedHashMap<StringName, bool>::Element E = icon_items.front(); E; E = E.next()) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key(), E.get()); + EditorResourcePicker *item_editor = memnew(EditorResourcePicker); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_editor->set_base_type("Texture2D"); + item_control->add_child(item_editor); + + if (E.get()) { + if (edited_theme->has_icon(E.key(), edited_type)) { + item_editor->set_edited_resource(edited_theme->get_icon(E.key(), edited_type)); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_icon_item_changed), varray(E.key())); + } else { + if (Theme::get_default()->has_icon(E.key(), edited_type)) { + item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key(), edited_type)); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->set_editable(false); + } + + _add_focusable(item_editor); + icon_items_list->add_child(item_control); + } + } + + // Styleboxes. + { + for (int i = stylebox_items_list->get_child_count() - 1; i >= 0; i--) { + Node *node = stylebox_items_list->get_child(i); + node->queue_delete(); + stylebox_items_list->remove_child(node); + } + + if (leading_stylebox.pinned) { + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, leading_stylebox.item_name, true); + EditorResourcePicker *item_editor = memnew(EditorResourcePicker); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_editor->set_stretch_ratio(1.5); + item_editor->set_base_type("StyleBox"); + + Button *pin_leader_button = memnew(Button); + pin_leader_button->set_flat(true); + pin_leader_button->set_toggle_mode(true); + pin_leader_button->set_pressed(true); + pin_leader_button->set_icon(get_theme_icon("Pin", "EditorIcons")); + pin_leader_button->set_tooltip(TTR("Unpin this StyleBox as a main style.")); + item_control->add_child(pin_leader_button); + pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_unpin_leading_stylebox)); + + item_control->add_child(item_editor); + + if (leading_stylebox.stylebox.is_valid()) { + item_editor->set_edited_resource(leading_stylebox.stylebox); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(leading_stylebox.item_name)); + + stylebox_items_list->add_child(item_control); + stylebox_items_list->add_child(memnew(HSeparator)); + } + + OrderedHashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default); + for (OrderedHashMap<StringName, bool>::Element E = stylebox_items.front(); E; E = E.next()) { + if (leading_stylebox.pinned && leading_stylebox.item_name == E.key()) { + continue; + } + + HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key(), E.get()); + EditorResourcePicker *item_editor = memnew(EditorResourcePicker); + item_editor->set_h_size_flags(SIZE_EXPAND_FILL); + item_editor->set_stretch_ratio(1.5); + item_editor->set_base_type("StyleBox"); + + if (E.get()) { + Ref<StyleBox> stylebox_value; + if (edited_theme->has_stylebox(E.key(), edited_type)) { + stylebox_value = edited_theme->get_stylebox(E.key(), edited_type); + item_editor->set_edited_resource(stylebox_value); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->connect("resource_selected", callable_mp(this, &ThemeTypeEditor::_edit_resource_item)); + item_editor->connect("resource_changed", callable_mp(this, &ThemeTypeEditor::_stylebox_item_changed), varray(E.key())); + + Button *pin_leader_button = memnew(Button); + pin_leader_button->set_flat(true); + pin_leader_button->set_toggle_mode(true); + pin_leader_button->set_icon(get_theme_icon("Pin", "EditorIcons")); + pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type.")); + item_control->add_child(pin_leader_button); + pin_leader_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_pin_leading_stylebox), varray(item_editor, E.key())); + } else { + if (Theme::get_default()->has_stylebox(E.key(), edited_type)) { + item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key(), edited_type)); + } else { + item_editor->set_edited_resource(RES()); + } + item_editor->set_editable(false); + } + + item_control->add_child(item_editor); + _add_focusable(item_editor); + stylebox_items_list->add_child(item_control); + } + } +} + +void ThemeTypeEditor::_list_type_selected(int p_index) { + edited_type = theme_type_list->get_item_text(p_index); + _update_type_items(); +} + +void ThemeTypeEditor::_add_type_button_cbk() { + add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE); + add_type_filter->grab_focus(); +} + +void ThemeTypeEditor::_add_type_filter_cbk(const String &p_value) { + _update_add_type_options(p_value); +} + +void ThemeTypeEditor::_add_type_options_cbk(int p_index) { + add_type_filter->set_text(add_type_options->get_item_text(p_index)); +} + +void ThemeTypeEditor::_add_type_dialog_confirmed() { + select_type(add_type_filter->get_text().strip_edges()); +} + +void ThemeTypeEditor::_add_type_dialog_entered(const String &p_value) { + select_type(p_value.strip_edges()); + add_type_dialog->hide(); +} + +void ThemeTypeEditor::_add_type_dialog_activated(int p_index) { + select_type(add_type_options->get_item_text(p_index)); + add_type_dialog->hide(); +} + +void ThemeTypeEditor::_add_default_type_items() { + List<StringName> names; + + updating = true; + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + + { + names.clear(); + Theme::get_default()->get_icon_list(edited_type, &names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!edited_theme->has_icon(E->get(), edited_type)) { + edited_theme->set_icon(E->get(), edited_type, Ref<Texture2D>()); + } + } + } + { + names.clear(); + Theme::get_default()->get_stylebox_list(edited_type, &names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!edited_theme->has_stylebox(E->get(), edited_type)) { + edited_theme->set_stylebox(E->get(), edited_type, Ref<StyleBox>()); + } + } + } + { + names.clear(); + Theme::get_default()->get_font_list(edited_type, &names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!edited_theme->has_font(E->get(), edited_type)) { + edited_theme->set_font(E->get(), edited_type, Ref<Font>()); + } + } + } + { + names.clear(); + Theme::get_default()->get_font_size_list(edited_type, &names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!edited_theme->has_font_size(E->get(), edited_type)) { + edited_theme->set_font_size(E->get(), edited_type, Theme::get_default()->get_font_size(E->get(), edited_type)); + } + } + } + { + names.clear(); + Theme::get_default()->get_color_list(edited_type, &names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!edited_theme->has_color(E->get(), edited_type)) { + edited_theme->set_color(E->get(), edited_type, Theme::get_default()->get_color(E->get(), edited_type)); + } + } + } + { + names.clear(); + Theme::get_default()->get_constant_list(edited_type, &names); + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (!edited_theme->has_constant(E->get(), edited_type)) { + edited_theme->set_constant(E->get(), edited_type, Theme::get_default()->get_constant(E->get(), edited_type)); + } + } + } + + // Allow changes to be reported now that the operation is finished. + edited_theme->_unfreeze_and_propagate_changes(); + updating = false; + + _update_type_items(); +} + +void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) { + LineEdit *le = Object::cast_to<LineEdit>(p_control); + if (le->get_text().strip_edges().is_empty()) { + return; + } + + String item_name = le->get_text().strip_edges(); + switch (p_data_type) { + case Theme::DATA_TYPE_COLOR: { + edited_theme->set_color(item_name, edited_type, Color()); + } break; + case Theme::DATA_TYPE_CONSTANT: { + edited_theme->set_constant(item_name, edited_type, 0); + } break; + case Theme::DATA_TYPE_FONT: { + edited_theme->set_font(item_name, edited_type, Ref<Font>()); + } break; + case Theme::DATA_TYPE_FONT_SIZE: { + edited_theme->set_font_size(item_name, edited_type, -1); + } break; + case Theme::DATA_TYPE_ICON: { + edited_theme->set_icon(item_name, edited_type, Ref<Texture2D>()); + } break; + case Theme::DATA_TYPE_STYLEBOX: { + edited_theme->set_stylebox(item_name, edited_type, Ref<StyleBox>()); + } break; + } + + le->set_text(""); +} + +void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control) { + _item_add_cbk(p_data_type, p_control); +} + +void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) { + switch (p_data_type) { + case Theme::DATA_TYPE_COLOR: { + edited_theme->set_color(p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type)); + } break; + case Theme::DATA_TYPE_CONSTANT: { + edited_theme->set_constant(p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type)); + } break; + case Theme::DATA_TYPE_FONT: { + edited_theme->set_font(p_item_name, edited_type, Ref<Font>()); + } break; + case Theme::DATA_TYPE_FONT_SIZE: { + edited_theme->set_font_size(p_item_name, edited_type, Theme::get_default()->get_font_size(p_item_name, edited_type)); + } break; + case Theme::DATA_TYPE_ICON: { + edited_theme->set_icon(p_item_name, edited_type, Ref<Texture2D>()); + } break; + case Theme::DATA_TYPE_STYLEBOX: { + edited_theme->set_stylebox(p_item_name, edited_type, Ref<StyleBox>()); + } break; + } +} + +void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) { + switch (p_data_type) { + case Theme::DATA_TYPE_COLOR: { + edited_theme->clear_color(p_item_name, edited_type); + } break; + case Theme::DATA_TYPE_CONSTANT: { + edited_theme->clear_constant(p_item_name, edited_type); + } break; + case Theme::DATA_TYPE_FONT: { + edited_theme->clear_font(p_item_name, edited_type); + } break; + case Theme::DATA_TYPE_FONT_SIZE: { + edited_theme->clear_font_size(p_item_name, edited_type); + } break; + case Theme::DATA_TYPE_ICON: { + edited_theme->clear_icon(p_item_name, edited_type); + } break; + case Theme::DATA_TYPE_STYLEBOX: { + edited_theme->clear_stylebox(p_item_name, edited_type); + + if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) { + _unpin_leading_stylebox(); + } + } break; + } +} + +void ThemeTypeEditor::_item_rename_cbk(int p_data_type, String p_item_name, Control *p_control) { + // Label + Object::cast_to<Label>(p_control->get_child(0))->hide(); + // Label buttons + Object::cast_to<Button>(p_control->get_child(2))->hide(); + Object::cast_to<Button>(p_control->get_child(3))->hide(); + + // LineEdit + Object::cast_to<LineEdit>(p_control->get_child(1))->set_text(p_item_name); + Object::cast_to<LineEdit>(p_control->get_child(1))->show(); + // LineEdit buttons + Object::cast_to<Button>(p_control->get_child(4))->show(); + Object::cast_to<Button>(p_control->get_child(5))->show(); +} + +void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control) { + LineEdit *le = Object::cast_to<LineEdit>(p_control->get_child(1)); + if (le->get_text().strip_edges().is_empty()) { + return; + } + + String new_name = le->get_text().strip_edges(); + if (new_name == p_item_name) { + _item_rename_canceled(p_data_type, p_item_name, p_control); + return; + } + + switch (p_data_type) { + case Theme::DATA_TYPE_COLOR: { + edited_theme->rename_color(p_item_name, new_name, edited_type); + } break; + case Theme::DATA_TYPE_CONSTANT: { + edited_theme->rename_constant(p_item_name, new_name, edited_type); + } break; + case Theme::DATA_TYPE_FONT: { + edited_theme->rename_font(p_item_name, new_name, edited_type); + } break; + case Theme::DATA_TYPE_FONT_SIZE: { + edited_theme->rename_font_size(p_item_name, new_name, edited_type); + } break; + case Theme::DATA_TYPE_ICON: { + edited_theme->rename_icon(p_item_name, new_name, edited_type); + } break; + case Theme::DATA_TYPE_STYLEBOX: { + edited_theme->rename_stylebox(p_item_name, new_name, edited_type); + + if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) { + leading_stylebox.item_name = new_name; + } + } break; + } +} + +void ThemeTypeEditor::_item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control) { + _item_rename_confirmed(p_data_type, p_item_name, p_control); +} + +void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, Control *p_control) { + // LineEdit + Object::cast_to<LineEdit>(p_control->get_child(1))->hide(); + // LineEdit buttons + Object::cast_to<Button>(p_control->get_child(4))->hide(); + Object::cast_to<Button>(p_control->get_child(5))->hide(); + + // Label + Object::cast_to<Label>(p_control->get_child(0))->show(); + // Label buttons + Object::cast_to<Button>(p_control->get_child(2))->show(); + Object::cast_to<Button>(p_control->get_child(3))->show(); +} + +void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) { + edited_theme->set_color(p_item_name, edited_type, p_value); +} + +void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) { + edited_theme->set_constant(p_item_name, edited_type, int(p_value)); +} + +void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) { + edited_theme->set_font_size(p_item_name, edited_type, int(p_value)); +} + +void ThemeTypeEditor::_edit_resource_item(RES p_resource) { + EditorNode::get_singleton()->edit_resource(p_resource); +} + +void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) { + edited_theme->set_font(p_item_name, edited_type, p_value); +} + +void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) { + edited_theme->set_icon(p_item_name, edited_type, p_value); +} + +void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) { + edited_theme->set_stylebox(p_item_name, edited_type, p_value); + + if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) { + if (leading_stylebox.stylebox.is_valid()) { + leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading)); + } + + leading_stylebox.stylebox = p_value; + leading_stylebox.ref_stylebox = (p_value.is_valid() ? p_value->duplicate() : RES()); + if (p_value.is_valid()) { + leading_stylebox.stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading)); + } + } +} + +void ThemeTypeEditor::_pin_leading_stylebox(Control *p_editor, String p_item_name) { + if (leading_stylebox.stylebox.is_valid()) { + leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading)); + } + + Ref<StyleBox> stylebox; + if (Object::cast_to<EditorResourcePicker>(p_editor)) { + stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource(); + } + + LeadingStylebox leader; + leader.pinned = true; + leader.item_name = p_item_name; + leader.stylebox = stylebox; + leader.ref_stylebox = (stylebox.is_valid() ? stylebox->duplicate() : RES()); + + leading_stylebox = leader; + if (leading_stylebox.stylebox.is_valid()) { + leading_stylebox.stylebox->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading)); + } + + _update_type_items(); +} + +void ThemeTypeEditor::_unpin_leading_stylebox() { + if (leading_stylebox.stylebox.is_valid()) { + leading_stylebox.stylebox->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_stylebox_from_leading)); + } + + LeadingStylebox leader; + leader.pinned = false; + leading_stylebox = leader; + + _update_type_items(); +} + +void ThemeTypeEditor::_update_stylebox_from_leading() { + if (!leading_stylebox.pinned || leading_stylebox.stylebox.is_null()) { + return; + } + + // Prevent changes from immediatelly being reported while the operation is still ongoing. + edited_theme->_freeze_change_propagation(); + + List<StringName> names; + edited_theme->get_stylebox_list(edited_type, &names); + List<Ref<StyleBox>> styleboxes; + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + if (E->get() == leading_stylebox.item_name) { + continue; + } + + Ref<StyleBox> sb = edited_theme->get_stylebox(E->get(), edited_type); + if (sb->get_class() == leading_stylebox.stylebox->get_class()) { + styleboxes.push_back(sb); + } + } + + List<PropertyInfo> props; + leading_stylebox.stylebox->get_property_list(&props); + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + + Variant value = leading_stylebox.stylebox->get(E->get().name); + Variant ref_value = leading_stylebox.ref_stylebox->get(E->get().name); + if (value == ref_value) { + continue; + } + + for (List<Ref<StyleBox>>::Element *F = styleboxes.front(); F; F = F->next()) { + Ref<StyleBox> sb = F->get(); + sb->set(E->get().name, value); + } + } + + leading_stylebox.ref_stylebox = leading_stylebox.stylebox->duplicate(); + + // Allow changes to be reported now that the operation is finished. + edited_theme->_unfreeze_and_propagate_changes(); +} + +void ThemeTypeEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + add_type_button->set_icon(get_theme_icon("Add", "EditorIcons")); + + data_type_tabs->set_tab_icon(0, get_theme_icon("Color", "EditorIcons")); + data_type_tabs->set_tab_icon(1, get_theme_icon("MemberConstant", "EditorIcons")); + data_type_tabs->set_tab_icon(2, get_theme_icon("Font", "EditorIcons")); + data_type_tabs->set_tab_icon(3, get_theme_icon("FontSize", "EditorIcons")); + data_type_tabs->set_tab_icon(4, get_theme_icon("ImageTexture", "EditorIcons")); + data_type_tabs->set_tab_icon(5, get_theme_icon("StyleBoxFlat", "EditorIcons")); + + data_type_tabs->add_theme_style_override("tab_selected", get_theme_stylebox("tab_selected_odd", "TabContainer")); + data_type_tabs->add_theme_style_override("panel", get_theme_stylebox("panel_odd", "TabContainer")); + + _update_add_type_options(); + } break; + } +} + +void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) { + if (edited_theme.is_valid()) { + edited_theme->disconnect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced)); + } + + edited_theme = p_theme; + edited_theme->connect("changed", callable_mp(this, &ThemeTypeEditor::_update_type_list_debounced)); + _update_type_list(); +} + +void ThemeTypeEditor::select_type(String p_type_name) { + edited_type = p_type_name; + bool type_exists = false; + + for (int i = 0; i < theme_type_list->get_item_count(); i++) { + String type_name = theme_type_list->get_item_text(i); + if (type_name == edited_type) { + theme_type_list->select(i); + type_exists = true; + break; + } + } + + if (type_exists) { + _update_type_items(); + } else { + edited_theme->add_icon_type(edited_type); + edited_theme->add_stylebox_type(edited_type); + edited_theme->add_font_type(edited_type); + edited_theme->add_font_size_type(edited_type); + edited_theme->add_color_type(edited_type); + edited_theme->add_constant_type(edited_type); + + _update_type_list(); + } +} + +ThemeTypeEditor::ThemeTypeEditor() { + VBoxContainer *main_vb = memnew(VBoxContainer); + add_child(main_vb); + + HBoxContainer *type_list_hb = memnew(HBoxContainer); + main_vb->add_child(type_list_hb); + + Label *type_list_label = memnew(Label); + type_list_label->set_text(TTR("Type:")); + type_list_hb->add_child(type_list_label); + + theme_type_list = memnew(OptionButton); + theme_type_list->set_h_size_flags(SIZE_EXPAND_FILL); + type_list_hb->add_child(theme_type_list); + theme_type_list->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_list_type_selected)); + + add_type_button = memnew(Button); + add_type_button->set_tooltip(TTR("Add Type")); + type_list_hb->add_child(add_type_button); + add_type_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_type_button_cbk)); + + add_type_dialog = memnew(ConfirmationDialog); + add_type_dialog->set_title(TTR("Add Item Type")); + type_list_hb->add_child(add_type_dialog); + add_type_dialog->connect("confirmed", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_confirmed)); + + VBoxContainer *add_type_vb = memnew(VBoxContainer); + add_type_dialog->add_child(add_type_vb); + + Label *add_type_filter_label = memnew(Label); + add_type_filter_label->set_text(TTR("Name:")); + add_type_vb->add_child(add_type_filter_label); + add_type_filter = memnew(LineEdit); + add_type_vb->add_child(add_type_filter); + add_type_filter->connect("text_changed", callable_mp(this, &ThemeTypeEditor::_add_type_filter_cbk)); + add_type_filter->connect("text_submitted", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_entered)); + Label *add_type_options_label = memnew(Label); + add_type_options_label->set_text(TTR("Node Types:")); + add_type_vb->add_child(add_type_options_label); + add_type_options = memnew(ItemList); + add_type_options->set_v_size_flags(SIZE_EXPAND_FILL); + add_type_vb->add_child(add_type_options); + add_type_options->connect("item_selected", callable_mp(this, &ThemeTypeEditor::_add_type_options_cbk)); + add_type_options->connect("item_activated", callable_mp(this, &ThemeTypeEditor::_add_type_dialog_activated)); + + HBoxContainer *type_controls = memnew(HBoxContainer); + main_vb->add_child(type_controls); + + show_default_items_button = memnew(CheckButton); + show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL); + show_default_items_button->set_text(TTR("Show Default")); + show_default_items_button->set_tooltip(TTR("Show default type items alongside items that have been overridden.")); + show_default_items_button->set_pressed(true); + type_controls->add_child(show_default_items_button); + show_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_update_type_items)); + + Button *add_default_items_button = memnew(Button); + add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL); + add_default_items_button->set_text(TTR("Override All")); + add_default_items_button->set_tooltip(TTR("Override all default type items.")); + type_controls->add_child(add_default_items_button); + add_default_items_button->connect("pressed", callable_mp(this, &ThemeTypeEditor::_add_default_type_items)); + + data_type_tabs = memnew(TabContainer); + main_vb->add_child(data_type_tabs); + data_type_tabs->set_v_size_flags(SIZE_EXPAND_FILL); + data_type_tabs->set_use_hidden_tabs_for_min_size(true); + + color_items_list = _create_item_list(Theme::DATA_TYPE_COLOR); + constant_items_list = _create_item_list(Theme::DATA_TYPE_CONSTANT); + font_items_list = _create_item_list(Theme::DATA_TYPE_FONT); + font_size_items_list = _create_item_list(Theme::DATA_TYPE_FONT_SIZE); + icon_items_list = _create_item_list(Theme::DATA_TYPE_ICON); + stylebox_items_list = _create_item_list(Theme::DATA_TYPE_STYLEBOX); + + update_debounce_timer = memnew(Timer); + update_debounce_timer->set_one_shot(true); + update_debounce_timer->set_wait_time(0.5); + update_debounce_timer->connect("timeout", callable_mp(this, &ThemeTypeEditor::_update_type_list)); + add_child(update_debounce_timer); +} + void ThemeEditor::edit(const Ref<Theme> &p_theme) { + if (theme == p_theme) { + return; + } + theme = p_theme; + theme_type_editor->set_edited_theme(p_theme); theme_edit_dialog->set_edited_theme(p_theme); - main_panel->set_theme(p_theme); - main_container->set_theme(p_theme); -} -void ThemeEditor::_propagate_redraw(Control *p_at) { - p_at->notification(NOTIFICATION_THEME_CHANGED); - p_at->minimum_size_changed(); - p_at->update(); - for (int i = 0; i < p_at->get_child_count(); i++) { - Control *a = Object::cast_to<Control>(p_at->get_child(i)); - if (a) { - _propagate_redraw(a); + for (int i = 0; i < preview_tabs_content->get_child_count(); i++) { + ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(i)); + if (!preview_tab) { + continue; } + + preview_tab->set_preview_theme(p_theme); } + + theme_name->set_text(TTR("Theme") + ": " + theme->get_path().get_file()); } -void ThemeEditor::_refresh_interval() { - _propagate_redraw(main_panel); - _propagate_redraw(main_container); +Ref<Theme> ThemeEditor::get_edited_theme() { + return theme; +} + +void ThemeEditor::_theme_save_button_cbk(bool p_save_as) { + ERR_FAIL_COND_MSG(theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing."); + + if (p_save_as) { + EditorNode::get_singleton()->save_resource_as(theme); + } else { + EditorNode::get_singleton()->save_resource(theme); + } } void ThemeEditor::_theme_edit_button_cbk() { theme_edit_dialog->popup_centered(Size2(850, 760) * EDSCALE); } +void ThemeEditor::_add_preview_button_cbk() { + preview_scene_dialog->popup_file_dialog(); +} + +void ThemeEditor::_preview_scene_dialog_cbk(const String &p_path) { + SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview); + if (!preview_tab->set_preview_scene(p_path)) { + return; + } + + _add_preview_tab(preview_tab, p_path.get_file(), get_theme_icon("PackedScene", "EditorIcons")); + preview_tab->connect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid), varray(preview_tab)); + preview_tab->connect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab), varray(preview_tab)); +} + +void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture2D> &p_icon) { + p_preview_tab->set_preview_theme(theme); + + preview_tabs->add_tab(p_preview_name, p_icon); + preview_tabs_content->add_child(p_preview_tab); + preview_tabs->set_tab_right_button(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("close", "Tabs")); + p_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked)); + + preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1); +} + +void ThemeEditor::_change_preview_tab(int p_tab) { + ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to open a preview tab that doesn't exist."); + + for (int i = 0; i < preview_tabs_content->get_child_count(); i++) { + Control *c = Object::cast_to<Control>(preview_tabs_content->get_child(i)); + if (!c) { + continue; + } + + c->set_visible(i == p_tab); + } +} + +void ThemeEditor::_remove_preview_tab(int p_tab) { + ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to remove a preview tab that doesn't exist."); + + ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(p_tab)); + ERR_FAIL_COND_MSG(Object::cast_to<DefaultThemeEditorPreview>(preview_tab), "Attemptying to remove the default preview tab."); + + if (preview_tab) { + preview_tab->disconnect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked)); + if (preview_tab->is_connected("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid))) { + preview_tab->disconnect("scene_invalidated", callable_mp(this, &ThemeEditor::_remove_preview_tab_invalid)); + } + if (preview_tab->is_connected("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab))) { + preview_tab->disconnect("scene_reloaded", callable_mp(this, &ThemeEditor::_update_preview_tab)); + } + + preview_tabs_content->remove_child(preview_tab); + preview_tabs->remove_tab(p_tab); + _change_preview_tab(preview_tabs->get_current_tab()); + } +} + +void ThemeEditor::_remove_preview_tab_invalid(Node *p_tab_control) { + int tab_index = p_tab_control->get_index(); + _remove_preview_tab(tab_index); +} + +void ThemeEditor::_update_preview_tab(Node *p_tab_control) { + if (!Object::cast_to<SceneThemeEditorPreview>(p_tab_control)) { + return; + } + + int tab_index = p_tab_control->get_index(); + SceneThemeEditorPreview *scene_preview = Object::cast_to<SceneThemeEditorPreview>(p_tab_control); + preview_tabs->set_tab_title(tab_index, scene_preview->get_preview_scene_path().get_file()); +} + +void ThemeEditor::_preview_control_picked(String p_class_name) { + theme_type_editor->select_type(p_class_name); +} + void ThemeEditor::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_PROCESS: { - time_left -= get_process_delta_time(); - if (time_left < 0) { - time_left = 1.5; - _refresh_interval(); - } + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + preview_tabs->add_theme_style_override("tab_selected", get_theme_stylebox("ThemeEditorPreviewFG", "EditorStyles")); + preview_tabs->add_theme_style_override("tab_unselected", get_theme_stylebox("ThemeEditorPreviewBG", "EditorStyles")); + preview_tabs_content->add_theme_style_override("panel", get_theme_stylebox("panel_odd", "TabContainer")); + + add_preview_button->set_icon(get_theme_icon("Add", "EditorIcons")); } break; } } -void ThemeEditor::_bind_methods() { -} - ThemeEditor::ThemeEditor() { HBoxContainer *top_menu = memnew(HBoxContainer); add_child(top_menu); - top_menu->add_child(memnew(Label(TTR("Preview:")))); + theme_name = memnew(Label); + theme_name->set_text(TTR("Theme") + ": "); + top_menu->add_child(theme_name); + top_menu->add_spacer(false); - theme_edit_button = memnew(Button); - theme_edit_button->set_text(TTR("Manage Items")); + Button *theme_save_button = memnew(Button); + theme_save_button->set_text(TTR("Save")); + theme_save_button->set_flat(true); + theme_save_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_save_button_cbk), varray(false)); + top_menu->add_child(theme_save_button); + + Button *theme_save_as_button = memnew(Button); + theme_save_as_button->set_text(TTR("Save As...")); + theme_save_as_button->set_flat(true); + theme_save_as_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_save_button_cbk), varray(true)); + top_menu->add_child(theme_save_as_button); + + top_menu->add_child(memnew(VSeparator)); + + Button *theme_edit_button = memnew(Button); + theme_edit_button->set_text(TTR("Manage Items...")); theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items.")); theme_edit_button->set_flat(true); theme_edit_button->connect("pressed", callable_mp(this, &ThemeEditor::_theme_edit_button_cbk)); top_menu->add_child(theme_edit_button); - ScrollContainer *scroll = memnew(ScrollContainer); - add_child(scroll); - scroll->set_enable_v_scroll(true); - scroll->set_enable_h_scroll(true); - scroll->set_v_size_flags(SIZE_EXPAND_FILL); - - MarginContainer *root_container = memnew(MarginContainer); - scroll->add_child(root_container); - root_container->set_theme(Theme::get_default()); - root_container->set_clip_contents(true); - root_container->set_custom_minimum_size(Size2(700, 0) * EDSCALE); - root_container->set_v_size_flags(SIZE_EXPAND_FILL); - root_container->set_h_size_flags(SIZE_EXPAND_FILL); - - //// Preview Controls //// - - main_panel = memnew(Panel); - root_container->add_child(main_panel); - - main_container = memnew(MarginContainer); - root_container->add_child(main_container); - main_container->add_theme_constant_override("margin_right", 4 * EDSCALE); - main_container->add_theme_constant_override("margin_top", 4 * EDSCALE); - main_container->add_theme_constant_override("margin_left", 4 * EDSCALE); - main_container->add_theme_constant_override("margin_bottom", 4 * EDSCALE); - - HBoxContainer *main_hb = memnew(HBoxContainer); - main_container->add_child(main_hb); - - VBoxContainer *first_vb = memnew(VBoxContainer); - main_hb->add_child(first_vb); - first_vb->set_h_size_flags(SIZE_EXPAND_FILL); - first_vb->add_theme_constant_override("separation", 10 * EDSCALE); - - first_vb->add_child(memnew(Label("Label"))); - - first_vb->add_child(memnew(Button("Button"))); - Button *bt = memnew(Button); - bt->set_text(TTR("Toggle Button")); - bt->set_toggle_mode(true); - bt->set_pressed(true); - first_vb->add_child(bt); - bt = memnew(Button); - bt->set_text(TTR("Disabled Button")); - bt->set_disabled(true); - first_vb->add_child(bt); - Button *tb = memnew(Button); - tb->set_flat(true); - tb->set_text("Button"); - first_vb->add_child(tb); - - CheckButton *cb = memnew(CheckButton); - cb->set_text("CheckButton"); - first_vb->add_child(cb); - CheckBox *cbx = memnew(CheckBox); - cbx->set_text("CheckBox"); - first_vb->add_child(cbx); - - MenuButton *test_menu_button = memnew(MenuButton); - test_menu_button->set_text("MenuButton"); - test_menu_button->get_popup()->add_item(TTR("Item")); - test_menu_button->get_popup()->add_item(TTR("Disabled Item")); - test_menu_button->get_popup()->set_item_disabled(1, true); - test_menu_button->get_popup()->add_separator(); - test_menu_button->get_popup()->add_check_item(TTR("Check Item")); - test_menu_button->get_popup()->add_check_item(TTR("Checked Item")); - test_menu_button->get_popup()->set_item_checked(4, true); - test_menu_button->get_popup()->add_separator(); - test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item")); - test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item")); - test_menu_button->get_popup()->set_item_checked(7, true); - test_menu_button->get_popup()->add_separator(TTR("Named Sep.")); - - PopupMenu *test_submenu = memnew(PopupMenu); - test_menu_button->get_popup()->add_child(test_submenu); - test_submenu->set_name("submenu"); - test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu"); - test_submenu->add_item(TTR("Subitem 1")); - test_submenu->add_item(TTR("Subitem 2")); - first_vb->add_child(test_menu_button); - - OptionButton *test_option_button = memnew(OptionButton); - test_option_button->add_item("OptionButton"); - test_option_button->add_separator(); - test_option_button->add_item(TTR("Has")); - test_option_button->add_item(TTR("Many")); - test_option_button->add_item(TTR("Options")); - first_vb->add_child(test_option_button); - first_vb->add_child(memnew(ColorPickerButton)); - - VBoxContainer *second_vb = memnew(VBoxContainer); - second_vb->set_h_size_flags(SIZE_EXPAND_FILL); - main_hb->add_child(second_vb); - second_vb->add_theme_constant_override("separation", 10 * EDSCALE); - LineEdit *le = memnew(LineEdit); - le->set_text("LineEdit"); - second_vb->add_child(le); - le = memnew(LineEdit); - le->set_text(TTR("Disabled LineEdit")); - le->set_editable(false); - second_vb->add_child(le); - TextEdit *te = memnew(TextEdit); - te->set_text("TextEdit"); - te->set_custom_minimum_size(Size2(0, 100) * EDSCALE); - second_vb->add_child(te); - second_vb->add_child(memnew(SpinBox)); - - HBoxContainer *vhb = memnew(HBoxContainer); - second_vb->add_child(vhb); - vhb->set_custom_minimum_size(Size2(0, 100) * EDSCALE); - vhb->add_child(memnew(VSlider)); - VScrollBar *vsb = memnew(VScrollBar); - vsb->set_page(25); - vhb->add_child(vsb); - vhb->add_child(memnew(VSeparator)); - VBoxContainer *hvb = memnew(VBoxContainer); - vhb->add_child(hvb); - hvb->set_alignment(ALIGN_CENTER); - hvb->set_h_size_flags(SIZE_EXPAND_FILL); - hvb->add_child(memnew(HSlider)); - HScrollBar *hsb = memnew(HScrollBar); - hsb->set_page(25); - hvb->add_child(hsb); - HSlider *hs = memnew(HSlider); - hs->set_editable(false); - hvb->add_child(hs); - hvb->add_child(memnew(HSeparator)); - ProgressBar *pb = memnew(ProgressBar); - pb->set_value(50); - hvb->add_child(pb); - - VBoxContainer *third_vb = memnew(VBoxContainer); - third_vb->set_h_size_flags(SIZE_EXPAND_FILL); - third_vb->add_theme_constant_override("separation", 10 * EDSCALE); - main_hb->add_child(third_vb); - - TabContainer *tc = memnew(TabContainer); - third_vb->add_child(tc); - tc->set_custom_minimum_size(Size2(0, 135) * EDSCALE); - Control *tcc = memnew(Control); - tcc->set_name(TTR("Tab 1")); - tc->add_child(tcc); - tcc = memnew(Control); - tcc->set_name(TTR("Tab 2")); - tc->add_child(tcc); - tcc = memnew(Control); - tcc->set_name(TTR("Tab 3")); - tc->add_child(tcc); - tc->set_tab_disabled(2, true); - - Tree *test_tree = memnew(Tree); - third_vb->add_child(test_tree); - test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE); - test_tree->add_theme_constant_override("draw_relationship_lines", 1); - - TreeItem *item = test_tree->create_item(); - item->set_text(0, "Tree"); - item = test_tree->create_item(test_tree->get_root()); - item->set_text(0, "Item"); - item = test_tree->create_item(test_tree->get_root()); - item->set_editable(0, true); - item->set_text(0, TTR("Editable Item")); - TreeItem *sub_tree = test_tree->create_item(test_tree->get_root()); - sub_tree->set_text(0, TTR("Subtree")); - item = test_tree->create_item(sub_tree); - item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); - item->set_editable(0, true); - item->set_text(0, "Check Item"); - item = test_tree->create_item(sub_tree); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0, true); - item->set_range_config(0, 0, 20, 0.1); - item->set_range(0, 2); - item = test_tree->create_item(sub_tree); - item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); - item->set_editable(0, true); - item->set_text(0, TTR("Has,Many,Options")); - item->set_range(0, 2); - - main_hb->add_theme_constant_override("separation", 20 * EDSCALE); - theme_edit_dialog = memnew(ThemeItemEditorDialog); theme_edit_dialog->hide(); - add_child(theme_edit_dialog); + top_menu->add_child(theme_edit_dialog); + + HSplitContainer *main_hs = memnew(HSplitContainer); + main_hs->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(main_hs); + + VBoxContainer *preview_tabs_vb = memnew(VBoxContainer); + preview_tabs_vb->set_h_size_flags(SIZE_EXPAND_FILL); + preview_tabs_vb->set_custom_minimum_size(Size2(520, 0) * EDSCALE); + preview_tabs_vb->add_theme_constant_override("separation", 2 * EDSCALE); + main_hs->add_child(preview_tabs_vb); + HBoxContainer *preview_tabbar_hb = memnew(HBoxContainer); + preview_tabs_vb->add_child(preview_tabbar_hb); + preview_tabs_content = memnew(PanelContainer); + preview_tabs_content->set_v_size_flags(SIZE_EXPAND_FILL); + preview_tabs_content->set_draw_behind_parent(true); + preview_tabs_vb->add_child(preview_tabs_content); + + preview_tabs = memnew(Tabs); + preview_tabs->set_tab_align(Tabs::ALIGN_LEFT); + preview_tabs->set_h_size_flags(SIZE_EXPAND_FILL); + preview_tabbar_hb->add_child(preview_tabs); + preview_tabs->connect("tab_changed", callable_mp(this, &ThemeEditor::_change_preview_tab)); + preview_tabs->connect("right_button_pressed", callable_mp(this, &ThemeEditor::_remove_preview_tab)); + + HBoxContainer *add_preview_button_hb = memnew(HBoxContainer); + preview_tabbar_hb->add_child(add_preview_button_hb); + add_preview_button = memnew(Button); + add_preview_button->set_text(TTR("Add Preview")); + add_preview_button_hb->add_child(add_preview_button); + add_preview_button->connect("pressed", callable_mp(this, &ThemeEditor::_add_preview_button_cbk)); + + DefaultThemeEditorPreview *default_preview_tab = memnew(DefaultThemeEditorPreview); + preview_tabs_content->add_child(default_preview_tab); + default_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked)); + preview_tabs->add_tab(TTR("Default Preview")); + + preview_scene_dialog = memnew(EditorFileDialog); + preview_scene_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE); + preview_scene_dialog->set_title(TTR("Select UI Scene:")); + List<String> ext; + ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext); + for (List<String>::Element *E = ext.front(); E; E = E->next()) { + preview_scene_dialog->add_filter("*." + E->get() + "; Scene"); + } + main_hs->add_child(preview_scene_dialog); + preview_scene_dialog->connect("file_selected", callable_mp(this, &ThemeEditor::_preview_scene_dialog_cbk)); + + theme_type_editor = memnew(ThemeTypeEditor); + main_hs->add_child(theme_type_editor); + theme_type_editor->set_custom_minimum_size(Size2(360, 0) * EDSCALE); } void ThemeEditorPlugin::edit(Object *p_node) { if (Object::cast_to<Theme>(p_node)) { theme_editor->edit(Object::cast_to<Theme>(p_node)); + } else if (Object::cast_to<Font>(p_node) || Object::cast_to<StyleBox>(p_node) || Object::cast_to<Texture2D>(p_node)) { + // Do nothing, keep editing the existing theme. } else { theme_editor->edit(Ref<Theme>()); } } bool ThemeEditorPlugin::handles(Object *p_node) const { - return p_node->is_class("Theme"); + if (Object::cast_to<Theme>(p_node)) { + return true; + } + + Ref<Theme> edited_theme = theme_editor->get_edited_theme(); + if (edited_theme.is_null()) { + return false; + } + + // If we are editing a theme already and this particular resource happens to belong to it, + // then we just keep editing it, despite not being able to directly handle it. + // This only goes one layer deep, but if required this can be extended to support, say, FontData inside of Font. + bool belongs_to_theme = false; + + if (Object::cast_to<Font>(p_node)) { + Ref<Font> font_item = Object::cast_to<Font>(p_node); + List<StringName> types; + List<StringName> names; + + edited_theme->get_font_type_list(&types); + for (List<StringName>::Element *E = types.front(); E; E = E->next()) { + names.clear(); + edited_theme->get_font_list(E->get(), &names); + + for (List<StringName>::Element *F = names.front(); F; F = F->next()) { + if (font_item == edited_theme->get_font(F->get(), E->get())) { + belongs_to_theme = true; + break; + } + } + } + } else if (Object::cast_to<StyleBox>(p_node)) { + Ref<StyleBox> stylebox_item = Object::cast_to<StyleBox>(p_node); + List<StringName> types; + List<StringName> names; + + edited_theme->get_stylebox_type_list(&types); + for (List<StringName>::Element *E = types.front(); E; E = E->next()) { + names.clear(); + edited_theme->get_stylebox_list(E->get(), &names); + + for (List<StringName>::Element *F = names.front(); F; F = F->next()) { + if (stylebox_item == edited_theme->get_stylebox(F->get(), E->get())) { + belongs_to_theme = true; + break; + } + } + } + } else if (Object::cast_to<Texture2D>(p_node)) { + Ref<Texture2D> icon_item = Object::cast_to<Texture2D>(p_node); + List<StringName> types; + List<StringName> names; + + edited_theme->get_icon_type_list(&types); + for (List<StringName>::Element *E = types.front(); E; E = E->next()) { + names.clear(); + edited_theme->get_icon_list(E->get(), &names); + + for (List<StringName>::Element *F = names.front(); F; F = F->next()) { + if (icon_item == edited_theme->get_icon(F->get(), E->get())) { + belongs_to_theme = true; + break; + } + } + } + } + + return belongs_to_theme; } void ThemeEditorPlugin::make_visible(bool p_visible) { if (p_visible) { - theme_editor->set_process(true); button->show(); editor->make_bottom_panel_item_visible(theme_editor); } else { - theme_editor->set_process(false); if (theme_editor->is_visible_in_tree()) { editor->hide_bottom_panel(); } diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index c42ebf1a19..cdedbbec8d 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -31,13 +31,13 @@ #ifndef THEME_EDITOR_PLUGIN_H #define THEME_EDITOR_PLUGIN_H -#include "scene/gui/check_box.h" -#include "scene/gui/file_dialog.h" #include "scene/gui/margin_container.h" #include "scene/gui/option_button.h" #include "scene/gui/scroll_container.h" +#include "scene/gui/tabs.h" #include "scene/gui/texture_rect.h" #include "scene/resources/theme.h" +#include "theme_editor_preview.h" #include "editor/editor_node.h" @@ -263,30 +263,123 @@ public: ThemeItemEditorDialog(); }; +class ThemeTypeEditor : public MarginContainer { + GDCLASS(ThemeTypeEditor, MarginContainer); + + Ref<Theme> edited_theme; + String edited_type; + bool updating = false; + + struct LeadingStylebox { + bool pinned = false; + StringName item_name; + Ref<StyleBox> stylebox; + Ref<StyleBox> ref_stylebox; + }; + + LeadingStylebox leading_stylebox; + + OptionButton *theme_type_list; + Button *add_type_button; + ConfirmationDialog *add_type_dialog; + LineEdit *add_type_filter; + ItemList *add_type_options; + + CheckButton *show_default_items_button; + + TabContainer *data_type_tabs; + VBoxContainer *color_items_list; + VBoxContainer *constant_items_list; + VBoxContainer *font_items_list; + VBoxContainer *font_size_items_list; + VBoxContainer *icon_items_list; + VBoxContainer *stylebox_items_list; + + Vector<Control *> focusables; + Timer *update_debounce_timer; + + VBoxContainer *_create_item_list(Theme::DataType p_data_type); + void _update_type_list(); + void _update_type_list_debounced(); + void _update_add_type_options(const String &p_filter = ""); + OrderedHashMap<StringName, bool> _get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default); + HBoxContainer *_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable); + void _add_focusable(Control *p_control); + void _update_type_items(); + + void _list_type_selected(int p_index); + void _select_type(String p_type_name); + void _add_type_button_cbk(); + void _add_type_filter_cbk(const String &p_value); + void _add_type_options_cbk(int p_index); + void _add_type_dialog_confirmed(); + void _add_type_dialog_entered(const String &p_value); + void _add_type_dialog_activated(int p_index); + void _add_default_type_items(); + + void _item_add_cbk(int p_data_type, Control *p_control); + void _item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control); + void _item_override_cbk(int p_data_type, String p_item_name); + void _item_remove_cbk(int p_data_type, String p_item_name); + void _item_rename_cbk(int p_data_type, String p_item_name, Control *p_control); + void _item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control); + void _item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control); + void _item_rename_canceled(int p_data_type, String p_item_name, Control *p_control); + + void _color_item_changed(Color p_value, String p_item_name); + void _constant_item_changed(float p_value, String p_item_name); + void _font_size_item_changed(float p_value, String p_item_name); + void _edit_resource_item(RES p_resource); + void _font_item_changed(Ref<Font> p_value, String p_item_name); + void _icon_item_changed(Ref<Texture2D> p_value, String p_item_name); + void _stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name); + void _pin_leading_stylebox(Control *p_editor, String p_item_name); + void _unpin_leading_stylebox(); + void _update_stylebox_from_leading(); + +protected: + void _notification(int p_what); + +public: + void set_edited_theme(const Ref<Theme> &p_theme); + void select_type(String p_type_name); + + ThemeTypeEditor(); +}; + class ThemeEditor : public VBoxContainer { GDCLASS(ThemeEditor, VBoxContainer); Ref<Theme> theme; - double time_left = 0; + Tabs *preview_tabs; + PanelContainer *preview_tabs_content; + Button *add_preview_button; + EditorFileDialog *preview_scene_dialog; - Button *theme_edit_button; - ThemeItemEditorDialog *theme_edit_dialog; + ThemeTypeEditor *theme_type_editor; - Panel *main_panel; - MarginContainer *main_container; - Tree *test_tree; + Label *theme_name; + ThemeItemEditorDialog *theme_edit_dialog; + void _theme_save_button_cbk(bool p_save_as); void _theme_edit_button_cbk(); - void _propagate_redraw(Control *p_at); - void _refresh_interval(); + + void _add_preview_button_cbk(); + void _preview_scene_dialog_cbk(const String &p_path); + void _add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture2D> &p_icon); + void _change_preview_tab(int p_tab); + void _remove_preview_tab(int p_tab); + void _remove_preview_tab_invalid(Node *p_tab_control); + void _update_preview_tab(Node *p_tab_control); + void _preview_control_picked(String p_class_name); protected: void _notification(int p_what); - static void _bind_methods(); public: void edit(const Ref<Theme> &p_theme); + Ref<Theme> get_edited_theme(); ThemeEditor(); }; diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp new file mode 100644 index 0000000000..0b02150444 --- /dev/null +++ b/editor/plugins/theme_editor_preview.cpp @@ -0,0 +1,464 @@ +/*************************************************************************/ +/* theme_editor_preview.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "theme_editor_preview.h" + +#include "core/input/input.h" +#include "core/math/math_funcs.h" +#include "scene/resources/packed_scene.h" + +#include "editor/editor_scale.h" + +void ThemeEditorPreview::set_preview_theme(const Ref<Theme> &p_theme) { + preview_content->set_theme(p_theme); +} + +void ThemeEditorPreview::add_preview_overlay(Control *p_overlay) { + preview_overlay->add_child(p_overlay); + p_overlay->hide(); +} + +void ThemeEditorPreview::_propagate_redraw(Control *p_at) { + p_at->notification(NOTIFICATION_THEME_CHANGED); + p_at->minimum_size_changed(); + p_at->update(); + for (int i = 0; i < p_at->get_child_count(); i++) { + Control *a = Object::cast_to<Control>(p_at->get_child(i)); + if (a) { + _propagate_redraw(a); + } + } +} + +void ThemeEditorPreview::_refresh_interval() { + // In case the project settings have changed. + preview_bg->set_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); + + _propagate_redraw(preview_bg); + _propagate_redraw(preview_content); +} + +void ThemeEditorPreview::_preview_visibility_changed() { + set_process(is_visible()); +} + +void ThemeEditorPreview::_picker_button_cbk() { + picker_overlay->set_visible(picker_button->is_pressed()); +} + +Control *ThemeEditorPreview::_find_hovered_control(Control *p_parent, Vector2 p_mouse_position) { + Control *found = nullptr; + + for (int i = 0; i < p_parent->get_child_count(); i++) { + Control *cc = Object::cast_to<Control>(p_parent->get_child(i)); + if (!cc || !cc->is_visible()) { + continue; + } + + Rect2 crect = cc->get_rect(); + if (crect.has_point(p_mouse_position)) { + // Check if there is a child control under mouse. + if (cc->get_child_count() > 0) { + found = _find_hovered_control(cc, p_mouse_position - cc->get_position()); + } + + // If there are no applicable children, use the control itself. + if (!found) { + found = cc; + } + break; + } + } + + return found; +} + +void ThemeEditorPreview::_draw_picker_overlay() { + if (!picker_button->is_pressed()) { + return; + } + + picker_overlay->draw_rect(Rect2(Vector2(0.0, 0.0), picker_overlay->get_size()), get_theme_color("preview_picker_overlay_color", "ThemeEditor")); + if (hovered_control) { + Rect2 highlight_rect = hovered_control->get_global_rect(); + highlight_rect.position = picker_overlay->get_global_transform().affine_inverse().xform(highlight_rect.position); + + picker_overlay->draw_style_box(get_theme_stylebox("preview_picker_overlay", "ThemeEditor"), highlight_rect); + } +} + +void ThemeEditorPreview::_gui_input_picker_overlay(const Ref<InputEvent> &p_event) { + if (!picker_button->is_pressed()) { + return; + } + + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (hovered_control) { + StringName theme_type = hovered_control->get_theme_custom_type(); + if (theme_type == StringName()) { + theme_type = hovered_control->get_class_name(); + } + + emit_signal("control_picked", theme_type); + picker_button->set_pressed(false); + picker_overlay->set_visible(false); + } + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid()) { + Vector2 mp = preview_content->get_local_mouse_position(); + hovered_control = _find_hovered_control(preview_content, mp); + picker_overlay->update(); + } +} + +void ThemeEditorPreview::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (is_visible_in_tree()) { + set_process(true); + } + + connect("visibility_changed", callable_mp(this, &ThemeEditorPreview::_preview_visibility_changed)); + [[fallthrough]]; + } + case NOTIFICATION_THEME_CHANGED: { + picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons")); + } break; + case NOTIFICATION_PROCESS: { + time_left -= get_process_delta_time(); + if (time_left < 0) { + time_left = 1.5; + _refresh_interval(); + } + } break; + } +} + +void ThemeEditorPreview::_bind_methods() { + ADD_SIGNAL(MethodInfo("control_picked", PropertyInfo(Variant::STRING, "class_name"))); +} + +ThemeEditorPreview::ThemeEditorPreview() { + preview_toolbar = memnew(HBoxContainer); + add_child(preview_toolbar); + + picker_button = memnew(Button); + preview_toolbar->add_child(picker_button); + picker_button->set_flat(true); + picker_button->set_toggle_mode(true); + picker_button->set_tooltip(TTR("Toggle the control picker, allowing to visually select control types for edit.")); + picker_button->connect("pressed", callable_mp(this, &ThemeEditorPreview::_picker_button_cbk)); + + MarginContainer *preview_body = memnew(MarginContainer); + preview_body->set_custom_minimum_size(Size2(480, 0) * EDSCALE); + preview_body->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(preview_body); + + ScrollContainer *preview_container = memnew(ScrollContainer); + preview_container->set_enable_v_scroll(true); + preview_container->set_enable_h_scroll(true); + preview_body->add_child(preview_container); + + MarginContainer *preview_root = memnew(MarginContainer); + preview_container->add_child(preview_root); + preview_root->set_theme(Theme::get_default()); + preview_root->set_clip_contents(true); + preview_root->set_custom_minimum_size(Size2(450, 0) * EDSCALE); + preview_root->set_v_size_flags(SIZE_EXPAND_FILL); + preview_root->set_h_size_flags(SIZE_EXPAND_FILL); + + preview_bg = memnew(ColorRect); + preview_bg->set_anchors_and_offsets_preset(PRESET_WIDE); + preview_bg->set_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); + preview_root->add_child(preview_bg); + + preview_content = memnew(MarginContainer); + preview_root->add_child(preview_content); + preview_content->add_theme_constant_override("margin_right", 4 * EDSCALE); + preview_content->add_theme_constant_override("margin_top", 4 * EDSCALE); + preview_content->add_theme_constant_override("margin_left", 4 * EDSCALE); + preview_content->add_theme_constant_override("margin_bottom", 4 * EDSCALE); + + preview_overlay = memnew(MarginContainer); + preview_overlay->set_mouse_filter(MOUSE_FILTER_IGNORE); + preview_body->add_child(preview_overlay); + + picker_overlay = memnew(Control); + add_preview_overlay(picker_overlay); + picker_overlay->connect("draw", callable_mp(this, &ThemeEditorPreview::_draw_picker_overlay)); + picker_overlay->connect("gui_input", callable_mp(this, &ThemeEditorPreview::_gui_input_picker_overlay)); +} + +DefaultThemeEditorPreview::DefaultThemeEditorPreview() { + Panel *main_panel = memnew(Panel); + preview_content->add_child(main_panel); + + MarginContainer *main_mc = memnew(MarginContainer); + main_mc->add_theme_constant_override("margin_right", 4 * EDSCALE); + main_mc->add_theme_constant_override("margin_top", 4 * EDSCALE); + main_mc->add_theme_constant_override("margin_left", 4 * EDSCALE); + main_mc->add_theme_constant_override("margin_bottom", 4 * EDSCALE); + preview_content->add_child(main_mc); + + HBoxContainer *main_hb = memnew(HBoxContainer); + main_mc->add_child(main_hb); + main_hb->add_theme_constant_override("separation", 20 * EDSCALE); + + VBoxContainer *first_vb = memnew(VBoxContainer); + main_hb->add_child(first_vb); + first_vb->set_h_size_flags(SIZE_EXPAND_FILL); + first_vb->add_theme_constant_override("separation", 10 * EDSCALE); + + first_vb->add_child(memnew(Label("Label"))); + + first_vb->add_child(memnew(Button("Button"))); + Button *bt = memnew(Button); + bt->set_text(TTR("Toggle Button")); + bt->set_toggle_mode(true); + bt->set_pressed(true); + first_vb->add_child(bt); + bt = memnew(Button); + bt->set_text(TTR("Disabled Button")); + bt->set_disabled(true); + first_vb->add_child(bt); + Button *tb = memnew(Button); + tb->set_flat(true); + tb->set_text("Button"); + first_vb->add_child(tb); + + CheckButton *cb = memnew(CheckButton); + cb->set_text("CheckButton"); + first_vb->add_child(cb); + CheckBox *cbx = memnew(CheckBox); + cbx->set_text("CheckBox"); + first_vb->add_child(cbx); + + MenuButton *test_menu_button = memnew(MenuButton); + test_menu_button->set_text("MenuButton"); + test_menu_button->get_popup()->add_item(TTR("Item")); + test_menu_button->get_popup()->add_item(TTR("Disabled Item")); + test_menu_button->get_popup()->set_item_disabled(1, true); + test_menu_button->get_popup()->add_separator(); + test_menu_button->get_popup()->add_check_item(TTR("Check Item")); + test_menu_button->get_popup()->add_check_item(TTR("Checked Item")); + test_menu_button->get_popup()->set_item_checked(4, true); + test_menu_button->get_popup()->add_separator(); + test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item")); + test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item")); + test_menu_button->get_popup()->set_item_checked(7, true); + test_menu_button->get_popup()->add_separator(TTR("Named Separator")); + + PopupMenu *test_submenu = memnew(PopupMenu); + test_menu_button->get_popup()->add_child(test_submenu); + test_submenu->set_name("submenu"); + test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu"); + test_submenu->add_item(TTR("Subitem 1")); + test_submenu->add_item(TTR("Subitem 2")); + first_vb->add_child(test_menu_button); + + OptionButton *test_option_button = memnew(OptionButton); + test_option_button->add_item("OptionButton"); + test_option_button->add_separator(); + test_option_button->add_item(TTR("Has")); + test_option_button->add_item(TTR("Many")); + test_option_button->add_item(TTR("Options")); + first_vb->add_child(test_option_button); + first_vb->add_child(memnew(ColorPickerButton)); + + VBoxContainer *second_vb = memnew(VBoxContainer); + second_vb->set_h_size_flags(SIZE_EXPAND_FILL); + main_hb->add_child(second_vb); + second_vb->add_theme_constant_override("separation", 10 * EDSCALE); + LineEdit *le = memnew(LineEdit); + le->set_text("LineEdit"); + second_vb->add_child(le); + le = memnew(LineEdit); + le->set_text(TTR("Disabled LineEdit")); + le->set_editable(false); + second_vb->add_child(le); + TextEdit *te = memnew(TextEdit); + te->set_text("TextEdit"); + te->set_custom_minimum_size(Size2(0, 100) * EDSCALE); + second_vb->add_child(te); + second_vb->add_child(memnew(SpinBox)); + + HBoxContainer *vhb = memnew(HBoxContainer); + second_vb->add_child(vhb); + vhb->set_custom_minimum_size(Size2(0, 100) * EDSCALE); + vhb->add_child(memnew(VSlider)); + VScrollBar *vsb = memnew(VScrollBar); + vsb->set_page(25); + vhb->add_child(vsb); + vhb->add_child(memnew(VSeparator)); + VBoxContainer *hvb = memnew(VBoxContainer); + vhb->add_child(hvb); + hvb->set_alignment(BoxContainer::ALIGN_CENTER); + hvb->set_h_size_flags(SIZE_EXPAND_FILL); + hvb->add_child(memnew(HSlider)); + HScrollBar *hsb = memnew(HScrollBar); + hsb->set_page(25); + hvb->add_child(hsb); + HSlider *hs = memnew(HSlider); + hs->set_editable(false); + hvb->add_child(hs); + hvb->add_child(memnew(HSeparator)); + ProgressBar *pb = memnew(ProgressBar); + pb->set_value(50); + hvb->add_child(pb); + + VBoxContainer *third_vb = memnew(VBoxContainer); + third_vb->set_h_size_flags(SIZE_EXPAND_FILL); + third_vb->add_theme_constant_override("separation", 10 * EDSCALE); + main_hb->add_child(third_vb); + + TabContainer *tc = memnew(TabContainer); + third_vb->add_child(tc); + tc->set_custom_minimum_size(Size2(0, 135) * EDSCALE); + Control *tcc = memnew(Control); + tcc->set_name(TTR("Tab 1")); + tc->add_child(tcc); + tcc = memnew(Control); + tcc->set_name(TTR("Tab 2")); + tc->add_child(tcc); + tcc = memnew(Control); + tcc->set_name(TTR("Tab 3")); + tc->add_child(tcc); + tc->set_tab_disabled(2, true); + + Tree *test_tree = memnew(Tree); + third_vb->add_child(test_tree); + test_tree->set_custom_minimum_size(Size2(0, 175) * EDSCALE); + + TreeItem *item = test_tree->create_item(); + item->set_text(0, "Tree"); + item = test_tree->create_item(test_tree->get_root()); + item->set_text(0, "Item"); + item = test_tree->create_item(test_tree->get_root()); + item->set_editable(0, true); + item->set_text(0, TTR("Editable Item")); + TreeItem *sub_tree = test_tree->create_item(test_tree->get_root()); + sub_tree->set_text(0, TTR("Subtree")); + item = test_tree->create_item(sub_tree); + item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); + item->set_editable(0, true); + item->set_text(0, "Check Item"); + item = test_tree->create_item(sub_tree); + item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); + item->set_editable(0, true); + item->set_range_config(0, 0, 20, 0.1); + item->set_range(0, 2); + item = test_tree->create_item(sub_tree); + item->set_cell_mode(0, TreeItem::CELL_MODE_RANGE); + item->set_editable(0, true); + item->set_text(0, TTR("Has,Many,Options")); + item->set_range(0, 2); +} + +void SceneThemeEditorPreview::_reload_scene() { + if (loaded_scene.is_null()) { + return; + } + + if (loaded_scene->get_path().is_empty() || !ResourceLoader::exists(loaded_scene->get_path())) { + EditorNode::get_singleton()->show_warning(TTR("Invalid path, the PackedScene resource was probably moved or removed.")); + emit_signal("scene_invalidated"); + return; + } + + for (int i = preview_content->get_child_count() - 1; i >= 0; i--) { + Node *node = preview_content->get_child(i); + node->queue_delete(); + preview_content->remove_child(node); + } + + Node *instance = loaded_scene->instantiate(); + if (!instance || !Object::cast_to<Control>(instance)) { + EditorNode::get_singleton()->show_warning(TTR("Invalid PackedScene resource, must have a Control node at its root.")); + emit_signal("scene_invalidated"); + return; + } + + preview_content->add_child(instance); + emit_signal("scene_reloaded"); +} + +void SceneThemeEditorPreview::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + reload_scene_button->set_icon(get_theme_icon("Reload", "EditorIcons")); + } break; + } +} + +void SceneThemeEditorPreview::_bind_methods() { + ADD_SIGNAL(MethodInfo("scene_invalidated")); + ADD_SIGNAL(MethodInfo("scene_reloaded")); +} + +bool SceneThemeEditorPreview::set_preview_scene(const String &p_path) { + loaded_scene = ResourceLoader::load(p_path); + if (loaded_scene.is_null()) { + EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a PackedScene resource.")); + return false; + } + + Node *instance = loaded_scene->instantiate(); + if (!instance || !Object::cast_to<Control>(instance)) { + EditorNode::get_singleton()->show_warning(TTR("Invalid PackedScene resource, must have a Control node at its root.")); + return false; + } + + preview_content->add_child(instance); + return true; +} + +String SceneThemeEditorPreview::get_preview_scene_path() const { + if (loaded_scene.is_null()) { + return ""; + } + + return loaded_scene->get_path(); +} + +SceneThemeEditorPreview::SceneThemeEditorPreview() { + preview_toolbar->add_child(memnew(VSeparator)); + + reload_scene_button = memnew(Button); + reload_scene_button->set_flat(true); + reload_scene_button->set_tooltip(TTR("Reload the scene to reflect its most actual state.")); + preview_toolbar->add_child(reload_scene_button); + reload_scene_button->connect("pressed", callable_mp(this, &SceneThemeEditorPreview::_reload_scene)); +} diff --git a/editor/plugins/theme_editor_preview.h b/editor/plugins/theme_editor_preview.h new file mode 100644 index 0000000000..efb7e424d4 --- /dev/null +++ b/editor/plugins/theme_editor_preview.h @@ -0,0 +1,118 @@ +/*************************************************************************/ +/* theme_editor_preview.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef THEME_EDITOR_PREVIEW_H +#define THEME_EDITOR_PREVIEW_H + +#include "scene/gui/box_container.h" +#include "scene/gui/check_box.h" +#include "scene/gui/check_button.h" +#include "scene/gui/color_picker.h" +#include "scene/gui/color_rect.h" +#include "scene/gui/label.h" +#include "scene/gui/margin_container.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/panel.h" +#include "scene/gui/progress_bar.h" +#include "scene/gui/scroll_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/spin_box.h" +#include "scene/gui/tab_container.h" +#include "scene/gui/text_edit.h" +#include "scene/gui/tree.h" +#include "scene/resources/theme.h" + +#include "editor/editor_node.h" + +class ThemeEditorPreview : public VBoxContainer { + GDCLASS(ThemeEditorPreview, VBoxContainer); + + ColorRect *preview_bg; + MarginContainer *preview_overlay; + Control *picker_overlay; + Control *hovered_control = nullptr; + + double time_left = 0; + + void _propagate_redraw(Control *p_at); + void _refresh_interval(); + void _preview_visibility_changed(); + + void _picker_button_cbk(); + Control *_find_hovered_control(Control *p_parent, Vector2 p_mouse_position); + + void _draw_picker_overlay(); + void _gui_input_picker_overlay(const Ref<InputEvent> &p_event); + +protected: + HBoxContainer *preview_toolbar; + MarginContainer *preview_content; + Button *picker_button; + + void add_preview_overlay(Control *p_overlay); + + void _notification(int p_what); + static void _bind_methods(); + +public: + void set_preview_theme(const Ref<Theme> &p_theme); + + ThemeEditorPreview(); +}; + +class DefaultThemeEditorPreview : public ThemeEditorPreview { + GDCLASS(DefaultThemeEditorPreview, ThemeEditorPreview); + +public: + DefaultThemeEditorPreview(); +}; + +class SceneThemeEditorPreview : public ThemeEditorPreview { + GDCLASS(SceneThemeEditorPreview, ThemeEditorPreview); + + Ref<PackedScene> loaded_scene; + + Button *reload_scene_button; + + void _reload_scene(); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + bool set_preview_scene(const String &p_path); + String get_preview_scene_path() const; + + SceneThemeEditorPreview(); +}; + +#endif // THEME_EDITOR_PREVIEW_H diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 78f181e321..374a255df3 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -33,7 +33,6 @@ #include "core/input/input.h" #include "core/os/keyboard.h" #include "scene/gui/box_container.h" -#include "scene/gui/center_container.h" #include "scene/gui/label.h" #include "scene/gui/panel.h" #include "scene/gui/texture_rect.h" @@ -44,21 +43,41 @@ void TileAtlasView::_gui_input(const Ref<InputEvent> &p_event) { bool ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL); - Ref<InputEventMouseButton> b = p_event; - if (b.is_valid()) { - if (ctrl && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + drag_type = DRAG_TYPE_NONE; + if (ctrl && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { // Zoom out zoom_widget->set_zoom_by_increments(-2); - emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())); - _update_zoom(zoom_widget->get_zoom(), true); + emit_signal("transform_changed", zoom_widget->get_zoom(), panning); + _update_zoom_and_panning(true); accept_event(); } - if (ctrl && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { + if (ctrl && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { // Zoom in zoom_widget->set_zoom_by_increments(2); - emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())); - _update_zoom(zoom_widget->get_zoom(), true); + emit_signal("transform_changed", zoom_widget->get_zoom(), panning); + _update_zoom_and_panning(true); + accept_event(); + } + + if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE || mb->get_button_index() == MOUSE_BUTTON_RIGHT) { + if (mb->is_pressed()) { + drag_type = DRAG_TYPE_PAN; + } else { + drag_type = DRAG_TYPE_NONE; + } + accept_event(); + } + } + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (drag_type == DRAG_TYPE_PAN) { + panning += mm->get_relative(); + _update_zoom_and_panning(); + emit_signal("transform_changed", zoom_widget->get_zoom(), panning); accept_event(); } } @@ -103,25 +122,27 @@ Size2i TileAtlasView::_compute_alternative_tiles_control_size() { return size; } -void TileAtlasView::_update_zoom(float p_zoom, bool p_zoom_on_mouse_pos, Vector2i p_scroll) { +void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) { + float zoom = zoom_widget->get_zoom(); + // Compute the minimum sizes. Size2i base_tiles_control_size = _compute_base_tiles_control_size(); - base_tiles_root_control->set_custom_minimum_size(Vector2(base_tiles_control_size) * p_zoom); + base_tiles_root_control->set_custom_minimum_size(Vector2(base_tiles_control_size) * zoom); Size2i alternative_tiles_control_size = _compute_alternative_tiles_control_size(); - alternative_tiles_root_control->set_custom_minimum_size(Vector2(alternative_tiles_control_size) * p_zoom); + alternative_tiles_root_control->set_custom_minimum_size(Vector2(alternative_tiles_control_size) * zoom); // Set the texture for the base tiles. Ref<Texture2D> texture = tile_set_atlas_source->get_texture(); // Set the scales. if (base_tiles_control_size.x > 0 && base_tiles_control_size.y > 0) { - base_tiles_drawing_root->set_scale(Vector2(p_zoom, p_zoom)); + base_tiles_drawing_root->set_scale(Vector2(zoom, zoom)); } else { base_tiles_drawing_root->set_scale(Vector2(1, 1)); } if (alternative_tiles_control_size.x > 0 && alternative_tiles_control_size.y > 0) { - alternative_tiles_drawing_root->set_scale(Vector2(p_zoom, p_zoom)); + alternative_tiles_drawing_root->set_scale(Vector2(zoom, zoom)); } else { alternative_tiles_drawing_root->set_scale(Vector2(1, 1)); } @@ -129,64 +150,40 @@ void TileAtlasView::_update_zoom(float p_zoom, bool p_zoom_on_mouse_pos, Vector2 // Update the margin container's margins. const char *constants[] = { "margin_left", "margin_top", "margin_right", "margin_bottom" }; for (int i = 0; i < 4; i++) { - margin_container->add_theme_constant_override(constants[i], margin_container_paddings[i] * p_zoom); + margin_container->add_theme_constant_override(constants[i], margin_container_paddings[i] * zoom); } // Update the backgrounds. background_left->update(); background_right->update(); - if (p_scroll != Vector2i(-1, -1)) { - scroll_container->set_h_scroll(p_scroll.x); - scroll_container->set_v_scroll(p_scroll.y); - } - // Zoom on the position. - if (previous_zoom != p_zoom) { - // TODO: solve this. - // There is however an issue with scrollcainter preventing this, as it seems - // that the scrollbars are not updated right aways after its children update. - - // Compute point on previous area. - /*Vector2 max = Vector2(scroll_container->get_h_scrollbar()->get_max(), scroll_container->get_v_scrollbar()->get_max()); - Vector2 min = Vector2(scroll_container->get_h_scrollbar()->get_min(), scroll_container->get_v_scrollbar()->get_min()); - Vector2 value = Vector2(scroll_container->get_h_scrollbar()->get_value(), scroll_container->get_v_scrollbar()->get_value()); - - Vector2 old_max = max * previous_zoom / p_zoom; - - Vector2 max_pixel_change = max - old_max; - Vector2 ratio = ((value + scroll_container->get_local_mouse_position()) / old_max).max(Vector2()).min(Vector2(1,1)); - Vector2 offset = max_pixel_change * ratio; - - print_line("--- ZOOMED ---"); - print_line(vformat("max: %s", max)); - print_line(vformat("min: %s", min)); - print_line(vformat("value: %s", value)); - print_line(vformat("size: %s", scroll_container->get_size())); - print_line(vformat("mouse_pos: %s", scroll_container->get_local_mouse_position())); - - print_line(vformat("ratio: %s", ratio)); - print_line(vformat("max_pixel_change: %s", max_pixel_change)); - print_line(vformat("offset: %s", offset)); - + if (p_zoom_on_mouse_pos) { + // Offset the panning relative to the center of panel. + Vector2 relative_mpos = get_local_mouse_position() - get_size() / 2; + panning = (panning - relative_mpos) * zoom / previous_zoom + relative_mpos; + } else { + // Center of panel. + panning = panning * zoom / previous_zoom; + } + button_center_view->set_disabled(panning.is_equal_approx(Vector2())); - print_line(vformat("value before: %s", Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()))); - scroll_container->set_h_scroll(10000);//scroll_container->get_h_scroll()+offset.x); - scroll_container->set_v_scroll(10000);//scroll_container->get_v_scroll()+offset.y); - print_line(vformat("value after: %s", Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll()))); - */ + previous_zoom = zoom; - previous_zoom = p_zoom; - } + center_container->set_begin(panning - center_container->get_minimum_size() / 2); + center_container->set_size(center_container->get_minimum_size()); } -void TileAtlasView::_scroll_changed() { - emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())); +void TileAtlasView::_zoom_widget_changed() { + _update_zoom_and_panning(); + emit_signal("transform_changed", zoom_widget->get_zoom(), panning); } -void TileAtlasView::_zoom_widget_changed() { - _update_zoom(zoom_widget->get_zoom()); - emit_signal("transform_changed", zoom_widget->get_zoom(), Vector2(scroll_container->get_h_scroll(), scroll_container->get_v_scroll())); +void TileAtlasView::_center_view() { + panning = Vector2(); + button_center_view->set_disabled(true); + _update_zoom_and_panning(); + emit_signal("transform_changed", zoom_widget->get_zoom(), panning); } void TileAtlasView::_base_tiles_root_control_gui_input(const Ref<InputEvent> &p_event) { @@ -415,7 +412,7 @@ void TileAtlasView::set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_ _update_alternative_tiles_rect_cache(); // Update everything. - _update_zoom(zoom_widget->get_zoom()); + _update_zoom_and_panning(); // Change children control size. Size2i base_tiles_control_size = _compute_base_tiles_control_size(); @@ -448,9 +445,10 @@ float TileAtlasView::get_zoom() const { return zoom_widget->get_zoom(); }; -void TileAtlasView::set_transform(float p_zoom, Vector2i p_scroll) { +void TileAtlasView::set_transform(float p_zoom, Vector2i p_panning) { zoom_widget->set_zoom(p_zoom); - _update_zoom(zoom_widget->get_zoom(), false, p_scroll); + panning = p_panning; + _update_zoom_and_panning(); }; void TileAtlasView::set_padding(Side p_side, int p_padding) { @@ -525,7 +523,7 @@ Rect2i TileAtlasView::get_alternative_tile_rect(const Vector2i p_coords, int p_a } void TileAtlasView::update() { - scroll_container->update(); + base_tiles_draw->update(); base_tiles_texture_grid->update(); base_tiles_shape_grid->update(); base_tiles_dark->update(); @@ -534,124 +532,149 @@ void TileAtlasView::update() { background_right->update(); } +void TileAtlasView::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: + button_center_view->set_icon(get_theme_icon("CenterView", "EditorIcons")); + break; + } +} + void TileAtlasView::_bind_methods() { + ClassDB::bind_method("_gui_input", &TileAtlasView::_gui_input); + ADD_SIGNAL(MethodInfo("transform_changed", PropertyInfo(Variant::FLOAT, "zoom"), PropertyInfo(Variant::VECTOR2, "scroll"))); } TileAtlasView::TileAtlasView() { - Panel *panel_container = memnew(Panel); - panel_container->set_h_size_flags(SIZE_EXPAND_FILL); - panel_container->set_v_size_flags(SIZE_EXPAND_FILL); - panel_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE); - add_child(panel_container); - - //Scrolling - scroll_container = memnew(ScrollContainer); - scroll_container->get_h_scrollbar()->connect("value_changed", callable_mp(this, &TileAtlasView::_scroll_changed).unbind(1)); - scroll_container->get_v_scrollbar()->connect("value_changed", callable_mp(this, &TileAtlasView::_scroll_changed).unbind(1)); - panel_container->add_child(scroll_container); - scroll_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); + + Panel *panel = memnew(Panel); + panel->set_clip_contents(true); + panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + panel->set_h_size_flags(SIZE_EXPAND_FILL); + panel->set_v_size_flags(SIZE_EXPAND_FILL); + add_child(panel); + // Scrollingsc zoom_widget = memnew(EditorZoomWidget); add_child(zoom_widget); zoom_widget->set_anchors_and_offsets_preset(Control::PRESET_TOP_LEFT, Control::PRESET_MODE_MINSIZE, 2 * EDSCALE); zoom_widget->connect("zoom_changed", callable_mp(this, &TileAtlasView::_zoom_widget_changed).unbind(1)); - CenterContainer *center_container = memnew(CenterContainer); - center_container->set_h_size_flags(SIZE_EXPAND_FILL); - center_container->set_v_size_flags(SIZE_EXPAND_FILL); + button_center_view = memnew(Button); + button_center_view->set_icon(get_theme_icon("CenterView", "EditorIcons")); + button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5); + button_center_view->connect("pressed", callable_mp(this, &TileAtlasView::_center_view)); + button_center_view->set_flat(true); + button_center_view->set_disabled(true); + add_child(button_center_view); + + center_container = memnew(CenterContainer); + center_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + center_container->set_anchors_preset(Control::PRESET_CENTER); center_container->connect("gui_input", callable_mp(this, &TileAtlasView::_gui_input)); - scroll_container->add_child(center_container); + panel->add_child(center_container); missing_source_label = memnew(Label); missing_source_label->set_text(TTR("No atlas source with a valid texture selected.")); center_container->add_child(missing_source_label); margin_container = memnew(MarginContainer); + margin_container->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); center_container->add_child(margin_container); hbox = memnew(HBoxContainer); + hbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); hbox->add_theme_constant_override("separation", 10); hbox->hide(); margin_container->add_child(hbox); VBoxContainer *left_vbox = memnew(VBoxContainer); + left_vbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); hbox->add_child(left_vbox); VBoxContainer *right_vbox = memnew(VBoxContainer); + right_vbox->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); hbox->add_child(right_vbox); // Base tiles. Label *base_tile_label = memnew(Label); + base_tile_label->set_mouse_filter(Control::MOUSE_FILTER_PASS); base_tile_label->set_text(TTR("Base Tiles")); base_tile_label->set_align(Label::ALIGN_CENTER); left_vbox->add_child(base_tile_label); base_tiles_root_control = memnew(Control); + base_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS); base_tiles_root_control->set_v_size_flags(Control::SIZE_EXPAND_FILL); base_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_base_tiles_root_control_gui_input)); left_vbox->add_child(base_tiles_root_control); background_left = memnew(Control); + background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); background_left->set_anchors_and_offsets_preset(Control::PRESET_WIDE); background_left->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); - background_left->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); background_left->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_left)); base_tiles_root_control->add_child(background_left); base_tiles_drawing_root = memnew(Control); + base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_drawing_root->set_anchors_and_offsets_preset(Control::PRESET_WIDE); base_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); - base_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_root_control->add_child(base_tiles_drawing_root); base_tiles_draw = memnew(Control); + base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_draw->set_anchors_and_offsets_preset(Control::PRESET_WIDE); base_tiles_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles)); - base_tiles_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_drawing_root->add_child(base_tiles_draw); base_tiles_texture_grid = memnew(Control); + base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_texture_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE); base_tiles_texture_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_texture_grid)); - base_tiles_texture_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_drawing_root->add_child(base_tiles_texture_grid); base_tiles_shape_grid = memnew(Control); + base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_shape_grid->set_anchors_and_offsets_preset(Control::PRESET_WIDE); base_tiles_shape_grid->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_shape_grid)); - base_tiles_shape_grid->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_drawing_root->add_child(base_tiles_shape_grid); base_tiles_dark = memnew(Control); + base_tiles_dark->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_dark->set_anchors_and_offsets_preset(Control::PRESET_WIDE); base_tiles_dark->connect("draw", callable_mp(this, &TileAtlasView::_draw_base_tiles_dark)); - base_tiles_dark->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); base_tiles_drawing_root->add_child(base_tiles_dark); // Alternative tiles. Label *alternative_tiles_label = memnew(Label); + alternative_tiles_label->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); alternative_tiles_label->set_text(TTR("Alternative Tiles")); alternative_tiles_label->set_align(Label::ALIGN_CENTER); right_vbox->add_child(alternative_tiles_label); alternative_tiles_root_control = memnew(Control); + alternative_tiles_root_control->set_mouse_filter(Control::MOUSE_FILTER_PASS); alternative_tiles_root_control->connect("gui_input", callable_mp(this, &TileAtlasView::_alternative_tiles_root_control_gui_input)); right_vbox->add_child(alternative_tiles_root_control); background_right = memnew(Control); + background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); background_right->set_texture_repeat(TextureRepeat::TEXTURE_REPEAT_ENABLED); background_right->connect("draw", callable_mp(this, &TileAtlasView::_draw_background_right)); - background_right->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + alternative_tiles_root_control->add_child(background_right); alternative_tiles_drawing_root = memnew(Control); - alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); alternative_tiles_drawing_root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + alternative_tiles_drawing_root->set_texture_filter(TEXTURE_FILTER_NEAREST); alternative_tiles_root_control->add_child(alternative_tiles_drawing_root); alternatives_draw = memnew(Control); - alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives)); alternatives_draw->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + alternatives_draw->connect("draw", callable_mp(this, &TileAtlasView::_draw_alternatives)); alternative_tiles_drawing_root->add_child(alternatives_draw); } diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h index 28fd3ed1e0..bafc2b3985 100644 --- a/editor/plugins/tiles/tile_atlas_view.h +++ b/editor/plugins/tiles/tile_atlas_view.h @@ -34,6 +34,7 @@ #include "editor/editor_zoom_widget.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" +#include "scene/gui/center_container.h" #include "scene/gui/label.h" #include "scene/gui/margin_container.h" #include "scene/gui/scroll_container.h" @@ -48,17 +49,24 @@ private: TileSetAtlasSource *tile_set_atlas_source; int source_id = -1; + enum DragType { + DRAG_TYPE_NONE, + DRAG_TYPE_PAN, + }; + DragType drag_type = DRAG_TYPE_NONE; float previous_zoom = 1.0; EditorZoomWidget *zoom_widget; + Button *button_center_view; + CenterContainer *center_container; + Vector2 panning; + void _update_zoom_and_panning(bool p_zoom_on_mouse_pos = false); void _zoom_widget_changed(); - void _scroll_changed(); - void _update_zoom(float p_zoom, bool p_zoom_on_mouse_pos = false, Vector2i p_scroll = Vector2i(-1, -1)); + void _center_view(); void _gui_input(const Ref<InputEvent> &p_event); Map<Vector2, Map<int, Rect2i>> alternative_tiles_rect_cache; void _update_alternative_tiles_rect_cache(); - ScrollContainer *scroll_container; MarginContainer *margin_container; int margin_container_paddings[4] = { 0, 0, 0, 0 }; HBoxContainer *hbox; @@ -102,16 +110,15 @@ private: Size2i _compute_alternative_tiles_control_size(); protected: + void _notification(int p_what); static void _bind_methods(); public: // Global. void set_atlas_source(TileSet *p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id); - ScrollContainer *get_scroll_container() { return scroll_container; }; - float get_zoom() const; - void set_transform(float p_zoom, Vector2i p_scroll); + void set_transform(float p_zoom, Vector2i p_panning); void set_padding(Side p_side, int p_padding); diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 61457e3e59..d9d0e48fb3 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -32,202 +32,2436 @@ #include "tile_set_editor.h" -TileData *TileDataEditor::_get_tile_data(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile) { - ERR_FAIL_COND_V(!p_tile_set, nullptr); - ERR_FAIL_COND_V(!p_tile_set->has_source(p_atlas_source_id), nullptr); +#include "core/math/geometry_2d.h" +#include "core/os/keyboard.h" + +#include "editor/editor_properties.h" +#include "editor/editor_scale.h" + +void TileDataEditor::_call_tile_set_changed() { + _tile_set_changed(); +} + +TileData *TileDataEditor::_get_tile_data(TileMapCell p_cell) { + ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); + ERR_FAIL_COND_V(!tile_set->has_source(p_cell.source_id), nullptr); TileData *td = nullptr; - TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id); + TileSetSource *source = *tile_set->get_source(p_cell.source_id); TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source); if (atlas_source) { - ERR_FAIL_COND_V(!atlas_source->has_tile(p_atlas_coords), nullptr); - ERR_FAIL_COND_V(!atlas_source->has_alternative_tile(p_atlas_coords, p_alternative_tile), nullptr); - td = Object::cast_to<TileData>(atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile)); + ERR_FAIL_COND_V(!atlas_source->has_tile(p_cell.get_atlas_coords()), nullptr); + ERR_FAIL_COND_V(!atlas_source->has_alternative_tile(p_cell.get_atlas_coords(), p_cell.alternative_tile), nullptr); + td = Object::cast_to<TileData>(atlas_source->get_tile_data(p_cell.get_atlas_coords(), p_cell.alternative_tile)); } return td; } -void TileDataEditor::edit(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { +void TileDataEditor::_bind_methods() { + ADD_SIGNAL(MethodInfo("needs_redraw")); } -void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); - ERR_FAIL_COND(!tile_data); +void TileDataEditor::set_tile_set(Ref<TileSet> p_tile_set) { + if (tile_set.is_valid()) { + tile_set->disconnect("changed", callable_mp(this, &TileDataEditor::_call_tile_set_changed)); + } + tile_set = p_tile_set; + if (tile_set.is_valid()) { + tile_set->connect("changed", callable_mp(this, &TileDataEditor::_call_tile_set_changed)); + } + _call_tile_set_changed(); +} - bool valid; - Variant value = tile_data->get(p_property, &valid); - if (!valid) { - return; +bool DummyObject::_set(const StringName &p_name, const Variant &p_value) { + if (properties.has(p_name)) { + properties[p_name] = p_value; + return true; } - ERR_FAIL_COND(value.get_type() != Variant::VECTOR2I); + return false; +} - Vector2i tile_set_tile_size = p_tile_set->get_tile_size(); - Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size); - p_tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), Color(1.0, 0.0, 0.0)); +bool DummyObject::_get(const StringName &p_name, Variant &r_ret) const { + if (properties.has(p_name)) { + r_ret = properties[p_name]; + return true; + } + return false; +} + +bool DummyObject::has_dummy_property(StringName p_name) { + return properties.has(p_name); +} + +void DummyObject::add_dummy_property(StringName p_name) { + ERR_FAIL_COND(properties.has(p_name)); + properties[p_name] = Variant(); +} + +void DummyObject::remove_dummy_property(StringName p_name) { + ERR_FAIL_COND(!properties.has(p_name)); + properties.erase(p_name); +} + +void DummyObject::clear_dummy_properties() { + properties.clear(); +} + +void GenericTilePolygonEditor::_base_control_draw() { + ERR_FAIL_COND(!tile_set.is_valid()); + + real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); + + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + const Ref<Texture2D> handle = get_theme_icon("EditorPathSharpHandle", "EditorIcons"); + const Ref<Texture2D> add_handle = get_theme_icon("EditorHandleAdd", "EditorIcons"); + + Size2 tile_size = tile_set->get_tile_size(); + + Transform2D xform; + xform.set_origin(base_control->get_size() / 2 + panning); + xform.set_scale(Vector2(editor_zoom_widget->get_zoom(), editor_zoom_widget->get_zoom())); + base_control->draw_set_transform_matrix(xform); + + // Draw the tile shape filled. + tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), Color(1.0, 1.0, 1.0, 0.3), true); + + // Draw the background. + if (background_texture.is_valid()) { + base_control->draw_texture_rect_region(background_texture, Rect2(-background_region.size / 2 - background_offset, background_region.size), background_region, background_modulate, background_transpose); + } + + // Draw the polygons. + for (unsigned int i = 0; i < polygons.size(); i++) { + const Vector<Vector2> &polygon = polygons[i]; + Color color = polygon_color; + if (!in_creation_polygon.is_empty()) { + color = color.darkened(0.3); + } + color.a = 0.5; + Vector<Color> v_color; + v_color.push_back(color); + base_control->draw_polygon(polygon, v_color); + + color.a = 0.7; + for (int j = 0; j < polygon.size(); j++) { + base_control->draw_line(polygon[j], polygon[(j + 1) % polygon.size()], color); + } + } + + // Draw the polygon in creation. + if (!in_creation_polygon.is_empty()) { + for (int i = 0; i < in_creation_polygon.size() - 1; i++) { + base_control->draw_line(in_creation_polygon[i], in_creation_polygon[i + 1], Color(1.0, 1.0, 1.0)); + } + } + + Point2 in_creation_point = xform.affine_inverse().xform(base_control->get_local_mouse_position()); + float in_creation_distance = grab_threshold * 2.0; + _snap_to_tile_shape(in_creation_point, in_creation_distance, grab_threshold / editor_zoom_widget->get_zoom()); + if (button_pixel_snap->is_pressed()) { + _snap_to_half_pixel(in_creation_point); + } + + if (drag_type == DRAG_TYPE_CREATE_POINT && !in_creation_polygon.is_empty()) { + base_control->draw_line(in_creation_polygon[in_creation_polygon.size() - 1], in_creation_point, Color(1.0, 1.0, 1.0)); + } + + // Draw the handles. + int tinted_polygon_index = -1; + int tinted_point_index = -1; + if (drag_type == DRAG_TYPE_DRAG_POINT) { + tinted_polygon_index = drag_polygon_index; + tinted_point_index = drag_point_index; + } else if (hovered_point_index >= 0) { + tinted_polygon_index = hovered_polygon_index; + tinted_point_index = hovered_point_index; + } + + base_control->draw_set_transform_matrix(Transform2D()); + if (!in_creation_polygon.is_empty()) { + for (int i = 0; i < in_creation_polygon.size(); i++) { + base_control->draw_texture(handle, xform.xform(in_creation_polygon[i]) - handle->get_size() / 2); + } + } else { + for (int i = 0; i < (int)polygons.size(); i++) { + const Vector<Vector2> &polygon = polygons[i]; + for (int j = 0; j < polygon.size(); j++) { + const Color modulate = (tinted_polygon_index == i && tinted_point_index == j) ? Color(0.5, 1, 2) : Color(1, 1, 1); + base_control->draw_texture(handle, xform.xform(polygon[j]) - handle->get_size() / 2, modulate); + } + } + } + + // Draw the text on top of the selected point. + if (tinted_polygon_index >= 0) { + Ref<Font> font = get_theme_font("font", "Label"); + int font_size = get_theme_font_size("font_size", "Label"); + String text = multiple_polygon_mode ? vformat("%d:%d", tinted_polygon_index, tinted_point_index) : vformat("%d", tinted_point_index); + Size2 text_size = font->get_string_size(text, font_size); + base_control->draw_string(font, xform.xform(polygons[tinted_polygon_index][tinted_point_index]) - text_size * 0.5, text, HALIGN_LEFT, -1, font_size, Color(1.0, 1.0, 1.0, 0.5)); + } + + if (drag_type == DRAG_TYPE_CREATE_POINT) { + base_control->draw_texture(handle, xform.xform(in_creation_point) - handle->get_size() / 2, Color(0.5, 1, 2)); + } + + // Draw the point creation preview in edit mode. + if (hovered_segment_index >= 0) { + base_control->draw_texture(add_handle, xform.xform(hovered_segment_point) - add_handle->get_size() / 2); + } + + // Draw the tile shape line. + base_control->draw_set_transform_matrix(xform); + tile_set->draw_tile_shape(base_control, Rect2(-tile_size / 2, tile_size), grid_color, false); + base_control->draw_set_transform_matrix(Transform2D()); +} + +void GenericTilePolygonEditor::_center_view() { + panning = Vector2(); + base_control->update(); + button_center_view->set_disabled(true); +} + +void GenericTilePolygonEditor::_zoom_changed() { + base_control->update(); +} + +void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) { + switch (p_item_pressed) { + case RESET_TO_DEFAULT_TILE: + undo_redo->create_action(TTR("Edit Polygons")); + undo_redo->add_do_method(this, "clear_polygons"); + undo_redo->add_do_method(this, "add_polygon", tile_set->get_tile_shape_polygon()); + undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); + undo_redo->add_undo_method(this, "clear_polygons"); + for (unsigned int i = 0; i < polygons.size(); i++) { + undo_redo->add_undo_method(this, "add_polygon", polygons[i]); + } + undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); + undo_redo->commit_action(true); + break; + case CLEAR_TILE: + undo_redo->create_action(TTR("Edit Polygons")); + undo_redo->add_do_method(this, "clear_polygons"); + undo_redo->add_do_method(base_control, "update"); + undo_redo->add_do_method(this, "emit_signal", "polygons_changed"); + undo_redo->add_undo_method(this, "clear_polygons"); + for (unsigned int i = 0; i < polygons.size(); i++) { + undo_redo->add_undo_method(this, "add_polygon", polygons[i]); + } + undo_redo->add_undo_method(base_control, "update"); + undo_redo->add_undo_method(this, "emit_signal", "polygons_changed"); + undo_redo->commit_action(true); + break; + default: + break; + } +} + +void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) { + const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); + r_polygon_index = -1; + r_point_index = -1; + float closest_distance = grab_threshold + 1.0; + for (unsigned int i = 0; i < polygons.size(); i++) { + const Vector<Vector2> &polygon = polygons[i]; + for (int j = 0; j < polygon.size(); j++) { + float distance = p_pos.distance_to(p_polygon_xform.xform(polygon[j])); + if (distance < grab_threshold && distance < closest_distance) { + r_polygon_index = i; + r_point_index = j; + closest_distance = distance; + } + } + } +} + +void GenericTilePolygonEditor::_grab_polygon_segment_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_segment_index, Vector2 &r_point) { + const real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); + + Point2 point = p_polygon_xform.affine_inverse().xform(p_pos); + r_polygon_index = -1; + r_segment_index = -1; + float closest_distance = grab_threshold * 2.0; + for (unsigned int i = 0; i < polygons.size(); i++) { + const Vector<Vector2> &polygon = polygons[i]; + for (int j = 0; j < polygon.size(); j++) { + Vector2 segment[2] = { polygon[j], polygon[(j + 1) % polygon.size()] }; + Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point, segment); + float distance = closest_point.distance_to(point); + if (distance < grab_threshold / editor_zoom_widget->get_zoom() && distance < closest_distance) { + r_polygon_index = i; + r_segment_index = j; + r_point = closest_point; + closest_distance = distance; + } + } + } +} + +void GenericTilePolygonEditor::_snap_to_tile_shape(Point2 &r_point, float &r_current_snapped_dist, float p_snap_dist) { + ERR_FAIL_COND(!tile_set.is_valid()); + + Vector<Point2> polygon = tile_set->get_tile_shape_polygon(); + Point2 snapped_point = r_point; + + // Snap to polygon vertices. + bool snapped = false; + for (int i = 0; i < polygon.size(); i++) { + float distance = r_point.distance_to(polygon[i]); + if (distance < p_snap_dist && distance < r_current_snapped_dist) { + snapped_point = polygon[i]; + r_current_snapped_dist = distance; + snapped = true; + } + } + + // Snap to edges if we did not snap to vertices. + if (!snapped) { + for (int i = 0; i < polygon.size(); i++) { + Point2 segment[2] = { polygon[i], polygon[(i + 1) % polygon.size()] }; + Point2 point = Geometry2D::get_closest_point_to_segment(r_point, segment); + float distance = r_point.distance_to(point); + if (distance < p_snap_dist && distance < r_current_snapped_dist) { + snapped_point = point; + r_current_snapped_dist = distance; + } + } + } + + r_point = snapped_point; +} + +void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) { + r_point = (r_point * 2).round() / 2.0; +} + +void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) { + real_t grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); + + hovered_polygon_index = -1; + hovered_point_index = -1; + hovered_segment_index = -1; + hovered_segment_point = Vector2(); + + Transform2D xform; + xform.set_origin(base_control->get_size() / 2 + panning); + xform.set_scale(Vector2(editor_zoom_widget->get_zoom(), editor_zoom_widget->get_zoom())); + + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (drag_type == DRAG_TYPE_DRAG_POINT) { + ERR_FAIL_INDEX(drag_polygon_index, (int)polygons.size()); + ERR_FAIL_INDEX(drag_point_index, polygons[drag_polygon_index].size()); + Point2 point = xform.affine_inverse().xform(mm->get_position()); + float distance = grab_threshold * 2.0; + _snap_to_tile_shape(point, distance, grab_threshold / editor_zoom_widget->get_zoom()); + if (button_pixel_snap->is_pressed()) { + _snap_to_half_pixel(point); + } + polygons[drag_polygon_index].write[drag_point_index] = point; + } else if (drag_type == DRAG_TYPE_PAN) { + panning += mm->get_position() - drag_last_pos; + drag_last_pos = mm->get_position(); + button_center_view->set_disabled(panning.is_equal_approx(Vector2())); + } else { + // Update hovered point. + _grab_polygon_point(mm->get_position(), xform, hovered_polygon_index, hovered_point_index); + + // If we have no hovered point, check if we hover a segment. + if (hovered_point_index == -1) { + _grab_polygon_segment_point(mm->get_position(), xform, hovered_polygon_index, hovered_segment_index, hovered_segment_point); + } + } + } + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_ctrl_pressed()) { + editor_zoom_widget->set_zoom_by_increments(1); + _zoom_changed(); + accept_event(); + } else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_ctrl_pressed()) { + editor_zoom_widget->set_zoom_by_increments(-1); + _zoom_changed(); + accept_event(); + } else if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (mb->is_pressed()) { + if (tools_button_group->get_pressed_button() != button_create) { + in_creation_polygon.clear(); + } + if (tools_button_group->get_pressed_button() == button_create) { + // Create points. + if (in_creation_polygon.size() >= 3 && mb->get_position().distance_to(xform.xform(in_creation_polygon[0])) < grab_threshold) { + // Closes and create polygon. + if (!multiple_polygon_mode) { + clear_polygons(); + } + int added = add_polygon(in_creation_polygon); + + in_creation_polygon.clear(); + button_edit->set_pressed(true); + undo_redo->create_action(TTR("Edit Polygons")); + if (!multiple_polygon_mode) { + undo_redo->add_do_method(this, "clear_polygons"); + } + undo_redo->add_do_method(this, "add_polygon", in_creation_polygon); + undo_redo->add_do_method(base_control, "update"); + undo_redo->add_undo_method(this, "remove_polygon", added); + undo_redo->add_undo_method(base_control, "update"); + undo_redo->commit_action(false); + emit_signal("polygons_changed"); + } else { + // Create a new point. + drag_type = DRAG_TYPE_CREATE_POINT; + } + } else if (tools_button_group->get_pressed_button() == button_edit) { + // Edit points. + int closest_polygon; + int closest_point; + _grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point); + if (closest_polygon >= 0) { + drag_type = DRAG_TYPE_DRAG_POINT; + drag_polygon_index = closest_polygon; + drag_point_index = closest_point; + drag_old_polygon = polygons[drag_polygon_index]; + } else { + // Create a point. + Vector2 point_to_create; + _grab_polygon_segment_point(mb->get_position(), xform, closest_polygon, closest_point, point_to_create); + if (closest_polygon >= 0) { + polygons[closest_polygon].insert(closest_point + 1, point_to_create); + drag_type = DRAG_TYPE_DRAG_POINT; + drag_polygon_index = closest_polygon; + drag_point_index = closest_point + 1; + drag_old_polygon = polygons[closest_polygon]; + } + } + } else if (tools_button_group->get_pressed_button() == button_delete) { + // Remove point. + int closest_polygon; + int closest_point; + _grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point); + if (closest_polygon >= 0) { + PackedVector2Array old_polygon = polygons[closest_polygon]; + polygons[closest_polygon].remove(closest_point); + undo_redo->create_action(TTR("Edit Polygons")); + if (polygons[closest_polygon].size() < 3) { + remove_polygon(closest_polygon); + undo_redo->add_do_method(this, "remove_polygon", closest_polygon); + undo_redo->add_undo_method(this, "add_polygon", old_polygon, closest_polygon); + } else { + undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]); + undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon); + } + undo_redo->add_do_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "update"); + undo_redo->commit_action(false); + emit_signal("polygons_changed"); + } + } + } else { + if (drag_type == DRAG_TYPE_DRAG_POINT) { + undo_redo->create_action(TTR("Edit Polygons")); + undo_redo->add_do_method(this, "set_polygon", drag_polygon_index, polygons[drag_polygon_index]); + undo_redo->add_do_method(base_control, "update"); + undo_redo->add_undo_method(this, "set_polygon", drag_polygon_index, drag_old_polygon); + undo_redo->add_undo_method(base_control, "update"); + undo_redo->commit_action(false); + emit_signal("polygons_changed"); + } else if (drag_type == DRAG_TYPE_CREATE_POINT) { + Point2 point = xform.affine_inverse().xform(mb->get_position()); + float distance = grab_threshold * 2; + _snap_to_tile_shape(point, distance, grab_threshold / editor_zoom_widget->get_zoom()); + if (button_pixel_snap->is_pressed()) { + _snap_to_half_pixel(point); + } + in_creation_polygon.push_back(point); + } + drag_type = DRAG_TYPE_NONE; + drag_point_index = -1; + } + + } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { + if (mb->is_pressed()) { + if (tools_button_group->get_pressed_button() == button_edit) { + // Remove point or pan. + int closest_polygon; + int closest_point; + _grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point); + if (closest_polygon >= 0) { + PackedVector2Array old_polygon = polygons[closest_polygon]; + polygons[closest_polygon].remove(closest_point); + undo_redo->create_action(TTR("Edit Polygons")); + if (polygons[closest_polygon].size() < 3) { + remove_polygon(closest_polygon); + undo_redo->add_do_method(this, "remove_polygon", closest_polygon); + undo_redo->add_undo_method(this, "add_polygon", old_polygon, closest_polygon); + } else { + undo_redo->add_do_method(this, "set_polygon", closest_polygon, polygons[closest_polygon]); + undo_redo->add_undo_method(this, "set_polygon", closest_polygon, old_polygon); + } + undo_redo->add_do_method(base_control, "update"); + undo_redo->add_undo_method(base_control, "update"); + undo_redo->commit_action(false); + emit_signal("polygons_changed"); + } else { + drag_type = DRAG_TYPE_PAN; + drag_last_pos = mb->get_position(); + } + } else { + drag_type = DRAG_TYPE_PAN; + drag_last_pos = mb->get_position(); + } + } else { + drag_type = DRAG_TYPE_NONE; + } + } else if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE) { + if (mb->is_pressed()) { + drag_type = DRAG_TYPE_PAN; + drag_last_pos = mb->get_position(); + } else { + drag_type = DRAG_TYPE_NONE; + } + } + } + + base_control->update(); +} + +void GenericTilePolygonEditor::set_tile_set(Ref<TileSet> p_tile_set) { + if (tile_set != p_tile_set) { + // Set the default tile shape + clear_polygons(); + if (p_tile_set.is_valid()) { + add_polygon(p_tile_set->get_tile_shape_polygon()); + } + } + tile_set = p_tile_set; +} + +void GenericTilePolygonEditor::set_background(Ref<Texture2D> p_texture, Rect2 p_region, Vector2 p_offset, bool p_flip_h, bool p_flip_v, bool p_transpose, Color p_modulate) { + background_texture = p_texture; + background_region = p_region; + background_offset = p_offset; + background_h_flip = p_flip_h; + background_v_flip = p_flip_v; + background_transpose = p_transpose; + background_modulate = p_modulate; + base_control->update(); +} + +int GenericTilePolygonEditor::get_polygon_count() { + return polygons.size(); +} + +int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index) { + ERR_FAIL_COND_V(p_polygon.size() < 3, -1); + ERR_FAIL_COND_V(!multiple_polygon_mode && polygons.size() >= 1, -1); + + if (p_index < 0) { + polygons.push_back(p_polygon); + base_control->update(); + button_edit->set_pressed(true); + return polygons.size() - 1; + } else { + polygons.insert(p_index, p_polygon); + button_edit->set_pressed(true); + base_control->update(); + return p_index; + } +} + +void GenericTilePolygonEditor::remove_polygon(int p_index) { + ERR_FAIL_INDEX(p_index, (int)polygons.size()); + polygons.remove(p_index); + + if (polygons.size() == 0) { + button_create->set_pressed(true); + } + base_control->update(); +} + +void GenericTilePolygonEditor::clear_polygons() { + polygons.clear(); + base_control->update(); +} + +void GenericTilePolygonEditor::set_polygon(int p_polygon_index, Vector<Point2> p_polygon) { + ERR_FAIL_INDEX(p_polygon_index, (int)polygons.size()); + ERR_FAIL_COND(p_polygon.size() < 3); + polygons[p_polygon_index] = p_polygon; + button_edit->set_pressed(true); + base_control->update(); } -void TileDataIntegerEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +Vector<Point2> GenericTilePolygonEditor::get_polygon(int p_polygon_index) { + ERR_FAIL_INDEX_V(p_polygon_index, (int)polygons.size(), Vector<Point2>()); + return polygons[p_polygon_index]; +} + +void GenericTilePolygonEditor::set_polygons_color(Color p_color) { + polygon_color = p_color; + base_control->update(); +} + +void GenericTilePolygonEditor::set_multiple_polygon_mode(bool p_multiple_polygon_mode) { + multiple_polygon_mode = p_multiple_polygon_mode; +} + +void GenericTilePolygonEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_READY: + button_create->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveCreate", "EditorIcons")); + button_edit->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveEdit", "EditorIcons")); + button_delete->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CurveDelete", "EditorIcons")); + button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CenterView", "EditorIcons")); + button_pixel_snap->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Snap", "EditorIcons")); + button_advanced_menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("GuiTabMenu", "EditorIcons")); + break; + } +} + +void GenericTilePolygonEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_polygon_count"), &GenericTilePolygonEditor::get_polygon_count); + ClassDB::bind_method(D_METHOD("add_polygon", "polygon", "index"), &GenericTilePolygonEditor::add_polygon, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("remove_polygon", "index"), &GenericTilePolygonEditor::remove_polygon); + ClassDB::bind_method(D_METHOD("clear_polygons"), &GenericTilePolygonEditor::clear_polygons); + ClassDB::bind_method(D_METHOD("set_polygon", "index", "polygon"), &GenericTilePolygonEditor::set_polygon); + ClassDB::bind_method(D_METHOD("get_polygon", "index"), &GenericTilePolygonEditor::set_polygon); + + ADD_SIGNAL(MethodInfo("polygons_changed")); +} + +GenericTilePolygonEditor::GenericTilePolygonEditor() { + toolbar = memnew(HBoxContainer); + add_child(toolbar); + + tools_button_group.instantiate(); + + button_create = memnew(Button); + button_create->set_flat(true); + button_create->set_toggle_mode(true); + button_create->set_button_group(tools_button_group); + button_create->set_pressed(true); + toolbar->add_child(button_create); + + button_edit = memnew(Button); + button_edit->set_flat(true); + button_edit->set_toggle_mode(true); + button_edit->set_button_group(tools_button_group); + toolbar->add_child(button_edit); + + button_delete = memnew(Button); + button_delete->set_flat(true); + button_delete->set_toggle_mode(true); + button_delete->set_button_group(tools_button_group); + toolbar->add_child(button_delete); + + button_advanced_menu = memnew(MenuButton); + button_advanced_menu->set_flat(true); + button_advanced_menu->set_toggle_mode(true); + button_advanced_menu->get_popup()->add_item(TTR("Reset to default tile shape"), RESET_TO_DEFAULT_TILE); + button_advanced_menu->get_popup()->add_item(TTR("Clear"), CLEAR_TILE); + button_advanced_menu->get_popup()->connect("id_pressed", callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed)); + toolbar->add_child(button_advanced_menu); + + toolbar->add_child(memnew(VSeparator)); + + button_pixel_snap = memnew(Button); + button_pixel_snap->set_flat(true); + button_pixel_snap->set_toggle_mode(true); + button_pixel_snap->set_pressed(true); + toolbar->add_child(button_pixel_snap); + + Control *root = memnew(Control); + root->set_h_size_flags(Control::SIZE_EXPAND_FILL); + root->set_custom_minimum_size(Size2(0, 200 * EDSCALE)); + root->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + add_child(root); + + panel = memnew(Panel); + panel->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + panel->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); + root->add_child(panel); + + base_control = memnew(Control); + base_control->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); + base_control->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + base_control->connect("draw", callable_mp(this, &GenericTilePolygonEditor::_base_control_draw)); + base_control->connect("gui_input", callable_mp(this, &GenericTilePolygonEditor::_base_control_gui_input)); + base_control->set_clip_contents(true); + root->add_child(base_control); + + editor_zoom_widget = memnew(EditorZoomWidget); + editor_zoom_widget->set_position(Vector2(5, 5)); + editor_zoom_widget->connect("zoom_changed", callable_mp(this, &GenericTilePolygonEditor::_zoom_changed).unbind(1)); + root->add_child(editor_zoom_widget); + + button_center_view = memnew(Button); + button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon("CenterView", "EditorIcons")); + button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5); + button_center_view->connect("pressed", callable_mp(this, &GenericTilePolygonEditor::_center_view)); + button_center_view->set_flat(true); + button_center_view->set_disabled(true); + root->add_child(button_center_view); +} + +void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { + ERR_FAIL_COND(!dummy_object); + dummy_object->set(p_property, p_value); +} + +Variant TileDataDefaultEditor::_get_painted_value() { + ERR_FAIL_COND_V(!dummy_object, Variant()); + return dummy_object->get(property); +} + +void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); ERR_FAIL_COND(!tile_data); + Variant value = tile_data->get(property); + dummy_object->set(property, value); + if (property_editor) { + property_editor->update_property(); + } +} - bool valid; - Variant value = tile_data->get(p_property, &valid); - if (!valid) { - return; +void TileDataDefaultEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND(!tile_data); + tile_data->set(property, p_value); +} + +Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND_V(!tile_data, Variant()); + return tile_data->get(property); +} + +void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) { + for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) { + Vector2i coords = E->key().get_atlas_coords(); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E->key().alternative_tile, property), E->get()); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E->key().alternative_tile, property), p_new_value); } - ERR_FAIL_COND(value.get_type() != Variant::INT); +} - Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts"); - int height = font->get_height(); - int width = 200; - p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-width / 2, height / 2), vformat("%d", value), HALIGN_CENTER, width, -1, Color(1, 1, 1), 1, Color(0, 0, 0, 1)); +void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) { + if (drag_type == DRAG_TYPE_PAINT_RECT) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + + p_canvas_item->draw_set_transform_matrix(p_transform); + + Rect2i rect; + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()))); + rect = rect.abs(); + + Set<TileMapCell> edited; + for (int x = rect.get_position().x; x <= rect.get_end().x; x++) { + for (int y = rect.get_position().y; y <= rect.get_end().y; y++) { + Vector2i coords = Vector2i(x, y); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + edited.insert(cell); + } + } + } + + for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) { + Vector2i coords = E->get().get_atlas_coords(); + p_canvas_item->draw_rect(p_tile_set_atlas_source->get_tile_texture_region(coords), selection_color, false); + } + p_canvas_item->draw_set_transform_matrix(Transform2D()); + } +}; + +void TileDataDefaultEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){ + +}; + +void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) { + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (drag_type == DRAG_TYPE_PAINT) { + Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position())); + for (int i = 0; i < line.size(); i++) { + Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + if (!drag_modified.has(cell)) { + drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, 0); + } + _set_value(p_tile_set_atlas_source, coords, 0, drag_painted_value); + } + } + drag_last_pos = mm->get_position(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (mb->is_pressed()) { + if (picker_button->is_pressed()) { + Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + _set_painted_value(p_tile_set_atlas_source, coords, 0); + picker_button->set_pressed(false); + } + } else if (mb->is_ctrl_pressed()) { + drag_type = DRAG_TYPE_PAINT_RECT; + drag_modified.clear(); + drag_painted_value = _get_painted_value(); + drag_start_pos = mb->get_position(); + } else { + drag_type = DRAG_TYPE_PAINT; + drag_modified.clear(); + drag_painted_value = _get_painted_value(); + Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, 0); + _set_value(p_tile_set_atlas_source, coords, 0, drag_painted_value); + } + drag_last_pos = mb->get_position(); + } + } else { + if (drag_type == DRAG_TYPE_PAINT_RECT) { + Rect2i rect; + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position())); + rect = rect.abs(); + + drag_modified.clear(); + for (int x = rect.get_position().x; x <= rect.get_end().x; x++) { + for (int y = rect.get_position().y; y <= rect.get_end().y; y++) { + Vector2i coords = Vector2i(x, y); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, 0); + } + } + } + undo_redo->create_action(TTR("Painting Tiles Property")); + _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value); + undo_redo->commit_action(true); + drag_type = DRAG_TYPE_NONE; + } else if (drag_type == DRAG_TYPE_PAINT) { + undo_redo->create_action(TTR("Painting Tiles Property")); + _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value); + undo_redo->commit_action(false); + drag_type = DRAG_TYPE_NONE; + } + } + } + } } -void TileDataFloatEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) { + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (drag_type == DRAG_TYPE_PAINT) { + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mm->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + if (!drag_modified.has(cell)) { + drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, alternative_tile); + } + _set_value(p_tile_set_atlas_source, coords, alternative_tile, drag_painted_value); + } + + drag_last_pos = mm->get_position(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (mb->is_pressed()) { + if (picker_button->is_pressed()) { + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + _set_painted_value(p_tile_set_atlas_source, coords, alternative_tile); + picker_button->set_pressed(false); + } + } else { + drag_type = DRAG_TYPE_PAINT; + drag_modified.clear(); + drag_painted_value = _get_painted_value(); + + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + drag_modified[cell] = _get_value(p_tile_set_atlas_source, coords, alternative_tile); + _set_value(p_tile_set_atlas_source, coords, alternative_tile, drag_painted_value); + } + drag_last_pos = mb->get_position(); + } + } else { + undo_redo->create_action(TTR("Painting Tiles Property")); + _setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value); + undo_redo->commit_action(false); + drag_type = DRAG_TYPE_NONE; + } + } + } +} + +void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); ERR_FAIL_COND(!tile_data); bool valid; - Variant value = tile_data->get(p_property, &valid); + Variant value = tile_data->get(property, &valid); if (!valid) { return; } - ERR_FAIL_COND(value.get_type() != Variant::FLOAT); - Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts"); - int height = font->get_height(); - int width = 200; - p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-width / 2, height / 2), vformat("%.2f", value), HALIGN_CENTER, width, -1, Color(1, 1, 1), 1, Color(0, 0, 0, 1)); + if (value.get_type() == Variant::BOOL) { + Ref<Texture2D> texture = (bool)value ? tile_bool_checked : tile_bool_unchecked; + int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3; + Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size))); + p_canvas_item->draw_texture_rect(texture, rect); + } else if (value.get_type() == Variant::COLOR) { + int size = MIN(tile_set->get_tile_size().x, tile_set->get_tile_size().y) / 3; + Rect2 rect = p_transform.xform(Rect2(Vector2(-size / 2, -size / 2), Vector2(size, size))); + p_canvas_item->draw_rect(rect, value); + } else { + Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts"); + String text; + switch (value.get_type()) { + case Variant::INT: + text = vformat("%d", value); + break; + case Variant::FLOAT: + text = vformat("%.2f", value); + break; + case Variant::STRING: + case Variant::STRING_NAME: + text = value; + break; + default: + return; + break; + } + + Color color = Color(1, 1, 1); + if (p_selected) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + selection_color.set_v(0.9); + color = selection_color; + } else if (is_visible_in_tree()) { + Variant painted_value = _get_painted_value(); + bool equal = (painted_value.get_type() == Variant::FLOAT && value.get_type() == Variant::FLOAT) ? Math::is_equal_approx(float(painted_value), float(value)) : painted_value == value; + if (equal) { + color = Color(0.7, 0.7, 0.7); + } + } + + Vector2 string_size = font->get_string_size(text); + p_canvas_item->draw_string(font, p_transform.get_origin() + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, -1, color, 1, Color(0, 0, 0, 1)); + } } -void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, String p_property, String p_label, Variant p_default_value) { + ERR_FAIL_COND_MSG(!property.is_empty(), "Cannot setup TileDataDefaultEditor twice"); + property = p_property; + + // Update everything. + if (property_editor) { + property_editor->queue_delete(); + } + + // Update the dummy object. + dummy_object->add_dummy_property(p_property); + + // Get the default value for the type. + if (p_default_value == Variant()) { + Callable::CallError error; + Variant painted_value; + Variant::construct(p_type, painted_value, nullptr, 0, error); + dummy_object->set(p_property, painted_value); + } else { + dummy_object->set(p_property, p_default_value); + } + + // Create and setup the property editor. + property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, p_type, p_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); + property_editor->set_object_and_property(dummy_object, p_property); + if (p_label.is_empty()) { + property_editor->set_label(p_property); + } else { + property_editor->set_label(p_label); + } + property_editor->connect("property_changed", callable_mp(this, &TileDataDefaultEditor::_property_value_changed).unbind(1)); + property_editor->update_property(); + add_child(property_editor); +} + +void TileDataDefaultEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: + picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons")); + tile_bool_checked = get_theme_icon("TileChecked", "EditorIcons"); + tile_bool_unchecked = get_theme_icon("TileUnchecked", "EditorIcons"); + break; + default: + break; + } +} + +TileDataDefaultEditor::TileDataDefaultEditor() { + label = memnew(Label); + label->set_text("Painting:"); + add_child(label); + + toolbar->add_child(memnew(VSeparator)); + + picker_button = memnew(Button); + picker_button->set_flat(true); + picker_button->set_toggle_mode(true); + picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P)); + toolbar->add_child(picker_button); +} + +TileDataDefaultEditor::~TileDataDefaultEditor() { + toolbar->queue_delete(); + memdelete(dummy_object); +} + +void TileDataTextureOffsetEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); + ERR_FAIL_COND(!tile_data); + + Vector2i tile_set_tile_size = tile_set->get_tile_size(); + Rect2i rect = Rect2i(-tile_set_tile_size / 2, tile_set_tile_size); + Color color = Color(1.0, 0.0, 0.0); + if (p_selected) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + color = selection_color; + } + tile_set->draw_tile_shape(p_canvas_item, p_transform.xform(rect), color); +} + +void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); ERR_FAIL_COND(!tile_data); bool valid; - Variant value = tile_data->get(p_property, &valid); + Variant value = tile_data->get(property, &valid); if (!valid) { return; } ERR_FAIL_COND(value.get_type() != Variant::VECTOR2I && value.get_type() != Variant::VECTOR2); + Color color = Color(1.0, 1.0, 1.0); + if (p_selected) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + color = selection_color; + } Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon("EditorPosition", "EditorIcons"); - p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(value)) - position_icon->get_size() / 2); + p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(value)) - position_icon->get_size() / 2, color); } -void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); ERR_FAIL_COND(!tile_data); - bool valid; - Variant value = tile_data->get(p_property, &valid); - if (!valid) { - return; + Color color = Color(1.0, 1.0, 1.0); + if (p_selected) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + color = selection_color; } - ERR_FAIL_COND(value.get_type() != Variant::INT); - Ref<Texture2D> position_icon = TileSetEditor::get_singleton()->get_theme_icon("EditorPosition", "EditorIcons"); - p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, value)) - position_icon->get_size() / 2); + p_canvas_item->draw_texture(position_icon, p_transform.xform(Vector2(0, tile_data->get_y_sort_origin())) - position_icon->get_size() / 2, color); } -void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); ERR_FAIL_COND(!tile_data); - Vector<String> components = String(p_property).split("/", true); - if (components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) { - int occlusion_layer = components[0].trim_prefix("occlusion_layer_").to_int(); - if (occlusion_layer >= 0 && occlusion_layer < p_tile_set->get_occlusion_layers_count()) { - // Draw all shapes. - Vector<Color> debug_occlusion_color; - debug_occlusion_color.push_back(Color(0.5, 0, 0, 0.6)); + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + Color color = grid_color.darkened(0.2); + if (p_selected) { + color = selection_color.darkened(0.2); + } + color.a *= 0.5; - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); - Ref<OccluderPolygon2D> occluder = tile_data->get_occluder(occlusion_layer); - if (occluder.is_valid() && occluder->get_polygon().size() >= 3) { - p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color); - } - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); + Vector<Color> debug_occlusion_color; + debug_occlusion_color.push_back(color); + + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + Ref<OccluderPolygon2D> occluder = tile_data->get_occluder(occlusion_layer); + if (occluder.is_valid() && occluder->get_polygon().size() >= 3) { + p_canvas_item->draw_polygon(Variant(occluder->get_polygon()), debug_occlusion_color); + } + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); +} + +Variant TileDataOcclusionShapeEditor::_get_painted_value() { + Ref<OccluderPolygon2D> occluder_polygon; + occluder_polygon.instantiate(); + if (polygon_editor->get_polygon_count() >= 1) { + occluder_polygon->set_polygon(polygon_editor->get_polygon(0)); + } + return occluder_polygon; +} + +void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND(!tile_data); + + Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer); + polygon_editor->clear_polygons(); + if (occluder_polygon.is_valid()) { + polygon_editor->add_polygon(occluder_polygon->get_polygon()); + } + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); +} + +void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND(!tile_data); + Ref<OccluderPolygon2D> occluder_polygon = p_value; + tile_data->set_occluder(occlusion_layer, occluder_polygon); + + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); +} + +Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND_V(!tile_data, Variant()); + return tile_data->get_occluder(occlusion_layer); +} + +void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) { + for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) { + Vector2i coords = E->key().get_atlas_coords(); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, occlusion_layer), E->get()); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, occlusion_layer), p_new_value); + } +} + +void TileDataOcclusionShapeEditor::_tile_set_changed() { + polygon_editor->set_tile_set(tile_set); +} + +void TileDataOcclusionShapeEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color()); + break; + default: + break; + } +} + +TileDataOcclusionShapeEditor::TileDataOcclusionShapeEditor() { + polygon_editor = memnew(GenericTilePolygonEditor); + add_child(polygon_editor); +} + +void TileDataCollisionEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { + dummy_object->set(p_property, p_value); +} + +void TileDataCollisionEditor::_polygons_changed() { + // Update the dummy object properties and their editors. + for (int i = 0; i < polygon_editor->get_polygon_count(); i++) { + StringName one_way_property = vformat("polygon_%d_one_way", i); + StringName one_way_margin_property = vformat("polygon_%d_one_way_margin", i); + + if (!dummy_object->has_dummy_property(one_way_property)) { + dummy_object->add_dummy_property(one_way_property); + dummy_object->set(one_way_property, false); } + + if (!dummy_object->has_dummy_property(one_way_margin_property)) { + dummy_object->add_dummy_property(one_way_margin_property); + dummy_object->set(one_way_margin_property, 1.0); + } + + if (!property_editors.has(one_way_property)) { + EditorProperty *one_way_property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, Variant::BOOL, one_way_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); + one_way_property_editor->set_object_and_property(dummy_object, one_way_property); + one_way_property_editor->set_label(one_way_property); + one_way_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1)); + one_way_property_editor->update_property(); + add_child(one_way_property_editor); + property_editors[one_way_property] = one_way_property_editor; + } + + if (!property_editors.has(one_way_margin_property)) { + EditorProperty *one_way_margin_property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, Variant::FLOAT, one_way_margin_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); + one_way_margin_property_editor->set_object_and_property(dummy_object, one_way_margin_property); + one_way_margin_property_editor->set_label(one_way_margin_property); + one_way_margin_property_editor->connect("property_changed", callable_mp(this, &TileDataCollisionEditor::_property_value_changed).unbind(1)); + one_way_margin_property_editor->update_property(); + add_child(one_way_margin_property_editor); + property_editors[one_way_margin_property] = one_way_margin_property_editor; + } + } + + // Remove uneeded properties and their editors. + for (int i = polygon_editor->get_polygon_count(); dummy_object->has_dummy_property(vformat("polygon_%d_one_way", i)); i++) { + dummy_object->remove_dummy_property(vformat("polygon_%d_one_way", i)); + } + for (int i = polygon_editor->get_polygon_count(); dummy_object->has_dummy_property(vformat("polygon_%d_one_way_margin", i)); i++) { + dummy_object->remove_dummy_property(vformat("polygon_%d_one_way_margin", i)); + } + for (int i = polygon_editor->get_polygon_count(); property_editors.has(vformat("polygon_%d_one_way", i)); i++) { + property_editors[vformat("polygon_%d_one_way", i)]->queue_delete(); + property_editors.erase(vformat("polygon_%d_one_way", i)); } + for (int i = polygon_editor->get_polygon_count(); property_editors.has(vformat("polygon_%d_one_way_margin", i)); i++) { + property_editors[vformat("polygon_%d_one_way_margin", i)]->queue_delete(); + property_editors.erase(vformat("polygon_%d_one_way_margin", i)); + } +} + +Variant TileDataCollisionEditor::_get_painted_value() { + Array array; + for (int i = 0; i < polygon_editor->get_polygon_count(); i++) { + ERR_FAIL_COND_V(polygon_editor->get_polygon(i).size() < 3, Variant()); + Dictionary dict; + dict["points"] = polygon_editor->get_polygon(i); + dict["one_way"] = dummy_object->get(vformat("polygon_%d_one_way", i)); + dict["one_way_margin"] = dummy_object->get(vformat("polygon_%d_one_way_margin", i)); + array.push_back(dict); + } + + return array; } -void TileDataCollisionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); ERR_FAIL_COND(!tile_data); - Vector<String> components = String(p_property).split("/", true); - if (components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) { - int physics_layer = components[0].trim_prefix("physics_layer_").to_int(); - if (physics_layer >= 0 && physics_layer < p_tile_set->get_physics_layers_count()) { - // Draw all shapes. - Color debug_collision_color = p_canvas_item->get_tree()->get_debug_collisions_color(); - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); - for (int i = 0; i < tile_data->get_collision_shapes_count(physics_layer); i++) { - Ref<Shape2D> shape = tile_data->get_collision_shape_shape(physics_layer, i); - if (shape.is_valid()) { - shape->draw(p_canvas_item->get_canvas_item(), debug_collision_color); - } - } - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); + polygon_editor->clear_polygons(); + for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) { + Vector<Vector2> polygon = tile_data->get_collision_polygon_points(physics_layer, i); + if (polygon.size() >= 3) { + polygon_editor->add_polygon(polygon); } } + + _polygons_changed(); + for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) { + dummy_object->set(vformat("polygon_%d_one_way", i), tile_data->is_collision_polygon_one_way(physics_layer, i)); + dummy_object->set(vformat("polygon_%d_one_way_margin", i), tile_data->get_collision_polygon_one_way_margin(physics_layer, i)); + } + for (Map<StringName, EditorProperty *>::Element *E = property_editors.front(); E; E = E->next()) { + E->get()->update_property(); + } + + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); } -void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); ERR_FAIL_COND(!tile_data); - Vector<String> components = String(p_property).split("/", true); - if (components[0] == "terrain_mode" || components[0] == "terrain" || components[0] == "terrains_peering_bit") { - TileSetPluginAtlasTerrain::draw_terrains(p_canvas_item, p_transform, p_tile_set, tile_data); + Array array = p_value; + tile_data->set_collision_polygons_count(physics_layer, array.size()); + for (int i = 0; i < array.size(); i++) { + Dictionary dict = array[i]; + tile_data->set_collision_polygon_points(physics_layer, i, dict["points"]); + tile_data->set_collision_polygon_one_way(physics_layer, i, dict["one_way"]); + tile_data->set_collision_polygon_one_way_margin(physics_layer, i, dict["one_way_margin"]); + } + + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); +} + +Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND_V(!tile_data, Variant()); + + Array array; + for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) { + Dictionary dict; + dict["points"] = tile_data->get_collision_polygon_points(physics_layer, i); + dict["one_way"] = tile_data->is_collision_polygon_one_way(physics_layer, i); + dict["one_way_margin"] = tile_data->get_collision_polygon_one_way_margin(physics_layer, i); + array.push_back(dict); + } + return array; +} + +void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) { + Array new_array = p_new_value; + for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) { + Array old_array = E->get(); + + Vector2i coords = E->key().get_atlas_coords(); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E->key().alternative_tile, physics_layer), old_array.size()); + for (int i = 0; i < old_array.size(); i++) { + Dictionary dict = old_array[i]; + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["points"]); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way"]); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way_margin"]); + } + + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E->key().alternative_tile, physics_layer), new_array.size()); + for (int i = 0; i < new_array.size(); i++) { + Dictionary dict = new_array[i]; + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["points"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E->key().alternative_tile, physics_layer, i), dict["one_way_margin"]); + } + } +} + +void TileDataCollisionEditor::_tile_set_changed() { + polygon_editor->set_tile_set(tile_set); + _polygons_changed(); +} + +void TileDataCollisionEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + polygon_editor->set_polygons_color(get_tree()->get_debug_collisions_color()); + break; + default: + break; } } -void TileDataNavigationPolygonEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) { - TileData *tile_data = _get_tile_data(p_tile_set, p_atlas_source_id, p_atlas_coords, p_alternative_tile); +TileDataCollisionEditor::TileDataCollisionEditor() { + polygon_editor = memnew(GenericTilePolygonEditor); + polygon_editor->set_multiple_polygon_mode(true); + polygon_editor->connect("polygons_changed", callable_mp(this, &TileDataCollisionEditor::_polygons_changed)); + add_child(polygon_editor); + + _polygons_changed(); +} + +TileDataCollisionEditor::~TileDataCollisionEditor() { + memdelete(dummy_object); +} + +void TileDataCollisionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); ERR_FAIL_COND(!tile_data); - Vector<String> components = String(p_property).split("/", true); - if (components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) { - int navigation_layer = components[0].trim_prefix("navigation_layer_").to_int(); - if (navigation_layer >= 0 && navigation_layer < p_tile_set->get_navigation_layers_count()) { - // Draw all shapes. - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + // Draw all shapes. + Vector<Color> color; + if (p_selected) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + selection_color.a = 0.7; + color.push_back(selection_color); + } else { + Color debug_collision_color = p_canvas_item->get_tree()->get_debug_collisions_color(); + color.push_back(debug_collision_color); + } + + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) { + Vector<Vector2> polygon = tile_data->get_collision_polygon_points(physics_layer, i); + if (polygon.size() >= 3) { + p_canvas_item->draw_polygon(polygon, color); + } + } + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); +} + +void TileDataTerrainsEditor::_update_terrain_selector() { + ERR_FAIL_COND(!tile_set.is_valid()); + + // Update the terrain set selector. + Vector<String> options; + options.push_back(String(TTR("No terrains")) + String(":-1")); + for (int i = 0; i < tile_set->get_terrain_sets_count(); i++) { + options.push_back(vformat("Terrain Set %d", i)); + } + terrain_set_property_editor->setup(options); + terrain_set_property_editor->update_property(); + + // Update the terrain selector. + int terrain_set = int(dummy_object->get("terrain_set")); + if (terrain_set == -1) { + terrain_property_editor->hide(); + } else { + options.clear(); + Vector<Vector<Ref<Texture2D>>> icons = tile_set->generate_terrains_icons(Size2(16, 16) * EDSCALE); + options.push_back(String(TTR("No terrain")) + String(":-1")); + for (int i = 0; i < tile_set->get_terrains_count(terrain_set); i++) { + String name = tile_set->get_terrain_name(terrain_set, i); + if (name.is_empty()) { + options.push_back(vformat("Terrain %d", i)); + } else { + options.push_back(name); + } + } + terrain_property_editor->setup(options); + terrain_property_editor->update_property(); + + // Kind of a hack to set icons. + // We could provide a way to modify that in the EditorProperty. + OptionButton *option_button = Object::cast_to<OptionButton>(terrain_property_editor->get_child(0)); + for (int terrain = 0; terrain < tile_set->get_terrains_count(terrain_set); terrain++) { + option_button->set_item_icon(terrain + 1, icons[terrain_set][terrain]); + } + terrain_property_editor->show(); + } +} + +void TileDataTerrainsEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { + Variant old_value = dummy_object->get(p_property); + dummy_object->set(p_property, p_value); + if (p_property == "terrain_set") { + if (p_value != old_value) { + dummy_object->set("terrain", -1); + } + _update_terrain_selector(); + } + emit_signal("needs_redraw"); +} + +void TileDataTerrainsEditor::_tile_set_changed() { + ERR_FAIL_COND(!tile_set.is_valid()); + + // Fix if wrong values are selected. + if (int(dummy_object->get("terrain_set")) > tile_set->get_terrain_sets_count()) { + dummy_object->set("terrain_set", -1); + } + int terrain_set = int(dummy_object->get("terrain")); + if (terrain_set >= 0) { + if (int(dummy_object->get("terrain")) > tile_set->get_terrains_count(terrain_set)) { + dummy_object->set("terrain", -1); + } + } + + _update_terrain_selector(); +} + +void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) { + ERR_FAIL_COND(!tile_set.is_valid()); - Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer); - if (navigation_polygon.is_valid()) { - Vector<Vector2> verts = navigation_polygon->get_vertices(); - if (verts.size() < 3) { - return; + // Draw the hovered terrain bit, or the whole tile if it has the wrong terrain set. + Vector2i hovered_coords = TileSetSource::INVALID_ATLAS_COORDS; + if (drag_type == DRAG_TYPE_NONE) { + Vector2i mouse_pos = p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()); + hovered_coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_pos); + hovered_coords = p_tile_set_atlas_source->get_tile_at_coords(hovered_coords); + if (hovered_coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, 0)); + int terrain_set = tile_data->get_terrain_set(); + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(hovered_coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, 0); + + if (terrain_set >= 0 && terrain_set == int(dummy_object->get("terrain_set"))) { + // Draw hovered bit. + Transform2D xform; + xform.set_origin(position); + + Vector<Color> color; + color.push_back(Color(1.0, 1.0, 1.0, 0.5)); + + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) { + p_canvas_item->draw_set_transform_matrix(p_transform * xform); + p_canvas_item->draw_polygon(polygon, color); + } + } } + } else { + // Draw hovered tile. + Vector2i tile_size = tile_set->get_tile_size(); + Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size)); + tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true); + } + } + } + + // Dim terrains with wrong terrain set. + Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts"); + for (int i = 0; i < p_tile_set_atlas_source->get_tiles_count(); i++) { + Vector2i coords = p_tile_set_atlas_source->get_tile_id(i); + if (coords != hovered_coords) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + if (tile_data->get_terrain_set() != int(dummy_object->get("terrain_set"))) { + // Dimming + p_canvas_item->draw_set_transform_matrix(p_transform); + Rect2i rect = p_tile_set_atlas_source->get_tile_texture_region(coords); + p_canvas_item->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.3)); + + // Text + p_canvas_item->draw_set_transform_matrix(Transform2D()); + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + + Color color = Color(1, 1, 1); + String text; + if (tile_data->get_terrain_set() >= 0) { + text = vformat("%d", tile_data->get_terrain_set()); + } else { + text = "-"; + } + Vector2 string_size = font->get_string_size(text); + p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, -1, color, 1, Color(0, 0, 0, 1)); + } + } + } + p_canvas_item->draw_set_transform_matrix(Transform2D()); + + if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) { + // Draw selection rectangle. + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + + p_canvas_item->draw_set_transform_matrix(p_transform); - Color color = p_canvas_item->get_tree()->get_debug_navigation_color(); + Rect2i rect; + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()))); + rect = rect.abs(); - RandomPCG rand; - for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { - // An array of vertices for this polygon. - Vector<int> polygon = navigation_polygon->get_polygon(i); - Vector<Vector2> vertices; - vertices.resize(polygon.size()); + Set<TileMapCell> edited; + for (int x = rect.get_position().x; x <= rect.get_end().x; x++) { + for (int y = rect.get_position().y; y <= rect.get_end().y; y++) { + Vector2i coords = Vector2i(x, y); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + edited.insert(cell); + } + } + } + + for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) { + Vector2i coords = E->get().get_atlas_coords(); + p_canvas_item->draw_rect(p_tile_set_atlas_source->get_tile_texture_region(coords), selection_color, false); + } + p_canvas_item->draw_set_transform_matrix(Transform2D()); + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS_RECT) { + // Highlight selected peering bits. + Dictionary painted = Dictionary(drag_painted_value); + int terrain_set = int(painted["terrain_set"]); + + Rect2i rect; + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()))); + rect = rect.abs(); + + Set<TileMapCell> edited; + for (int x = rect.get_position().x; x <= rect.get_end().x; x++) { + for (int y = rect.get_position().y; y <= rect.get_end().y; y++) { + Vector2i coords = Vector2i(x, y); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + if (tile_data->get_terrain_set() == terrain_set) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + edited.insert(cell); + } + } + } + } + + Vector2 end = p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()); + Vector<Point2> mouse_pos_rect_polygon; + mouse_pos_rect_polygon.push_back(drag_start_pos); + mouse_pos_rect_polygon.push_back(Vector2(end.x, drag_start_pos.y)); + mouse_pos_rect_polygon.push_back(end); + mouse_pos_rect_polygon.push_back(Vector2(drag_start_pos.x, end.y)); + + Vector<Color> color; + color.push_back(Color(1.0, 1.0, 1.0, 0.5)); + + p_canvas_item->draw_set_transform_matrix(p_transform); + + for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) { + Vector2i coords = E->get().get_atlas_coords(); + + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); for (int j = 0; j < polygon.size(); j++) { - ERR_FAIL_INDEX(polygon[j], verts.size()); - vertices.write[j] = verts[polygon[j]]; + polygon.write[j] += position; + } + if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) { + // Draw bit. + p_canvas_item->draw_polygon(polygon, color); + } + } + } + } + + p_canvas_item->draw_set_transform_matrix(Transform2D()); + } +} + +void TileDataTerrainsEditor::forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) { + ERR_FAIL_COND(!tile_set.is_valid()); + + // Draw the hovered terrain bit, or the whole tile if it has the wrong terrain set. + Vector2i hovered_coords = TileSetSource::INVALID_ATLAS_COORDS; + int hovered_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE; + if (drag_type == DRAG_TYPE_NONE) { + Vector2i mouse_pos = p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()); + Vector3i hovered = p_tile_atlas_view->get_alternative_tile_at_pos(mouse_pos); + hovered_coords = Vector2i(hovered.x, hovered.y); + hovered_alternative = hovered.z; + if (hovered_coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(hovered_coords, hovered_alternative)); + int terrain_set = tile_data->get_terrain_set(); + Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(hovered_coords, hovered_alternative); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(hovered_coords, hovered_alternative); + + if (terrain_set == int(dummy_object->get("terrain_set"))) { + // Draw hovered bit. + Transform2D xform; + xform.set_origin(position); + + Vector<Color> color; + color.push_back(Color(1.0, 1.0, 1.0, 0.5)); + + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + if (Geometry2D::is_point_in_polygon(xform.affine_inverse().xform(mouse_pos), polygon)) { + p_canvas_item->draw_set_transform_matrix(p_transform * xform); + p_canvas_item->draw_polygon(polygon, color); + } + } + } + } else { + // Draw hovered tile. + Vector2i tile_size = tile_set->get_tile_size(); + Rect2i rect = p_transform.xform(Rect2i(position - tile_size / 2, tile_size)); + tile_set->draw_tile_shape(p_canvas_item, rect, Color(1.0, 1.0, 1.0, 0.5), true); + } + } + } + + // Dim terrains with wrong terrain set. + Ref<Font> font = TileSetEditor::get_singleton()->get_theme_font("bold", "EditorFonts"); + for (int i = 0; i < p_tile_set_atlas_source->get_tiles_count(); i++) { + Vector2i coords = p_tile_set_atlas_source->get_tile_id(i); + for (int j = 1; j < p_tile_set_atlas_source->get_alternative_tiles_count(coords); j++) { + int alternative_tile = p_tile_set_atlas_source->get_alternative_tile_id(coords, j); + if (coords != hovered_coords || alternative_tile != hovered_alternative) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile)); + if (tile_data->get_terrain_set() != int(dummy_object->get("terrain_set"))) { + // Dimming + p_canvas_item->draw_set_transform_matrix(p_transform); + Rect2i rect = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); + p_canvas_item->draw_rect(rect, Color(0.0, 0.0, 0.0, 0.3)); + + // Text + p_canvas_item->draw_set_transform_matrix(Transform2D()); + Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + + Color color = Color(1, 1, 1); + String text; + if (tile_data->get_terrain_set() >= 0) { + text = vformat("%d", tile_data->get_terrain_set()); + } else { + text = "-"; + } + Vector2 string_size = font->get_string_size(text); + p_canvas_item->draw_string(font, p_transform.xform(position) + Vector2i(-string_size.x / 2, string_size.y / 2), text, HALIGN_CENTER, string_size.x, -1, color, 1, Color(0, 0, 0, 1)); + } + } + } + } + + p_canvas_item->draw_set_transform_matrix(Transform2D()); +} + +void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) { + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { + Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position())); + for (int i = 0; i < line.size(); i++) { + Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + int terrain_set = drag_painted_value; + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + + // Save the old terrain_set and terrains bits. + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + if (!drag_modified.has(cell)) { + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + } + + // Set the terrain_set. + tile_data->set_terrain_set(terrain_set); + } + } + drag_last_pos = mm->get_position(); + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) { + int terrain_set = Dictionary(drag_painted_value)["terrain_set"]; + int terrain = Dictionary(drag_painted_value)["terrain"]; + Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position())); + for (int i = 0; i < line.size(); i++) { + Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + if (tile_data->get_terrain_set() == terrain_set) { + // Save the old terrain_set and terrains bits. + if (!drag_modified.has(cell)) { + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + } + + // Set the terrains bits. + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_data->is_valid_peering_bit_terrain(bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit); + if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) { + tile_data->set_peering_bit_terrain(bit, terrain); + } + } + } + } + } + } + drag_last_pos = mm->get_position(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (mb->is_pressed()) { + if (picker_button->is_pressed()) { + Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + int terrain_set = tile_data->get_terrain_set(); + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + dummy_object->set("terrain_set", terrain_set); + dummy_object->set("terrain", -1); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) { + dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit)); + } + } + } + terrain_set_property_editor->update_property(); + _update_terrain_selector(); + picker_button->set_pressed(false); + } + } else { + Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + TileData *tile_data = nullptr; + if (coords != TileSetAtlasSource::INVALID_ATLAS_COORDS) { + tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + } + int terrain_set = int(dummy_object->get("terrain_set")); + int terrain = int(dummy_object->get("terrain")); + if (terrain_set == -1 || !tile_data || tile_data->get_terrain_set() != terrain_set) { + if (mb->is_ctrl_pressed()) { + // Paint terrain set with rect. + drag_type = DRAG_TYPE_PAINT_TERRAIN_SET_RECT; + drag_modified.clear(); + drag_painted_value = terrain_set; + drag_start_pos = mb->get_position(); + } else { + // Paint terrain set. + drag_type = DRAG_TYPE_PAINT_TERRAIN_SET; + drag_modified.clear(); + drag_painted_value = terrain_set; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + + // Save the old terrain_set and terrains bits. + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + + // Set the terrain_set. + tile_data->set_terrain_set(terrain_set); + } + drag_last_pos = mb->get_position(); + } + } else if (tile_data && tile_data->get_terrain_set() == terrain_set) { + if (mb->is_ctrl_pressed()) { + // Paint terrain set with rect. + drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS_RECT; + drag_modified.clear(); + Dictionary painted_dict; + painted_dict["terrain_set"] = terrain_set; + painted_dict["terrain"] = terrain; + drag_painted_value = painted_dict; + drag_start_pos = mb->get_position(); + } else { + // Paint terrain bits. + drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS; + drag_modified.clear(); + Dictionary painted_dict; + painted_dict["terrain_set"] = terrain_set; + painted_dict["terrain"] = terrain; + drag_painted_value = painted_dict; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + + // Save the old terrain_set and terrains bits. + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + + // Set the terrain bit. + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) { + tile_data->set_peering_bit_terrain(bit, terrain); + } + } + } + } + drag_last_pos = mb->get_position(); + } + } + } + } else { + if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) { + Rect2i rect; + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position())); + rect = rect.abs(); + + Set<TileMapCell> edited; + for (int x = rect.get_position().x; x <= rect.get_end().x; x++) { + for (int y = rect.get_position().y; y <= rect.get_end().y; y++) { + Vector2i coords = Vector2i(x, y); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + edited.insert(cell); + } + } + } + undo_redo->create_action(TTR("Painting Terrain Set")); + for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) { + Vector2i coords = E->get().get_atlas_coords(); + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->get().alternative_tile), tile_data->get_terrain_set()); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->get().alternative_tile), drag_painted_value); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_data->is_valid_peering_bit_terrain(bit)) { + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->get().alternative_tile), tile_data->get_peering_bit_terrain(bit)); + } + } + } + undo_redo->commit_action(true); + drag_type = DRAG_TYPE_NONE; + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { + undo_redo->create_action(TTR("Painting Terrain Set")); + for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) { + Dictionary dict = E->get(); + Vector2i coords = E->key().get_atlas_coords(); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), drag_painted_value); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), dict["terrain_set"]); + Array array = dict["terrain_peering_bits"]; + for (int i = 0; i < array.size(); i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) { + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]); + } + } + } + undo_redo->commit_action(false); + drag_type = DRAG_TYPE_NONE; + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) { + Dictionary painted = Dictionary(drag_painted_value); + int terrain_set = int(painted["terrain_set"]); + int terrain = int(painted["terrain"]); + undo_redo->create_action(TTR("Painting Terrain")); + for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) { + Dictionary dict = E->get(); + Vector2i coords = E->key().get_atlas_coords(); + Array array = dict["terrain_peering_bits"]; + for (int i = 0; i < array.size(); i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), terrain); + } + if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) { + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]); + } + } + } + undo_redo->commit_action(false); + drag_type = DRAG_TYPE_NONE; + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS_RECT) { + Dictionary painted = Dictionary(drag_painted_value); + int terrain_set = int(painted["terrain_set"]); + int terrain = int(painted["terrain"]); + + Rect2i rect; + rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos)); + rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position())); + rect = rect.abs(); + + Set<TileMapCell> edited; + for (int x = rect.get_position().x; x <= rect.get_end().x; x++) { + for (int y = rect.get_position().y; y <= rect.get_end().y; y++) { + Vector2i coords = Vector2i(x, y); + coords = p_tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + if (tile_data->get_terrain_set() == terrain_set) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + edited.insert(cell); + } + } + } + } + + Vector<Point2> mouse_pos_rect_polygon; + mouse_pos_rect_polygon.push_back(drag_start_pos); + mouse_pos_rect_polygon.push_back(Vector2(mb->get_position().x, drag_start_pos.y)); + mouse_pos_rect_polygon.push_back(mb->get_position()); + mouse_pos_rect_polygon.push_back(Vector2(drag_start_pos.x, mb->get_position().y)); + + undo_redo->create_action(TTR("Painting Terrain")); + for (Set<TileMapCell>::Element *E = edited.front(); E; E = E->next()) { + Vector2i coords = E->get().get_atlas_coords(); + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, 0)); + + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Rect2i texture_region = p_tile_set_atlas_source->get_tile_texture_region(coords); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0); + + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + for (int j = 0; j < polygon.size(); j++) { + polygon.write[j] += position; + } + if (!Geometry2D::intersect_polygons(polygon, mouse_pos_rect_polygon).is_empty()) { + // Draw bit. + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->get().alternative_tile), terrain); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->get().alternative_tile), tile_data->get_peering_bit_terrain(bit)); + } + } + } + } + undo_redo->commit_action(true); + drag_type = DRAG_TYPE_NONE; + } + } + } + } +} + +void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_set_atlas_source, const Ref<InputEvent> &p_event) { + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mm->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile)); + if (!drag_modified.has(cell)) { + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + } + tile_data->set_terrain_set(drag_painted_value); + } + + drag_last_pos = mm->get_position(); + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) { + Dictionary painted = Dictionary(drag_painted_value); + int terrain_set = int(painted["terrain_set"]); + int terrain = int(painted["terrain"]); + + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mm->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + + // Save the old terrain_set and terrains bits. + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile)); + if (tile_data->get_terrain_set() == terrain_set) { + if (!drag_modified.has(cell)) { + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + } + + // Set the terrains bits. + Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + for (int j = 0; j < TileSet::CELL_NEIGHBOR_MAX; j++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(j); + if (tile_data->is_valid_peering_bit_terrain(bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(tile_data->get_terrain_set(), bit); + if (Geometry2D::is_segment_intersecting_polygon(mm->get_position() - position, drag_last_pos - position, polygon)) { + tile_data->set_peering_bit_terrain(bit, terrain); + } + } + } + } + } + drag_last_pos = mm->get_position(); + } + } + + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (mb->is_pressed()) { + if (picker_button->is_pressed()) { + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile)); + int terrain_set = tile_data->get_terrain_set(); + Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + dummy_object->set("terrain_set", terrain_set); + dummy_object->set("terrain", -1); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) { + dummy_object->set("terrain", tile_data->get_peering_bit_terrain(bit)); + } + } + } + terrain_set_property_editor->update_property(); + _update_terrain_selector(); + picker_button->set_pressed(false); } + } else { + int terrain_set = int(dummy_object->get("terrain_set")); + int terrain = int(dummy_object->get("terrain")); + + Vector3i tile = p_tile_atlas_view->get_alternative_tile_at_pos(mb->get_position()); + Vector2i coords = Vector2i(tile.x, tile.y); + int alternative_tile = tile.z; - // Generate the polygon color, slightly randomly modified from the settings one. - Color random_variation_color; - random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1); - random_variation_color.a = color.a; - Vector<Color> colors; - colors.push_back(random_variation_color); + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(coords, alternative_tile)); - RenderingServer::get_singleton()->canvas_item_add_polygon(p_canvas_item->get_canvas_item(), vertices, colors); + if (terrain_set == -1 || !tile_data || tile_data->get_terrain_set() != terrain_set) { + drag_type = DRAG_TYPE_PAINT_TERRAIN_SET; + drag_modified.clear(); + drag_painted_value = int(dummy_object->get("terrain_set")); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + tile_data->set_terrain_set(drag_painted_value); + } + drag_last_pos = mb->get_position(); + } else if (tile_data && tile_data->get_terrain_set() == terrain_set) { + // Paint terrain bits. + drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS; + drag_modified.clear(); + Dictionary painted_dict; + painted_dict["terrain_set"] = terrain_set; + painted_dict["terrain"] = terrain; + drag_painted_value = painted_dict; + + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + TileMapCell cell; + cell.source_id = 0; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + + // Save the old terrain_set and terrains bits. + Dictionary dict; + dict["terrain_set"] = tile_data->get_terrain_set(); + Array array; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + array.push_back(tile_data->is_valid_peering_bit_terrain(bit) ? tile_data->get_peering_bit_terrain(bit) : -1); + } + dict["terrain_peering_bits"] = array; + drag_modified[cell] = dict; + + // Set the terrain bit. + Rect2i texture_region = p_tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + p_tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative_tile); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + Vector<Vector2> polygon = tile_set->get_terrain_bit_polygon(terrain_set, bit); + if (Geometry2D::is_point_in_polygon(mb->get_position() - position, polygon)) { + tile_data->set_peering_bit_terrain(bit, terrain); + } + } + } + } + drag_last_pos = mb->get_position(); + } + } + } else { + if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) { + undo_redo->create_action(TTR("Painting Tiles Property")); + for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) { + Dictionary dict = E->get(); + Vector2i coords = E->key().get_atlas_coords(); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), dict["terrain_set"]); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrain_set", coords.x, coords.y, E->key().alternative_tile), drag_painted_value); + Array array = dict["terrain_peering_bits"]; + for (int i = 0; i < array.size(); i++) { + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]); + } + } + undo_redo->commit_action(false); + drag_type = DRAG_TYPE_NONE; + } else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) { + Dictionary painted = Dictionary(drag_painted_value); + int terrain_set = int(painted["terrain_set"]); + int terrain = int(painted["terrain"]); + undo_redo->create_action(TTR("Painting Terrain")); + for (Map<TileMapCell, Variant>::Element *E = drag_modified.front(); E; E = E->next()) { + Dictionary dict = E->get(); + Vector2i coords = E->key().get_atlas_coords(); + Array array = dict["terrain_peering_bits"]; + for (int i = 0; i < array.size(); i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(terrain_set, bit)) { + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), terrain); + } + if (tile_set->is_valid_peering_bit_terrain(dict["terrain_set"], bit)) { + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]), coords.x, coords.y, E->key().alternative_tile), array[i]); + } + } + } + undo_redo->commit_action(false); + drag_type = DRAG_TYPE_NONE; } } + } + } +} + +void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); + ERR_FAIL_COND(!tile_data); - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); + tile_set->draw_terrains(p_canvas_item, p_transform, tile_data); +} + +void TileDataTerrainsEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: + picker_button->set_icon(get_theme_icon("ColorPick", "EditorIcons")); + break; + default: + break; + } +} + +TileDataTerrainsEditor::TileDataTerrainsEditor() { + label = memnew(Label); + label->set_text("Painting:"); + add_child(label); + + // Toolbar + toolbar->add_child(memnew(VSeparator)); + + picker_button = memnew(Button); + picker_button->set_flat(true); + picker_button->set_toggle_mode(true); + picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", "Picker", KEY_P)); + toolbar->add_child(picker_button); + + // Setup + dummy_object->add_dummy_property("terrain_set"); + dummy_object->set("terrain_set", -1); + dummy_object->add_dummy_property("terrain"); + dummy_object->set("terrain", -1); + + // Get the default value for the type. + terrain_set_property_editor = memnew(EditorPropertyEnum); + terrain_set_property_editor->set_object_and_property(dummy_object, "terrain_set"); + terrain_set_property_editor->set_label("Terrain Set"); + terrain_set_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1)); + add_child(terrain_set_property_editor); + + terrain_property_editor = memnew(EditorPropertyEnum); + terrain_property_editor->set_object_and_property(dummy_object, "terrain"); + terrain_property_editor->set_label("Terrain"); + terrain_property_editor->connect("property_changed", callable_mp(this, &TileDataTerrainsEditor::_property_value_changed).unbind(1)); + add_child(terrain_property_editor); +} + +TileDataTerrainsEditor::~TileDataTerrainsEditor() { + toolbar->queue_delete(); + memdelete(dummy_object); +} + +Variant TileDataNavigationEditor::_get_painted_value() { + Ref<NavigationPolygon> navigation_polygon; + navigation_polygon.instantiate(); + + for (int i = 0; i < polygon_editor->get_polygon_count(); i++) { + Vector<Vector2> polygon = polygon_editor->get_polygon(i); + navigation_polygon->add_outline(polygon); + } + + navigation_polygon->make_polygons_from_outlines(); + return navigation_polygon; +} + +void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND(!tile_data); + + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer); + polygon_editor->clear_polygons(); + if (navigation_polygon.is_valid()) { + for (int i = 0; i < navigation_polygon->get_outline_count(); i++) { + polygon_editor->add_polygon(navigation_polygon->get_outline(i)); + } + } + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); +} + +void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND(!tile_data); + Ref<NavigationPolygon> navigation_polygon = p_value; + tile_data->set_navigation_polygon(navigation_layer, navigation_polygon); + + polygon_editor->set_background(p_tile_set_atlas_source->get_texture(), p_tile_set_atlas_source->get_tile_texture_region(p_coords), p_tile_set_atlas_source->get_tile_effective_texture_offset(p_coords, p_alternative_tile), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate()); +} + +Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) { + TileData *tile_data = Object::cast_to<TileData>(p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile)); + ERR_FAIL_COND_V(!tile_data, Variant()); + return tile_data->get_navigation_polygon(navigation_layer); +} + +void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) { + for (Map<TileMapCell, Variant>::Element *E = p_previous_values.front(); E; E = E->next()) { + Vector2i coords = E->key().get_atlas_coords(); + undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, navigation_layer), E->get()); + undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E->key().alternative_tile, navigation_layer), p_new_value); + } +} + +void TileDataNavigationEditor::_tile_set_changed() { + polygon_editor->set_tile_set(tile_set); +} + +void TileDataNavigationEditor::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + polygon_editor->set_polygons_color(get_tree()->get_debug_navigation_color()); + break; + default: + break; + } +} + +TileDataNavigationEditor::TileDataNavigationEditor() { + polygon_editor = memnew(GenericTilePolygonEditor); + polygon_editor->set_multiple_polygon_mode(true); + add_child(polygon_editor); +} + +void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) { + TileData *tile_data = _get_tile_data(p_cell); + ERR_FAIL_COND(!tile_data); + + // Draw all shapes. + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + + Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(navigation_layer); + if (navigation_polygon.is_valid()) { + Vector<Vector2> verts = navigation_polygon->get_vertices(); + if (verts.size() < 3) { + return; + } + + Color color = p_canvas_item->get_tree()->get_debug_navigation_color(); + if (p_selected) { + Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color"); + Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); + selection_color.a = 0.7; + color = selection_color; + } + + RandomPCG rand; + for (int i = 0; i < navigation_polygon->get_polygon_count(); i++) { + // An array of vertices for this polygon. + Vector<int> polygon = navigation_polygon->get_polygon(i); + Vector<Vector2> vertices; + vertices.resize(polygon.size()); + for (int j = 0; j < polygon.size(); j++) { + ERR_FAIL_INDEX(polygon[j], verts.size()); + vertices.write[j] = verts[polygon[j]]; + } + + // Generate the polygon color, slightly randomly modified from the settings one. + Color random_variation_color; + random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1); + random_variation_color.a = color.a; + Vector<Color> colors; + colors.push_back(random_variation_color); + + RenderingServer::get_singleton()->canvas_item_add_polygon(p_canvas_item->get_canvas_item(), vertices, colors); } } + + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); } diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index b82189e1ee..781f26cc02 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -31,87 +31,378 @@ #ifndef TILE_DATA_EDITORS_H #define TILE_DATA_EDITORS_H +#include "tile_atlas_view.h" + +#include "editor/editor_node.h" +#include "editor/editor_properties.h" + +#include "scene/gui/box_container.h" #include "scene/gui/control.h" +#include "scene/gui/label.h" #include "scene/resources/tile_set.h" -class TileDataEditor : public Control { - GDCLASS(TileDataEditor, Control); +class TileDataEditor : public VBoxContainer { + GDCLASS(TileDataEditor, VBoxContainer); + +private: + void _call_tile_set_changed(); protected: - TileData *tile_data; - String property; + Ref<TileSet> tile_set; + TileData *_get_tile_data(TileMapCell p_cell); + virtual void _tile_set_changed(){}; - TileData *_get_tile_data(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile); + static void _bind_methods(); public: - // Edits a TileData property. - void edit(TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property); + void set_tile_set(Ref<TileSet> p_tile_set); + + // Input to handle painting. + virtual Control *get_toolbar() { return nullptr; }; + virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){}; + virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform){}; + virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event){}; + virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event){}; - // Used to draw the value over a tile. - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property){}; + // Used to draw the tile data property value over a tile. + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false){}; }; -class TileDataTextureOffsetEditor : public TileDataEditor { - GDCLASS(TileDataTextureOffsetEditor, TileDataEditor); +class DummyObject : public Object { + GDCLASS(DummyObject, Object) +private: + Map<String, Variant> properties; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + bool has_dummy_property(StringName p_name); + void add_dummy_property(StringName p_name); + void remove_dummy_property(StringName p_name); + void clear_dummy_properties(); }; -class TileDataIntegerEditor : public TileDataEditor { - GDCLASS(TileDataIntegerEditor, TileDataEditor); +class GenericTilePolygonEditor : public VBoxContainer { + GDCLASS(GenericTilePolygonEditor, VBoxContainer); + +private: + Ref<TileSet> tile_set; + LocalVector<Vector<Point2>> polygons; + bool multiple_polygon_mode = false; + + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + // UI + int hovered_polygon_index = -1; + int hovered_point_index = -1; + int hovered_segment_index = -1; + Vector2 hovered_segment_point; + + enum DragType { + DRAG_TYPE_NONE, + DRAG_TYPE_DRAG_POINT, + DRAG_TYPE_CREATE_POINT, + DRAG_TYPE_PAN, + }; + DragType drag_type; + int drag_polygon_index; + int drag_point_index; + Vector2 drag_last_pos; + PackedVector2Array drag_old_polygon; + + HBoxContainer *toolbar; + Ref<ButtonGroup> tools_button_group; + Button *button_create; + Button *button_edit; + Button *button_delete; + Button *button_pixel_snap; + MenuButton *button_advanced_menu; + + Vector<Point2> in_creation_polygon; + + Panel *panel; + Control *base_control; + EditorZoomWidget *editor_zoom_widget; + Button *button_center_view; + Vector2 panning; + + Ref<Texture2D> background_texture; + Rect2 background_region; + Vector2 background_offset; + bool background_h_flip; + bool background_v_flip; + bool background_transpose; + Color background_modulate; + + Color polygon_color = Color(1.0, 0.0, 0.0); + + enum AdvancedMenuOption { + RESET_TO_DEFAULT_TILE, + CLEAR_TILE, + }; + + void _base_control_draw(); + void _zoom_changed(); + void _advanced_menu_item_pressed(int p_item_pressed); + void _center_view(); + void _base_control_gui_input(Ref<InputEvent> p_event); + + void _snap_to_tile_shape(Point2 &r_point, float &r_current_snapped_dist, float p_snap_dist); + void _snap_to_half_pixel(Point2 &r_point); + void _grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index); + void _grab_polygon_segment_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_segment_index, Vector2 &r_point); + +protected: + void _notification(int p_what); + static void _bind_methods(); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + void set_tile_set(Ref<TileSet> p_tile_set); + void set_background(Ref<Texture2D> p_texture, Rect2 p_region = Rect2(), Vector2 p_offset = Vector2(), bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false, Color p_modulate = Color(1.0, 1.0, 1.0, 0.0)); + + int get_polygon_count(); + int add_polygon(Vector<Point2> p_polygon, int p_index = -1); + void remove_polygon(int p_index); + void clear_polygons(); + void set_polygon(int p_polygon_index, Vector<Point2> p_polygon); + Vector<Point2> get_polygon(int p_polygon_index); + + void set_polygons_color(Color p_color); + void set_multiple_polygon_mode(bool p_multiple_polygon_mode); + + GenericTilePolygonEditor(); }; -class TileDataFloatEditor : public TileDataEditor { - GDCLASS(TileDataFloatEditor, TileDataEditor); +class TileDataDefaultEditor : public TileDataEditor { + GDCLASS(TileDataDefaultEditor, TileDataEditor); + +private: + // Toolbar + HBoxContainer *toolbar = memnew(HBoxContainer); + Button *picker_button; + + // UI + Ref<Texture2D> tile_bool_checked; + Ref<Texture2D> tile_bool_unchecked; + Label *label; + + EditorProperty *property_editor = nullptr; + + // Painting state. + enum DragType { + DRAG_TYPE_NONE = 0, + DRAG_TYPE_PAINT, + DRAG_TYPE_PAINT_RECT, + }; + DragType drag_type = DRAG_TYPE_NONE; + Vector2 drag_start_pos; + Vector2 drag_last_pos; + Map<TileMapCell, Variant> drag_modified; + Variant drag_painted_value; + + void _property_value_changed(StringName p_property, Variant p_value, StringName p_field); + +protected: + DummyObject *dummy_object = memnew(DummyObject); + + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + StringName type; + String property; + void _notification(int p_what); + + virtual Variant _get_painted_value(); + virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile); + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value); + virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile); + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual Control *get_toolbar() override { return toolbar; }; + virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override; + virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override; + virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override; + virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; + + void setup_property_editor(Variant::Type p_type, String p_property, String p_label = "", Variant p_default_value = Variant()); + + TileDataDefaultEditor(); + ~TileDataDefaultEditor(); }; -class TileDataPositionEditor : public TileDataEditor { - GDCLASS(TileDataPositionEditor, TileDataEditor); +class TileDataTextureOffsetEditor : public TileDataDefaultEditor { + GDCLASS(TileDataTextureOffsetEditor, TileDataDefaultEditor); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; }; -class TileDataYSortEditor : public TileDataEditor { - GDCLASS(TileDataYSortEditor, TileDataEditor); +class TileDataPositionEditor : public TileDataDefaultEditor { + GDCLASS(TileDataPositionEditor, TileDataDefaultEditor); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; }; -class TileDataOcclusionShapeEditor : public TileDataEditor { - GDCLASS(TileDataOcclusionShapeEditor, TileDataEditor); +class TileDataYSortEditor : public TileDataDefaultEditor { + GDCLASS(TileDataYSortEditor, TileDataDefaultEditor); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; }; -class TileDataCollisionShapeEditor : public TileDataEditor { - GDCLASS(TileDataCollisionShapeEditor, TileDataEditor); +class TileDataOcclusionShapeEditor : public TileDataDefaultEditor { + GDCLASS(TileDataOcclusionShapeEditor, TileDataDefaultEditor); + +private: + int occlusion_layer = -1; + + // UI + GenericTilePolygonEditor *polygon_editor; + + void _polygon_changed(PackedVector2Array p_polygon); + + virtual Variant _get_painted_value() override; + virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; + virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override; + +protected: + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + virtual void _tile_set_changed() override; + + void _notification(int p_what); + +public: + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; + + void set_occlusion_layer(int p_occlusion_layer) { occlusion_layer = p_occlusion_layer; } + + TileDataOcclusionShapeEditor(); +}; + +class TileDataCollisionEditor : public TileDataDefaultEditor { + GDCLASS(TileDataCollisionEditor, TileDataDefaultEditor); + + int physics_layer = -1; + + // UI + GenericTilePolygonEditor *polygon_editor; + DummyObject *dummy_object = memnew(DummyObject); + Map<StringName, EditorProperty *> property_editors; + + void _property_value_changed(StringName p_property, Variant p_value, StringName p_field); + void _polygons_changed(); + + virtual Variant _get_painted_value() override; + virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; + virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override; + +protected: + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + virtual void _tile_set_changed() override; + + void _notification(int p_what); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; + + void set_physics_layer(int p_physics_layer) { physics_layer = p_physics_layer; } + + TileDataCollisionEditor(); + ~TileDataCollisionEditor(); }; class TileDataTerrainsEditor : public TileDataEditor { GDCLASS(TileDataTerrainsEditor, TileDataEditor); +private: + // Toolbar + HBoxContainer *toolbar = memnew(HBoxContainer); + Button *picker_button; + + // Painting state. + enum DragType { + DRAG_TYPE_NONE = 0, + DRAG_TYPE_PAINT_TERRAIN_SET, + DRAG_TYPE_PAINT_TERRAIN_SET_RECT, + DRAG_TYPE_PAINT_TERRAIN_BITS, + DRAG_TYPE_PAINT_TERRAIN_BITS_RECT, + }; + DragType drag_type = DRAG_TYPE_NONE; + Vector2 drag_start_pos; + Vector2 drag_last_pos; + Map<TileMapCell, Variant> drag_modified; + Variant drag_painted_value; + + // UI + Label *label; + DummyObject *dummy_object = memnew(DummyObject); + EditorPropertyEnum *terrain_set_property_editor = nullptr; + EditorPropertyEnum *terrain_property_editor = nullptr; + + void _property_value_changed(StringName p_property, Variant p_value, StringName p_field); + + void _update_terrain_selector(); + +protected: + virtual void _tile_set_changed() override; + + void _notification(int p_what); + + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual Control *get_toolbar() override { return toolbar; }; + virtual void forward_draw_over_atlas(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override; + virtual void forward_draw_over_alternatives(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, CanvasItem *p_canvas_item, Transform2D p_transform) override; + virtual void forward_painting_atlas_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override; + virtual void forward_painting_alternatives_gui_input(TileAtlasView *p_tile_atlas_view, TileSetAtlasSource *p_tile_atlas_source, const Ref<InputEvent> &p_event) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; + + TileDataTerrainsEditor(); + ~TileDataTerrainsEditor(); }; -class TileDataNavigationPolygonEditor : public TileDataEditor { - GDCLASS(TileDataNavigationPolygonEditor, TileDataEditor); +class TileDataNavigationEditor : public TileDataDefaultEditor { + GDCLASS(TileDataNavigationEditor, TileDataDefaultEditor); + +private: + int navigation_layer = -1; + PackedVector2Array navigation_polygon; + + // UI + GenericTilePolygonEditor *polygon_editor; + + void _polygon_changed(PackedVector2Array p_polygon); + + virtual Variant _get_painted_value() override; + virtual void _set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; + virtual void _set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) override; + virtual Variant _get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) override; + virtual void _setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, Map<TileMapCell, Variant> p_previous_values, Variant p_new_value) override; + +protected: + UndoRedo *undo_redo = EditorNode::get_undo_redo(); + + virtual void _tile_set_changed() override; + + void _notification(int p_what); public: - virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, String p_property) override; + virtual void draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected = false) override; + + void set_navigation_layer(int p_navigation_layer) { navigation_layer = p_navigation_layer; } + + TileDataNavigationEditor(); }; #endif // TILE_DATA_EDITORS_H diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index ef13d8ea12..86bd115ac2 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -1756,7 +1756,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer); - tool_buttons_group.instance(); + tool_buttons_group.instantiate(); select_tool_button = memnew(Button); select_tool_button->set_flat(true); @@ -2989,6 +2989,7 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() { } // Fill in the terrain list. + Vector<Vector<Ref<Texture2D>>> icons = tile_set->generate_terrains_icons(Size2(16, 16) * EDSCALE); for (int terrain_set_index = 0; terrain_set_index < tile_set->get_terrain_sets_count(); terrain_set_index++) { // Add an item for the terrain set. TreeItem *terrain_set_tree_item = terrains_tree->create_item(); @@ -3007,58 +3008,12 @@ void TileMapEditorTerrainsPlugin::_update_terrains_tree() { terrain_set_tree_item->set_selectable(0, false); for (int terrain_index = 0; terrain_index < tile_set->get_terrains_count(terrain_set_index); terrain_index++) { - // Compute the terrains_tile_pattern used for terrain preview (whenever possible). - TerrainsTilePattern terrains_tile_pattern; - int max_bit_count = -1; - for (Set<TerrainsTilePattern>::Element *E = per_terrain_terrains_tile_patterns[terrain_set_index][terrain_index].front(); E; E = E->next()) { - int count = 0; - for (int i = 0; i < E->get().size(); i++) { - if (int(E->get()[i]) == terrain_index) { - count++; - } - } - if (count > max_bit_count) { - terrains_tile_pattern = E->get(); - max_bit_count = count; - } - } - - // Get the preview. - Ref<Texture2D> icon; - Rect2 region; - if (max_bit_count >= 0) { - double max_probability = -1.0; - for (Set<TileMapCell>::Element *E = per_terrain_terrains_tile_patterns_tiles[terrain_set_index][terrains_tile_pattern].front(); E; E = E->next()) { - Ref<TileSetSource> source = tile_set->get_source(E->get().source_id); - - Ref<TileSetAtlasSource> atlas_source = source; - if (atlas_source.is_valid()) { - TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(E->get().get_atlas_coords(), E->get().alternative_tile)); - if (tile_data->get_probability() > max_probability) { - icon = atlas_source->get_texture(); - region = atlas_source->get_tile_texture_region(E->get().get_atlas_coords()); - max_probability = tile_data->get_probability(); - } - } - } - } else { - Ref<Image> image; - image.instance(); - image->create(1, 1, false, Image::FORMAT_RGBA8); - image->set_pixel(0, 0, tile_set->get_terrain_color(terrain_set_index, terrain_index)); - Ref<ImageTexture> image_texture; - image_texture.instance(); - image_texture->create_from_image(image); - image_texture->set_size_override(Size2(32, 32) * EDSCALE); - icon = image_texture; - } - // Add the item to the terrain list. TreeItem *terrain_tree_item = terrains_tree->create_item(terrain_set_tree_item); terrain_tree_item->set_text(0, tile_set->get_terrain_name(terrain_set_index, terrain_index)); terrain_tree_item->set_icon_max_width(0, 32 * EDSCALE); - terrain_tree_item->set_icon(0, icon); - terrain_tree_item->set_icon_region(0, region); + terrain_tree_item->set_icon(0, icons[terrain_set_index][terrain_index]); + Dictionary metadata_dict; metadata_dict["terrain_set"] = terrain_set_index; metadata_dict["terrain_id"] = terrain_index; @@ -3188,7 +3143,7 @@ TileMapEditorTerrainsPlugin::TileMapEditorTerrainsPlugin() { HBoxContainer *tilemap_tiles_tools_buttons = memnew(HBoxContainer); - tool_buttons_group.instance(); + tool_buttons_group.instantiate(); paint_tool_button = memnew(Button); paint_tool_button->set_flat(true); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 8e7d613027..9d849a0df5 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -357,6 +357,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_bind_methods() { void TileSetAtlasSourceEditor::_inspector_property_selected(String p_property) { selected_property = p_property; _update_atlas_view(); + _update_current_tile_data_editor(); } void TileSetAtlasSourceEditor::_update_tile_id_label() { @@ -398,17 +399,315 @@ void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() { } } +void TileSetAtlasSourceEditor::_update_atlas_source_inspector() { + // Update visibility. + bool visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button; + atlas_source_inspector_label->set_visible(visible); + atlas_source_inspector->set_visible(visible); +} + void TileSetAtlasSourceEditor::_update_tile_inspector() { - bool has_atlas_tile_selected = (tools_button_group->get_pressed_button() == tool_select_button) && !selection.is_empty(); + // Update visibility. + if (tools_button_group->get_pressed_button() == tool_select_button) { + if (!selection.is_empty()) { + tile_proxy_object->edit(tile_set_atlas_source, selection); + } + tile_inspector_label->show(); + tile_inspector->set_visible(!selection.is_empty()); + tile_inspector_no_tile_selected_label->set_visible(selection.is_empty()); + } else { + tile_inspector_label->hide(); + tile_inspector->hide(); + tile_inspector_no_tile_selected_label->hide(); + } +} - // Update the proxy object. - if (has_atlas_tile_selected) { - tile_proxy_object->edit(tile_set_atlas_source, selection); +void TileSetAtlasSourceEditor::_update_tile_data_editors() { + String previously_selected; + if (tile_data_editors_tree && tile_data_editors_tree->get_selected()) { + previously_selected = tile_data_editors_tree->get_selected()->get_metadata(0); + } + + tile_data_editors_tree->clear(); + + TreeItem *root = tile_data_editors_tree->create_item(); + + TreeItem *group; +#define ADD_TILE_DATA_EDITOR_GROUP(text) \ + group = tile_data_editors_tree->create_item(root); \ + group->set_custom_bg_color(0, group_color); \ + group->set_selectable(0, false); \ + group->set_disable_folding(true); \ + group->set_text(0, text); + + TreeItem *item; +#define ADD_TILE_DATA_EDITOR(parent, text, property) \ + item = tile_data_editors_tree->create_item(parent); \ + item->set_text(0, text); \ + item->set_metadata(0, property); \ + if (property == previously_selected) { \ + item->select(0); \ + } + + // Theming. + tile_data_editors_tree->add_theme_constant_override("vseparation", 1); + tile_data_editors_tree->add_theme_constant_override("hseparation", 3); + + Color group_color = get_theme_color("prop_category", "Editor"); + + // List of editors. + // --- Rendering --- + ADD_TILE_DATA_EDITOR_GROUP("Rendering"); + + ADD_TILE_DATA_EDITOR(group, "Texture Offset", "texture_offset"); + if (!tile_data_editors.has("texture_offset")) { + TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor); + tile_data_texture_offset_editor->hide(); + tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset"); + tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors["texture_offset"] = tile_data_texture_offset_editor; + } + + ADD_TILE_DATA_EDITOR(group, "Modulate", "modulate"); + if (!tile_data_editors.has("modulate")) { + TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor()); + tile_data_modulate_editor->hide(); + tile_data_modulate_editor->setup_property_editor(Variant::COLOR, "modulate", "", Color(1.0, 1.0, 1.0, 1.0)); + tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors["modulate"] = tile_data_modulate_editor; + } + + ADD_TILE_DATA_EDITOR(group, "Z Index", "z_index"); + if (!tile_data_editors.has("z_index")) { + TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor()); + tile_data_z_index_editor->hide(); + tile_data_z_index_editor->setup_property_editor(Variant::INT, "z_index"); + tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors["z_index"] = tile_data_z_index_editor; + } + + ADD_TILE_DATA_EDITOR(group, "Y Sort Origin", "y_sort_origin"); + if (!tile_data_editors.has("y_sort_origin")) { + TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor); + tile_data_y_sort_editor->hide(); + tile_data_y_sort_editor->setup_property_editor(Variant::INT, "y_sort_origin"); + tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors["y_sort_origin"] = tile_data_y_sort_editor; + } + + for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) { + ADD_TILE_DATA_EDITOR(group, vformat("Occlusion Layer %d", i), vformat("occlusion_layer_%d", i)); + if (!tile_data_editors.has(vformat("occlusion_layer_%d", i))) { + TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor()); + tile_data_occlusion_shape_editor->hide(); + tile_data_occlusion_shape_editor->set_occlusion_layer(i); + tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors[vformat("occlusion_layer_%d", i)] = tile_data_occlusion_shape_editor; + } + } + for (int i = tile_set->get_occlusion_layers_count(); tile_data_editors.has(vformat("occlusion_layer_%d", i)); i++) { + tile_data_editors[vformat("occlusion_layer_%d", i)]->queue_delete(); + tile_data_editors.erase(vformat("occlusion_layer_%d", i)); + } + + // --- Rendering --- + ADD_TILE_DATA_EDITOR(root, "Terrains", "terrain_set"); + if (!tile_data_editors.has("terrain_set")) { + TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor); + tile_data_terrains_editor->hide(); + tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors["terrain_set"] = tile_data_terrains_editor; + } + + // --- Miscellaneous --- + ADD_TILE_DATA_EDITOR(root, "Probability", "probability"); + if (!tile_data_editors.has("probability")) { + TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor()); + tile_data_probability_editor->hide(); + tile_data_probability_editor->setup_property_editor(Variant::FLOAT, "probability", "", 1.0); + tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors["probability"] = tile_data_probability_editor; + } + + // --- Physics --- + ADD_TILE_DATA_EDITOR_GROUP("Physics"); + for (int i = 0; i < tile_set->get_physics_layers_count(); i++) { + ADD_TILE_DATA_EDITOR(group, vformat("Physics Layer %d", i), vformat("physics_layer_%d", i)); + if (!tile_data_editors.has(vformat("physics_layer_%d", i))) { + TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor()); + tile_data_collision_editor->hide(); + tile_data_collision_editor->set_physics_layer(i); + tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors[vformat("physics_layer_%d", i)] = tile_data_collision_editor; + } + } + for (int i = tile_set->get_physics_layers_count(); tile_data_editors.has(vformat("physics_layer_%d", i)); i++) { + tile_data_editors[vformat("physics_layer_%d", i)]->queue_delete(); + tile_data_editors.erase(vformat("physics_layer_%d", i)); + } + + // --- Navigation --- + ADD_TILE_DATA_EDITOR_GROUP("Navigation"); + for (int i = 0; i < tile_set->get_navigation_layers_count(); i++) { + ADD_TILE_DATA_EDITOR(group, vformat("Navigation Layer %d", i), vformat("navigation_layer_%d", i)); + if (!tile_data_editors.has(vformat("navigation_layer_%d", i))) { + TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor()); + tile_data_navigation_editor->hide(); + tile_data_navigation_editor->set_navigation_layer(i); + tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors[vformat("navigation_layer_%d", i)] = tile_data_navigation_editor; + } + } + for (int i = tile_set->get_navigation_layers_count(); tile_data_editors.has(vformat("navigation_layer_%d", i)); i++) { + tile_data_editors[vformat("navigation_layer_%d", i)]->queue_delete(); + tile_data_editors.erase(vformat("navigation_layer_%d", i)); + } + + // --- Custom Data --- + ADD_TILE_DATA_EDITOR_GROUP("Custom Data"); + for (int i = 0; i < tile_set->get_custom_data_layers_count(); i++) { + if (tile_set->get_custom_data_name(i).is_empty()) { + ADD_TILE_DATA_EDITOR(group, vformat("Custom Data %d", i), vformat("custom_data_%d", i)); + } else { + ADD_TILE_DATA_EDITOR(group, tile_set->get_custom_data_name(i), vformat("custom_data_%d", i)); + } + if (!tile_data_editors.has(vformat("custom_data_%d", i))) { + TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor()); + tile_data_custom_data_editor->hide(); + tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_name(i)); + tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::update)); + tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::update)); + tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor; + } + } + for (int i = tile_set->get_custom_data_layers_count(); tile_data_editors.has(vformat("custom_data_%d", i)); i++) { + tile_data_editors[vformat("custom_data_%d", i)]->queue_delete(); + tile_data_editors.erase(vformat("custom_data_%d", i)); + } + +#undef ADD_TILE_DATA_EDITOR_GROUP +#undef ADD_TILE_DATA_EDITOR + + // Add tile data editors as children. + for (Map<String, TileDataEditor *>::Element *E = tile_data_editors.front(); E; E = E->next()) { + // Tile Data Editor. + TileDataEditor *tile_data_editor = E->get(); + if (!tile_data_editor->is_inside_tree()) { + tile_data_painting_editor_container->add_child(tile_data_editor); + } + tile_data_editor->set_tile_set(tile_set); + + // Toolbar. + Control *toolbar = tile_data_editor->get_toolbar(); + if (!toolbar->is_inside_tree()) { + tool_settings_tile_data_toolbar_container->add_child(toolbar); + } + toolbar->hide(); } // Update visibility. - tile_inspector_label->set_visible(has_atlas_tile_selected); - tile_inspector->set_visible(has_atlas_tile_selected); + bool is_visible = tools_button_group->get_pressed_button() == tool_paint_button; + tile_data_editor_dropdown_button->set_visible(is_visible); + tile_data_editor_dropdown_button->set_text(TTR("Select a property editor")); + tile_data_editors_label->set_visible(is_visible); +} + +void TileSetAtlasSourceEditor::_update_current_tile_data_editor() { + // Find the property to use. + String property; + if (tools_button_group->get_pressed_button() == tool_select_button && tile_inspector->is_visible() && !tile_inspector->get_selected_path().is_empty()) { + Vector<String> components = tile_inspector->get_selected_path().split("/"); + if (components.size() >= 1) { + property = components[0]; + + // Workaround for terrains as they don't have a common first component. + if (property.begins_with("terrains_")) { + property = "terrain_set"; + } + } + } else if (tools_button_group->get_pressed_button() == tool_paint_button && tile_data_editors_tree->get_selected()) { + property = tile_data_editors_tree->get_selected()->get_metadata(0); + tile_data_editor_dropdown_button->set_text(tile_data_editors_tree->get_selected()->get_text(0)); + } + + // Hide all editors but the current one. + for (Map<String, TileDataEditor *>::Element *E = tile_data_editors.front(); E; E = E->next()) { + E->get()->hide(); + E->get()->get_toolbar()->hide(); + } + if (tile_data_editors.has(property)) { + current_tile_data_editor = tile_data_editors[property]; + } else { + current_tile_data_editor = nullptr; + } + + // Get the correct editor for the TileData's property. + if (current_tile_data_editor) { + current_tile_data_editor_toolbar = current_tile_data_editor->get_toolbar(); + current_property = property; + current_tile_data_editor->set_visible(tools_button_group->get_pressed_button() == tool_paint_button); + current_tile_data_editor_toolbar->set_visible(tools_button_group->get_pressed_button() == tool_paint_button); + } +} + +void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw() { + if (!has_theme_icon("arrow", "OptionButton")) { + return; + } + + RID ci = tile_data_editor_dropdown_button->get_canvas_item(); + Ref<Texture2D> arrow = Control::get_theme_icon("arrow", "OptionButton"); + Color clr = Color(1, 1, 1); + if (get_theme_constant("modulate_arrow")) { + switch (tile_data_editor_dropdown_button->get_draw_mode()) { + case BaseButton::DRAW_PRESSED: + clr = get_theme_color("font_pressed_color"); + break; + case BaseButton::DRAW_HOVER: + clr = get_theme_color("font_hover_color"); + break; + case BaseButton::DRAW_DISABLED: + clr = get_theme_color("font_disabled_color"); + break; + default: + clr = get_theme_color("font_color"); + } + } + + Size2 size = tile_data_editor_dropdown_button->get_size(); + + Point2 ofs; + if (is_layout_rtl()) { + ofs = Point2(get_theme_constant("arrow_margin", "OptionButton"), int(Math::abs((size.height - arrow->get_height()) / 2))); + } else { + ofs = Point2(size.width - arrow->get_width() - get_theme_constant("arrow_margin", "OptionButton"), int(Math::abs((size.height - arrow->get_height()) / 2))); + } + arrow->draw(ci, ofs, clr); +} + +void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() { + Size2 size = tile_data_editor_dropdown_button->get_size(); + tile_data_editors_popup->set_position(tile_data_editor_dropdown_button->get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y)); + tile_data_editors_popup->set_size(Size2(size.width, 0)); + tile_data_editors_popup->popup(); +} + +void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() { + tile_data_editors_popup->call_deferred("hide"); + _update_current_tile_data_editor(); + tile_atlas_control->update(); + tile_atlas_control_unscaled->update(); + alternative_tiles_control->update(); + alternative_tiles_control_unscaled->update(); } void TileSetAtlasSourceEditor::_update_atlas_view() { @@ -467,19 +766,28 @@ void TileSetAtlasSourceEditor::_update_atlas_view() { } void TileSetAtlasSourceEditor::_update_toolbar() { - // Hide all settings. - for (int i = 0; i < tool_settings->get_child_count(); i++) { - Object::cast_to<CanvasItem>(tool_settings->get_child(i))->hide(); - } - - // SHow only the correct settings. - if (tools_button_group->get_pressed_button() == tool_select_button) { - } else if (tools_button_group->get_pressed_button() == tool_add_remove_button) { - tool_settings_vsep->show(); - tools_settings_erase_button->show(); - } else if (tools_button_group->get_pressed_button() == tool_add_remove_rect_button) { + // Show the tools and settings. + if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) { + if (current_tile_data_editor_toolbar) { + current_tile_data_editor_toolbar->hide(); + } tool_settings_vsep->show(); tools_settings_erase_button->show(); + tool_advanced_menu_buttom->show(); + } else if (tools_button_group->get_pressed_button() == tool_select_button) { + if (current_tile_data_editor_toolbar) { + current_tile_data_editor_toolbar->hide(); + } + tool_settings_vsep->hide(); + tools_settings_erase_button->hide(); + tool_advanced_menu_buttom->hide(); + } else if (tools_button_group->get_pressed_button() == tool_paint_button) { + if (current_tile_data_editor_toolbar) { + current_tile_data_editor_toolbar->show(); + } + tool_settings_vsep->hide(); + tools_settings_erase_button->hide(); + tool_advanced_menu_buttom->hide(); } } @@ -499,357 +807,336 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven // Update the hovered coords. hovered_base_tile_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); - // Handle the event. - Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid()) { - Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos); - Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); + // Forward the event to the current tile data editor if we are in the painting mode. + if (tools_button_group->get_pressed_button() == tool_paint_button) { + if (current_tile_data_editor) { + current_tile_data_editor->forward_painting_atlas_gui_input(tile_atlas_view, tile_set_atlas_source, p_event); + } + // Update only what's needed. + tile_set_atlas_source_changed_needs_update = false; - Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); + tile_atlas_control->update(); + tile_atlas_control_unscaled->update(); + alternative_tiles_control->update(); + alternative_tiles_control_unscaled->update(); + tile_atlas_view->update(); + return; + } else { + // Handle the event. + Ref<InputEventMouseMotion> mm = p_event; + if (mm.is_valid()) { + Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); + Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos); + Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position()); - if (drag_type == DRAG_TYPE_NONE) { - if (selection.size() == 1) { - // Change the cursor depending on the hovered thing. - TileSelection selected = selection.front()->get(); - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) { - Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position(); - Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); - Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); - Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); - Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); - const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; - const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; - CursorShape cursor_shape = CURSOR_ARROW; - bool can_grow[4]; - for (int i = 0; i < 4; i++) { - can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); - can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; - } - for (int i = 0; i < 4; i++) { - Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i]; - if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) { - cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; + Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); + + if (drag_type == DRAG_TYPE_NONE) { + if (selection.size() == 1) { + // Change the cursor depending on the hovered thing. + TileSelection selected = selection.front()->get(); + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) { + Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position(); + Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); + Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); + Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); + Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); + const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; + const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; + CursorShape cursor_shape = CURSOR_ARROW; + bool can_grow[4]; + for (int i = 0; i < 4; i++) { + can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); + can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; } - Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4]; - if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { - cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; + for (int i = 0; i < 4; i++) { + Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i]; + if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) { + cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; + } + Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4]; + if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { + cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; + } } + tile_atlas_control->set_default_cursor_shape(cursor_shape); } - tile_atlas_control->set_default_cursor_shape(cursor_shape); } - } - } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) { - // Create big tile. - new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - - Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); - new_rect.size += Vector2i(1, 1); - // Check if the new tile can fit in the new rect. - if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) { - // Move and resize the tile. - tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size); - drag_current_tile = new_rect.position; - } - } else if (drag_type == DRAG_TYPE_CREATE_TILES) { - // Create tiles. - last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - - Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords); - for (int i = 0; i < line.size(); i++) { - if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) { - tile_set_atlas_source->create_tile(line[i]); - drag_modified_tiles.insert(line[i]); + } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) { + // Create big tile. + new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); + + Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs(); + new_rect.size += Vector2i(1, 1); + // Check if the new tile can fit in the new rect. + if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) { + // Move and resize the tile. + tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size); + drag_current_tile = new_rect.position; + } + } else if (drag_type == DRAG_TYPE_CREATE_TILES) { + // Create tiles. + last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); + new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); + + Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords); + for (int i = 0; i < line.size(); i++) { + if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) { + tile_set_atlas_source->create_tile(line[i]); + drag_modified_tiles.insert(line[i]); + } } - } - drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position(); + drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position(); - } else if (drag_type == DRAG_TYPE_REMOVE_TILES) { - // Remove tiles. - last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); + } else if (drag_type == DRAG_TYPE_REMOVE_TILES) { + // Remove tiles. + last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); + new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords); - for (int i = 0; i < line.size(); i++) { - Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]); - if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) { - drag_modified_tiles.insert(base_tile_coords); + Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords); + for (int i = 0; i < line.size(); i++) { + Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]); + if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) { + drag_modified_tiles.insert(base_tile_coords); + } } - } - drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position(); - } else if (drag_type == DRAG_TYPE_MOVE_TILE) { - // Move tile. - Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size(); - Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset); - coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); - if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) { - tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords); - selection.clear(); - selection.insert({ coords, 0 }); - drag_current_tile = coords; + drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position(); + } else if (drag_type == DRAG_TYPE_MOVE_TILE) { + // Move tile. + Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size(); + Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset); + coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1)); + if (drag_current_tile != coords && tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, coords)) { + tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords); + selection.clear(); + selection.insert({ coords, 0 }); + drag_current_tile = coords; - // Update only what's needed. - tile_set_atlas_source_changed_needs_update = false; - _update_tile_inspector(); - _update_atlas_view(); - _update_tile_id_label(); - } - } else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) { - // Resizing a tile. - new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size); + // Update only what's needed. + tile_set_atlas_source_changed_needs_update = false; + _update_tile_inspector(); + _update_atlas_view(); + _update_tile_id_label(); + _update_current_tile_data_editor(); + } + } else if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) { + if (Vector2(drag_start_mouse_pos).distance_to(tile_atlas_control->get_local_mouse_position()) > 5.0 * EDSCALE) { + drag_type = DRAG_TYPE_NONE; + } + } else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) { + // Resizing a tile. + new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size); - Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)); - Rect2i new_rect = old_rect; + Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)); + Rect2i new_rect = old_rect; - if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) { - new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1); - new_rect.size.x = old_rect.get_end().x - new_rect.position.x; - } - if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) { - new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1); - new_rect.size.y = old_rect.get_end().y - new_rect.position.y; - } + if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) { + new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1); + new_rect.size.x = old_rect.get_end().x - new_rect.position.x; + } + if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) { + new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1); + new_rect.size.y = old_rect.get_end().y - new_rect.position.y; + } - if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) { - new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y)); - } - if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) { - new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1))); - } + if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) { + new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y)); + } + if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) { + new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1))); + } - if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) { - tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size); - selection.clear(); - selection.insert({ new_rect.position, 0 }); - drag_current_tile = new_rect.position; + if (tile_set_atlas_source->can_move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size)) { + tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size); + selection.clear(); + selection.insert({ new_rect.position, 0 }); + drag_current_tile = new_rect.position; - // Update only what's needed. - tile_set_atlas_source_changed_needs_update = false; - _update_tile_inspector(); - _update_atlas_view(); - _update_tile_id_label(); + // Update only what's needed. + tile_set_atlas_source_changed_needs_update = false; + _update_tile_inspector(); + _update_atlas_view(); + _update_tile_id_label(); + _update_current_tile_data_editor(); + } } + + // Redraw for the hovered tile. + tile_atlas_control->update(); + tile_atlas_control_unscaled->update(); + alternative_tiles_control->update(); + alternative_tiles_control_unscaled->update(); + tile_atlas_view->update(); + return; } - // Redraw for the hovered tile. - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); - return; - } + Ref<InputEventMouseButton> mb = p_event; + if (mb.is_valid()) { + Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position(); + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (mb->is_pressed()) { + // Left click pressed. + if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) { + if (tools_settings_erase_button->is_pressed()) { + // Erasing + if (mb->is_ctrl_pressed() || mb->is_shift_pressed()) { + // Remove tiles using rect. + + // Setup the dragging info. + drag_type = DRAG_TYPE_REMOVE_TILES_USING_RECT; + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + } else { + // Remove tiles. - Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid()) { - Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position(); - if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { - if (mb->is_pressed()) { - // Left click pressed. - if (tools_button_group->get_pressed_button() == tool_add_remove_button) { - if (tools_settings_erase_button->is_pressed()) { - // Remove tiles. - - // Setup the dragging info. - drag_type = DRAG_TYPE_REMOVE_TILES; - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; - - // Remove a first tile. - Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - if (coords != TileSetSource::INVALID_ATLAS_COORDS) { - coords = tile_set_atlas_source->get_tile_at_coords(coords); - } - if (coords != TileSetSource::INVALID_ATLAS_COORDS) { - drag_modified_tiles.insert(coords); - } - } else { - if (mb->is_shift_pressed()) { - // Create a big tile. - Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos); - if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { - // Setup the dragging info, only if we start on an empty tile. - drag_type = DRAG_TYPE_CREATE_BIG_TILE; + // Setup the dragging info. + drag_type = DRAG_TYPE_REMOVE_TILES; drag_start_mouse_pos = mouse_local_pos; drag_last_mouse_pos = drag_start_mouse_pos; - drag_current_tile = coords; - // Create a tile. - tile_set_atlas_source->create_tile(coords); + // Remove a first tile. + Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + coords = tile_set_atlas_source->get_tile_at_coords(coords); + } + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + drag_modified_tiles.insert(coords); + } } } else { - // Create tiles. - - // Setup the dragging info. - drag_type = DRAG_TYPE_CREATE_TILES; - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; - - // Create a first tile if needed. - Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); - if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { - tile_set_atlas_source->create_tile(coords); - drag_modified_tiles.insert(coords); - } - } - } - } else if (tools_button_group->get_pressed_button() == tool_add_remove_rect_button) { - if (tools_settings_erase_button->is_pressed()) { - // Remove tiles using rect. - - // Setup the dragging info. - drag_type = DRAG_TYPE_REMOVE_TILES_USING_RECT; - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; - } else { - if (mb->is_shift_pressed()) { - // Create a big tile. - Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos); - if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { - // Setup the dragging info, only if we start on an empty tile. - drag_type = DRAG_TYPE_CREATE_BIG_TILE; + // Creating + if (mb->is_shift_pressed()) { + // Create a big tile. + Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos); + if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { + // Setup the dragging info, only if we start on an empty tile. + drag_type = DRAG_TYPE_CREATE_BIG_TILE; + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + drag_current_tile = coords; + + // Create a tile. + tile_set_atlas_source->create_tile(coords); + } + } else if (mb->is_ctrl_pressed()) { + // Create tiles using rect. + drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT; drag_start_mouse_pos = mouse_local_pos; drag_last_mouse_pos = drag_start_mouse_pos; - drag_current_tile = coords; + } else { + // Create tiles. - // Create a tile. - tile_set_atlas_source->create_tile(coords); + // Setup the dragging info. + drag_type = DRAG_TYPE_CREATE_TILES; + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + + // Create a first tile if needed. + Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos); + if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { + tile_set_atlas_source->create_tile(coords); + drag_modified_tiles.insert(coords); + } } - } else { - // Create tiles using rect. - drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT; - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; } - } - } else if (tools_button_group->get_pressed_button() == tool_select_button) { - // Dragging a handle. - drag_type = DRAG_TYPE_NONE; - if (selection.size() == 1) { - TileSelection selected = selection.front()->get(); - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) { - Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); - Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); - Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); - Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); - const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; - const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; - CursorShape cursor_shape = CURSOR_ARROW; - bool can_grow[4]; - for (int i = 0; i < 4; i++) { - can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); - can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; - } - for (int i = 0; i < 4; i++) { - Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i]; - if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) { - drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP_LEFT + i * 2); - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; - drag_current_tile = selected.tile; - drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); - cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; + } else if (tools_button_group->get_pressed_button() == tool_select_button) { + // Dragging a handle. + drag_type = DRAG_TYPE_NONE; + if (selection.size() == 1) { + TileSelection selected = selection.front()->get(); + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) { + Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile); + Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile); + Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom(); + Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0); + const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) }; + const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) }; + CursorShape cursor_shape = CURSOR_ARROW; + bool can_grow[4]; + for (int i = 0; i < 4; i++) { + can_grow[i] = tile_set_atlas_source->can_move_tile_in_atlas(selected.tile, selected.tile + directions[i]); + can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1; } - Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4]; - if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { - drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP + i * 2); - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; - drag_current_tile = selected.tile; - drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); - cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; + for (int i = 0; i < 4; i++) { + Vector2 pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[i]; + if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) { + drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP_LEFT + i * 2); + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + drag_current_tile = selected.tile; + drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); + cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE; + } + Vector2 next_pos = rect.position + Vector2(rect.size.x, rect.size.y) * coords[(i + 1) % 4]; + if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) { + drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP + i * 2); + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + drag_current_tile = selected.tile; + drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); + cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE; + } } + tile_atlas_control->set_default_cursor_shape(cursor_shape); } - tile_atlas_control->set_default_cursor_shape(cursor_shape); } - } - // Selecting then dragging a tile. - if (drag_type == DRAG_TYPE_NONE) { - TileSelection selected = { TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE }; - Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos); - if (coords != TileSetSource::INVALID_ATLAS_COORDS) { - coords = tile_set_atlas_source->get_tile_at_coords(coords); + // Selecting then dragging a tile. + if (drag_type == DRAG_TYPE_NONE) { + TileSelection selected = { TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE }; + Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos); if (coords != TileSetSource::INVALID_ATLAS_COORDS) { - selected = { coords, 0 }; + coords = tile_set_atlas_source->get_tile_at_coords(coords); + if (coords != TileSetSource::INVALID_ATLAS_COORDS) { + selected = { coords, 0 }; + } } - } - bool shift = mb->is_shift_pressed(); - if (!shift && selection.size() == 1 && selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) { - // Start move dragging. - drag_type = DRAG_TYPE_MOVE_TILE; - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; - drag_current_tile = selected.tile; - drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); - tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE); - } else { - // Start selection dragging. - drag_type = DRAG_TYPE_RECT_SELECT; - drag_start_mouse_pos = mouse_local_pos; - drag_last_mouse_pos = drag_start_mouse_pos; + bool shift = mb->is_shift_pressed(); + if (!shift && selection.size() == 1 && selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) { + // Start move dragging. + drag_type = DRAG_TYPE_MOVE_TILE; + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + drag_current_tile = selected.tile; + drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile)); + tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE); + } else { + // Start selection dragging. + drag_type = DRAG_TYPE_RECT_SELECT; + drag_start_mouse_pos = mouse_local_pos; + drag_last_mouse_pos = drag_start_mouse_pos; + } } } + } else { + // Left click released. + _end_dragging(); } - } else { - // Left click released. - _end_dragging(); - } - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); - return; - } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { - if (mb->is_pressed()) { + tile_atlas_control->update(); + tile_atlas_control_unscaled->update(); + alternative_tiles_control->update(); + alternative_tiles_control_unscaled->update(); + tile_atlas_view->update(); + return; + } else if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { // Right click pressed. - - TileSelection selected = { tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos), 0 }; - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) { - selected.tile = tile_set_atlas_source->get_tile_at_coords(selected.tile); - } - - // Set the selection if needed. - if (selection.size() <= 1) { - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) { - undo_redo->create_action(TTR("Select tiles")); - undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array()); - selection.clear(); - selection.insert(selected); - undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array()); - undo_redo->commit_action(false); - _update_tile_inspector(); - _update_tile_id_label(); - } - } - - // Pops up the correct menu, depending on whether we have a tile or not. - if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) { - // We have a tile. - menu_option_coords = selected.tile; - menu_option_alternative = 0; - base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); - } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) { - // We don't have a tile, but can create one. - menu_option_coords = hovered_base_tile_coords; - menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE; - empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + if (mb->is_pressed()) { + drag_type = DRAG_TYPE_MAY_POPUP_MENU; + drag_start_mouse_pos = tile_atlas_control->get_local_mouse_position(); + } else { + // Right click released. + _end_dragging(); } - } else { - // Right click released. - _end_dragging(); + tile_atlas_control->update(); + tile_atlas_control_unscaled->update(); + alternative_tiles_control->update(); + alternative_tiles_control_unscaled->update(); + tile_atlas_view->update(); + return; } - tile_atlas_control->update(); - tile_atlas_control_unscaled->update(); - alternative_tiles_control->update(); - alternative_tiles_control_unscaled->update(); - tile_atlas_view->update(); - return; } } } @@ -1000,10 +1287,45 @@ void TileSetAtlasSourceEditor::_end_dragging() { } _update_tile_inspector(); _update_tile_id_label(); + _update_current_tile_data_editor(); undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array()); undo_redo->commit_action(false); - break; - } + } break; + case DRAG_TYPE_MAY_POPUP_MENU: { + Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position(); + TileSelection selected = { tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos), 0 }; + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) { + selected.tile = tile_set_atlas_source->get_tile_at_coords(selected.tile); + } + + // Set the selection if needed. + if (selection.size() <= 1) { + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) { + undo_redo->create_action(TTR("Select tiles")); + undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array()); + selection.clear(); + selection.insert(selected); + undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array()); + undo_redo->commit_action(false); + _update_tile_inspector(); + _update_tile_id_label(); + _update_current_tile_data_editor(); + } + } + + // Pops up the correct menu, depending on whether we have a tile or not. + if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) { + // We have a tile. + menu_option_coords = selected.tile; + menu_option_alternative = 0; + base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) { + // We don't have a tile, but can create one. + menu_option_coords = hovered_base_tile_coords; + menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE; + empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i())); + } + } break; case DRAG_TYPE_RESIZE_TOP_LEFT: case DRAG_TYPE_RESIZE_TOP: case DRAG_TYPE_RESIZE_TOP_RIGHT: @@ -1040,7 +1362,7 @@ Map<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_prope Vector<String> components = String(E_property->get().name).split("/", true, 1); if (components.size() >= 1) { Vector<String> coord_arr = components[0].split(":"); - if (coord_arr.size() == 2 && coord_arr[0].is_valid_integer() && coord_arr[1].is_valid_integer()) { + if (coord_arr.size() == 2 && coord_arr[0].is_valid_int() && coord_arr[1].is_valid_int()) { Vector2i coords = Vector2i(coord_arr[0].to_int(), coord_arr[1].to_int()); per_tile[coords].push_back(&(E_property->get())); } @@ -1088,7 +1410,7 @@ void TileSetAtlasSourceEditor::_menu_option(int p_option) { if (per_tile.has(selected.tile)) { for (List<const PropertyInfo *>::Element *E_property = per_tile[selected.tile].front(); E_property; E_property = E_property->next()) { Vector<String> components = E_property->get()->name.split("/", true, 2); - if (components.size() >= 2 && components[1].is_valid_integer() && components[1].to_int() == selected.alternative) { + if (components.size() >= 2 && components[1].is_valid_int() && components[1].to_int() == selected.alternative) { String property = E_property->get()->name; Variant value = tile_set_atlas_source->get(property); if (value.get_type() != Variant::NIL) { @@ -1166,6 +1488,7 @@ void TileSetAtlasSourceEditor::_set_selection_from_array(Array p_selection) { _update_tile_inspector(); _update_tile_id_label(); _update_atlas_view(); + _update_current_tile_data_editor(); } Array TileSetAtlasSourceEditor::_get_selection_as_array() { @@ -1297,7 +1620,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile), Color(1.0, 1.0, 1.0), false); } else { // Draw empty tile, only in add/remove tiles mode. - if (tools_button_group->get_pressed_button() == tool_add_remove_button || tools_button_group->get_pressed_button() == tool_add_remove_rect_button) { + if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) { Vector2i margins = tile_set_atlas_source->get_margins(); Vector2i separation = tile_set_atlas_source->get_separation(); Vector2i tile_size = tile_set_atlas_source->get_texture_region_size(); @@ -1310,9 +1633,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { } void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() { - // Draw the preview of the selected property. - TileDataEditor *tile_data_editor = TileSetEditor::get_singleton()->get_tile_data_editor(selected_property); - if (tile_data_editor && tile_inspector->is_visible_in_tree()) { + if (current_tile_data_editor) { + // Draw the preview of the selected property. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { Vector2i coords = tile_set_atlas_source->get_tile_id(i); Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords); @@ -1321,7 +1643,41 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() { Transform2D xform = tile_atlas_control->get_parent_control()->get_transform(); xform.translate(position); - tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, *tile_set, tile_set_atlas_source_id, coords, 0, selected_property); + if (tools_button_group->get_pressed_button() == tool_select_button && selection.has({ coords, 0 })) { + continue; + } + + TileMapCell cell; + cell.source_id = tile_set_atlas_source_id; + cell.set_atlas_coords(coords); + cell.alternative_tile = 0; + current_tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, cell); + } + + // Draw the selection on top of other. + if (tools_button_group->get_pressed_button() == tool_select_button) { + for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) { + if (E->get().alternative != 0) { + continue; + } + Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E->get().tile); + Vector2i position = (texture_region.position + texture_region.get_end()) / 2 + tile_set_atlas_source->get_tile_effective_texture_offset(E->get().tile, 0); + + Transform2D xform = tile_atlas_control->get_parent_control()->get_transform(); + xform.translate(position); + + TileMapCell cell; + cell.source_id = tile_set_atlas_source_id; + cell.set_atlas_coords(E->get().tile); + cell.alternative_tile = 0; + current_tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, cell, true); + } + } + + // Call the TileData's editor custom draw function. + if (tools_button_group->get_pressed_button() == tool_paint_button) { + Transform2D xform = tile_atlas_control->get_parent_control()->get_transform(); + current_tile_data_editor->forward_draw_over_atlas(tile_atlas_view, tile_set_atlas_source, tile_atlas_control_unscaled, xform); } } } @@ -1330,6 +1686,19 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In // Update the hovered alternative tile. hovered_alternative_tile_coords = tile_atlas_view->get_alternative_tile_at_pos(alternative_tiles_control->get_local_mouse_position()); + // Forward the event to the current tile data editor if we are in the painting mode. + if (tools_button_group->get_pressed_button() == tool_paint_button) { + if (current_tile_data_editor) { + current_tile_data_editor->forward_painting_alternatives_gui_input(tile_atlas_view, tile_set_atlas_source, p_event); + } + tile_atlas_control->update(); + tile_atlas_control_unscaled->update(); + alternative_tiles_control->update(); + alternative_tiles_control_unscaled->update(); + tile_atlas_view->update(); + return; + } + Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { tile_atlas_control->update(); @@ -1425,7 +1794,60 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { } void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() { - //TODO + // Draw the preview of the selected property. + if (current_tile_data_editor) { + // Draw the preview of the currently selected property. + for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) { + Vector2i coords = tile_set_atlas_source->get_tile_id(i); + for (int j = 0; j < tile_set_atlas_source->get_alternative_tiles_count(coords); j++) { + int alternative_tile = tile_set_atlas_source->get_alternative_tile_id(coords, j); + if (alternative_tile == 0) { + continue; + } + Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile); + Vector2 position = (rect.get_position() + rect.get_end()) / 2; + + Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform(); + xform.translate(position); + + if (tools_button_group->get_pressed_button() == tool_select_button && selection.has({ coords, alternative_tile })) { + continue; + } + + TileMapCell cell; + cell.source_id = tile_set_atlas_source_id; + cell.set_atlas_coords(coords); + cell.alternative_tile = alternative_tile; + current_tile_data_editor->draw_over_tile(alternative_tiles_control_unscaled, xform, cell); + } + } + + // Draw the selection on top of other. + if (tools_button_group->get_pressed_button() == tool_select_button) { + for (Set<TileSelection>::Element *E = selection.front(); E; E = E->next()) { + if (E->get().alternative == 0) { + continue; + } + Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E->get().tile, E->get().alternative); + Vector2 position = (rect.get_position() + rect.get_end()) / 2; + + Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform(); + xform.translate(position); + + TileMapCell cell; + cell.source_id = tile_set_atlas_source_id; + cell.set_atlas_coords(E->get().tile); + cell.alternative_tile = E->get().alternative; + current_tile_data_editor->draw_over_tile(alternative_tiles_control_unscaled, xform, cell, true); + } + } + + // Call the TileData's editor custom draw function. + if (tools_button_group->get_pressed_button() == tool_paint_button) { + Transform2D xform = tile_atlas_control->get_parent_control()->get_transform(); + current_tile_data_editor->forward_draw_over_alternatives(tile_atlas_view, tile_set_atlas_source, alternative_tiles_control_unscaled, xform); + } + } } void TileSetAtlasSourceEditor::_tile_set_atlas_source_changed() { @@ -1449,15 +1871,23 @@ void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo AtlasTileProxyObject *tile_data = Object::cast_to<AtlasTileProxyObject>(p_edited); if (tile_data) { Vector<String> components = String(p_property).split("/", true, 2); - if (components.size() == 2 && components[1] == "shapes_count") { + if (components.size() == 2 && components[1] == "polygons_count") { int layer_index = components[0].trim_prefix("physics_layer_").to_int(); - int new_shapes_count = p_new_value; - int old_shapes_count = tile_data->get(vformat("physics_layer_%d/shapes_count", layer_index)); - if (new_shapes_count < old_shapes_count) { - for (int i = new_shapes_count - 1; i < old_shapes_count; i++) { - ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/shape", layer_index, i)); - ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way", layer_index, i)); - ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way_margin", layer_index, i)); + int new_polygons_count = p_new_value; + int old_polygons_count = tile_data->get(vformat("physics_layer_%d/polygons_count", layer_index)); + if (new_polygons_count < old_polygons_count) { + for (int i = new_polygons_count - 1; i < old_polygons_count; i++) { + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", layer_index, i)); + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i)); + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, i)); + } + } + } else if (p_property == "terrain_set") { + int current_terrain_set = tile_data->get("terrain_set"); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (tile_set->is_valid_peering_bit_terrain(current_terrain_set, bit)) { + ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i])); } } } @@ -1500,7 +1930,10 @@ void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource _update_fix_selected_and_hovered_tiles(); _update_tile_id_label(); _update_atlas_view(); + _update_atlas_source_inspector(); _update_tile_inspector(); + _update_tile_data_editors(); + _update_current_tile_data_editor(); } void TileSetAtlasSourceEditor::init_source() { @@ -1616,13 +2049,13 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: case NOTIFICATION_THEME_CHANGED: + tool_setup_atlas_source_button->set_icon(get_theme_icon("Tools", "EditorIcons")); tool_select_button->set_icon(get_theme_icon("ToolSelect", "EditorIcons")); - tool_add_remove_button->set_icon(get_theme_icon("EditAddRemove", "EditorIcons")); - tool_add_remove_rect_button->set_icon(get_theme_icon("RectangleAddRemove", "EditorIcons")); + tool_paint_button->set_icon(get_theme_icon("CanvasItem", "EditorIcons")); tools_settings_erase_button->set_icon(get_theme_icon("Eraser", "EditorIcons")); - tool_advanced_menu_buttom->set_icon(get_theme_icon("Tools", "EditorIcons")); + tool_advanced_menu_buttom->set_icon(get_theme_icon("GuiTabMenu", "EditorIcons")); resize_handle = get_theme_icon("EditorHandle", "EditorIcons"); resize_handle_disabled = get_theme_icon("EditorHandleDisabled", "EditorIcons"); @@ -1636,7 +2069,10 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { _update_fix_selected_and_hovered_tiles(); _update_tile_id_label(); _update_atlas_view(); + _update_atlas_source_inspector(); _update_tile_inspector(); + _update_tile_data_editors(); + _update_current_tile_data_editor(); tile_set_atlas_source_changed_needs_update = false; } @@ -1675,7 +2111,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { // Tile inspector. tile_inspector_label = memnew(Label); tile_inspector_label->set_text(TTR("Tile Properties:")); - tile_inspector_label->hide(); middle_vbox_container->add_child(tile_inspector_label); tile_proxy_object = memnew(AtlasTileProxyObject(this)); @@ -1689,6 +2124,36 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected)); middle_vbox_container->add_child(tile_inspector); + tile_inspector_no_tile_selected_label = memnew(Label); + tile_inspector_no_tile_selected_label->set_align(Label::ALIGN_CENTER); + tile_inspector_no_tile_selected_label->set_text(TTR("No tile selected.")); + middle_vbox_container->add_child(tile_inspector_no_tile_selected_label); + + // Property values palette. + tile_data_editors_popup = memnew(Popup); + + tile_data_editors_label = memnew(Label); + tile_data_editors_label->set_text(TTR("Paint Properties:")); + middle_vbox_container->add_child(tile_data_editors_label); + + tile_data_editor_dropdown_button = memnew(Button); + tile_data_editor_dropdown_button->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw)); + tile_data_editor_dropdown_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed)); + middle_vbox_container->add_child(tile_data_editor_dropdown_button); + tile_data_editor_dropdown_button->add_child(tile_data_editors_popup); + + tile_data_editors_tree = memnew(Tree); + tile_data_editors_tree->set_hide_root(true); + tile_data_editors_tree->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + tile_data_editors_tree->set_h_scroll_enabled(false); + tile_data_editors_tree->set_v_scroll_enabled(false); + tile_data_editors_tree->connect("item_selected", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editors_tree_selected)); + tile_data_editors_popup->add_child(tile_data_editors_tree); + + tile_data_painting_editor_container = memnew(VBoxContainer); + tile_data_painting_editor_container->set_h_size_flags(SIZE_EXPAND_FILL); + middle_vbox_container->add_child(tile_data_painting_editor_container); + // Atlas source inspector. atlas_source_inspector_label = memnew(Label); atlas_source_inspector_label->set_text(TTR("Atlas Properties:")); @@ -1719,47 +2184,41 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { add_child(confirm_auto_create_tiles); // -- Toolbox -- - tools_button_group.instance(); + tools_button_group.instantiate(); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_source_inspector).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_data_editors).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_current_tile_data_editor).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar).unbind(1)); toolbox = memnew(HBoxContainer); right_panel->add_child(toolbox); + tool_setup_atlas_source_button = memnew(Button); + tool_setup_atlas_source_button->set_flat(true); + tool_setup_atlas_source_button->set_toggle_mode(true); + tool_setup_atlas_source_button->set_pressed(true); + tool_setup_atlas_source_button->set_button_group(tools_button_group); + tool_setup_atlas_source_button->set_tooltip(TTR("Atlas Setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing).")); + toolbox->add_child(tool_setup_atlas_source_button); + tool_select_button = memnew(Button); tool_select_button->set_flat(true); tool_select_button->set_toggle_mode(true); - tool_select_button->set_pressed(true); + tool_select_button->set_pressed(false); tool_select_button->set_button_group(tools_button_group); tool_select_button->set_tooltip(TTR("Select tiles.")); - tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles)); - tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label)); - tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector)); - tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view)); - tool_select_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar)); toolbox->add_child(tool_select_button); - tool_add_remove_button = memnew(Button); - tool_add_remove_button->set_flat(true); - tool_add_remove_button->set_toggle_mode(true); - tool_add_remove_button->set_button_group(tools_button_group); - tool_add_remove_button->set_tooltip(TTR("Add/Remove tiles tool (use the shift key to create big tiles).")); - tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles)); - tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label)); - tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector)); - tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view)); - tool_add_remove_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar)); - toolbox->add_child(tool_add_remove_button); - - tool_add_remove_rect_button = memnew(Button); - tool_add_remove_rect_button->set_flat(true); - tool_add_remove_rect_button->set_toggle_mode(true); - tool_add_remove_rect_button->set_button_group(tools_button_group); - tool_add_remove_rect_button->set_tooltip(TTR("Add/Remove tiles rectangle tool (use the shift key to create big tiles).")); - tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles)); - tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label)); - tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector)); - tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view)); - tool_add_remove_rect_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar)); - toolbox->add_child(tool_add_remove_rect_button); + tool_paint_button = memnew(Button); + tool_paint_button->set_flat(true); + tool_paint_button->set_toggle_mode(true); + tool_paint_button->set_button_group(tools_button_group); + tool_paint_button->set_tooltip(TTR("Paint properties.")); + toolbox->add_child(tool_paint_button); // Tool settings. tool_settings = memnew(HBoxContainer); @@ -1768,6 +2227,9 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tool_settings_vsep = memnew(VSeparator); tool_settings->add_child(tool_settings_vsep); + tool_settings_tile_data_toolbar_container = memnew(HBoxContainer); + tool_settings->add_child(tool_settings_tile_data_toolbar_container); + tools_settings_erase_button = memnew(Button); tools_settings_erase_button->set_flat(true); tools_settings_erase_button->set_toggle_mode(true); @@ -1775,9 +2237,6 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tools_settings_erase_button->set_shortcut_context(this); tool_settings->add_child(tools_settings_erase_button); - VSeparator *tool_advanced_vsep = memnew(VSeparator); - toolbox->add_child(tool_advanced_vsep); - tool_advanced_menu_buttom = memnew(MenuButton); tool_advanced_menu_buttom->set_flat(true); tool_advanced_menu_buttom->get_popup()->add_item(TTR("Cleanup Tiles Outside Texture"), ADVANCED_CLEANUP_TILES_OUTSIDE_TEXTURE); @@ -1844,7 +2303,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { alternative_tiles_control_unscaled = memnew(Control); alternative_tiles_control_unscaled->set_anchors_and_offsets_preset(Control::PRESET_WIDE); alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw)); - tile_atlas_view->add_control_over_atlas_tiles(alternative_tiles_control_unscaled, false); + tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false); alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); tile_atlas_view_missing_source_label = memnew(Label); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 70f2cdbe01..dbb0756a16 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -32,6 +32,7 @@ #define TILE_SET_ATLAS_SOURCE_EDITOR_H #include "tile_atlas_view.h" +#include "tile_data_editors.h" #include "editor/editor_node.h" #include "scene/gui/split_container.h" @@ -113,10 +114,27 @@ private: bool tile_set_atlas_source_changed_needs_update = false; + // -- Properties painting -- + VBoxContainer *tile_data_painting_editor_container; + Label *tile_data_editors_label; + Button *tile_data_editor_dropdown_button; + Popup *tile_data_editors_popup; + Tree *tile_data_editors_tree; + void _tile_data_editor_dropdown_button_draw(); + void _tile_data_editor_dropdown_button_pressed(); + + // -- Tile data editors -- + String current_property; + Control *current_tile_data_editor_toolbar = nullptr; + Map<String, TileDataEditor *> tile_data_editors; + TileDataEditor *current_tile_data_editor = nullptr; + void _tile_data_editors_tree_selected(); + // -- Inspector -- AtlasTileProxyObject *tile_proxy_object; Label *tile_inspector_label; EditorInspector *tile_inspector; + Label *tile_inspector_no_tile_selected_label; String selected_property; void _inspector_property_selected(String p_property); @@ -142,6 +160,8 @@ private: DRAG_TYPE_RECT_SELECT, + DRAG_TYPE_MAY_POPUP_MENU, + // Warning: keep in this order. DRAG_TYPE_RESIZE_TOP_LEFT, DRAG_TYPE_RESIZE_TOP, @@ -179,15 +199,16 @@ private: // Tool buttons. Ref<ButtonGroup> tools_button_group; + Button *tool_setup_atlas_source_button; Button *tool_select_button; - Button *tool_add_remove_button; - Button *tool_add_remove_rect_button; + Button *tool_paint_button; Label *tool_tile_id_label; + // Tool settings. HBoxContainer *tool_settings; VSeparator *tool_settings_vsep; + HBoxContainer *tool_settings_tile_data_toolbar_container; Button *tools_settings_erase_button; - MenuButton *tool_advanced_menu_buttom; // Selection. @@ -226,7 +247,10 @@ private: void _update_tile_id_label(); void _update_source_inspector(); void _update_fix_selected_and_hovered_tiles(); + void _update_atlas_source_inspector(); void _update_tile_inspector(); + void _update_tile_data_editors(); + void _update_current_tile_data_editor(); void _update_manage_tile_properties_button(); void _update_atlas_view(); void _update_toolbar(); diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index 6078c986cb..2c2ebd107f 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -347,65 +347,23 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p int old_layer_count = tile_set->get_physics_layers_count(); if (new_layer_count < old_layer_count) { for (int physics_layer_index = new_layer_count - 1; physics_layer_index < old_layer_count; physics_layer_index++) { - ADD_UNDO(tile_data, vformat("physics_layer_%d/shapes_count", physics_layer_index)); - for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(physics_layer_index); shape_index++) { - ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/shape", physics_layer_index, shape_index)); - ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way", physics_layer_index, shape_index)); - ADD_UNDO(tile_data, vformat("physics_layer_%d/shape_%d/one_way_margin", physics_layer_index, shape_index)); + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygons_count", physics_layer_index)); + for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(physics_layer_index); polygon_index++) { + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/points", physics_layer_index, polygon_index)); + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way", physics_layer_index, polygon_index)); + ADD_UNDO(tile_data, vformat("physics_layer_%d/polygon_%d/one_way_margin", physics_layer_index, polygon_index)); } } } } else if ((p_property == "terrains_sets_count" && tile_data->get_terrain_set() >= (int)p_new_value) || - (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer() && components[1] == "mode") || - (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer() && components[1] == "terrains_count" && tile_data->get_terrain_set() == components[0].trim_prefix("terrain_set_").to_int() && (int)p_new_value < tile_set->get_terrains_count(tile_data->get_terrain_set()))) { + (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") || + (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrains_count" && tile_data->get_terrain_set() == components[0].trim_prefix("terrain_set_").to_int() && (int)p_new_value < tile_set->get_terrains_count(tile_data->get_terrain_set()))) { ADD_UNDO(tile_data, "terrain_set"); - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/right_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/right_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/bottom_right_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/bottom_right_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/bottom_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/bottom_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/bottom_left_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/bottom_left_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/left_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/left_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/top_left_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/top_left_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/top_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/top_corner"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)) { - ADD_UNDO(tile_data, "terrains_peering_bit/top_right_side"); - } - if (tile_data->is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER)) { - ADD_UNDO(tile_data, "terrains_peering_bit/top_right_corner"); + for (int l = 0; l < TileSet::CELL_NEIGHBOR_MAX; l++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(l); + if (tile_data->is_valid_peering_bit_terrain(bit)) { + ADD_UNDO(tile_data, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[l])); + } } } else if (p_property == "navigation_layers_count") { int new_layer_count = p_new_value; @@ -423,8 +381,8 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer_index)); } } - } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer() && components[1] == "type") { - int custom_data_layer = components[0].trim_prefix("custom_data_layer_").is_valid_integer(); + } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int() && components[1] == "type") { + int custom_data_layer = components[0].trim_prefix("custom_data_layer_").is_valid_int(); ADD_UNDO(tile_data, vformat("custom_data_%d", custom_data_layer)); } } @@ -436,32 +394,8 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p } void TileSetEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &TileSetEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &TileSetEditor::drop_data_fw); -} - -TileDataEditor *TileSetEditor::get_tile_data_editor(String p_property) { - Vector<String> components = String(p_property).split("/", true); - - if (p_property == "z_index") { - return tile_data_integer_editor; - } else if (p_property == "probability") { - return tile_data_float_editor; - } else if (p_property == "y_sort_origin") { - return tile_data_y_sort_editor; - } else if (p_property == "texture_offset") { - return tile_data_texture_offset_editor; - } else if (components.size() >= 1 && components[0].begins_with("occlusion_layer_")) { - return tile_data_occlusion_shape_editor; - } else if (components.size() >= 1 && components[0].begins_with("physics_layer_")) { - return tile_data_collision_shape_editor; - } else if (p_property == "mode" || p_property == "terrain" || (components.size() >= 1 && components[0] == "terrains_peering_bit")) { - return tile_data_terrains_editor; - } else if (components.size() >= 1 && components[0].begins_with("navigation_layer_")) { - return tile_data_navigation_polygon_editor; - } - - return nullptr; + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::drop_data_fw); } void TileSetEditor::edit(Ref<TileSet> p_tile_set) { @@ -575,14 +509,4 @@ TileSetEditor::~TileSetEditor() { if (tile_set.is_valid()) { tile_set->disconnect("changed", callable_mp(this, &TileSetEditor::_tile_set_changed)); } - - // Delete tile data editors. - memdelete(tile_data_texture_offset_editor); - memdelete(tile_data_y_sort_editor); - memdelete(tile_data_integer_editor); - memdelete(tile_data_float_editor); - memdelete(tile_data_occlusion_shape_editor); - memdelete(tile_data_collision_shape_editor); - memdelete(tile_data_terrains_editor); - memdelete(tile_data_navigation_polygon_editor); } diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h index f584c043cc..9e50aca62f 100644 --- a/editor/plugins/tiles/tile_set_editor.h +++ b/editor/plugins/tiles/tile_set_editor.h @@ -33,7 +33,6 @@ #include "scene/gui/box_container.h" #include "scene/resources/tile_set.h" -#include "tile_data_editors.h" #include "tile_set_atlas_source_editor.h" #include "tile_set_scenes_collection_source_editor.h" @@ -54,16 +53,6 @@ private: void _update_atlas_sources_list(int force_selected_id = -1); - // List of tile data editors. - TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor); - TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor); - TileDataIntegerEditor *tile_data_integer_editor = memnew(TileDataIntegerEditor); - TileDataFloatEditor *tile_data_float_editor = memnew(TileDataFloatEditor); - TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor); - TileDataCollisionShapeEditor *tile_data_collision_shape_editor = memnew(TileDataCollisionShapeEditor); - TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor); - TileDataNavigationPolygonEditor *tile_data_navigation_polygon_editor = memnew(TileDataNavigationPolygonEditor); - // -- Sources management -- Button *sources_delete_button; MenuButton *sources_add_button; @@ -84,7 +73,6 @@ protected: public: _FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; } - TileDataEditor *get_tile_data_editor(String property); void edit(Ref<TileSet> p_tile_set); void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 75a944e910..10679ad6f2 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -476,6 +476,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { version_control_dock = memnew(PanelContainer); version_control_dock->set_v_size_flags(Control::SIZE_EXPAND_FILL); + version_control_dock->set_custom_minimum_size(Size2(0, 300) * EDSCALE); version_control_dock->hide(); diff_vbc = memnew(VBoxContainer); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index e6a5ed0e63..fb91cbb866 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -44,6 +44,7 @@ #include "scene/gui/panel.h" #include "scene/main/window.h" #include "scene/resources/visual_shader_nodes.h" +#include "scene/resources/visual_shader_particle_nodes.h" #include "scene/resources/visual_shader_sdf_nodes.h" #include "servers/display_server.h" #include "servers/rendering/shader_types.h" @@ -71,13 +72,13 @@ const int MAX_FLOAT_CONST_DEFS = sizeof(float_constant_defs) / sizeof(FloatConst Control *VisualShaderNodePlugin::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) { if (get_script_instance()) { - return get_script_instance()->call("create_editor", p_parent_resource, p_node); + return get_script_instance()->call("_create_editor", p_parent_resource, p_node); } return nullptr; } void VisualShaderNodePlugin::_bind_methods() { - BIND_VMETHOD(MethodInfo(Variant::OBJECT, "create_editor", PropertyInfo(Variant::OBJECT, "parent_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::OBJECT, "for_node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode"))); + BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_create_editor", PropertyInfo(Variant::OBJECT, "parent_resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"), PropertyInfo(Variant::OBJECT, "for_node", PROPERTY_HINT_RESOURCE_TYPE, "VisualShaderNode"))); } /////////////////// @@ -109,6 +110,7 @@ void VisualShaderGraphPlugin::_bind_methods() { ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name); ClassDB::bind_method("set_expression", &VisualShaderGraphPlugin::set_expression); ClassDB::bind_method("update_curve", &VisualShaderGraphPlugin::update_curve); + ClassDB::bind_method("update_curve3", &VisualShaderGraphPlugin::update_curve3); ClassDB::bind_method("update_constant", &VisualShaderGraphPlugin::update_constant); } @@ -210,9 +212,19 @@ void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_ } void VisualShaderGraphPlugin::update_curve(int p_node_id) { - if (links.has(p_node_id) && links[p_node_id].curve_editor) { + if (links.has(p_node_id) && links[p_node_id].curve_editors[0]) { if (((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture().is_valid()) { - links[p_node_id].curve_editor->set_curve(((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture()->get_curve()); + links[p_node_id].curve_editors[0]->set_curve(((VisualShaderNodeCurveTexture *)links[p_node_id].visual_node)->get_texture()->get_curve()); + } + } +} + +void VisualShaderGraphPlugin::update_curve3(int p_node_id) { + if (links.has(p_node_id) && links[p_node_id].curve_editors[0] && links[p_node_id].curve_editors[1] && links[p_node_id].curve_editors[2]) { + if (((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture().is_valid()) { + links[p_node_id].curve_editors[0]->set_curve(((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture()->get_curve_x()); + links[p_node_id].curve_editors[1]->set_curve(((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture()->get_curve_y()); + links[p_node_id].curve_editors[2]->set_curve(((VisualShaderNodeCurve3Texture *)links[p_node_id].visual_node)->get_texture()->get_curve_z()); } } } @@ -264,8 +276,8 @@ void VisualShaderGraphPlugin::register_expression_edit(int p_node_id, CodeEdit * links[p_node_id].expression_edit = p_expression_edit; } -void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, CurveEditor *p_curve_editor) { - links[p_node_id].curve_editor = p_curve_editor; +void VisualShaderGraphPlugin::register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor) { + links[p_node_id].curve_editors[p_index] = p_curve_editor; } void VisualShaderGraphPlugin::update_uniform_refs() { @@ -311,7 +323,7 @@ void VisualShaderGraphPlugin::make_dirty(bool p_enabled) { } void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) { - links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, nullptr, nullptr, nullptr }); + links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } }); } void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) { @@ -417,6 +429,11 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { } } + Ref<VisualShaderNodeParticleEmit> emit = vsnode; + if (emit.is_valid()) { + node->set_custom_minimum_size(Size2(200 * EDSCALE, 0)); + } + Ref<VisualShaderNodeUniform> uniform = vsnode; if (uniform.is_valid()) { VisualShaderEditor::get_singleton()->graph->add_child(node); @@ -426,7 +443,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { register_uniform_name(p_id, uniform_name); uniform_name->set_text(uniform->get_uniform_name()); node->add_child(uniform_name); - uniform_name->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id)); + uniform_name->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_changed), varray(p_id)); uniform_name->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_uniform_line_edit_focus_out), varray(uniform_name, p_id)); if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") { @@ -466,6 +483,18 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { custom_editor = hbox; } + Ref<VisualShaderNodeCurve3Texture> curve3 = vsnode; + if (curve3.is_valid()) { + if (curve3->get_texture().is_valid() && !curve3->get_texture()->is_connected("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve3))) { + curve3->get_texture()->connect("changed", callable_mp(VisualShaderEditor::get_singleton()->get_graph_plugin(), &VisualShaderGraphPlugin::update_curve3), varray(p_id)); + } + + HBoxContainer *hbox = memnew(HBoxContainer); + custom_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); + hbox->add_child(custom_editor); + custom_editor = hbox; + } + Ref<VisualShaderNodeFloatConstant> float_const = vsnode; if (float_const.is_valid()) { HBoxContainer *hbox = memnew(HBoxContainer); @@ -489,19 +518,12 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { port_offset++; node->add_child(custom_editor); - if (curve.is_valid()) { + bool is_curve = curve.is_valid() || curve3.is_valid(); + + if (is_curve) { VisualShaderEditor::get_singleton()->graph->add_child(node); VisualShaderEditor::get_singleton()->_update_created_node(node); - CurveEditor *curve_editor = memnew(CurveEditor); - node->add_child(curve_editor); - register_curve_editor(p_id, curve_editor); - curve_editor->set_custom_minimum_size(Size2(300, 0)); - curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); - if (curve->get_texture().is_valid()) { - curve_editor->set_curve(curve->get_texture()->get_curve()); - } - TextureButton *preview = memnew(TextureButton); preview->set_toggle_mode(true); preview->set_normal_texture(VisualShaderEditor::get_singleton()->get_theme_icon("GuiVisibilityHidden", "EditorIcons")); @@ -513,12 +535,59 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { preview->connect("pressed", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_preview_select_port), varray(p_id, 0), CONNECT_DEFERRED); custom_editor->add_child(preview); + if (vsnode->get_output_port_for_preview() >= 0) { + show_port_preview(p_type, p_id, vsnode->get_output_port_for_preview()); + } + } + + if (curve.is_valid()) { + CurveEditor *curve_editor = memnew(CurveEditor); + node->add_child(curve_editor); + register_curve_editor(p_id, 0, curve_editor); + curve_editor->set_custom_minimum_size(Size2(300, 0)); + curve_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve->get_texture().is_valid()) { + curve_editor->set_curve(curve->get_texture()->get_curve()); + } + } + + if (curve3.is_valid()) { + CurveEditor *curve_editor_x = memnew(CurveEditor); + node->add_child(curve_editor_x); + register_curve_editor(p_id, 0, curve_editor_x); + curve_editor_x->set_custom_minimum_size(Size2(300, 0)); + curve_editor_x->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve3->get_texture().is_valid()) { + curve_editor_x->set_curve(curve3->get_texture()->get_curve_x()); + } + + CurveEditor *curve_editor_y = memnew(CurveEditor); + node->add_child(curve_editor_y); + register_curve_editor(p_id, 1, curve_editor_y); + curve_editor_y->set_custom_minimum_size(Size2(300, 0)); + curve_editor_y->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve3->get_texture().is_valid()) { + curve_editor_y->set_curve(curve3->get_texture()->get_curve_y()); + } + + CurveEditor *curve_editor_z = memnew(CurveEditor); + node->add_child(curve_editor_z); + register_curve_editor(p_id, 2, curve_editor_z); + curve_editor_z->set_custom_minimum_size(Size2(300, 0)); + curve_editor_z->set_h_size_flags(Control::SIZE_EXPAND_FILL); + if (curve3->get_texture().is_valid()) { + curve_editor_z->set_curve(curve3->get_texture()->get_curve_z()); + } + } + + if (is_curve) { VisualShaderNode::PortType port_left = vsnode->get_input_port_type(0); VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0); node->set_slot(0, true, port_left, type_color[port_left], true, port_right, type_color[port_right]); VisualShaderEditor::get_singleton()->call_deferred("_set_node_size", (int)p_type, p_id, size); } + if (vsnode->is_use_prop_slots()) { return; } @@ -660,7 +729,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0)); name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); name_box->set_text(name_left); - name_box->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED); + name_box->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_input_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED); name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, false), CONNECT_DEFERRED); Button *remove_btn = memnew(Button); @@ -701,7 +770,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { name_box->set_custom_minimum_size(Size2(65 * EDSCALE, 0)); name_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); name_box->set_text(name_right); - name_box->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED); + name_box->connect("text_submitted", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_change_output_port_name), varray(name_box, p_id, i), CONNECT_DEFERRED); name_box->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_port_name_focus_out), varray(name_box, p_id, i, true), CONNECT_DEFERRED); OptionButton *type_box = memnew(OptionButton); @@ -812,7 +881,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) { if (is_expression) { CodeEdit *expression_box = memnew(CodeEdit); Ref<CodeHighlighter> expression_syntax_highlighter; - expression_syntax_highlighter.instance(); + expression_syntax_highlighter.instantiate(); expression_node->set_ctrl_pressed(expression_box, 0); node->add_child(expression_box); register_expression_edit(p_id, expression_box); @@ -882,6 +951,7 @@ void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id) { void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { if (visual_shader->get_shader_type() == p_type) { VisualShaderEditor::get_singleton()->graph->connect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); + connections.push_back({ p_from_node, p_from_port, p_to_node, p_to_port }); if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr) { links[p_to_node].input_ports[p_to_port].default_input_button->hide(); } @@ -891,6 +961,12 @@ void VisualShaderGraphPlugin::connect_nodes(VisualShader::Type p_type, int p_fro void VisualShaderGraphPlugin::disconnect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { if (visual_shader->get_shader_type() == p_type) { VisualShaderEditor::get_singleton()->graph->disconnect_node(itos(p_from_node), p_from_port, itos(p_to_node), p_to_port); + for (List<VisualShader::Connection>::Element *E = connections.front(); E; E = E->next()) { + if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) { + connections.erase(E); + break; + } + } if (links[p_to_node].input_ports.has(p_to_port) && links[p_to_node].input_ports[p_to_port].default_input_button != nullptr && links[p_to_node].visual_node->get_input_port_default_value(p_to_port).get_type() != Variant::NIL) { links[p_to_node].input_ports[p_to_port].default_input_button->show(); set_input_port_default_value(p_type, p_to_node, p_to_port, links[p_to_node].visual_node->get_input_port_default_value(p_to_port)); @@ -1013,13 +1089,13 @@ bool VisualShaderEditor::_is_available(int p_mode) { if (p_mode != -1) { switch (current_mode) { - case 0: // Vertex or Emit + case 0: // Vertex / Emit current_mode = 1; break; - case 1: // Fragment or Process + case 1: // Fragment / Process current_mode = 2; break; - case 2: // Light or End + case 2: // Light / Collide current_mode = 4; break; default: @@ -1047,7 +1123,7 @@ void VisualShaderEditor::update_custom_nodes() { Ref<Script> script = Ref<Script>(res); Ref<VisualShaderNodeCustom> ref; - ref.instance(); + ref.instantiate(); ref->set_script(script); String name; @@ -1221,7 +1297,7 @@ void VisualShaderEditor::_update_options_menu() { item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons")); break; case VisualShaderNode::PORT_TYPE_TRANSFORM: - item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons")); + item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform3D", "EditorIcons")); break; case VisualShaderNode::PORT_TYPE_SAMPLER: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons")); @@ -1235,22 +1311,29 @@ void VisualShaderEditor::_update_options_menu() { void VisualShaderEditor::_set_mode(int p_which) { if (p_which == VisualShader::MODE_SKY) { - edit_type_standart->set_visible(false); + edit_type_standard->set_visible(false); edit_type_particles->set_visible(false); edit_type_sky->set_visible(true); edit_type = edit_type_sky; + custom_mode_box->set_visible(false); mode = MODE_FLAGS_SKY; } else if (p_which == VisualShader::MODE_PARTICLES) { - edit_type_standart->set_visible(false); + edit_type_standard->set_visible(false); edit_type_particles->set_visible(true); edit_type_sky->set_visible(false); edit_type = edit_type_particles; + if ((edit_type->get_selected() + 3) > VisualShader::TYPE_PROCESS) { + custom_mode_box->set_visible(false); + } else { + custom_mode_box->set_visible(true); + } mode = MODE_FLAGS_PARTICLES; } else { edit_type_particles->set_visible(false); - edit_type_standart->set_visible(true); + edit_type_standard->set_visible(true); edit_type_sky->set_visible(false); - edit_type = edit_type_standart; + edit_type = edit_type_standard; + custom_mode_box->set_visible(false); mode = MODE_FLAGS_SPATIAL_CANVASITEM; } visual_shader->set_shader_type(get_current_shader_type()); @@ -1403,9 +1486,9 @@ void VisualShaderEditor::_update_graph() { VisualShader::Type VisualShaderEditor::get_current_shader_type() const { VisualShader::Type type; if (mode & MODE_FLAGS_PARTICLES) { - type = VisualShader::Type(edit_type->get_selected() + 3); + type = VisualShader::Type(edit_type->get_selected() + 3 + (custom_mode_enabled ? 3 : 0)); } else if (mode & MODE_FLAGS_SKY) { - type = VisualShader::Type(edit_type->get_selected() + 6); + type = VisualShader::Type(edit_type->get_selected() + 8); } else { type = VisualShader::Type(edit_type->get_selected()); } @@ -1842,7 +1925,7 @@ void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) { comment_title_change_popup->set_size(Size2(-1, -1)); } -void VisualShaderEditor::_comment_title_text_entered(const String &p_new_text) { +void VisualShaderEditor::_comment_title_text_submitted(const String &p_new_text) { comment_title_change_popup->hide(); } @@ -2081,6 +2164,16 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) { } } + //UV_FUNC + { + VisualShaderNodeUVFunc *uvFunc = Object::cast_to<VisualShaderNodeUVFunc>(p_node); + + if (uvFunc) { + uvFunc->set_function((VisualShaderNodeUVFunc::Function)p_op_idx); + return; + } + } + // IS { VisualShaderNodeIs *is = Object::cast_to<VisualShaderNodeIs>(p_node); @@ -2181,12 +2274,14 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, int p_op_idx) { void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_path, int p_node_idx) { ERR_FAIL_INDEX(p_idx, add_options.size()); + VisualShader::Type type = get_current_shader_type(); + Ref<VisualShaderNode> vsnode; bool is_custom = add_options[p_idx].is_custom; if (!is_custom && add_options[p_idx].type != String()) { - VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type)); + VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type)); ERR_FAIL_COND(!vsn); VisualShaderNodeFloatConstant *constant = Object::cast_to<VisualShaderNodeFloatConstant>(vsn); @@ -2207,11 +2302,34 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa } } + VisualShaderNodeUniformRef *uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(vsn); + + if (uniform_ref && to_node != -1 && to_slot != -1) { + VisualShaderNode::PortType input_port_type = visual_shader->get_node(type, to_node)->get_input_port_type(to_slot); + bool success = false; + + for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) { + if (uniform_ref->get_port_type_by_index(i) == input_port_type) { + uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i)); + success = true; + break; + } + } + if (!success) { + for (int i = 0; i < uniform_ref->get_uniforms_count(); i++) { + if (visual_shader->is_port_types_compatible(uniform_ref->get_port_type_by_index(i), input_port_type)) { + uniform_ref->set_uniform_name(uniform_ref->get_uniform_name_by_index(i)); + break; + } + } + } + } + vsnode = Ref<VisualShaderNode>(vsn); } else { ERR_FAIL_COND(add_options[p_idx].script.is_null()); String base_type = add_options[p_idx].script->get_instance_base_type(); - VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(base_type)); + VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type)); ERR_FAIL_COND(!vsn); vsnode = Ref<VisualShaderNode>(vsn); vsnode->set_script(add_options[p_idx].script); @@ -2227,8 +2345,6 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa } saved_node_pos_dirty = false; - VisualShader::Type type = get_current_shader_type(); - int id_to_use = visual_shader->get_valid_node_id(type); if (p_resource_path.is_empty()) { @@ -2292,6 +2408,13 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa undo_redo->add_do_method(graph_plugin.ptr(), "connect_nodes", type, _from_node, _from_slot, to_node, to_slot); undo_redo->add_undo_method(graph_plugin.ptr(), "disconnect_nodes", type, _from_node, _from_slot, to_node, to_slot); } else { + // Need to setting up Input node properly before committing since `is_port_types_compatible` (calling below) is using `mode` and `shader_type`. + VisualShaderNodeInput *input = Object::cast_to<VisualShaderNodeInput>(vsnode.ptr()); + if (input) { + input->set_shader_mode(visual_shader->get_mode()); + input->set_shader_type(visual_shader->get_shader_type()); + } + // Attempting to connect to the first correct port. for (int i = 0; i < vsnode->get_output_port_count(); i++) { if (visual_shader->is_port_types_compatible(vsnode->get_output_port_type(i), input_port_type)) { @@ -2350,6 +2473,11 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa graph_plugin->call_deferred("update_curve", id_to_use); } + VisualShaderNodeCurve3Texture *curve3 = Object::cast_to<VisualShaderNodeCurve3Texture>(vsnode.ptr()); + if (curve3) { + graph_plugin->call_deferred("update_curve3", id_to_use); + } + if (p_resource_path.is_empty()) { undo_redo->commit_action(); } else { @@ -2358,7 +2486,7 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx, String p_resource_pa VisualShaderNodeTexture *texture2d = Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()); VisualShaderNodeTexture3D *texture3d = Object::cast_to<VisualShaderNodeTexture3D>(vsnode.ptr()); - if (texture2d || texture3d || curve) { + if (texture2d || texture3d || curve || curve3) { undo_redo->add_do_method(vsnode.ptr(), "set_texture", ResourceLoader::load(p_resource_path)); return; } @@ -3214,8 +3342,18 @@ void VisualShaderEditor::_mode_selected(int p_id) { int offset = 0; if (mode & MODE_FLAGS_PARTICLES) { offset = 3; + if (p_id + offset > VisualShader::TYPE_PROCESS) { + custom_mode_box->set_visible(false); + custom_mode_enabled = false; + } else { + custom_mode_box->set_visible(true); + if (custom_mode_box->is_pressed()) { + custom_mode_enabled = true; + offset += 3; + } + } } else if (mode & MODE_FLAGS_SKY) { - offset = 6; + offset = 8; } visual_shader->set_shader_type(VisualShader::Type(p_id + offset)); @@ -3223,6 +3361,21 @@ void VisualShaderEditor::_mode_selected(int p_id) { _update_graph(); } +void VisualShaderEditor::_custom_mode_toggled(bool p_enabled) { + if (!(mode & MODE_FLAGS_PARTICLES)) { + return; + } + custom_mode_enabled = p_enabled; + int id = edit_type->get_selected() + 3; + if (p_enabled) { + visual_shader->set_shader_type(VisualShader::Type(id + 3)); + } else { + visual_shader->set_shader_type(VisualShader::Type(id)); + } + _update_options_menu(); + _update_graph(); +} + void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name) { String prev_name = p_input->get_input_name(); @@ -3528,6 +3681,10 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); saved_node_pos_dirty = true; _add_node(curve_node_option_idx, -1, arr[i], i); + } else if (type == "Curve3Texture") { + saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); + saved_node_pos_dirty = true; + _add_node(curve3_node_option_idx, -1, arr[i], i); } else if (ClassDB::get_parent_class(type) == "Texture2D") { saved_node_pos = p_point + Vector2(0, i * 250 * EDSCALE); saved_node_pos_dirty = true; @@ -3646,9 +3803,9 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_update_uniform", &VisualShaderEditor::_update_uniform); ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &VisualShaderEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &VisualShaderEditor::drop_data_fw); ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available); } @@ -3721,17 +3878,23 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->add_child(vs); graph->get_zoom_hbox()->move_child(vs, 0); - edit_type_standart = memnew(OptionButton); - edit_type_standart->add_item(TTR("Vertex")); - edit_type_standart->add_item(TTR("Fragment")); - edit_type_standart->add_item(TTR("Light")); - edit_type_standart->select(1); - edit_type_standart->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected)); + custom_mode_box = memnew(CheckBox); + custom_mode_box->set_text(TTR("Custom")); + custom_mode_box->set_pressed(false); + custom_mode_box->set_visible(false); + custom_mode_box->connect("toggled", callable_mp(this, &VisualShaderEditor::_custom_mode_toggled)); + + edit_type_standard = memnew(OptionButton); + edit_type_standard->add_item(TTR("Vertex")); + edit_type_standard->add_item(TTR("Fragment")); + edit_type_standard->add_item(TTR("Light")); + edit_type_standard->select(1); + edit_type_standard->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected)); edit_type_particles = memnew(OptionButton); - edit_type_particles->add_item(TTR("Emit")); + edit_type_particles->add_item(TTR("Start")); edit_type_particles->add_item(TTR("Process")); - edit_type_particles->add_item(TTR("End")); + edit_type_particles->add_item(TTR("Collide")); edit_type_particles->select(0); edit_type_particles->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected)); @@ -3740,14 +3903,16 @@ VisualShaderEditor::VisualShaderEditor() { edit_type_sky->select(0); edit_type_sky->connect("item_selected", callable_mp(this, &VisualShaderEditor::_mode_selected)); - edit_type = edit_type_standart; + edit_type = edit_type_standard; + graph->get_zoom_hbox()->add_child(custom_mode_box); + graph->get_zoom_hbox()->move_child(custom_mode_box, 0); + graph->get_zoom_hbox()->add_child(edit_type_standard); + graph->get_zoom_hbox()->move_child(edit_type_standard, 0); graph->get_zoom_hbox()->add_child(edit_type_particles); graph->get_zoom_hbox()->move_child(edit_type_particles, 0); graph->get_zoom_hbox()->add_child(edit_type_sky); graph->get_zoom_hbox()->move_child(edit_type_sky, 0); - graph->get_zoom_hbox()->add_child(edit_type_standart); - graph->get_zoom_hbox()->move_child(edit_type_standart, 0); add_node = memnew(Button); add_node->set_flat(true); @@ -3779,7 +3944,7 @@ VisualShaderEditor::VisualShaderEditor() { preview_vbox->add_theme_constant_override("separation", 0); preview_text = memnew(CodeEdit); - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); preview_vbox->add_child(preview_text); preview_text->set_v_size_flags(Control::SIZE_EXPAND_FILL); preview_text->set_syntax_highlighter(syntax_highlighter); @@ -3888,7 +4053,7 @@ VisualShaderEditor::VisualShaderEditor() { comment_title_change_edit = memnew(LineEdit); comment_title_change_edit->set_expand_to_text_length_enabled(true); comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed)); - comment_title_change_edit->connect("text_entered", callable_mp(this, &VisualShaderEditor::_comment_title_text_entered)); + comment_title_change_edit->connect("text_submitted", callable_mp(this, &VisualShaderEditor::_comment_title_text_submitted)); comment_title_change_popup->add_child(comment_title_change_edit); comment_title_change_edit->set_size(Size2(-1, -1)); comment_title_change_popup->set_size(Size2(-1, -1)); @@ -3967,9 +4132,10 @@ VisualShaderEditor::VisualShaderEditor() { // INPUT + const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes."); + // SPATIAL-FOR-ALL - const String input_param_shader_modes = TTR("'%s' input parameter for all shader modes."); add_options.push_back(AddOption("Camera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "camera"), "camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InvCamera", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_camera"), "inv_camera", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("InvProjection", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "inv_projection"), "inv_projection", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_SPATIAL)); @@ -3988,6 +4154,23 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("UV", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "uv"), "uv", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_CANVAS_ITEM)); + // PARTICLES-FOR-ALL + + add_options.push_back(AddOption("Active", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Alpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("AttractorForce", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "attractor_force"), "attractor_force", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Color", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Custom", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("CustomAlpha", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Delta", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("EmissionTransform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Index", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("LifeTime", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Restart", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_BOOLEAN, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Time", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Transform", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("Velocity", "Input", "All", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, -1, Shader::MODE_PARTICLES)); + ///////////////// add_options.push_back(AddOption("Input", "Input", "Common", "VisualShaderNodeInput", TTR("Input parameter."))); @@ -4000,11 +4183,12 @@ VisualShaderEditor::VisualShaderEditor() { const String input_param_for_sky_shader_mode = TTR("'%s' input parameter for sky shader mode."); const String input_param_for_light_shader_mode = TTR("'%s' input parameter for light shader mode."); const String input_param_for_vertex_shader_mode = TTR("'%s' input parameter for vertex shader mode."); - const String input_param_for_emit_shader_mode = TTR("'%s' input parameter for emit shader mode."); + const String input_param_for_start_shader_mode = TTR("'%s' input parameter for start shader mode."); const String input_param_for_process_shader_mode = TTR("'%s' input parameter for process shader mode."); - const String input_param_for_end_shader_mode = TTR("'%s' input parameter for end shader mode."); - const String input_param_for_emit_and_process_shader_mode = TTR("'%s' input parameter for emit and process shader mode."); - const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader mode."); + const String input_param_for_collide_shader_mode = TTR("'%s' input parameter for collide shader mode."); + const String input_param_for_start_and_process_shader_mode = TTR("'%s' input parameter for start and process shader modes."); + const String input_param_for_process_and_collide_shader_mode = TTR("'%s' input parameter for process and collide shader modes."); + const String input_param_for_vertex_and_fragment_shader_mode = TTR("'%s' input parameter for vertex and fragment shader modes."); add_options.push_back(AddOption("Alpha", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Binormal", "Input", "Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal"), "binormal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); @@ -4081,50 +4265,6 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Vertex", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "vertex"), "vertex", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); add_options.push_back(AddOption("World", "Input", "Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_shader_mode, "world"), "world", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_CANVAS_ITEM)); - // PARTICLES INPUTS - - add_options.push_back(AddOption("Active", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Alpha", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Color", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Custom", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("CustomAlpha", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Delta", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("EmissionTransform", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Index", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("LifeTime", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Restart", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Time", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Transform", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Velocity", "Input", "Emit", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); - - add_options.push_back(AddOption("Active", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Alpha", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Color", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Custom", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("CustomAlpha", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Delta", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("EmissionTransform", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Index", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("LifeTime", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Restart", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Time", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Transform", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Velocity", "Input", "Process", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); - - add_options.push_back(AddOption("Active", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "active"), "active", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Alpha", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "alpha"), "alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Color", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "color"), "color", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Custom", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom"), "custom", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("CustomAlpha", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "custom_alpha"), "custom_alpha", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Delta", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "delta"), "delta", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("EmissionTransform", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "emission_transform"), "emission_transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Index", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "index"), "index", VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("LifeTime", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "lifetime"), "lifetime", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Restart", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "restart"), "restart", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Time", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Transform", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "transform"), "transform", VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - add_options.push_back(AddOption("Velocity", "Input", "End", "VisualShaderNodeInput", vformat(input_param_shader_modes, "velocity"), "velocity", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_END, Shader::MODE_PARTICLES)); - // SKY INPUTS add_options.push_back(AddOption("AtCubeMapPass", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "at_cubemap_pass"), "at_cubemap_pass", VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_SKY, Shader::MODE_SKY)); @@ -4157,6 +4297,22 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("SkyCoords", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "sky_coords"), "sky_coords", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_SKY, Shader::MODE_SKY)); add_options.push_back(AddOption("Time", "Input", "Sky", "VisualShaderNodeInput", vformat(input_param_for_sky_shader_mode, "time"), "time", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_SKY, Shader::MODE_SKY)); + // PARTICLES + + add_options.push_back(AddOption("CollisionDepth", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_depth"), "collision_depth", VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("CollisionNormal", "Input", "Collide", "VisualShaderNodeInput", vformat(input_param_for_collide_shader_mode, "collision_normal"), "collision_normal", VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); + + add_options.push_back(AddOption("EmitParticle", "Particles", "", "VisualShaderNodeParticleEmit", "", -1, -1, -1, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("ParticleAccelerator", "Particles", "", "VisualShaderNodeParticleAccelerator", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_PROCESS, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("ParticleRandomness", "Particles", "", "VisualShaderNodeParticleRandomness", "", -1, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", "A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters.", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES)); + + add_options.push_back(AddOption("BoxEmitter", "Particles", "Emitters", "VisualShaderNodeParticleBoxEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("RingEmitter", "Particles", "Emitters", "VisualShaderNodeParticleRingEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + add_options.push_back(AddOption("SphereEmitter", "Particles", "Emitters", "VisualShaderNodeParticleSphereEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + + add_options.push_back(AddOption("ConeVelocity", "Particles", "Velocity", "VisualShaderNodeParticleConeVelocity", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES)); + // SCALAR add_options.push_back(AddOption("FloatFunc", "Scalar", "Common", "VisualShaderNodeFloatFunc", TTR("Float function."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -4244,16 +4400,22 @@ VisualShaderEditor::VisualShaderEditor() { // TEXTURES + add_options.push_back(AddOption("UVFunc", "Textures", "Common", "VisualShaderNodeUVFunc", TTR("Function to be applied on texture coordinates."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + cubemap_node_option_idx = add_options.size(); add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubemap", TTR("Perform the cubic texture lookup."), -1, -1)); curve_node_option_idx = add_options.size(); add_options.push_back(AddOption("CurveTexture", "Textures", "Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), -1, -1)); + curve3_node_option_idx = add_options.size(); + add_options.push_back(AddOption("CurveTexture3", "Textures", "Functions", "VisualShaderNodeCurve3Texture", TTR("Perform the ternary curve texture lookup."), -1, -1)); texture2d_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2D", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), -1, -1)); texture2d_array_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2DArray", "Textures", "Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), -1, -1, -1, -1, -1)); texture3d_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture3D", "Textures", "Functions", "VisualShaderNodeTexture3D", TTR("Perform the 3D texture lookup."), -1, -1)); + add_options.push_back(AddOption("UVPanning", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply panning function on texture coordinates."), VisualShaderNodeUVFunc::FUNC_PANNING, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("UVScaling", "Textures", "Functions", "VisualShaderNodeUVFunc", TTR("Apply scaling function on texture coordinates."), VisualShaderNodeUVFunc::FUNC_SCALING, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubemapUniform", TTR("Cubic texture uniform lookup."), -1, -1)); add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, -1)); @@ -4376,10 +4538,10 @@ VisualShaderEditor::VisualShaderEditor() { undo_redo = EditorNode::get_singleton()->get_undo_redo(); Ref<VisualShaderNodePluginDefault> default_plugin; - default_plugin.instance(); + default_plugin.instantiate(); add_plugin(default_plugin); - graph_plugin.instance(); + graph_plugin.instantiate(); property_editor = memnew(CustomPropertyEditor); add_child(property_editor); @@ -4453,7 +4615,7 @@ public: EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"), - EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform3D", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"), }; @@ -4498,7 +4660,7 @@ public: EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"), - EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"), + EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform3D", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Color", "EditorIcons"), EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"), }; @@ -4689,7 +4851,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par if (Object::cast_to<EditorPropertyResource>(prop)) { Object::cast_to<EditorPropertyResource>(prop)->set_use_sub_inspector(false); prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); - } else if (Object::cast_to<EditorPropertyTransform>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) { + } else if (Object::cast_to<EditorPropertyTransform3D>(prop) || Object::cast_to<EditorPropertyVector3>(prop)) { prop->set_custom_minimum_size(Size2(250 * EDSCALE, 0)); } else if (Object::cast_to<EditorPropertyFloat>(prop)) { prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); @@ -4806,7 +4968,7 @@ void EditorInspectorShaderModePlugin::parse_begin(Object *p_object) { //do none } -bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide) { +bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) { if (p_path == "mode" && p_object->is_class("VisualShader") && p_type == Variant::INT) { EditorPropertyShaderMode *editor = memnew(EditorPropertyShaderMode); Vector<String> options = p_hint_text.split(","); @@ -4834,14 +4996,14 @@ void VisualShaderNodePortPreview::_shader_changed() { String shader_code = shader->generate_preview_shader(type, node, port, default_textures); Ref<Shader> preview_shader; - preview_shader.instance(); + preview_shader.instantiate(); preview_shader->set_code(shader_code); for (int i = 0; i < default_textures.size(); i++) { preview_shader->set_default_texture_param(default_textures[i].name, default_textures[i].param); } Ref<ShaderMaterial> material; - material.instance(); + material.instantiate(); material->set_shader(preview_shader); //find if a material is also being edited and copy parameters to this one @@ -4926,7 +5088,7 @@ Ref<Resource> VisualShaderConversionPlugin::convert(const Ref<Resource> &p_resou ERR_FAIL_COND_V(!vshader.is_valid(), Ref<Resource>()); Ref<Shader> shader; - shader.instance(); + shader.instantiate(); String code = vshader->get_code(); shader->set_code(code); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index f12d05f7ed..2b354db7b3 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -41,8 +41,8 @@ #include "scene/gui/tree.h" #include "scene/resources/visual_shader.h" -class VisualShaderNodePlugin : public Reference { - GDCLASS(VisualShaderNodePlugin, Reference); +class VisualShaderNodePlugin : public RefCounted { + GDCLASS(VisualShaderNodePlugin, RefCounted); protected: static void _bind_methods(); @@ -51,8 +51,8 @@ public: virtual Control *create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node); }; -class VisualShaderGraphPlugin : public Reference { - GDCLASS(VisualShaderGraphPlugin, Reference); +class VisualShaderGraphPlugin : public RefCounted { + GDCLASS(VisualShaderGraphPlugin, RefCounted); private: struct InputPort { @@ -75,7 +75,7 @@ private: LineEdit *uniform_name = nullptr; OptionButton *const_op = nullptr; CodeEdit *expression_edit = nullptr; - CurveEditor *curve_editor = nullptr; + CurveEditor *curve_editors[3] = { nullptr, nullptr, nullptr }; }; Ref<VisualShader> visual_shader; @@ -97,7 +97,7 @@ public: void register_default_input_button(int p_node_id, int p_port_id, Button *p_button); void register_constant_option_btn(int p_node_id, OptionButton *p_button); void register_expression_edit(int p_node_id, CodeEdit *p_expression_edit); - void register_curve_editor(int p_node_id, CurveEditor *p_curve_editor); + void register_curve_editor(int p_node_id, int p_index, CurveEditor *p_curve_editor); void clear_links(); void set_shader_type(VisualShader::Type p_type); bool is_preview_visible(int p_id) const; @@ -117,6 +117,7 @@ public: void update_uniform_refs(); void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name); void update_curve(int p_node_id); + void update_curve3(int p_node_id); void update_constant(VisualShader::Type p_type, int p_node_id); void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression); int get_constant_index(float p_constant) const; @@ -142,9 +143,11 @@ class VisualShaderEditor : public VBoxContainer { Button *preview_shader; OptionButton *edit_type = nullptr; - OptionButton *edit_type_standart; + OptionButton *edit_type_standard; OptionButton *edit_type_particles; OptionButton *edit_type_sky; + CheckBox *custom_mode_box; + bool custom_mode_enabled = false; bool pending_update_preview; bool shader_error; @@ -189,7 +192,9 @@ class VisualShaderEditor : public VBoxContainer { enum ParticlesTypeFlags { TYPE_FLAGS_EMIT = 1, TYPE_FLAGS_PROCESS = 2, - TYPE_FLAGS_END = 4 + TYPE_FLAGS_COLLIDE = 4, + TYPE_FLAGS_EMIT_CUSTOM = 8, + TYPE_FLAGS_PROCESS_CUSTOM = 16, }; enum SkyTypeFlags { @@ -285,6 +290,7 @@ class VisualShaderEditor : public VBoxContainer { int texture3d_node_option_idx; int custom_node_option_idx; int curve_node_option_idx; + int curve3_node_option_idx; List<String> keyword_list; List<VisualShaderNodeUniformRef> uniform_refs; @@ -354,7 +360,7 @@ class VisualShaderEditor : public VBoxContainer { void _comment_title_popup_hide(); void _comment_title_popup_focus_out(); void _comment_title_text_changed(const String &p_new_text); - void _comment_title_text_entered(const String &p_new_text); + void _comment_title_text_submitted(const String &p_new_text); void _comment_desc_popup_show(const Point2 &p_position, int p_node_id); void _comment_desc_popup_hide(); @@ -385,6 +391,7 @@ class VisualShaderEditor : public VBoxContainer { Ref<VisualShaderGraphPlugin> graph_plugin; void _mode_selected(int p_id); + void _custom_mode_toggled(bool p_enabled); void _input_select_item(Ref<VisualShaderNodeInput> input, String name); void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name); @@ -500,7 +507,7 @@ class EditorInspectorShaderModePlugin : public EditorInspectorPlugin { public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; - virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage, bool p_wide = false) override; + virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override; virtual void parse_end() override; }; diff --git a/editor/plugins/gi_probe_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index f309c5da01..162379a49d 100644 --- a/editor/plugins/gi_probe_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gi_probe_editor_plugin.cpp */ +/* voxel_gi_editor_plugin.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,51 +28,48 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gi_probe_editor_plugin.h" +#include "voxel_gi_editor_plugin.h" -void GIProbeEditorPlugin::_bake() { - if (gi_probe) { - if (gi_probe->get_probe_data().is_null()) { +void VoxelGIEditorPlugin::_bake() { + if (voxel_gi) { + if (voxel_gi->get_probe_data().is_null()) { String path = get_tree()->get_edited_scene_root()->get_filename(); if (path == String()) { - path = "res://" + gi_probe->get_name() + "_data.res"; + path = "res://" + voxel_gi->get_name() + "_data.res"; } else { String ext = path.get_extension(); - path = path.get_basename() + "." + gi_probe->get_name() + "_data.res"; + path = path.get_basename() + "." + voxel_gi->get_name() + "_data.res"; } probe_file->set_current_path(path); probe_file->popup_file_dialog(); return; } - gi_probe->bake(); + voxel_gi->bake(); } } -void GIProbeEditorPlugin::edit(Object *p_object) { - GIProbe *s = Object::cast_to<GIProbe>(p_object); +void VoxelGIEditorPlugin::edit(Object *p_object) { + VoxelGI *s = Object::cast_to<VoxelGI>(p_object); if (!s) { return; } - gi_probe = s; + voxel_gi = s; } -bool GIProbeEditorPlugin::handles(Object *p_object) const { - return p_object->is_class("GIProbe"); +bool VoxelGIEditorPlugin::handles(Object *p_object) const { + return p_object->is_class("VoxelGI"); } -void GIProbeEditorPlugin::_notification(int p_what) { +void VoxelGIEditorPlugin::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { - if (!gi_probe) { + if (!voxel_gi) { return; } - const Vector3i size = gi_probe->get_estimated_cell_size(); + const Vector3i size = voxel_gi->get_estimated_cell_size(); String text = vformat(String::utf8("%d × %d × %d"), size.x, size.y, size.z); - int data_size = 4; - if (GLOBAL_GET("rendering/quality/gi_probes/anisotropic")) { - data_size += 4; - } + const int data_size = 4; const double size_mb = size.x * size.y * size.z * data_size / (1024.0 * 1024.0); text += " - " + vformat(TTR("VRAM Size: %s MB"), String::num(size_mb, 2)); @@ -98,7 +95,7 @@ void GIProbeEditorPlugin::_notification(int p_what) { } } -void GIProbeEditorPlugin::make_visible(bool p_visible) { +void VoxelGIEditorPlugin::make_visible(bool p_visible) { if (p_visible) { bake_hb->show(); set_process(true); @@ -108,38 +105,38 @@ void GIProbeEditorPlugin::make_visible(bool p_visible) { } } -EditorProgress *GIProbeEditorPlugin::tmp_progress = nullptr; +EditorProgress *VoxelGIEditorPlugin::tmp_progress = nullptr; -void GIProbeEditorPlugin::bake_func_begin(int p_steps) { +void VoxelGIEditorPlugin::bake_func_begin(int p_steps) { ERR_FAIL_COND(tmp_progress != nullptr); tmp_progress = memnew(EditorProgress("bake_gi", TTR("Bake GI Probe"), p_steps)); } -void GIProbeEditorPlugin::bake_func_step(int p_step, const String &p_description) { +void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) { ERR_FAIL_COND(tmp_progress == nullptr); tmp_progress->step(p_description, p_step, false); } -void GIProbeEditorPlugin::bake_func_end() { +void VoxelGIEditorPlugin::bake_func_end() { ERR_FAIL_COND(tmp_progress == nullptr); memdelete(tmp_progress); tmp_progress = nullptr; } -void GIProbeEditorPlugin::_giprobe_save_path_and_bake(const String &p_path) { +void VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake(const String &p_path) { probe_file->hide(); - if (gi_probe) { - gi_probe->bake(); - ERR_FAIL_COND(gi_probe->get_probe_data().is_null()); - ResourceSaver::save(p_path, gi_probe->get_probe_data(), ResourceSaver::FLAG_CHANGE_PATH); + if (voxel_gi) { + voxel_gi->bake(); + ERR_FAIL_COND(voxel_gi->get_probe_data().is_null()); + ResourceSaver::save(p_path, voxel_gi->get_probe_data(), ResourceSaver::FLAG_CHANGE_PATH); } } -void GIProbeEditorPlugin::_bind_methods() { +void VoxelGIEditorPlugin::_bind_methods() { } -GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { +VoxelGIEditorPlugin::VoxelGIEditorPlugin(EditorNode *p_node) { editor = p_node; bake_hb = memnew(HBoxContainer); bake_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -148,7 +145,7 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { bake->set_flat(true); bake->set_icon(editor->get_gui_base()->get_theme_icon("Bake", "EditorIcons")); bake->set_text(TTR("Bake GI Probe")); - bake->connect("pressed", callable_mp(this, &GIProbeEditorPlugin::_bake)); + bake->connect("pressed", callable_mp(this, &VoxelGIEditorPlugin::_bake)); bake_hb->add_child(bake); bake_info = memnew(Label); bake_info->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -156,18 +153,18 @@ GIProbeEditorPlugin::GIProbeEditorPlugin(EditorNode *p_node) { bake_hb->add_child(bake_info); add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake_hb); - gi_probe = nullptr; + voxel_gi = nullptr; probe_file = memnew(EditorFileDialog); probe_file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); probe_file->add_filter("*.res"); - probe_file->connect("file_selected", callable_mp(this, &GIProbeEditorPlugin::_giprobe_save_path_and_bake)); + probe_file->connect("file_selected", callable_mp(this, &VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake)); get_editor_interface()->get_base_control()->add_child(probe_file); - probe_file->set_title(TTR("Select path for GIProbe Data File")); + probe_file->set_title(TTR("Select path for VoxelGI Data File")); - GIProbe::bake_begin_function = bake_func_begin; - GIProbe::bake_step_function = bake_func_step; - GIProbe::bake_end_function = bake_func_end; + VoxelGI::bake_begin_function = bake_func_begin; + VoxelGI::bake_step_function = bake_func_step; + VoxelGI::bake_end_function = bake_func_end; } -GIProbeEditorPlugin::~GIProbeEditorPlugin() { +VoxelGIEditorPlugin::~VoxelGIEditorPlugin() { } diff --git a/editor/plugins/gi_probe_editor_plugin.h b/editor/plugins/voxel_gi_editor_plugin.h index fdf0623561..4d3cfe90f6 100644 --- a/editor/plugins/gi_probe_editor_plugin.h +++ b/editor/plugins/voxel_gi_editor_plugin.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gi_probe_editor_plugin.h */ +/* voxel_gi_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GIPROBEEDITORPLUGIN_H -#define GIPROBEEDITORPLUGIN_H +#ifndef VOXEL_GIEDITORPLUGIN_H +#define VOXEL_GIEDITORPLUGIN_H #include "editor/editor_node.h" #include "editor/editor_plugin.h" -#include "scene/3d/gi_probe.h" +#include "scene/3d/voxel_gi.h" #include "scene/resources/material.h" -class GIProbeEditorPlugin : public EditorPlugin { - GDCLASS(GIProbeEditorPlugin, EditorPlugin); +class VoxelGIEditorPlugin : public EditorPlugin { + GDCLASS(VoxelGIEditorPlugin, EditorPlugin); - GIProbe *gi_probe; + VoxelGI *voxel_gi; HBoxContainer *bake_hb; Label *bake_info; @@ -54,21 +54,21 @@ class GIProbeEditorPlugin : public EditorPlugin { static void bake_func_end(); void _bake(); - void _giprobe_save_path_and_bake(const String &p_path); + void _voxel_gi_save_path_and_bake(const String &p_path); protected: static void _bind_methods(); void _notification(int p_what); public: - virtual String get_name() const override { return "GIProbe"; } + virtual String get_name() const override { return "VoxelGI"; } bool has_main_screen() const override { return false; } virtual void edit(Object *p_object) override; virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; - GIProbeEditorPlugin(EditorNode *p_node); - ~GIProbeEditorPlugin(); + VoxelGIEditorPlugin(EditorNode *p_node); + ~VoxelGIEditorPlugin(); }; -#endif // GIPROBEEDITORPLUGIN_H +#endif // VOXEL_GIEDITORPLUGIN_H diff --git a/editor/pot_generator.h b/editor/pot_generator.h index ab055e0c0e..61300064ba 100644 --- a/editor/pot_generator.h +++ b/editor/pot_generator.h @@ -31,7 +31,7 @@ #ifndef POT_GENERATOR_H #define POT_GENERATOR_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/templates/ordered_hash_map.h" #include "core/templates/set.h" diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 9b99372735..ad88e1b45b 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -31,11 +31,11 @@ #include "project_export.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/image_loader.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/string/optimized_translation.h" #include "editor_data.h" @@ -64,6 +64,7 @@ void ProjectExportDialog::_notification(int p_what) { duplicate_preset->set_icon(presets->get_theme_icon("Duplicate", "EditorIcons")); delete_preset->set_icon(presets->get_theme_icon("Remove", "EditorIcons")); connect("confirmed", callable_mp(this, &ProjectExportDialog::_export_pck_zip)); + _update_export_all(); } break; } } @@ -182,10 +183,12 @@ void ProjectExportDialog::_update_export_all() { } } + export_all_button->set_disabled(!can_export); + if (can_export) { - export_all_button->set_disabled(false); + export_all_button->set_tooltip(TTR("Export the project for all the presets defined.")); } else { - export_all_button->set_disabled(true); + export_all_button->set_tooltip(TTR("All presets must have an export path defined for Export All to work.")); } } @@ -433,6 +436,7 @@ void ProjectExportDialog::_export_path_changed(const StringName &p_property, con current->set_export_path(p_value); _update_presets(); + _update_export_all(); } void ProjectExportDialog::_enc_filters_changed(const String &p_filters) { @@ -589,6 +593,10 @@ void ProjectExportDialog::_delete_preset_confirm() { get_ok_button()->set_disabled(true); EditorExport::get_singleton()->remove_export_preset(idx); _update_presets(); + + // The Export All button might become enabled (if all other presets have an export path defined), + // or it could be disabled (if there are no presets anymore). + _update_export_all(); } Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) { @@ -871,10 +879,10 @@ void ProjectExportDialog::_validate_export_path(const String &p_path) { if (invalid_path) { export_project->get_ok_button()->set_disabled(true); - export_project->get_line_edit()->disconnect("text_entered", Callable(export_project, "_file_entered")); + export_project->get_line_edit()->disconnect("text_submitted", Callable(export_project, "_file_submitted")); } else { export_project->get_ok_button()->set_disabled(false); - export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered")); + export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted")); } } @@ -905,10 +913,10 @@ void ProjectExportDialog::_export_project() { // Ensure that signal is connected if previous attempt left it disconnected // with _validate_export_path. // FIXME: This is a hack, we should instead change EditorFileDialog to allow - // disabling validation by the "text_entered" signal. - if (!export_project->get_line_edit()->is_connected("text_entered", Callable(export_project, "_file_entered"))) { + // disabling validation by the "text_submitted" signal. + if (!export_project->get_line_edit()->is_connected("text_submitted", Callable(export_project, "_file_submitted"))) { export_project->get_ok_button()->set_disabled(false); - export_project->get_line_edit()->connect("text_entered", Callable(export_project, "_file_entered")); + export_project->get_line_edit()->connect("text_submitted", Callable(export_project, "_file_submitted")); } export_project->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); @@ -978,9 +986,9 @@ void ProjectExportDialog::_export_all(bool p_debug) { } void ProjectExportDialog::_bind_methods() { - ClassDB::bind_method("get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &ProjectExportDialog::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &ProjectExportDialog::drop_data_fw); ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all); ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path); ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path); @@ -1110,9 +1118,9 @@ ProjectExportDialog::ProjectExportDialog() { exclude_filters->connect("text_changed", callable_mp(this, &ProjectExportDialog::_filter_changed)); script_mode = memnew(OptionButton); - resources_vb->add_margin_child(TTR("Script Export Mode:"), script_mode); + resources_vb->add_margin_child(TTR("GDScript Export Mode:"), script_mode); script_mode->add_item(TTR("Text"), (int)EditorExportPreset::MODE_SCRIPT_TEXT); - script_mode->add_item(TTR("Compiled"), (int)EditorExportPreset::MODE_SCRIPT_COMPILED); + script_mode->add_item(TTR("Compiled Bytecode (Faster Loading)"), (int)EditorExportPreset::MODE_SCRIPT_COMPILED); script_mode->connect("item_selected", callable_mp(this, &ProjectExportDialog::_script_export_mode_changed)); // Feature tags. @@ -1137,12 +1145,12 @@ ProjectExportDialog::ProjectExportDialog() { enc_pck = memnew(CheckButton); enc_pck->connect("toggled", callable_mp(this, &ProjectExportDialog::_enc_pck_changed)); - enc_pck->set_text(TTR("Encrypt exported PCK")); + enc_pck->set_text(TTR("Encrypt Exported PCK")); sec_vb->add_child(enc_pck); enc_directory = memnew(CheckButton); enc_directory->connect("toggled", callable_mp(this, &ProjectExportDialog::_enc_directory_changed)); - enc_directory->set_text("Encrypt index (file names and info)."); + enc_directory->set_text("Encrypt Index (File Names and Info)"); sec_vb->add_child(enc_directory); enc_in_filters = memnew(LineEdit); @@ -1160,9 +1168,9 @@ ProjectExportDialog::ProjectExportDialog() { script_key = memnew(LineEdit); script_key->connect("text_changed", callable_mp(this, &ProjectExportDialog::_script_encryption_key_changed)); script_key_error = memnew(Label); - script_key_error->set_text("- " + TTR("Invalid Encryption Key (must be 64 characters long)")); + script_key_error->set_text("- " + TTR("Invalid Encryption Key (must be 64 hexadecimal characters long)")); script_key_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color("error_color", "Editor")); - sec_vb->add_margin_child(TTR("Encryption Key (256-bits as hex):"), script_key); + sec_vb->add_margin_child(TTR("Encryption Key (256-bits as hexadecimal):"), script_key); sec_vb->add_child(script_key_error); sections->add_child(sec_vb); @@ -1199,8 +1207,8 @@ ProjectExportDialog::ProjectExportDialog() { updating = false; get_cancel_button()->set_text(TTR("Close")); - get_ok_button()->set_text(TTR("Export PCK/Zip")); - export_button = add_button(TTR("Export Project"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export"); + get_ok_button()->set_text(TTR("Export PCK/ZIP...")); + export_button = add_button(TTR("Export Project..."), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export"); export_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_project)); // Disable initially before we select a valid preset export_button->set_disabled(true); @@ -1209,19 +1217,19 @@ ProjectExportDialog::ProjectExportDialog() { export_all_dialog = memnew(ConfirmationDialog); add_child(export_all_dialog); export_all_dialog->set_title("Export All"); - export_all_dialog->set_text(TTR("Export mode?")); + export_all_dialog->set_text(TTR("Choose an export mode:")); export_all_dialog->get_ok_button()->hide(); export_all_dialog->add_button(TTR("Debug"), true, "debug"); export_all_dialog->add_button(TTR("Release"), true, "release"); export_all_dialog->connect("custom_action", callable_mp(this, &ProjectExportDialog::_export_all_dialog_action)); - export_all_button = add_button(TTR("Export All"), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export"); + export_all_button = add_button(TTR("Export All..."), !DisplayServer::get_singleton()->get_swap_cancel_ok(), "export"); export_all_button->connect("pressed", callable_mp(this, &ProjectExportDialog::_export_all_dialog)); export_all_button->set_disabled(true); export_pck_zip = memnew(EditorFileDialog); export_pck_zip->add_filter("*.zip ; " + TTR("ZIP File")); - export_pck_zip->add_filter("*.pck ; " + TTR("Godot Game Pack")); + export_pck_zip->add_filter("*.pck ; " + TTR("Godot Project Pack")); export_pck_zip->set_access(EditorFileDialog::ACCESS_FILESYSTEM); export_pck_zip->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); add_child(export_pck_zip); @@ -1282,8 +1290,6 @@ ProjectExportDialog::ProjectExportDialog() { default_filename = "UnnamedProject"; } } - - _update_export_all(); } ProjectExportDialog::~ProjectExportDialog() { diff --git a/editor/project_export.h b/editor/project_export.h index cfd4934c34..aeace708b8 100644 --- a/editor/project_export.h +++ b/editor/project_export.h @@ -31,7 +31,7 @@ #ifndef PROJECT_EXPORT_SETTINGS_H #define PROJECT_EXPORT_SETTINGS_H -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/thread.h" #include "editor/editor_export.h" #include "editor/editor_file_dialog.h" diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 8bde397b5c..50a763f05a 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -31,11 +31,11 @@ #include "project_manager.h" #include "core/io/config_file.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" #include "core/io/stream_peer_ssl.h" #include "core/io/zip_io.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/translation.h" @@ -862,7 +862,7 @@ public: rasterizer_container->add_child(l); Container *rshb = memnew(HBoxContainer); rasterizer_container->add_child(rshb); - rasterizer_button_group.instance(); + rasterizer_button_group.instantiate(); Container *rvb = memnew(VBoxContainer); rvb->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -1145,7 +1145,7 @@ void ProjectList::load_project_icon(int p_index) { Ref<Texture2D> icon; if (item.icon != "") { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = img->load(item.icon.replace_first("res://", item.path + "/")); if (err == OK) { img->resize(default_icon->get_width(), default_icon->get_height(), Image::INTERPOLATE_LANCZOS); @@ -1924,9 +1924,6 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) { case KEY_ENTER: { _open_selected_projects_ask(); } break; - case KEY_DELETE: { - _erase_project(); - } break; case KEY_HOME: { if (_project_list->get_project_count() > 0) { _project_list->select_project(0); @@ -2400,34 +2397,10 @@ ProjectManager::ProjectManager() { int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale"); switch (display_scale) { - case 0: { + case 0: // Try applying a suitable display scale automatically. - // The code below is adapted in `editor/editor_settings.cpp` and `editor/editor_node.cpp`. - // Make sure to update those when modifying the code below. -#ifdef OSX_ENABLED - editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale()); -#else - const int screen = DisplayServer::get_singleton()->window_get_current_screen(); - float scale; - if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) { - // hiDPI display. - scale = 2.0; - } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) { - // Likely a hiDPI display, but we aren't certain due to the returned DPI. - // Use an intermediate scale to handle this situation. - scale = 1.5; - } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) { - // Small loDPI display. Use a smaller display scale so that editor elements fit more easily. - // Icons won't look great, but this is better than having editor elements overflow from its window. - scale = 0.75; - } else { - scale = 1.0; - } - - editor_set_scale(scale); -#endif - } break; - + editor_set_scale(EditorSettings::get_singleton()->get_auto_display_scale()); + break; case 1: editor_set_scale(0.75); break; @@ -2490,7 +2463,7 @@ ProjectManager::ProjectManager() { tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed)); HBoxContainer *projects_hb = memnew(HBoxContainer); - projects_hb->set_name(TTR("Projects")); + projects_hb->set_name(TTR("Local Projects")); tabs->add_child(projects_hb); { @@ -2556,16 +2529,19 @@ ProjectManager::ProjectManager() { Button *create = memnew(Button); create->set_text(TTR("New Project")); + create->set_shortcut(ED_SHORTCUT("project_manager/new_project", TTR("New Project"), KEY_MASK_CMD | KEY_N)); create->connect("pressed", callable_mp(this, &ProjectManager::_new_project)); tree_vb->add_child(create); Button *import = memnew(Button); import->set_text(TTR("Import")); + import->set_shortcut(ED_SHORTCUT("project_manager/import_project", TTR("Import Project"), KEY_MASK_CMD | KEY_I)); import->connect("pressed", callable_mp(this, &ProjectManager::_import_project)); tree_vb->add_child(import); Button *scan = memnew(Button); scan->set_text(TTR("Scan")); + scan->set_shortcut(ED_SHORTCUT("project_manager/scan_projects", TTR("Scan Projects"), KEY_MASK_CMD | KEY_S)); scan->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects)); tree_vb->add_child(scan); @@ -2573,21 +2549,25 @@ ProjectManager::ProjectManager() { open_btn = memnew(Button); open_btn->set_text(TTR("Edit")); + open_btn->set_shortcut(ED_SHORTCUT("project_manager/edit_project", TTR("Edit Project"), KEY_MASK_CMD | KEY_E)); open_btn->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask)); tree_vb->add_child(open_btn); run_btn = memnew(Button); run_btn->set_text(TTR("Run")); + run_btn->set_shortcut(ED_SHORTCUT("project_manager/run_project", TTR("Run Project"), KEY_MASK_CMD | KEY_R)); run_btn->connect("pressed", callable_mp(this, &ProjectManager::_run_project)); tree_vb->add_child(run_btn); rename_btn = memnew(Button); rename_btn->set_text(TTR("Rename")); + rename_btn->set_shortcut(ED_SHORTCUT("project_manager/rename_project", TTR("Rename Project"), KEY_F2)); rename_btn->connect("pressed", callable_mp(this, &ProjectManager::_rename_project)); tree_vb->add_child(rename_btn); erase_btn = memnew(Button); erase_btn->set_text(TTR("Remove")); + erase_btn->set_shortcut(ED_SHORTCUT("project_manager/remove_project", TTR("Remove Project"), KEY_DELETE)); erase_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_project)); tree_vb->add_child(erase_btn); @@ -2621,7 +2601,7 @@ ProjectManager::ProjectManager() { version_btn = memnew(LinkButton); String hash = String(VERSION_HASH); if (hash.length() != 0) { - hash = "." + hash.left(9); + hash = " " + vformat("[%s]", hash.left(9)); } version_btn->set_text("v" VERSION_FULL_BUILD + hash); // Fade the version label to be less prominent, but still readable. @@ -2672,7 +2652,7 @@ ProjectManager::ProjectManager() { if (StreamPeerSSL::is_available()) { asset_library = memnew(EditorAssetLibrary(true)); - asset_library->set_name(TTR("Templates")); + asset_library->set_name(TTR("Asset Library Projects")); tabs->add_child(asset_library); asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project)); } else { diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 8b0d9ae0fc..7414c2d8e6 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -192,7 +192,7 @@ void CustomPropertyEditor::_menu_option(int p_which) { String orig_type = res_orig->get_class(); - Object *inst = ClassDB::instance(orig_type); + Object *inst = ClassDB::instantiate(orig_type); Ref<Resource> res = Ref<Resource>(Object::cast_to<Resource>(inst)); @@ -262,7 +262,7 @@ void CustomPropertyEditor::_menu_option(int p_which) { return; } - Variant obj = ClassDB::instance(intype); + Variant obj = ClassDB::instantiate(intype); if (!obj) { if (ScriptServer::is_global_class(intype)) { @@ -727,13 +727,13 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: value_editor[3]->set_text(String::num(plane.d)); } break; - case Variant::QUAT: { + case Variant::QUATERNION: { field_names.push_back("x"); field_names.push_back("y"); field_names.push_back("z"); field_names.push_back("w"); config_value_editors(4, 4, 10, field_names); - Quat q = v; + Quaternion q = v; value_editor[0]->set_text(String::num(q.x)); value_editor[1]->set_text(String::num(q.y)); value_editor[2]->set_text(String::num(q.z)); @@ -791,7 +791,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { field_names.push_back("xx"); field_names.push_back("xy"); field_names.push_back("xz"); @@ -806,7 +806,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: field_names.push_back("zo"); config_value_editors(12, 4, 16, field_names); - Transform tr = v; + Transform3D tr = v; for (int i = 0; i < 9; i++) { value_editor[(i / 3) * 4 + i % 3]->set_text(String::num(tr.basis.elements[i / 3][i % 3])); } @@ -908,7 +908,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant:: } } - if (!is_custom_resource && !ClassDB::can_instance(t)) { + if (!is_custom_resource && !ClassDB::can_instantiate(t)) { continue; } @@ -1078,7 +1078,7 @@ void CustomPropertyEditor::_type_create_selected(int p_idx) { String intype = inheritors_array[p_idx]; - Variant obj = ClassDB::instance(intype); + Variant obj = ClassDB::instantiate(intype); if (!obj) { if (ScriptServer::is_global_class(intype)) { @@ -1111,7 +1111,7 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) { } Ref<ViewportTexture> vt; - vt.instance(); + vt.instantiate(); vt->set_viewport_path_in_scene(get_tree()->get_edited_scene_root()->get_path_to(to_node)); vt->setup_local_to_scene(); v = vt; @@ -1268,7 +1268,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) { String intype = inheritors_array[0]; if (hint == PROPERTY_HINT_RESOURCE_TYPE) { - Variant obj = ClassDB::instance(intype); + Variant obj = ClassDB::instantiate(intype); if (!obj) { if (ScriptServer::is_global_class(intype)) { @@ -1332,7 +1332,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) { propvalues.push_back(p); } - Ref<Resource> res = Ref<Resource>(ClassDB::instance(res_orig->get_class())); + Ref<Resource> res = Ref<Resource>(ClassDB::instantiate(res_orig->get_class())); ERR_FAIL_COND(res.is_null()); @@ -1446,12 +1446,14 @@ void CustomPropertyEditor::_modified(String p_string) { return; } + Variant prev_v = v; + updating = true; switch (type) { case Variant::INT: { String text = TS->parse_number(value_editor[0]->get_text()); Ref<Expression> expr; - expr.instance(); + expr.instantiate(); Error err = expr->parse(text); if (err != OK) { v = value_editor[0]->get_text().to_int(); @@ -1459,14 +1461,18 @@ void CustomPropertyEditor::_modified(String p_string) { } else { v = expr->execute(Array(), nullptr, false); } - emit_signal("variant_changed"); + if (v != prev_v) { + emit_signal("variant_changed"); + } } break; case Variant::FLOAT: { if (hint != PROPERTY_HINT_EXP_EASING) { String text = TS->parse_number(value_editor[0]->get_text()); v = _parse_real_expression(text); - emit_signal("variant_changed"); + if (v != prev_v) { + emit_signal("variant_changed"); + } } } break; @@ -1479,7 +1485,9 @@ void CustomPropertyEditor::_modified(String p_string) { vec.x = _parse_real_expression(value_editor[0]->get_text()); vec.y = _parse_real_expression(value_editor[1]->get_text()); v = vec; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; case Variant::RECT2: { @@ -1490,7 +1498,9 @@ void CustomPropertyEditor::_modified(String p_string) { r2.size.x = _parse_real_expression(value_editor[2]->get_text()); r2.size.y = _parse_real_expression(value_editor[3]->get_text()); v = r2; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; @@ -1500,7 +1510,9 @@ void CustomPropertyEditor::_modified(String p_string) { vec.y = _parse_real_expression(value_editor[1]->get_text()); vec.z = _parse_real_expression(value_editor[2]->get_text()); v = vec; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; case Variant::PLANE: { @@ -1510,17 +1522,21 @@ void CustomPropertyEditor::_modified(String p_string) { pl.normal.z = _parse_real_expression(value_editor[2]->get_text()); pl.d = _parse_real_expression(value_editor[3]->get_text()); v = pl; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; - case Variant::QUAT: { - Quat q; + case Variant::QUATERNION: { + Quaternion q; q.x = _parse_real_expression(value_editor[0]->get_text()); q.y = _parse_real_expression(value_editor[1]->get_text()); q.z = _parse_real_expression(value_editor[2]->get_text()); q.w = _parse_real_expression(value_editor[3]->get_text()); v = q; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; case Variant::AABB: { @@ -1534,7 +1550,9 @@ void CustomPropertyEditor::_modified(String p_string) { size.y = _parse_real_expression(value_editor[4]->get_text()); size.z = _parse_real_expression(value_editor[5]->get_text()); v = AABB(pos, size); - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; case Variant::TRANSFORM2D: { @@ -1544,7 +1562,9 @@ void CustomPropertyEditor::_modified(String p_string) { } v = m; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; case Variant::BASIS: { @@ -1554,10 +1574,12 @@ void CustomPropertyEditor::_modified(String p_string) { } v = m; - _emit_changed_whole_or_field(); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { Basis basis; for (int i = 0; i < 9; i++) { basis.elements[i / 3][i % 3] = _parse_real_expression(value_editor[(i / 3) * 4 + i % 3]->get_text()); @@ -1569,8 +1591,10 @@ void CustomPropertyEditor::_modified(String p_string) { origin.y = _parse_real_expression(value_editor[7]->get_text()); origin.z = _parse_real_expression(value_editor[11]->get_text()); - v = Transform(basis, origin); - _emit_changed_whole_or_field(); + v = Transform3D(basis, origin); + if (v != prev_v) { + _emit_changed_whole_or_field(); + } } break; case Variant::COLOR: { @@ -1578,7 +1602,9 @@ void CustomPropertyEditor::_modified(String p_string) { case Variant::NODE_PATH: { v = NodePath(value_editor[0]->get_text()); - emit_signal("variant_changed"); + if (v != prev_v) { + emit_signal("variant_changed"); + } } break; case Variant::DICTIONARY: { } break; @@ -1603,7 +1629,7 @@ void CustomPropertyEditor::_modified(String p_string) { real_t CustomPropertyEditor::_parse_real_expression(String text) { Ref<Expression> expr; - expr.instance(); + expr.instantiate(); Error err = expr->parse(text); real_t out; if (err != OK) { @@ -1635,11 +1661,11 @@ void CustomPropertyEditor::_focus_enter() { case Variant::RECT2: case Variant::VECTOR3: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::TRANSFORM2D: case Variant::BASIS: - case Variant::TRANSFORM: { + case Variant::TRANSFORM3D: { for (int i = 0; i < MAX_VALUE_EDITORS; ++i) { if (value_editor[i]->has_focus()) { focused_value_editor = i; @@ -1654,25 +1680,7 @@ void CustomPropertyEditor::_focus_enter() { } void CustomPropertyEditor::_focus_exit() { - switch (type) { - case Variant::FLOAT: - case Variant::STRING: - case Variant::VECTOR2: - case Variant::RECT2: - case Variant::VECTOR3: - case Variant::PLANE: - case Variant::QUAT: - case Variant::AABB: - case Variant::TRANSFORM2D: - case Variant::BASIS: - case Variant::TRANSFORM: { - for (int i = 0; i < MAX_VALUE_EDITORS; ++i) { - value_editor[i]->select(0, 0); - } - } break; - default: { - } - } + _modified(String()); } void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) { @@ -1773,7 +1781,7 @@ CustomPropertyEditor::CustomPropertyEditor() { value_hboxes[hbox_idx]->add_child(value_editor[i]); value_editor[i]->set_h_size_flags(Control::SIZE_EXPAND_FILL); value_editor[i]->hide(); - value_editor[i]->connect("text_entered", callable_mp(this, &CustomPropertyEditor::_modified)); + value_editor[i]->connect("text_submitted", callable_mp(this, &CustomPropertyEditor::_modified)); value_editor[i]->connect("focus_entered", callable_mp(this, &CustomPropertyEditor::_focus_enter)); value_editor[i]->connect("focus_exited", callable_mp(this, &CustomPropertyEditor::_focus_exit)); } diff --git a/editor/property_editor.h b/editor/property_editor.h index c6929f3b42..8a587b50b0 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -50,8 +50,8 @@ class PropertyValueEvaluator; class CreateDialog; class PropertySelector; -class EditorResourceConversionPlugin : public Reference { - GDCLASS(EditorResourceConversionPlugin, Reference); +class EditorResourceConversionPlugin : public RefCounted { + GDCLASS(EditorResourceConversionPlugin, RefCounted); protected: static void _bind_methods(); diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index bf31be536c..00652c02c8 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -125,18 +125,23 @@ void PropertySelector::_update_search() { search_options->get_theme_icon("float", "EditorIcons"), search_options->get_theme_icon("String", "EditorIcons"), search_options->get_theme_icon("Vector2", "EditorIcons"), + search_options->get_theme_icon("Vector2i", "EditorIcons"), search_options->get_theme_icon("Rect2", "EditorIcons"), + search_options->get_theme_icon("Rect2i", "EditorIcons"), search_options->get_theme_icon("Vector3", "EditorIcons"), + search_options->get_theme_icon("Vector3i", "EditorIcons"), search_options->get_theme_icon("Transform2D", "EditorIcons"), search_options->get_theme_icon("Plane", "EditorIcons"), - search_options->get_theme_icon("Quat", "EditorIcons"), + search_options->get_theme_icon("Quaternion", "EditorIcons"), search_options->get_theme_icon("AABB", "EditorIcons"), search_options->get_theme_icon("Basis", "EditorIcons"), - search_options->get_theme_icon("Transform", "EditorIcons"), + search_options->get_theme_icon("Transform3D", "EditorIcons"), search_options->get_theme_icon("Color", "EditorIcons"), - search_options->get_theme_icon("Path", "EditorIcons"), + search_options->get_theme_icon("NodePath", "EditorIcons"), search_options->get_theme_icon("RID", "EditorIcons"), - search_options->get_theme_icon("Object", "EditorIcons"), + search_options->get_theme_icon("MiniObject", "EditorIcons"), + search_options->get_theme_icon("Callable", "EditorIcons"), + search_options->get_theme_icon("Signal", "EditorIcons"), search_options->get_theme_icon("Dictionary", "EditorIcons"), search_options->get_theme_icon("Array", "EditorIcons"), search_options->get_theme_icon("PackedByteArray", "EditorIcons"), diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 349e05b47b..a9dcbc9f09 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -58,7 +58,7 @@ void SceneTreeDock::_nodes_drag_begin() { } void SceneTreeDock::_quick_open() { - instance_scenes(quick_open->get_selected_files(), scene_tree->get_selected()); + instantiate_scenes(quick_open->get_selected_files(), scene_tree->get_selected()); } void SceneTreeDock::_input(Ref<InputEvent> p_event) { @@ -89,7 +89,7 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { } else if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { - _tool_selected(TOOL_INSTANCE); + _tool_selected(TOOL_INSTANTIATE); } else if (ED_IS_SHORTCUT("scene_tree/expand_collapse_all", p_event)) { _tool_selected(TOOL_EXPAND_COLLAPSE); } else if (ED_IS_SHORTCUT("scene_tree/cut_node", p_event)) { @@ -128,13 +128,13 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { accept_event(); } -void SceneTreeDock::instance(const String &p_file) { +void SceneTreeDock::instantiate(const String &p_file) { Vector<String> scenes; scenes.push_back(p_file); - instance_scenes(scenes, scene_tree->get_selected()); + instantiate_scenes(scenes, scene_tree->get_selected()); } -void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_parent) { +void SceneTreeDock::instantiate_scenes(const Vector<String> &p_files, Node *p_parent) { Node *parent = p_parent; if (!parent) { @@ -147,18 +147,18 @@ void SceneTreeDock::instance_scenes(const Vector<String> &p_files, Node *p_paren if (!parent) { if (p_files.size() == 1) { - accept->set_text(TTR("No parent to instance a child at.")); + accept->set_text(TTR("No parent to instantiate a child at.")); } else { - accept->set_text(TTR("No parent to instance the scenes at.")); + accept->set_text(TTR("No parent to instantiate the scenes at.")); } accept->popup_centered(); return; }; - _perform_instance_scenes(p_files, parent, -1); + _perform_instantiate_scenes(p_files, parent, -1); } -void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node *parent, int p_pos) { +void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos) { ERR_FAIL_COND(!parent); Vector<Node *> instances; @@ -175,8 +175,8 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node break; } - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { current_option = -1; accept->set_text(vformat(TTR("Error instancing scene from %s"), p_files[i])); accept->popup_centered(); @@ -185,7 +185,7 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node } if (edited_scene->get_filename() != "") { - if (_cyclical_dependency_exists(edited_scene->get_filename(), instanced_scene)) { + if (_cyclical_dependency_exists(edited_scene->get_filename(), instantiated_scene)) { accept->set_text(vformat(TTR("Cannot instance the scene '%s' because the current scene exists within one of its nodes."), p_files[i])); accept->popup_centered(); error = true; @@ -193,9 +193,9 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node } } - instanced_scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_files[i])); + instantiated_scene->set_filename(ProjectSettings::get_singleton()->localize_path(p_files[i])); - instances.push_back(instanced_scene); + instances.push_back(instantiated_scene); } if (error) { @@ -208,19 +208,19 @@ void SceneTreeDock::_perform_instance_scenes(const Vector<String> &p_files, Node editor_data->get_undo_redo().create_action(TTR("Instance Scene(s)")); for (int i = 0; i < instances.size(); i++) { - Node *instanced_scene = instances[i]; + Node *instantiated_scene = instances[i]; - editor_data->get_undo_redo().add_do_method(parent, "add_child", instanced_scene); + editor_data->get_undo_redo().add_do_method(parent, "add_child", instantiated_scene); if (p_pos >= 0) { - editor_data->get_undo_redo().add_do_method(parent, "move_child", instanced_scene, p_pos + i); + editor_data->get_undo_redo().add_do_method(parent, "move_child", instantiated_scene, p_pos + i); } - editor_data->get_undo_redo().add_do_method(instanced_scene, "set_owner", edited_scene); + editor_data->get_undo_redo().add_do_method(instantiated_scene, "set_owner", edited_scene); editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); - editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instanced_scene); - editor_data->get_undo_redo().add_do_reference(instanced_scene); - editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instanced_scene); + editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", instantiated_scene); + editor_data->get_undo_redo().add_do_reference(instantiated_scene); + editor_data->get_undo_redo().add_undo_method(parent, "remove_child", instantiated_scene); - String new_name = parent->validate_child_name(instanced_scene); + String new_name = parent->validate_child_name(instantiated_scene); EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton(); editor_data->get_undo_redo().add_do_method(ed, "live_debug_instance_node", edited_scene->get_path_to(parent), p_files[i], new_name); editor_data->get_undo_redo().add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).plus_file(new_name))); @@ -241,8 +241,8 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) return; } - Node *instanced_scene = sdata->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); - if (!instanced_scene) { + Node *instantiated_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); + if (!instantiated_scene) { accept->set_text(vformat(TTR("Error instancing scene from %s"), p_file)); accept->popup_centered(); return; @@ -254,10 +254,10 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) Node *parent = base->get_parent(); int pos = base->get_index(); undo_redo->add_do_method(parent, "remove_child", base); - undo_redo->add_undo_method(parent, "remove_child", instanced_scene); - undo_redo->add_do_method(parent, "add_child", instanced_scene); + undo_redo->add_undo_method(parent, "remove_child", instantiated_scene); + undo_redo->add_do_method(parent, "add_child", instantiated_scene); undo_redo->add_undo_method(parent, "add_child", base); - undo_redo->add_do_method(parent, "move_child", instanced_scene, pos); + undo_redo->add_do_method(parent, "move_child", instantiated_scene, pos); undo_redo->add_undo_method(parent, "move_child", base, pos); List<Node *> owned; @@ -266,17 +266,17 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) for (List<Node *>::Element *F = owned.front(); F; F = F->next()) { owners.push_back(F->get()); } - undo_redo->add_do_method(instanced_scene, "set_owner", edited_scene); + undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene); undo_redo->add_undo_method(this, "_set_owners", edited_scene, owners); undo_redo->add_do_method(editor_selection, "clear"); undo_redo->add_undo_method(editor_selection, "clear"); - undo_redo->add_do_method(editor_selection, "add_node", instanced_scene); + undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene); undo_redo->add_undo_method(editor_selection, "add_node", base); - undo_redo->add_do_property(scene_tree, "set_selected", instanced_scene); + undo_redo->add_do_property(scene_tree, "set_selected", instantiated_scene); undo_redo->add_undo_property(scene_tree, "set_selected", base); - undo_redo->add_do_reference(instanced_scene); + undo_redo->add_do_reference(instantiated_scene); undo_redo->add_undo_reference(base); undo_redo->commit_action(); } @@ -313,7 +313,7 @@ bool SceneTreeDock::_track_inherit(const String &p_target_scene_path, Node *p_de String path = ss->get_path(); Ref<PackedScene> data = ResourceLoader::load(path); if (data.is_valid()) { - p = data->instance(PackedScene::GEN_EDIT_STATE_INSTANCE); + p = data->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); if (!p) { continue; } @@ -359,7 +359,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { break; } - if (reset_create_dialog) { + if (reset_create_dialog && !p_confirm_override) { create_dialog->set_base_type("Node"); reset_create_dialog = false; } @@ -388,7 +388,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { emit_signal("add_node_used"); } } break; - case TOOL_INSTANCE: { + case TOOL_INSTANTIATE: { if (!profile_allow_editing) { break; } @@ -400,7 +400,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } quick_open->popup_dialog("PackedScene", true); - quick_open->set_title(TTR("Instance Child Scene")); + quick_open->set_title(TTR("Instantiate Child Scene")); if (!p_confirm_override) { emit_signal("add_node_used"); } @@ -881,7 +881,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (node == editor_data->get_edited_scene_root()) { msg = vformat(TTR("Delete the root node \"%s\"?"), node->get_name()); } else if (node->get_filename() == "" && node->get_child_count() > 0) { - // Display this message only for non-instanced scenes + // Display this message only for non-instantiated scenes msg = vformat(TTR("Delete node \"%s\" and its children?"), node->get_name()); } else { msg = vformat(TTR("Delete node \"%s\"?"), node->get_name()); @@ -922,13 +922,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { Node *tocopy = selection.front()->get(); if (tocopy == scene) { - accept->set_text(TTR("Can't save the root node branch as an instanced scene.\nTo create an editable copy of the current scene, duplicate it using the FileSystem dock context menu\nor create an inherited scene using Scene > New Inherited Scene... instead.")); + accept->set_text(TTR("Can't save the root node branch as an instantiated scene.\nTo create an editable copy of the current scene, duplicate it using the FileSystem dock context menu\nor create an inherited scene using Scene > New Inherited Scene... instead.")); accept->popup_centered(); break; } if (tocopy != editor_data->get_edited_scene_root() && tocopy->get_filename() != "") { - accept->set_text(TTR("Can't save the branch of an already instanced scene.\nTo create a variation of a scene, you can make an inherited scene based on the instanced scene using Scene > New Inherited Scene... instead.")); + accept->set_text(TTR("Can't save the branch of an already instantiated scene.\nTo create a variation of a scene, you can make an inherited scene based on the instantiated scene using Scene > New Inherited Scene... instead.")); accept->popup_centered(); break; } @@ -1103,14 +1103,14 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (TOOL_CREATE_FAVORITE == p_tool) { String name = selected_favorite_root.get_slicec(' ', 0); if (ScriptServer::is_global_class(name)) { - new_node = Object::cast_to<Node>(ClassDB::instance(ScriptServer::get_global_class_native_base(name))); + new_node = Object::cast_to<Node>(ClassDB::instantiate(ScriptServer::get_global_class_native_base(name))); Ref<Script> script = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); if (new_node && script.is_valid()) { new_node->set_script(script); new_node->set_name(name); } } else { - new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root)); + new_node = Object::cast_to<Node>(ClassDB::instantiate(selected_favorite_root)); } if (!new_node) { @@ -1134,12 +1134,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } - editor_data->get_undo_redo().create_action(TTR("New Scene Root")); - editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", new_node); - editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); - editor_data->get_undo_redo().add_do_reference(new_node); - editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr); - editor_data->get_undo_redo().commit_action(); + add_root_node(new_node); editor->edit_node(new_node); editor_selection->clear(); @@ -1162,6 +1157,15 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } } +void SceneTreeDock::add_root_node(Node *p_node) { + editor_data->get_undo_redo().create_action(TTR("New Scene Root")); + editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", p_node); + editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree"); + editor_data->get_undo_redo().add_do_reference(p_node); + editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", (Object *)nullptr); + editor_data->get_undo_redo().commit_action(); +} + void SceneTreeDock::_node_collapsed(Object *p_obj) { TreeItem *ti = Object::cast_to<TreeItem>(p_obj); if (!ti) { @@ -1202,9 +1206,6 @@ void SceneTreeDock::_notification(int p_what) { filter->set_right_icon(get_theme_icon("Search", "EditorIcons")); filter->set_clear_button_enabled(true); - EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); - scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed)); - // create_root_dialog HBoxContainer *top_row = memnew(HBoxContainer); top_row->set_name("NodeShortcutsTopRow"); @@ -1409,9 +1410,102 @@ void SceneTreeDock::fill_path_renames(Node *p_node, Node *p_new_parent, List<Pai _fill_path_renames(base_path, new_base_path, p_node, p_renames); } +bool SceneTreeDock::_update_node_path(const NodePath &p_root_path, NodePath &r_node_path, List<Pair<NodePath, NodePath>> *p_renames) { + NodePath root_path_new = p_root_path; + for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { + if (p_root_path == F->get().first) { + root_path_new = F->get().second; + break; + } + } + + // Goes through all paths to check if it's matching. + for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { + NodePath rel_path_old = p_root_path.rel_path_to(F->get().first); + + // If old path detected, then it needs to be replaced with the new one. + if (r_node_path == rel_path_old) { + NodePath rel_path_new = F->get().second; + + // If not empty, get new relative path. + if (!rel_path_new.is_empty()) { + rel_path_new = root_path_new.rel_path_to(rel_path_new); + } + + r_node_path = rel_path_new; + return true; + } + + // Update the node itself if it has a valid node path and has not been deleted. + if (p_root_path == F->get().first && r_node_path != NodePath() && F->get().second != NodePath()) { + NodePath abs_path = NodePath(String(root_path_new).plus_file(r_node_path)).simplified(); + NodePath rel_path_new = F->get().second.rel_path_to(abs_path); + + r_node_path = rel_path_new; + return true; + } + } + + return false; +} + +bool SceneTreeDock::_check_node_path_recursive(const NodePath &p_root_path, Variant &r_variant, List<Pair<NodePath, NodePath>> *p_renames) { + switch (r_variant.get_type()) { + case Variant::NODE_PATH: { + NodePath node_path = r_variant; + if (_update_node_path(p_root_path, node_path, p_renames)) { + r_variant = node_path; + return true; + } + } break; + + case Variant::ARRAY: { + Array a = r_variant; + bool updated = false; + for (int i = 0; i < a.size(); i++) { + Variant value = a[i]; + if (_check_node_path_recursive(p_root_path, value, p_renames)) { + if (!updated) { + a = a.duplicate(); // Need to duplicate for undo-redo to work. + updated = true; + } + a[i] = value; + } + } + if (updated) { + r_variant = a; + return true; + } + } break; + + case Variant::DICTIONARY: { + Dictionary d = r_variant; + bool updated = false; + for (int i = 0; i < d.size(); i++) { + Variant value = d.get_value_at_index(i); + if (_check_node_path_recursive(p_root_path, value, p_renames)) { + if (!updated) { + d = d.duplicate(); // Need to duplicate for undo-redo to work. + updated = true; + } + d[d.get_key_at_index(i)] = value; + } + } + if (updated) { + r_variant = d; + return true; + } + } break; + + default: { + } + } + + return false; +} + void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims) { Map<Ref<Animation>, Set<int>> rem_anims; - if (!r_rem_anims) { r_rem_anims = &rem_anims; } @@ -1424,60 +1518,22 @@ void SceneTreeDock::perform_node_renames(Node *p_base, List<Pair<NodePath, NodeP return; } - // Renaming node paths used in script instances - if (p_base->get_script_instance()) { - ScriptInstance *si = p_base->get_script_instance(); - - if (si) { - List<PropertyInfo> properties; - si->get_property_list(&properties); - NodePath root_path = p_base->get_path(); - - for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { - String propertyname = E->get().name; - Variant p = p_base->get(propertyname); - if (p.get_type() == Variant::NODE_PATH) { - NodePath root_path_new = root_path; - for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { - if (root_path == F->get().first) { - root_path_new = F->get().second; - break; - } - } - - // Goes through all paths to check if its matching - for (List<Pair<NodePath, NodePath>>::Element *F = p_renames->front(); F; F = F->next()) { - NodePath rel_path_old = root_path.rel_path_to(F->get().first); - - // if old path detected, then it needs to be replaced with the new one - if (p == rel_path_old) { - NodePath rel_path_new = F->get().second; - - // if not empty, get new relative path - if (!rel_path_new.is_empty()) { - rel_path_new = root_path_new.rel_path_to(F->get().second); - } + // Renaming node paths used in node properties. + List<PropertyInfo> properties; + p_base->get_property_list(&properties); + NodePath base_root_path = p_base->get_path(); - editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new); - editor_data->get_undo_redo().add_undo_property(p_base, propertyname, rel_path_old); - - p_base->set(propertyname, rel_path_new); - break; - } - - // update the node itself if it has a valid node path and has not been deleted - if (root_path == F->get().first && p != NodePath() && F->get().second != NodePath()) { - NodePath abs_path = NodePath(String(root_path).plus_file(p)).simplified(); - NodePath rel_path_new = F->get().second.rel_path_to(abs_path); - - editor_data->get_undo_redo().add_do_property(p_base, propertyname, rel_path_new); - editor_data->get_undo_redo().add_undo_property(p_base, propertyname, p); - - p_base->set(propertyname, rel_path_new); - } - } - } - } + for (List<PropertyInfo>::Element *E = properties.front(); E; E = E->next()) { + if (!(E->get().usage & (PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_EDITOR))) { + continue; + } + String propertyname = E->get().name; + Variant old_variant = p_base->get(propertyname); + Variant updated_variant = old_variant; + if (_check_node_path_recursive(base_root_path, updated_variant, p_renames)) { + editor_data->get_undo_redo().add_do_property(p_base, propertyname, updated_variant); + editor_data->get_undo_redo().add_undo_property(p_base, propertyname, old_variant); + p_base->set(propertyname, updated_variant); } } @@ -1640,7 +1696,7 @@ bool SceneTreeDock::_validate_no_instance() { for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { if (E->get() != edited_scene && E->get()->get_filename() != "") { - accept->set_text(TTR("This operation can't be done on instanced scenes.")); + accept->set_text(TTR("This operation can't be done on instantiated scenes.")); accept->popup_centered(); return false; } @@ -2218,7 +2274,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop Node *newnode = p_by_node; if (p_keep_properties) { - Node *default_oldnode = Object::cast_to<Node>(ClassDB::instance(n->get_class())); + Node *default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(n->get_class())); List<PropertyInfo> pinfo; n->get_property_list(&pinfo); @@ -2459,7 +2515,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_ int to_pos = -1; _normalize_drop(node, to_pos, p_type); - _perform_instance_scenes(p_files, node, to_pos); + _perform_instantiate_scenes(p_files, node, to_pos); } void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) { @@ -2542,7 +2598,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->clear(); if (profile_allow_editing) { menu->add_icon_shortcut(get_theme_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); - menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE); + menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); } menu->set_size(Size2(1, 1)); @@ -2575,7 +2631,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { } menu->add_icon_shortcut(get_theme_icon("Add", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/add_child_node"), TOOL_NEW); - menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANCE); + menu->add_icon_shortcut(get_theme_icon("Instance", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE); } menu->add_icon_shortcut(get_theme_icon("Collapse", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/expand_collapse_all"), TOOL_EXPAND_COLLAPSE); menu->add_separator(); @@ -2813,7 +2869,7 @@ void SceneTreeDock::open_add_child_dialog() { } void SceneTreeDock::open_instance_child_dialog() { - _tool_selected(TOOL_INSTANCE, true); + _tool_selected(TOOL_INSTANTIATE, true); } void SceneTreeDock::add_remote_tree_editor(Control *p_remote) { @@ -2959,6 +3015,7 @@ void SceneTreeDock::_clear_clipboard() { void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) { List<PropertyInfo> props; p_node->get_property_list(&props); + bool is_instantiated = EditorPropertyRevert::may_node_be_in_instance(p_node); for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { @@ -2969,6 +3026,15 @@ void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) if (v.is_ref()) { RES res = v; if (res.is_valid()) { + if (is_instantiated) { + Variant orig; + if (EditorPropertyRevert::get_instantiated_node_original_property(p_node, E->get().name, orig)) { + if (!EditorPropertyRevert::is_node_property_different(p_node, v, orig)) { + continue; + } + } + } + if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) { _create_remap_for_resource(res, r_remap); } @@ -3010,7 +3076,7 @@ void SceneTreeDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_input"), &SceneTreeDock::_input); ClassDB::bind_method(D_METHOD("_update_script_button"), &SceneTreeDock::_update_script_button); - ClassDB::bind_method(D_METHOD("instance"), &SceneTreeDock::instance); + ClassDB::bind_method(D_METHOD("instantiate"), &SceneTreeDock::instantiate); ClassDB::bind_method(D_METHOD("get_tree_editor"), &SceneTreeDock::get_tree_editor); ClassDB::bind_method(D_METHOD("replace_node"), &SceneTreeDock::replace_node); @@ -3044,7 +3110,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel ED_SHORTCUT("scene_tree/rename", TTR("Rename"), KEY_F2); ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_SHIFT | KEY_F2); ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KEY_MASK_CMD | KEY_A); - ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_A); + ED_SHORTCUT("scene_tree/instance_scene", TTR("Instantiate Child Scene"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_A); ED_SHORTCUT("scene_tree/expand_collapse_all", TTR("Expand/Collapse All")); ED_SHORTCUT("scene_tree/cut_node", TTR("Cut"), KEY_MASK_CMD | KEY_X); ED_SHORTCUT("scene_tree/copy_node", TTR("Copy"), KEY_MASK_CMD | KEY_C); @@ -3073,8 +3139,8 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel button_instance = memnew(Button); button_instance->set_flat(true); - button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_INSTANCE, false)); - button_instance->set_tooltip(TTR("Instance a scene file as a Node. Creates an inherited scene if no root node exists.")); + button_instance->connect("pressed", callable_mp(this, &SceneTreeDock::_tool_selected), make_binds(TOOL_INSTANTIATE, false)); + button_instance->set_tooltip(TTR("Instantiate a scene file as a Node. Creates an inherited scene if no root node exists.")); button_instance->set_shortcut(ED_GET_SHORTCUT("scene_tree/instance_scene")); filter_hbc->add_child(button_instance); @@ -3147,6 +3213,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel scene_tree->connect("nodes_dragged", callable_mp(this, &SceneTreeDock::_nodes_drag_begin)); scene_tree->get_scene_tree()->connect("item_double_clicked", callable_mp(this, &SceneTreeDock::_focus_node)); + scene_tree->get_scene_tree()->connect("item_collapsed", callable_mp(this, &SceneTreeDock::_node_collapsed)); + + editor_selection->connect("selection_changed", callable_mp(this, &SceneTreeDock::_selection_changed)); scene_tree->set_undo_redo(&editor_data->get_undo_redo()); scene_tree->set_editor_selection(editor_selection); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 53f31375f8..08d992d465 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -55,7 +55,7 @@ class SceneTreeDock : public VBoxContainer { enum Tool { TOOL_NEW, - TOOL_INSTANCE, + TOOL_INSTANTIATE, TOOL_EXPAND_COLLAPSE, TOOL_CUT, TOOL_COPY, @@ -224,7 +224,7 @@ class SceneTreeDock : public VBoxContainer { void _filter_changed(const String &p_filter); - void _perform_instance_scenes(const Vector<String> &p_files, Node *parent, int p_pos); + void _perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos); void _replace_with_branch_scene(const String &p_file, Node *base); void _file_selected(String p_file); @@ -247,6 +247,9 @@ class SceneTreeDock : public VBoxContainer { static SceneTreeDock *singleton; static void _update_configuration_warning(); + static bool _update_node_path(const NodePath &p_root_path, NodePath &r_node_path, List<Pair<NodePath, NodePath>> *p_renames); + static bool _check_node_path_recursive(const NodePath &p_root_path, Variant &r_variant, List<Pair<NodePath, NodePath>> *p_renames); + protected: void _notification(int p_what); static void _bind_methods(); @@ -258,9 +261,10 @@ public: void _focus_node(); void import_subscene(); + void add_root_node(Node *p_node); void set_edited_scene(Node *p_scene); - void instance(const String &p_file); - void instance_scenes(const Vector<String> &p_files, Node *p_parent = nullptr); + void instantiate(const String &p_file); + void instantiate_scenes(const Vector<String> &p_files, Node *p_parent = nullptr); void set_selected(Node *p_node, bool p_emit_selected = false); void fill_path_renames(Node *p_node, Node *p_new_parent, List<Pair<NodePath, NodePath>> *p_renames); void perform_node_renames(Node *p_base, List<Pair<NodePath, NodePath>> *p_renames, Map<Ref<Animation>, Set<int>> *r_rem_anims = nullptr); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 6f9b0ae873..ee66f28045 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -659,7 +659,14 @@ void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_ } else { editor_selection->remove_node(n); } - emit_signal("node_changed"); + + // Selection changed to be single node, so emit "selected" (for single node) rather than "changed" (for multiple nodes) + if (editor_selection->get_selected_nodes().size() == 1) { + selected = editor_selection->get_selected_node_list()[0]; + emit_signal("node_selected"); + } else { + emit_signal("node_changed"); + } } void SceneTreeEditor::_notification(int p_what) { @@ -944,7 +951,7 @@ Variant SceneTreeEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from Node *n = get_node(np); if (n) { - // Only allow selection if not part of an instanced scene. + // Only allow selection if not part of an instantiated scene. if (!n->get_owner() || n->get_owner() == get_scene_node() || n->get_owner()->get_filename() == String()) { selected.push_back(n); icons.push_back(next->get_icon(0)); @@ -1129,9 +1136,9 @@ void SceneTreeEditor::_bind_methods() { ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node); ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree); - ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw); - ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw); - ClassDB::bind_method(D_METHOD("drop_data_fw"), &SceneTreeEditor::drop_data_fw); + ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SceneTreeEditor::drop_data_fw); ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index c2bfdaae96..97edf84488 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -31,47 +31,44 @@ #include "script_create_dialog.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/string/string_builder.h" #include "editor/create_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor_file_system.h" -void ScriptCreateDialog::_theme_changed() { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - String lang = ScriptServer::get_language(i)->get_type(); - Ref<Texture2D> lang_icon = gc->get_theme_icon(lang, "EditorIcons"); - if (lang_icon.is_valid()) { - language_menu->set_item_icon(i, lang_icon); - } - } - - String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); - if (!last_lang.is_empty()) { - for (int i = 0; i < language_menu->get_item_count(); i++) { - if (language_menu->get_item_text(i) == last_lang) { - language_menu->select(i); - current_language = i; - break; +void ScriptCreateDialog::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + String lang = ScriptServer::get_language(i)->get_type(); + Ref<Texture2D> lang_icon = get_theme_icon(lang, "EditorIcons"); + if (lang_icon.is_valid()) { + language_menu->set_item_icon(i, lang_icon); + } } - } - } else { - language_menu->select(default_language); - } - path_button->set_icon(gc->get_theme_icon("Folder", "EditorIcons")); - parent_browse_button->set_icon(gc->get_theme_icon("Folder", "EditorIcons")); - parent_search_button->set_icon(gc->get_theme_icon("ClassList", "EditorIcons")); - status_panel->add_theme_style_override("panel", gc->get_theme_stylebox("bg", "Tree")); -} + String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); + if (!last_lang.is_empty()) { + for (int i = 0; i < language_menu->get_item_count(); i++) { + if (language_menu->get_item_text(i) == last_lang) { + language_menu->select(i); + current_language = i; + break; + } + } + } else { + language_menu->select(default_language); + } -void ScriptCreateDialog::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - _theme_changed(); + path_button->set_icon(get_theme_icon("Folder", "EditorIcons")); + parent_browse_button->set_icon(get_theme_icon("Folder", "EditorIcons")); + parent_search_button->set_icon(get_theme_icon("ClassList", "EditorIcons")); + status_panel->add_theme_style_override("panel", get_theme_stylebox("bg", "Tree")); } break; } } @@ -451,7 +448,7 @@ void ScriptCreateDialog::_lang_changed(int l) { override_info += ", "; } } - template_menu->set_item_icon(extended.id, gc->get_theme_icon("Override", "EditorIcons")); + template_menu->set_item_icon(extended.id, get_theme_icon("Override", "EditorIcons")); template_menu->get_popup()->set_item_tooltip(extended.id, override_info.as_string()); } // Reselect last selected template @@ -602,25 +599,25 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { _update_dialog(); } -void ScriptCreateDialog::_path_entered(const String &p_path) { +void ScriptCreateDialog::_path_submitted(const String &p_path) { ok_pressed(); } void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) { error_label->set_text("- " + p_msg); if (valid) { - error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); + error_label->add_theme_color_override("font_color", get_theme_color("success_color", "Editor")); } else { - error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor")); + error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); } } void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) { path_error_label->set_text("- " + p_msg); if (valid) { - path_error_label->add_theme_color_override("font_color", gc->get_theme_color("success_color", "Editor")); + path_error_label->add_theme_color_override("font_color", get_theme_color("success_color", "Editor")); } else { - path_error_label->add_theme_color_override("font_color", gc->get_theme_color("error_color", "Editor")); + path_error_label->add_theme_color_override("font_color", get_theme_color("error_color", "Editor")); } } @@ -731,13 +728,13 @@ void ScriptCreateDialog::_update_dialog() { get_ok_button()->set_disabled(!script_ok); - Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_entered); + Callable entered_call = callable_mp(this, &ScriptCreateDialog::_path_submitted); if (script_ok) { - if (!file_path->is_connected("text_entered", entered_call)) { - file_path->connect("text_entered", entered_call); + if (!file_path->is_connected("text_submitted", entered_call)) { + file_path->connect("text_submitted", entered_call); } - } else if (file_path->is_connected("text_entered", entered_call)) { - file_path->disconnect("text_entered", entered_call); + } else if (file_path->is_connected("text_submitted", entered_call)) { + file_path->disconnect("text_submitted", entered_call); } } @@ -748,15 +745,11 @@ void ScriptCreateDialog::_bind_methods() { } ScriptCreateDialog::ScriptCreateDialog() { - /* DIALOG */ - /* Main Controls */ - gc = memnew(GridContainer); + GridContainer *gc = memnew(GridContainer); gc->set_columns(2); - gc->connect("theme_changed", callable_mp(this, &ScriptCreateDialog::_theme_changed)); - /* Error Messages Field */ VBoxContainer *vb = memnew(VBoxContainer); @@ -784,6 +777,7 @@ ScriptCreateDialog::ScriptCreateDialog() { status_panel = memnew(PanelContainer); status_panel->set_h_size_flags(Control::SIZE_FILL); + status_panel->set_v_size_flags(Control::SIZE_EXPAND_FILL); status_panel->add_child(vb); /* Spacing */ @@ -795,10 +789,7 @@ ScriptCreateDialog::ScriptCreateDialog() { vb->add_child(gc); vb->add_child(spacing); vb->add_child(status_panel); - HBoxContainer *hb = memnew(HBoxContainer); - hb->add_child(vb); - - add_child(hb); + add_child(vb); /* Language */ @@ -827,14 +818,13 @@ ScriptCreateDialog::ScriptCreateDialog() { base_type = "Object"; - hb = memnew(HBoxContainer); + HBoxContainer *hb = memnew(HBoxContainer); hb->set_h_size_flags(Control::SIZE_EXPAND_FILL); parent_name = memnew(LineEdit); parent_name->connect("text_changed", callable_mp(this, &ScriptCreateDialog::_parent_name_changed)); parent_name->set_h_size_flags(Control::SIZE_EXPAND_FILL); hb->add_child(parent_name); parent_search_button = memnew(Button); - parent_search_button->set_flat(true); parent_search_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_class_in_tree)); hb->add_child(parent_search_button); parent_browse_button = memnew(Button); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index d6417b9d33..7c2ef1e150 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -45,7 +45,6 @@ class CreateDialog; class ScriptCreateDialog : public ConfirmationDialog { GDCLASS(ScriptCreateDialog, ConfirmationDialog); - GridContainer *gc; LineEdit *class_name; Label *error_label; Label *path_error_label; @@ -105,7 +104,7 @@ class ScriptCreateDialog : public ConfirmationDialog { void _path_hbox_sorted(); bool _can_be_built_in(); void _path_changed(const String &p_path = String()); - void _path_entered(const String &p_path = String()); + void _path_submitted(const String &p_path = String()); void _lang_changed(int l = 0); void _built_in_pressed(); bool _validate_parent(const String &p_string); @@ -127,7 +126,6 @@ class ScriptCreateDialog : public ConfirmationDialog { void _update_dialog(); protected: - void _theme_changed(); void _notification(int p_what); static void _bind_methods(); diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp index 4cdf820877..c2c99ed17f 100644 --- a/editor/settings_config_dialog.cpp +++ b/editor/settings_config_dialog.cpp @@ -261,10 +261,6 @@ void EditorSettingsDialog::_update_shortcuts() { for (OrderedHashMap<StringName, InputMap::Action>::Element E = action_map.front(); E; E = E.next()) { String action_name = E.key(); - if (!shortcut_filter.is_subsequence_ofi(action_name)) { - continue; - } - InputMap::Action action = E.get(); Array events; // Need to get the list of events into an array so it can be set as metadata on the item. @@ -289,7 +285,7 @@ void EditorSettingsDialog::_update_shortcuts() { event_strings.push_back(I->get()->as_text()); // Only check if the events have been the same so far - once one fails, we don't need to check any more. - if (same_as_defaults && !key_default_events[count]->shortcut_match(I->get())) { + if (same_as_defaults && !key_default_events[count]->is_match(I->get())) { same_as_defaults = false; } count++; @@ -298,6 +294,10 @@ void EditorSettingsDialog::_update_shortcuts() { // Join the text of the events with a delimiter so they can all be displayed in one cell. String events_display_string = event_strings.is_empty() ? "None" : String("; ").join(event_strings); + if (!shortcut_filter.is_subsequence_ofi(action_name) && (events_display_string == "None" || !shortcut_filter.is_subsequence_ofi(events_display_string))) { + continue; + } + TreeItem *item = shortcuts->create_item(common_section); item->set_text(0, action_name); item->set_text(1, events_display_string); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index ebef5be9ed..1893c6b6bb 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -199,7 +199,7 @@ protected: pinfo.type = Variant::TRANSFORM2D; } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM: { - pinfo.type = Variant::TRANSFORM; + pinfo.type = Variant::TRANSFORM3D; } break; case RS::GLOBAL_VAR_TYPE_MAT4: { pinfo.type = Variant::PACKED_INT32_ARRAY; @@ -326,7 +326,7 @@ static Variant create_var(RS::GlobalVariableType p_type) { return Transform2D(); } case RS::GLOBAL_VAR_TYPE_TRANSFORM: { - return Transform(); + return Transform3D(); } case RS::GLOBAL_VAR_TYPE_MAT4: { Vector<real_t> xform; diff --git a/editor/translations/af.po b/editor/translations/af.po index 3b031597c5..40669c01fb 100644 --- a/editor/translations/af.po +++ b/editor/translations/af.po @@ -1151,6 +1151,10 @@ msgstr "Verander Woordeboek Waarde" msgid "Thanks from the Godot community!" msgstr "Dankie van die Godot gemeenskap!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Enjin bydraers" @@ -12201,10 +12205,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ar.po b/editor/translations/ar.po index 14e83cd623..ceeda7a037 100644 --- a/editor/translations/ar.po +++ b/editor/translations/ar.po @@ -1154,6 +1154,10 @@ msgstr "تغيير قيمة ÙÙŠ القاموس" msgid "Thanks from the Godot community!" msgstr "شكراً من مجتمع غودوت!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "المسهامين ÙÙŠ Ù…ØØ±Ùƒ غودوت" @@ -12204,12 +12208,24 @@ msgstr "" "لم يتم تنزيل قالب بناء Android لهذا المشروع. نزّل ÙˆØ§ØØ¯Ø§Ù‹ من قائمة المشروع." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Ù…ÙÙ†Ù‚Ø Ø£Ø®Ø·Ø§Ø¡ Ù…ÙØªØ§Ø المتجر keystore غير Ù…Ùهيئ ÙÙŠ إعدادت Ø§Ù„Ù…ÙØØ±Ø± أو ÙÙŠ الإعدادات " "الموضوعة Ø³Ù„ÙØ§Ù‹." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "ØªØØ±Ø± مخزن Ø§Ù„Ù…ÙØ§ØªÙŠØ غير Ù…Ùهيئ بشكل صØÙŠØ ÙÙŠ إعدادت المسبقة للتصدير." diff --git a/editor/translations/az.po b/editor/translations/az.po index 70bae366d7..32efc852f8 100644 --- a/editor/translations/az.po +++ b/editor/translations/az.po @@ -1149,6 +1149,10 @@ msgstr "Lüğət dÉ™yÉ™rini dÉ™yiÅŸ" msgid "Thanks from the Godot community!" msgstr "Godot topluluÄŸundan təşəkkürlÉ™r!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot oyun motoruna töhvÉ™ verÉ™nlÉ™r" @@ -11756,10 +11760,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/bg.po b/editor/translations/bg.po index f934340bfe..65a77ffd74 100644 --- a/editor/translations/bg.po +++ b/editor/translations/bg.po @@ -1097,6 +1097,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "БлагодарноÑти от общноÑтта на Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11807,10 +11811,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/bn.po b/editor/translations/bn.po index 9c6d70b301..999d6f59d5 100644 --- a/editor/translations/bn.po +++ b/editor/translations/bn.po @@ -15,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-14 11:19+0000\n" -"Last-Translator: Oymate <dhruboadittya96@gmail.com>\n" +"PO-Revision-Date: 2021-06-11 14:49+0000\n" +"Last-Translator: Mokarrom Hossain <mhb2016.bzs@gmail.com>\n" "Language-Team: Bengali <https://hosted.weblate.org/projects/godot-engine/" "godot/bn/>\n" "Language: bn\n" @@ -47,7 +47,7 @@ msgstr "অবৈধ ইনপà§à¦Ÿ %i (পাস করা হয়নি) ঠ#: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "self বà§à¦¯à¦¬à¦¹à¦¾à¦° করা যাবে না কারণ instance যà§à¦•à§à¦¤à¦¿à¦¯à§à¦•à§à¦¤ নয়" +msgstr "self বà§à¦¯à¦¬à¦¹à¦¾à¦° করা যাবে না কারণ instance যà§à¦•à§à¦¤à¦¿à¦¯à§à¦•à§à¦¤ নয় (not passed)" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." @@ -103,7 +103,7 @@ msgstr "মà§à¦•à§à¦¤ করে দিন" #: editor/animation_bezier_editor.cpp msgid "Balanced" -msgstr "সà§à¦¥à¦¿à¦°" +msgstr "সà§à¦·à¦®" #: editor/animation_bezier_editor.cpp msgid "Mirror" @@ -591,7 +591,7 @@ msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨ (Animation) পরিচà§à¦›à¦¨à§à¦¨ à #: editor/animation_track_editor.cpp msgid "Pick the node that will be animated:" -msgstr "" +msgstr "নোডটি চয়ন করà§à¦¨ যা অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦Ÿà§‡à¦¡ হবে:" #: editor/animation_track_editor.cpp msgid "Use Bezier Curves" @@ -655,22 +655,20 @@ msgid "Copy" msgstr "পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿/কপি করà§à¦¨" #: editor/animation_track_editor.cpp -#, fuzzy msgid "Select All/None" -msgstr "কোনোটাই নিরà§à¦¬à¦¾à¦šà¦¨ করবেন না" +msgstr "কোনোটাই নিরà§à¦¬à¦¾à¦šà¦¨ করবেন/না" #: editor/animation_track_editor_plugins.cpp -#, fuzzy msgid "Add Audio Track Clip" -msgstr "অডিও শà§à¦°à§‹à¦¤à¦¾" +msgstr "অডিও টà§à¦°à§à¦¯à¦¾à¦• কà§à¦²à¦¿à¦ª যà§à¦•à§à¦¤ করà§à¦¨" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip Start Offset" -msgstr "" +msgstr "অডিও টà§à¦°à§à¦¯à¦¾à¦• কà§à¦²à¦¿à¦ª শà§à¦°à§ অফসেট পরিবরà§à¦¤à¦¨ করà§à¦¨" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip End Offset" -msgstr "" +msgstr "অডিও টà§à¦°à§à¦¯à¦¾à¦• কà§à¦²à¦¿à¦ª শেষ অফসেট পরিবরà§à¦¤à¦¨ করà§à¦¨" #: editor/array_property_edit.cpp msgid "Resize Array" @@ -693,18 +691,16 @@ msgid "Line Number:" msgstr "লাইন নামà§à¦¬à¦¾à¦°:" #: editor/code_editor.cpp -#, fuzzy msgid "%d replaced." -msgstr "পà§à¦°à¦¤à¦¿à¦¸à§à¦¥à¦¾à¦ªà¦¨..." +msgstr "%d পà§à¦°à¦¤à¦¿à¦¸à§à¦¥à¦¾à¦ªà¦¨ করা হয়েছে।" #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d match." -msgstr "" +msgstr "% d মিল।" #: editor/code_editor.cpp editor/editor_help.cpp -#, fuzzy msgid "%d matches." -msgstr "কোনো মিল নেই" +msgstr "% d টি মিলছে।" #: editor/code_editor.cpp editor/find_in_files.cpp msgid "Match Case" @@ -732,9 +728,8 @@ msgid "Standard" msgstr "আদরà§à¦¶" #: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Toggle Scripts Panel" -msgstr "ফেবরিট/পà§à¦°à¦¿à¦¯à¦¼-সমূহ অদলবদল/টগল করà§à¦¨" +msgstr "সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿà¦¸ পà§à¦¯à¦¾à¦¨à§‡à¦² টগল করà§à¦¨" #: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/texture_region_editor_plugin.cpp @@ -753,7 +748,6 @@ msgid "Reset Zoom" msgstr "সমà§à¦ªà§à¦°à¦¸à¦¾à¦°à¦¨/সংকোচন অপসারণ করà§à¦¨ (রিসেট জà§à¦®à§)" #: editor/code_editor.cpp -#, fuzzy msgid "Warnings" msgstr "সতরà§à¦•তা" @@ -1149,6 +1143,10 @@ msgstr "ডিকশনারি à¦à§à¦¯à¦¾à¦²à§ পরিবরà§à¦¤à¦¨ ঠmsgid "Thanks from the Godot community!" msgstr "Godot কমিউনিটি হতে আপনাকে ধনà§à¦¯à¦¬à¦¾à¦¦!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine কনà§à¦Ÿà§à¦°à¦¿à¦¬à¦¿à¦‰à¦Ÿà¦°à¦¸" @@ -2598,9 +2596,8 @@ msgid "Exit the editor?" msgstr "à¦à¦¡à¦¿à¦Ÿà¦° হতে পà§à¦°à¦¸à§à¦¥à¦¾à¦¨ করবেন?" #: editor/editor_node.cpp -#, fuzzy msgid "Open Project Manager?" -msgstr "পà§à¦°à¦•লà§à¦ª মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦°" +msgstr "Open পà§à¦°à¦•লà§à¦ª মà§à¦¯à¦¾à¦¨à§‡à¦œà¦¾à¦°?" #: editor/editor_node.cpp #, fuzzy @@ -3276,13 +3273,12 @@ msgid "Open & Run a Script" msgstr "à¦à¦•টি সà§à¦•à§à¦°à¦¿à¦ªà§à¦Ÿ খà§à¦²à§à¦¨ à¦à¦¬à¦‚ চালান" #: editor/editor_node.cpp -#, fuzzy msgid "" "The following files are newer on disk.\n" "What action should be taken?" msgstr "" "নিমà§à¦¨à§‹à¦•à§à¦¤ ফাইলসমূহ ডিসà§à¦•ে নতà§à¦¨à¦¤à¦°à¥¤\n" -"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?:" +"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/plugins/shader_editor_plugin.cpp @@ -3839,9 +3835,8 @@ msgid "Remove Template" msgstr "বসà§à¦¤à§ অপসারণ করà§à¦¨" #: editor/export_template_manager.cpp -#, fuzzy msgid "Select Template File" -msgstr "নিরà§à¦¬à¦¾à¦šà¦¿à¦¤ ফাইলসমূহ অপসারণ করবেন?" +msgstr "টেমপà§à¦²à§‡à¦Ÿ ফাইল নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨" #: editor/export_template_manager.cpp #, fuzzy @@ -4855,9 +4850,8 @@ msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨à§‡à¦° নাম পরিবরà§à¦¤à¦¨ #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp -#, fuzzy msgid "Delete Animation?" -msgstr "অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨ পà§à¦°à¦¤à¦¿à¦²à¦¿à¦ªà¦¿ করà§à¦¨" +msgstr "Delete অà§à¦¯à¦¾à¦¨à¦¿à¦®à§‡à¦¶à¦¨?" #: editor/plugins/animation_player_editor_plugin.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp @@ -5563,9 +5557,8 @@ msgid "Bake Lightmaps" msgstr "লাইটà§à¦®à§à¦¯à¦¾à¦ªà§‡ হসà§à¦¤à¦¾à¦¨à§à¦¤à¦° করà§à¦¨:" #: editor/plugins/baked_lightmap_editor_plugin.cpp -#, fuzzy msgid "Select lightmap bake file:" -msgstr "নিরà§à¦¬à¦¾à¦šà¦¿à¦¤ ফাইলসমূহ অপসারণ করবেন?" +msgstr "লাইটমà§à¦¯à¦¾à¦ª বেক ফাইলটি নিরà§à¦¬à¦¾à¦šà¦¨ করà§à¦¨:" #: editor/plugins/camera_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -7235,11 +7228,8 @@ msgid "Clear Recent Files" msgstr "বোনà§â€Œ/হাড় পরিষà§à¦•ার করà§à¦¨" #: editor/plugins/script_editor_plugin.cpp -#, fuzzy msgid "Close and save changes?" -msgstr "" -"বনà§à¦§ à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ সংরকà§à¦·à¦£ করবেন?\n" -"\"" +msgstr "বনà§à¦§ à¦à¦¬à¦‚ পরিবরà§à¦¤à¦¨ সংরকà§à¦·à¦£ করবেন?" #: editor/plugins/script_editor_plugin.cpp #, fuzzy @@ -7740,13 +7730,12 @@ msgid "Go to Previous Breakpoint" msgstr "পূরà§à¦¬à§‡à¦° বিরতিবিনà§à¦¦à§à¦¤à§‡ যান" #: editor/plugins/shader_editor_plugin.cpp -#, fuzzy msgid "" "This shader has been modified on on disk.\n" "What action should be taken?" msgstr "" "নিমà§à¦¨à§‹à¦•à§à¦¤ ফাইলসমূহ ডিসà§à¦•ে নতà§à¦¨à¦¤à¦°à¥¤\n" -"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?:" +"কোন সিধানà§à¦¤à¦Ÿà¦¿ নেয়া উচিত হবে?" #: editor/plugins/shader_editor_plugin.cpp msgid "Shader" @@ -12971,10 +12960,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/br.po b/editor/translations/br.po index 307b5b365f..21e33b7372 100644 --- a/editor/translations/br.po +++ b/editor/translations/br.po @@ -1098,6 +1098,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11701,10 +11705,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ca.po b/editor/translations/ca.po index 5dd319fbc1..e9dc4400fc 100644 --- a/editor/translations/ca.po +++ b/editor/translations/ca.po @@ -15,12 +15,13 @@ # Carles Pastor Badosa <cpbadosa@gmail.com>, 2021. # Roberto Pérez <djleizar@gmail.com>, 2021. # Joel Garcia Cascalló <jocsencat@gmail.com>, 2021. +# DFC <damiafluixacanals28@gmail.com>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-14 11:19+0000\n" -"Last-Translator: Joel Garcia Cascalló <jocsencat@gmail.com>\n" +"PO-Revision-Date: 2021-06-29 12:48+0000\n" +"Last-Translator: DFC <damiafluixacanals28@gmail.com>\n" "Language-Team: Catalan <https://hosted.weblate.org/projects/godot-engine/" "godot/ca/>\n" "Language: ca\n" @@ -28,7 +29,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7.1-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1127,6 +1128,10 @@ msgstr "Modifica Valor del Diccionari" msgid "Thanks from the Godot community!" msgstr "Grà cies de la part de la Comunitat del Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Fes click per a copiar." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Col·laboradors de Godot Engine" @@ -2327,6 +2332,8 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" +"S'ha produit un error al desar el diseny de l'editor.\n" +"Assegura't de que el directori de dades d'usuari de l'editor és editable." #: editor/editor_node.cpp msgid "" @@ -2334,6 +2341,9 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" +"S'ha anulat el diseny per defecte de l'editor.\n" +"Per a restaurar el Diseny per defecte a la seva configuració base, usa la " +"opció d'Esborrar el Diseny i esborra el Diseny per defecte." #: editor/editor_node.cpp msgid "Layout name not found!" @@ -2397,7 +2407,7 @@ msgstr "No s'ha definit cap escena per executar." #: editor/editor_node.cpp msgid "Save scene before running..." -msgstr "" +msgstr "Desar l'escena abans de executar-la..." #: editor/editor_node.cpp msgid "Could not start subprocess!" @@ -3018,7 +3028,7 @@ msgstr "Quant a" #: editor/editor_node.cpp msgid "Support Godot Development" -msgstr "" +msgstr "Contribueix a el Desenvolupament de Godot" #: editor/editor_node.cpp msgid "Play the project." @@ -3722,6 +3732,8 @@ msgstr "Estat: No s'ha pogut importar. Corregiu el fitxer i torneu a importar." msgid "" "Importing has been disabled for this file, so it can't be opened for editing." msgstr "" +"La importació s'ha desactivat per a aquest fitxer, per tant aquest no pot " +"ser obert per a editar." #: editor/filesystem_dock.cpp msgid "Cannot move/rename resources root." @@ -3768,6 +3780,12 @@ msgid "" "\n" "Do you wish to overwrite them?" msgstr "" +"Els fitxers o directoris següents entren en conflicte amb els elements de la " +"ubicació de destà '%s':\n" +"\n" +"%s\n" +"\n" +"Vols reemplaçar-los?" #: editor/filesystem_dock.cpp msgid "Renaming file:" @@ -4132,7 +4150,7 @@ msgstr "Carrega Valors predeterminats" #: editor/import_dock.cpp msgid "Keep File (No Import)" -msgstr "" +msgstr "Mantenir Fitxer (No Importar)" #: editor/import_dock.cpp msgid "%d Files" @@ -12568,10 +12586,22 @@ msgstr "" "des del menú Editor." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/cs.po b/editor/translations/cs.po index dd0f7a51c9..2557308828 100644 --- a/editor/translations/cs.po +++ b/editor/translations/cs.po @@ -30,8 +30,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-21 11:33+0000\n" -"Last-Translator: swifterik <blaha.j502@gmail.com>\n" +"PO-Revision-Date: 2021-06-25 02:57+0000\n" +"Last-Translator: VojtÄ›ch Å amla <auzkok@seznam.cz>\n" "Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/" "cs/>\n" "Language: cs\n" @@ -39,7 +39,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7.1-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1135,6 +1135,10 @@ msgstr "ZmÄ›nit hodnotu slovnÃku" msgid "Thanks from the Godot community!" msgstr "DÄ›kujeme za komunitu Godotu!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "PÅ™ispÄ›vatelé do Godot Enginu" @@ -5220,11 +5224,11 @@ msgstr "" "Ätvercové oblasti [0.0, 1.0]." #: editor/plugins/baked_lightmap_editor_plugin.cpp -#, fuzzy msgid "" "Godot editor was built without ray tracing support, lightmaps can't be baked." msgstr "" -"Godot byl sestaven bez podpory ray tracingu, svÄ›telné mapy nelze zapéct." +"Editor Godot byl sestaven bez podpory ray tracingu, svÄ›telné mapy nelze " +"zapéct." #: editor/plugins/baked_lightmap_editor_plugin.cpp msgid "Bake Lightmaps" @@ -12153,12 +12157,24 @@ msgstr "" "z nabÃdky Projekt." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "ÚložiÅ¡tÄ› klÃÄů k ladÄ›nà nenà nakonfigurováno v Nastavenà editoru nebo v " "export profilu." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "ÚložiÅ¡tÄ› klÃÄů pro vydánà je nakonfigurováno nesprávnÄ› v profilu exportu." diff --git a/editor/translations/da.po b/editor/translations/da.po index a4ed166f41..77cd37e20b 100644 --- a/editor/translations/da.po +++ b/editor/translations/da.po @@ -1170,6 +1170,10 @@ msgstr "Ændre Dictionary Værdi" msgid "Thanks from the Godot community!" msgstr "Tak fra Godot fællesskabet!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine bidragsydere" @@ -12485,10 +12489,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/de.po b/editor/translations/de.po index 567a096e48..fcf5522011 100644 --- a/editor/translations/de.po +++ b/editor/translations/de.po @@ -69,12 +69,14 @@ # El Captian <elcaptian@posteo.me>, 2021. # Ron Eric Hackländer <mail@roneric.net>, 2021. # Stephan Kerbl <stephankerbl@gmail.com>, 2021. +# Philipp Wabnitz <philipp.wabnitz@s2011.tu-chemnitz.de>, 2021. +# jmih03 <joerni@mail.de>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-24 21:36+0000\n" -"Last-Translator: Stephan Kerbl <stephankerbl@gmail.com>\n" +"PO-Revision-Date: 2021-06-28 22:34+0000\n" +"Last-Translator: jmih03 <joerni@mail.de>\n" "Language-Team: German <https://hosted.weblate.org/projects/godot-engine/" "godot/de/>\n" "Language: de\n" @@ -82,7 +84,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7.1-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1187,6 +1189,10 @@ msgstr "Wörterbuchwert ändern" msgid "Thanks from the Godot community!" msgstr "Die Godot-Gemeinschaft bedankt sich!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Zum kopieren klicken." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Mitwirkende der Godot Engine" @@ -1382,7 +1388,7 @@ msgstr "Stummschalten" #: editor/editor_audio_buses.cpp msgid "Bypass" -msgstr "Brücke" +msgstr "Überbrückung" #: editor/editor_audio_buses.cpp msgid "Bus options" @@ -7149,7 +7155,7 @@ msgstr "" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Debugger" -msgstr "Testhilfsprogramm" +msgstr "Debugger" #: editor/plugins/script_editor_plugin.cpp msgid "Search Results" @@ -7412,6 +7418,7 @@ msgid "Play IK" msgstr "IK abspielen" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Orthogonal" msgstr "Orthogonal" @@ -7657,7 +7664,7 @@ msgid "" "To zoom further, change the camera's clipping planes (View -> Settings...)" msgstr "" "Um weiter zoomen zu können müssen die Kameraausschnittebenen geändert werden " -"(Anzeige -> Einstellungen… )" +"(Ansicht -> Einstellungen… )" #: editor/plugins/spatial_editor_plugin.cpp msgid "" @@ -10349,7 +10356,7 @@ msgstr "Ereignis hinzufügen" #: editor/project_settings_editor.cpp msgid "Button" -msgstr "Knopf" +msgstr "Button" #: editor/project_settings_editor.cpp msgid "Left Button." @@ -12322,12 +12329,28 @@ msgstr "" "im Projektmenü installiert werden." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Die drei Einstellungen Debug Keystore, Debug User und Debug Password müssen " +"entweder alle angegeben, oder alle nicht angegeben sein." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Debug-Keystore wurde weder in den Editoreinstellungen noch in der Vorlage " "konfiguriert." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Die drei Einstellungen Release Keystore, Release User und Release Password " +"müssen entweder alle angegeben, oder alle nicht angegeben sein." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Release-Keystore wurde nicht korrekt konfiguriert in den Exporteinstellungen." diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 2ecb929f1f..603b07a6d5 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -1076,6 +1076,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11679,10 +11683,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/el.po b/editor/translations/el.po index e968002238..d85918f2b2 100644 --- a/editor/translations/el.po +++ b/editor/translations/el.po @@ -1129,6 +1129,10 @@ msgstr "Αλλαγή τιμής λεξικοÏ" msgid "Thanks from the Godot community!" msgstr "ΕυχαÏιστίες από την κοινότητα της Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "ΣυνεισφÎÏοντες στην Godot Engine" @@ -12294,12 +12298,24 @@ msgstr "" "«ΈÏγο»." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Το «debug keystore» δεν Îχει καθοÏιστεί στις Ρυθμίσεις ΕπεξεÏγαστή ή την " "διαμόÏφωση." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "ΕσφαλμÎνη ÏÏθμιση αποθετηÏίου κλειδιών διανομής στην διαμόÏφωση εξαγωγής." diff --git a/editor/translations/eo.po b/editor/translations/eo.po index 81bc346073..21d94bda5e 100644 --- a/editor/translations/eo.po +++ b/editor/translations/eo.po @@ -1119,6 +1119,10 @@ msgstr "ÅœanÄi la vortaran valoron" msgid "Thanks from the Godot community!" msgstr "Dankon de la komunumo de Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Kontribuantoj de Godot Engine" @@ -12013,10 +12017,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/es.po b/editor/translations/es.po index fcb8ffc033..7d3288527c 100644 --- a/editor/translations/es.po +++ b/editor/translations/es.po @@ -63,12 +63,16 @@ # Cam <cameron.toms@gmail.com>, 2021. # Juan camilo <jugarciago01@gmail.com>, 2021. # Manuel González <mgoopazo@gmail.com>, 2021. +# softonicblip <blazeawardspace@gmail.com>, 2021. +# Ib Quezada <ib@ibquezada.com>, 2021. +# hiking <joaquinfc@protonmail.com>, 2021. +# pabloggomez <pgg2733@gmail.com>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-29 13:49+0000\n" -"Last-Translator: Manuel González <mgoopazo@gmail.com>\n" +"PO-Revision-Date: 2021-06-23 21:56+0000\n" +"Last-Translator: pabloggomez <pgg2733@gmail.com>\n" "Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/" "godot/es/>\n" "Language: es\n" @@ -76,7 +80,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7.1-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1185,6 +1189,10 @@ msgstr "Cambiar Valor del Diccionario" msgid "Thanks from the Godot community!" msgstr "¡Muchas gracias de parte de la comunidad de Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Clic para copiar." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Contribuidores de Godot" @@ -4924,8 +4932,8 @@ msgstr "Eliminar el nodo o transición seleccionado/a." #: editor/plugins/animation_state_machine_editor.cpp msgid "Toggle autoplay this animation on start, restart or seek to zero." msgstr "" -"Act./Desact. reproducción automática de esta animación al comenzar, " -"reiniciar o hacer seek hasta el cero." +"Alternar reproducción automática de esta animación al comenzar, reiniciar o " +"hacer puesta a cero." #: editor/plugins/animation_state_machine_editor.cpp msgid "Set the end animation. This is useful for sub-transitions." @@ -5318,11 +5326,10 @@ msgstr "" "están contenidos dentro de la región cuadrangular [0,0,1,0]." #: editor/plugins/baked_lightmap_editor_plugin.cpp -#, fuzzy msgid "" "Godot editor was built without ray tracing support, lightmaps can't be baked." msgstr "" -"El editor de Godot se construyó sin soporte de trazado de rayos, los " +"El editor de Godot se construyó sin soporte para trazado de rayos, los " "lightmaps no pueden ser bakeados." #: editor/plugins/baked_lightmap_editor_plugin.cpp @@ -12320,11 +12327,27 @@ msgstr "" "Instalala desde el menú de Proyecto." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Deben configurarse los ajustes de Depuración de Claves, Depuración de " +"Usuarios Y Depuración de Contraseñas O ninguno de ellos." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Debug keystore no configurada en Configuración del Editor ni en el preset." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Deben configurarse los ajustes de Liberación del Almacén de Claves, " +"Liberación del Usuario Y Liberación de la Contraseña O ninguno de ellos." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Release keystore no está configurado correctamente en el preset de " diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po index c4f8c6c4e4..4bac2d84e9 100644 --- a/editor/translations/es_AR.po +++ b/editor/translations/es_AR.po @@ -21,7 +21,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-29 13:49+0000\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" "Last-Translator: Lisandro Lorea <lisandrolorea@gmail.com>\n" "Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/" "godot-engine/godot/es_AR/>\n" @@ -30,7 +30,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1136,6 +1136,10 @@ msgstr "Cambiar Valor del Diccionario" msgid "Thanks from the Godot community!" msgstr "Gracias de parte de la comunidad Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Click para copiar." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Colaboradores de Godot Engine" @@ -12257,11 +12261,27 @@ msgstr "" "Instalala desde el menú de Proyecto." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Deben estar configurados o bien Debug Keystore, Debug User Y Debug Password " +"o bien ninguno de ellos." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Keystore debug no configurada en Configuración del Editor ni en el preset." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Deben estar configurados o bien Release Keystore, Release User y Release " +"Passoword o bien ninguno de ellos." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Release keystore no está configurado correctamente en el preset de " diff --git a/editor/translations/et.po b/editor/translations/et.po index d75337154a..d81e10e9d7 100644 --- a/editor/translations/et.po +++ b/editor/translations/et.po @@ -1091,6 +1091,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "Suur tänu Godot kogukonnalt!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot mängumootori panustajad" @@ -11752,10 +11756,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/eu.po b/editor/translations/eu.po index b74c0906fc..0f8ef2de33 100644 --- a/editor/translations/eu.po +++ b/editor/translations/eu.po @@ -4,23 +4,25 @@ # This file is distributed under the same license as the Godot source code. # Julen Irazoki <rktzbkr.julen@gmail.com>, 2019. # Osoitz <oelkoro@gmail.com>, 2019, 2020. +# Erik Zubiria <erik@ezsd.net>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2020-06-15 01:48+0000\n" -"Last-Translator: Osoitz <oelkoro@gmail.com>\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" +"Last-Translator: Erik Zubiria <erik@ezsd.net>\n" "Language-Team: Basque <https://hosted.weblate.org/projects/godot-engine/" "godot/eu/>\n" "Language: eu\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.1-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp msgid "Invalid type argument to convert(), use TYPE_* constants." msgstr "" +"'convert()'-entzat argumentu baliogabea, erabil itzazu TYPE_* konstanteak." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." @@ -34,23 +36,24 @@ msgstr "Ez daude byte nahikoa byteak deskodetzeko, edo formatua ez da zuzena." #: core/math/expression.cpp msgid "Invalid input %i (not passed) in expression" -msgstr "" +msgstr "%i (onartu gabea) sarrera baliogabea espresioan" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "" +msgstr "ezin da self erabili instantzia null (pasatu gabea) delako" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." -msgstr "" +msgstr "%s, %s eta %s operatzaileentzat operando baliogabeak." #: core/math/expression.cpp msgid "Invalid index of type %s for base type %s" -msgstr "" +msgstr "%s tipo oinarriarentzat %s tipo adierazle baliogabea" #: core/math/expression.cpp msgid "Invalid named index '%s' for base type %s" msgstr "" +"'%s' izena daukan adierazleak ez dauka baliorik %s oinarri tipoarentzat" #: core/math/expression.cpp msgid "Invalid arguments to construct '%s'" @@ -130,51 +133,51 @@ msgstr "Mugitu Bezier puntuak" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" -msgstr "" +msgstr "Animazio giltza bikoiztuak" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Delete Keys" -msgstr "" +msgstr "Animazio giltza ezabatuak" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Time" -msgstr "" +msgstr "Animazioaren giltza fotogramaren denbora aldatu" #: editor/animation_track_editor.cpp msgid "Anim Change Transition" -msgstr "" +msgstr "Animazioaren transizioa aldatu" #: editor/animation_track_editor.cpp msgid "Anim Change Transform" -msgstr "" +msgstr "Animazioaren transformazioa aldatu" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "" +msgstr "Animazioaren giltza fotogramen balioa aldatu" #: editor/animation_track_editor.cpp msgid "Anim Change Call" -msgstr "" +msgstr "Animazioaren deia aldatu" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Keyframe Time" -msgstr "" +msgstr "Fotograma anitzen animazio giltzen denbora aldatu" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Transition" -msgstr "" +msgstr "Animazio transizio anitzak aldatu" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Transform" -msgstr "" +msgstr "Animazio Transform anitz aldatu" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Keyframe Value" -msgstr "" +msgstr "Animazio anitzen giltza fotogramen balioa aldatu" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Call" -msgstr "" +msgstr "Animazio dei anitz aldatu" #: editor/animation_track_editor.cpp msgid "Change Animation Length" @@ -187,27 +190,27 @@ msgstr "Aldatu animazioaren begizta" #: editor/animation_track_editor.cpp msgid "Property Track" -msgstr "" +msgstr "Propietateen pista" #: editor/animation_track_editor.cpp msgid "3D Transform Track" -msgstr "" +msgstr "3D Transformazioaren pista" #: editor/animation_track_editor.cpp msgid "Call Method Track" -msgstr "" +msgstr "Metodoen deiaren pista" #: editor/animation_track_editor.cpp msgid "Bezier Curve Track" -msgstr "" +msgstr "Bezier kurbaren pista" #: editor/animation_track_editor.cpp msgid "Audio Playback Track" -msgstr "" +msgstr "Audioaren erreprodukzio pista" #: editor/animation_track_editor.cpp msgid "Animation Playback Track" -msgstr "" +msgstr "Animazioaren erreprodukzio pista" #: editor/animation_track_editor.cpp msgid "Animation length (frames)" @@ -219,130 +222,130 @@ msgstr "Animazioaren iraupena (segundoak)" #: editor/animation_track_editor.cpp msgid "Add Track" -msgstr "" +msgstr "Gehitu pista" #: editor/animation_track_editor.cpp msgid "Animation Looping" -msgstr "" +msgstr "Animazioaren loop-a" #: editor/animation_track_editor.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Functions:" -msgstr "" +msgstr "Funtzioak:" #: editor/animation_track_editor.cpp msgid "Audio Clips:" -msgstr "" +msgstr "Audio klipak:" #: editor/animation_track_editor.cpp msgid "Anim Clips:" -msgstr "" +msgstr "Animazio klipak:" #: editor/animation_track_editor.cpp msgid "Change Track Path" -msgstr "" +msgstr "Pistaren bidea aldatu" #: editor/animation_track_editor.cpp msgid "Toggle this track on/off." -msgstr "" +msgstr "Pista hau aktibatu/desaktibatu." #: editor/animation_track_editor.cpp msgid "Update Mode (How this property is set)" -msgstr "" +msgstr "Eguneratze mota (Nola ezartzen da)" #: editor/animation_track_editor.cpp msgid "Interpolation Mode" -msgstr "" +msgstr "Interpolazio mota" #: editor/animation_track_editor.cpp msgid "Loop Wrap Mode (Interpolate end with beginning on loop)" -msgstr "" +msgstr "Loop Modu Bildua (bukaera interpolatu looparen hasierarekin)" #: editor/animation_track_editor.cpp msgid "Remove this track." -msgstr "" +msgstr "Pista hau ezabatu." #: editor/animation_track_editor.cpp msgid "Time (s): " -msgstr "" +msgstr "Denbora (s): " #: editor/animation_track_editor.cpp msgid "Toggle Track Enabled" -msgstr "" +msgstr "Pista Akt./Desakt." #: editor/animation_track_editor.cpp msgid "Continuous" -msgstr "" +msgstr "Etengabea" #: editor/animation_track_editor.cpp msgid "Discrete" -msgstr "" +msgstr "Diskretua" #: editor/animation_track_editor.cpp msgid "Trigger" -msgstr "" +msgstr "Kakoa" #: editor/animation_track_editor.cpp msgid "Capture" -msgstr "" +msgstr "Kaptura" #: editor/animation_track_editor.cpp msgid "Nearest" -msgstr "" +msgstr "Gertukoena" #: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp #: editor/property_editor.cpp msgid "Linear" -msgstr "" +msgstr "Lineal" #: editor/animation_track_editor.cpp msgid "Cubic" -msgstr "" +msgstr "Kubiko" #: editor/animation_track_editor.cpp msgid "Clamp Loop Interp" -msgstr "" +msgstr "Loop Ebakitzailearen Interp" #: editor/animation_track_editor.cpp msgid "Wrap Loop Interp" -msgstr "" +msgstr "Loop Inguratzailearen Interp" #: editor/animation_track_editor.cpp #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert Key" -msgstr "" +msgstr "Sartu Giltza" #: editor/animation_track_editor.cpp msgid "Duplicate Key(s)" -msgstr "" +msgstr "Bikoiztu Giltza(k)" #: editor/animation_track_editor.cpp msgid "Delete Key(s)" -msgstr "" +msgstr "Ezabatu Giltza(k)" #: editor/animation_track_editor.cpp msgid "Change Animation Update Mode" -msgstr "" +msgstr "Animazioaren Eguneraketa Modua Aldatu" #: editor/animation_track_editor.cpp msgid "Change Animation Interpolation Mode" -msgstr "" +msgstr "Animazioaren Interpolazio Modua Aldatu" #: editor/animation_track_editor.cpp msgid "Change Animation Loop Mode" -msgstr "" +msgstr "Animazioaren Loop Modua Aldatu" #: editor/animation_track_editor.cpp msgid "Remove Anim Track" -msgstr "" +msgstr "Ezabatu Animazio Pista" #: editor/animation_track_editor.cpp msgid "Create NEW track for %s and insert key?" -msgstr "" +msgstr "%s-rentzat pista berria sortu eta giltza sartu?" #: editor/animation_track_editor.cpp msgid "Create %d NEW tracks and insert keys?" -msgstr "" +msgstr "%d pista berri sortu eta giltzak sartu?" #: editor/animation_track_editor.cpp editor/create_dialog.cpp #: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp @@ -354,39 +357,41 @@ msgstr "" #: editor/script_create_dialog.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Create" -msgstr "" +msgstr "Sortu" #: editor/animation_track_editor.cpp msgid "Anim Insert" -msgstr "" +msgstr "Animazioa Sartu" #: editor/animation_track_editor.cpp msgid "AnimationPlayer can't animate itself, only other players." -msgstr "" +msgstr "AnimationPlayer bat ezin da norbera animatu, soilik beste playerrak." #: editor/animation_track_editor.cpp msgid "Anim Create & Insert" -msgstr "" +msgstr "Animazioa Sortu eta Txertatu" #: editor/animation_track_editor.cpp msgid "Anim Insert Track & Key" -msgstr "" +msgstr "Pista eta Animazio Giltza Sartu" #: editor/animation_track_editor.cpp msgid "Anim Insert Key" -msgstr "" +msgstr "Animazio Giltza Sartu" #: editor/animation_track_editor.cpp msgid "Change Animation Step" -msgstr "" +msgstr "Animazioaren Urratsa Aldatu" #: editor/animation_track_editor.cpp msgid "Rearrange Tracks" -msgstr "" +msgstr "Pistak Berrantolatu" #: editor/animation_track_editor.cpp msgid "Transform tracks only apply to Spatial-based nodes." msgstr "" +"Transformazio pistak Spatial-en oinarritutako nodoetan bakarrik aplikatzen " +"dira." #: editor/animation_track_editor.cpp msgid "" @@ -395,38 +400,42 @@ msgid "" "-AudioStreamPlayer2D\n" "-AudioStreamPlayer3D" msgstr "" +"Audio pistek era hontako nodoak bakarrik apunta ditzakete:\n" +"-AudioStreamPlayer\n" +"-AudioStreamPlayer2D\n" +"-AudioStreamPlayer3D" #: editor/animation_track_editor.cpp msgid "Animation tracks can only point to AnimationPlayer nodes." -msgstr "" +msgstr "Animazio pistek AnimationPlayer nodoak bakarrik apunta ditzakete." #: editor/animation_track_editor.cpp msgid "An animation player can't animate itself, only other players." -msgstr "" +msgstr "Animazio irakurgailua ezin da norbera animatu, bakarrik beste batzuk." #: editor/animation_track_editor.cpp msgid "Not possible to add a new track without a root" -msgstr "" +msgstr "Ez da posiblea pista berri bat gehitzea sustrairik gabe" #: editor/animation_track_editor.cpp msgid "Invalid track for Bezier (no suitable sub-properties)" -msgstr "" +msgstr "Bezier-entzat pista baliogabea (ez dago azpipropietate egokirik)" #: editor/animation_track_editor.cpp msgid "Add Bezier Track" -msgstr "" +msgstr "Gehitu Bezier Pista" #: editor/animation_track_editor.cpp msgid "Track path is invalid, so can't add a key." -msgstr "" +msgstr "Pistaren bidea baliogabea da, beraz ezin da giltzarik gehitu." #: editor/animation_track_editor.cpp msgid "Track is not of type Spatial, can't insert key" -msgstr "" +msgstr "Pista ez da Spatial erakoa, ezin da giltza txertatu" #: editor/animation_track_editor.cpp msgid "Add Transform Track Key" -msgstr "" +msgstr "Gehitu Pistaren Transformazio Giltza" #: editor/animation_track_editor.cpp msgid "Add Track Key" @@ -1088,6 +1097,10 @@ msgstr "Aldatu hiztegiaren balioa" msgid "Thanks from the Godot community!" msgstr "Eskerrik asko Godot komunitatearen partetik!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11717,10 +11730,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/fa.po b/editor/translations/fa.po index 388bf1ca48..ba8c4f9302 100644 --- a/editor/translations/fa.po +++ b/editor/translations/fa.po @@ -1126,6 +1126,10 @@ msgstr "تغییر مقدار دیکشنری" msgid "Thanks from the Godot community!" msgstr "با تشکر از سوی جامعه‌ی Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "شرکت‌کنندگان در ساخت موتور Godot" @@ -12332,10 +12336,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/fi.po b/editor/translations/fi.po index 9a1d7d7df1..9b0cb63c86 100644 --- a/editor/translations/fi.po +++ b/editor/translations/fi.po @@ -16,7 +16,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-19 20:16+0000\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" "Last-Translator: Tapani Niemi <tapani.niemi@kapsi.fi>\n" "Language-Team: Finnish <https://hosted.weblate.org/projects/godot-engine/" "godot/fi/>\n" @@ -25,7 +25,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1118,6 +1118,10 @@ msgstr "Vaihda hakurakenteen arvoa" msgid "Thanks from the Godot community!" msgstr "Kiitos Godot-yhteisöltä!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Napsauta kopioidaksesi." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot moottorin kehittäjät" @@ -12196,11 +12200,27 @@ msgstr "" "valikosta." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Joko Debug Keystore, Debug User JA Debug Password asetukset on kaikki " +"konfiguroitava TAI ei mitään niistä." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Debug keystore ei ole määritettynä editorin asetuksissa eikä esiasetuksissa." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Joko Release Keystore, Release User JA Release Password asetukset on kaikki " +"konfiguroitava TAI ei mitään niistä." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "Release keystore on konfiguroitu väärin viennin esiasetuksissa." diff --git a/editor/translations/fil.po b/editor/translations/fil.po index e0bc6cd724..54df144dd9 100644 --- a/editor/translations/fil.po +++ b/editor/translations/fil.po @@ -6,11 +6,12 @@ # Amado Wilkins <epicalert68@gmail.com>, 2019. # Bakainkorp <Ryan.Bautista86@myhunter.cuny.edu>, 2019. # Jethro Parker <lionbearjet@hotmail.com>, 2020. +# Sven Sorupia <stsorupia@gmail.com>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" -"PO-Revision-Date: 2020-08-14 03:56+0000\n" -"Last-Translator: Jethro Parker <lionbearjet@hotmail.com>\n" +"PO-Revision-Date: 2021-06-07 23:43+0000\n" +"Last-Translator: Sven Sorupia <stsorupia@gmail.com>\n" "Language-Team: Filipino <https://hosted.weblate.org/projects/godot-engine/" "godot/fil/>\n" "Language: fil\n" @@ -18,7 +19,7 @@ msgstr "" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=n != 1 && n != 2 && n != 3 && (n % 10 == 4 " "|| n % 10 == 6 || n % 10 == 9);\n" -"X-Generator: Weblate 4.2-dev\n" +"X-Generator: Weblate 4.7-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -29,7 +30,7 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "Nanghihingi ng string na may habang 1 (character)." +msgstr "Inasahan na ang haba ng string ay 1 (isang character)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp @@ -98,7 +99,7 @@ msgstr "EiB" #: editor/animation_bezier_editor.cpp msgid "Free" -msgstr "Malaya" +msgstr "Libre" #: editor/animation_bezier_editor.cpp msgid "Balanced" @@ -138,64 +139,64 @@ msgstr "Maglipat ng (mga) Bezier Point" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Duplicate Keys" -msgstr "I-anim ang (mga) Duplicate Key" +msgstr "Pagduplika ng mga Animation Keys" #: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp msgid "Anim Delete Keys" -msgstr "I-anim ang (mga) Delete Key" +msgstr "Pagbura ng mga Animation Key" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Time" -msgstr "I-anim ang Oras ng Pagbago ng Keyframe" +msgstr "Pagbago ng Keyframe Time ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Change Transition" -msgstr "I-anim ang Transition ng Pagbago" +msgstr "Pagbago ng Transition ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Change Transform" -msgstr "I-anim ang Pagbabago sa Transform" +msgstr "Pagbago ng Transform ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Change Keyframe Value" -msgstr "I-anim ang Halaga ng Keyframe na Binago" +msgstr "Pagbago ng Nilalaman ng Keyframe ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Change Call" -msgstr "" +msgstr "Pagbago ng Pagtawag sa Animation" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Keyframe Time" -msgstr "" +msgstr "Pagbago ng Time ng Maraming Keyframe ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Transition" -msgstr "" +msgstr "Pagbago ng Maraming Transition ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Transform" -msgstr "" +msgstr "Pagbago ng Maraming Transform ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Keyframe Value" -msgstr "" +msgstr "Pagbago ng Nilalaman ng Maraming Keyframe ng Animation" #: editor/animation_track_editor.cpp msgid "Anim Multi Change Call" -msgstr "" +msgstr "Pagbago ng Maraming Pagtawag ng Animation" #: editor/animation_track_editor.cpp msgid "Change Animation Length" -msgstr "Ibahin ang haba ng Animation" +msgstr "Pagbago ng Haba ng Animation" #: editor/animation_track_editor.cpp #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Change Animation Loop" -msgstr "Ibahin ang ulit ng Animation" +msgstr "Pagbago ng Animation Loop" #: editor/animation_track_editor.cpp msgid "Property Track" -msgstr "" +msgstr "Property Track" #: editor/animation_track_editor.cpp msgid "3D Transform Track" @@ -236,7 +237,7 @@ msgstr "Pagulit ng Animation" #: editor/animation_track_editor.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Functions:" -msgstr "Functions:" +msgstr "Mga Functions:" #: editor/animation_track_editor.cpp msgid "Audio Clips:" @@ -326,7 +327,7 @@ msgstr "Kopyahin Ang (Mga) Key(s)" #: editor/animation_track_editor.cpp msgid "Delete Key(s)" -msgstr "" +msgstr "Tanggalin Ang (Mga) Key(s)" #: editor/animation_track_editor.cpp msgid "Change Animation Update Mode" @@ -575,11 +576,11 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Pick the node that will be animated:" -msgstr "" +msgstr "Piliin ang node na i-aanimate:" #: editor/animation_track_editor.cpp msgid "Use Bezier Curves" -msgstr "" +msgstr "Gumamit ng Bezier Curves" #: editor/animation_track_editor.cpp msgid "Anim. Optimizer" @@ -611,11 +612,11 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Clean-up all animations" -msgstr "" +msgstr "Linisin ang lahat ng mga animation" #: editor/animation_track_editor.cpp msgid "Clean-Up Animation(s) (NO UNDO!)" -msgstr "" +msgstr "Linisin ang (mga) Animation (HINDI MAIBABALIK!)" #: editor/animation_track_editor.cpp msgid "Clean-Up" @@ -627,7 +628,7 @@ msgstr "" #: editor/animation_track_editor.cpp msgid "Select Tracks to Copy" -msgstr "" +msgstr "Piliin ang mga Tracks na Kokopyahin" #: editor/animation_track_editor.cpp editor/editor_log.cpp #: editor/editor_properties.cpp @@ -656,15 +657,15 @@ msgstr "" #: editor/array_property_edit.cpp msgid "Resize Array" -msgstr "" +msgstr "Baguhin ang Laki ng Array" #: editor/array_property_edit.cpp msgid "Change Array Value Type" -msgstr "" +msgstr "Baguhin ang Type ng Nilalaman ng Array" #: editor/array_property_edit.cpp msgid "Change Array Value" -msgstr "" +msgstr "Baguhin ang Nilalaman ng Array" #: editor/code_editor.cpp msgid "Go to Line" @@ -675,17 +676,16 @@ msgid "Line Number:" msgstr "" #: editor/code_editor.cpp -#, fuzzy msgid "%d replaced." -msgstr "Palitan" +msgstr "%d ay pinalitan." #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d match." -msgstr "" +msgstr "%d magkatugma." #: editor/code_editor.cpp editor/editor_help.cpp msgid "%d matches." -msgstr "" +msgstr "%d magkatugma." #: editor/code_editor.cpp editor/find_in_files.cpp msgid "Match Case" @@ -1090,6 +1090,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11712,10 +11716,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/fr.po b/editor/translations/fr.po index 5b310fc215..129ab4f687 100644 --- a/editor/translations/fr.po +++ b/editor/translations/fr.po @@ -73,7 +73,7 @@ # Kevin Bouancheau <kevin.bouancheau@gmail.com>, 2020. # LaurentOngaro <laurent@gameamea.com>, 2020. # Julien Humbert <julroy67@gmail.com>, 2020. -# Nathan <bonnemainsnathan@gmail.com>, 2020. +# Nathan <bonnemainsnathan@gmail.com>, 2020, 2021. # Léo Vincent <l009.vincent@gmail.com>, 2020. # Joseph Boudou <joseph.boudou@matabio.net>, 2020. # Vincent Foulon <vincent.foulon80@gmail.com>, 2020. @@ -84,8 +84,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-04-30 23:03+0000\n" -"Last-Translator: Julien Vanelian <julienvanelian@hotmail.com>\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" +"Last-Translator: Nathan <bonnemainsnathan@gmail.com>\n" "Language-Team: French <https://hosted.weblate.org/projects/godot-engine/" "godot/fr/>\n" "Language: fr\n" @@ -93,7 +93,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1201,6 +1201,10 @@ msgstr "Modifier valeur du dictionnaire" msgid "Thanks from the Godot community!" msgstr "La communauté Godot vous dit merci !" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Cliquez pour copier." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Contributeurs de Godot Engine" @@ -12362,12 +12366,28 @@ msgstr "" "Installez-le à partir du menu Projet." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Il faut configurer soit les paramètres Debug Keystore, Debug User ET Debug " +"Password, soit aucun d'entre eux." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Le Debug keystore n'est pas configuré dans les Paramètres de l'éditeur, ni " "dans le préréglage." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Il faut configurer soit les paramètres Release Keystore, Release User ET " +"Release Password, soit aucun d'entre eux." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "La clé de version n'est pas configurée correctement dans le préréglage " diff --git a/editor/translations/ga.po b/editor/translations/ga.po index 4da29e17ba..e3b1137cee 100644 --- a/editor/translations/ga.po +++ b/editor/translations/ga.po @@ -1083,6 +1083,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11707,10 +11711,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/gl.po b/editor/translations/gl.po index f4394da9da..f6905f4bef 100644 --- a/editor/translations/gl.po +++ b/editor/translations/gl.po @@ -1117,6 +1117,10 @@ msgstr "Cambiar Valor do Dicionario" msgid "Thanks from the Godot community!" msgstr "Moitas grazas de parte da comunidade de Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Colaboradores de Godot Engine" @@ -12000,12 +12004,24 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Non está configurado o Keystore de depuración nin na configuración do " "editor, nin nos axustes de exportación." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "O Keystore Release non está configurado correctamente nos axustes de " diff --git a/editor/translations/he.po b/editor/translations/he.po index 08780f2e03..f0e3fa4383 100644 --- a/editor/translations/he.po +++ b/editor/translations/he.po @@ -1127,6 +1127,10 @@ msgstr "החלפת ערך מילון" msgid "Thanks from the Godot community!" msgstr "תודה רבה מקהילת Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "×ž×ª× ×“×‘×™ ×ž× ×•×¢ גודו" @@ -12228,10 +12232,22 @@ msgid "" msgstr "×ª×‘× ×™×ª ×‘× ×™×™×” ל×× ×“×¨×•×יד ×œ× ×ž×•×ª×§× ×ª בפרוייקט. ×”×”×ª×§× ×” ×”×™× ×ž×ª×¤×¨×™×˜ המיז×." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "מפתח ×œ× ×™×¤×•×™ שגי×ות ×œ× × ×§×‘×¢ בהגדרות העורך ×•×œ× ×‘×”×’×“×¨×•×ª הייצו×." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "מפתח גירסת שיחרור × ×§×‘×¢ ב×ופן שגוי בהגדרות הייצו×." diff --git a/editor/translations/hi.po b/editor/translations/hi.po index 30381cf861..a70f058a65 100644 --- a/editor/translations/hi.po +++ b/editor/translations/hi.po @@ -1116,6 +1116,10 @@ msgstr "शबà¥à¤¦ बदलें मूलà¥à¤¯" msgid "Thanks from the Godot community!" msgstr "गोडोट समà¥à¤¦à¤¾à¤¯ से आपको धनà¥à¤¯à¤µà¤¾à¤¦!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "गॉडोट इंजन योगदानकरà¥à¤¤à¤¾" @@ -11984,10 +11988,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/hr.po b/editor/translations/hr.po index 826d73fda0..f49ba47c29 100644 --- a/editor/translations/hr.po +++ b/editor/translations/hr.po @@ -1097,6 +1097,10 @@ msgstr "Promijeni vrijednost u rjeÄniku" msgid "Thanks from the Godot community!" msgstr "Hvala od Godot zajednice!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine suradnici" @@ -11732,10 +11736,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/hu.po b/editor/translations/hu.po index 698e87b776..eda808eef4 100644 --- a/editor/translations/hu.po +++ b/editor/translations/hu.po @@ -1130,6 +1130,10 @@ msgstr "Szótár Érték MódosÃtása" msgid "Thanks from the Godot community!" msgstr "Köszönet a Godot közösségétÅ‘l!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine közreműködÅ‘k" @@ -11917,10 +11921,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/id.po b/editor/translations/id.po index 8d20cb79fb..08bfa5969d 100644 --- a/editor/translations/id.po +++ b/editor/translations/id.po @@ -1142,6 +1142,10 @@ msgstr "Ubah Nilai Kamus" msgid "Thanks from the Godot community!" msgstr "Terimakasih dari komunitas Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine kontributor" @@ -12217,12 +12221,24 @@ msgstr "" "Proyek." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Berkas debug keystore belum dikonfigurasi dalam Pengaturan Editor maupun di " "prasetel proyek." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "Berkas keystore rilis belum dikonfigurasi di prasetel ekspor." diff --git a/editor/translations/is.po b/editor/translations/is.po index 8f3e11c207..72472c2215 100644 --- a/editor/translations/is.po +++ b/editor/translations/is.po @@ -1118,6 +1118,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11835,10 +11839,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/it.po b/editor/translations/it.po index d8a4db264f..3d0509ba15 100644 --- a/editor/translations/it.po +++ b/editor/translations/it.po @@ -63,7 +63,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-06-02 09:04+0000\n" +"PO-Revision-Date: 2021-06-15 19:34+0000\n" "Last-Translator: Riteo Siuga <lorenzocerqua@tutanota.com>\n" "Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/" "godot/it/>\n" @@ -289,11 +289,11 @@ msgstr "Funzioni:" #: editor/animation_track_editor.cpp msgid "Audio Clips:" -msgstr "Clip audio:" +msgstr "Segmenti audio:" #: editor/animation_track_editor.cpp msgid "Anim Clips:" -msgstr "Clip animazione:" +msgstr "Segmenti d'animazione:" #: editor/animation_track_editor.cpp msgid "Change Track Path" @@ -301,7 +301,7 @@ msgstr "Cambia Percorso Traccia" #: editor/animation_track_editor.cpp msgid "Toggle this track on/off." -msgstr "Attiva/Disattiva questa traccia." +msgstr "Abilita/Disabilita questa traccia." #: editor/animation_track_editor.cpp msgid "Update Mode (How this property is set)" @@ -435,7 +435,7 @@ msgstr "Inserisci un fotogramma chiave in un'animazione" #: editor/animation_track_editor.cpp msgid "Change Animation Step" -msgstr "Cambia passo animazione" +msgstr "Cambia il passo di animazione" #: editor/animation_track_editor.cpp msgid "Rearrange Tracks" @@ -714,15 +714,15 @@ msgstr "Seleziona/Deseleziona tutto" #: editor/animation_track_editor_plugins.cpp msgid "Add Audio Track Clip" -msgstr "Aggiungi audio in una traccia sonora" +msgstr "Aggiungi un segmento audio in una traccia sonora" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip Start Offset" -msgstr "Cambia lo scostamento dell'inizio della traccia audio" +msgstr "Cambia l'inizio di un segmento audio di una traccia sonora" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip End Offset" -msgstr "Cambia lo scostamento della fine della traccia audio" +msgstr "Cambia la fine del segmento audio di una traccia sonora" #: editor/array_property_edit.cpp msgid "Resize Array" @@ -1173,6 +1173,10 @@ msgstr "Cambia il valore di un dizionario" msgid "Thanks from the Godot community!" msgstr "Grazie dalla comunità di Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Contributori di Godot Engine" @@ -1336,7 +1340,7 @@ msgstr "Commuta l'ammutolimento di un bus audio" #: editor/editor_audio_buses.cpp #, fuzzy msgid "Toggle Audio Bus Bypass Effects" -msgstr "Commuta bypass effetti del bus audio" +msgstr "Commuta il bypass degli effetti del bus audio" #: editor/editor_audio_buses.cpp msgid "Select Audio Bus Send" @@ -1732,19 +1736,16 @@ msgid "Scene Tree Editing" msgstr "Modifica delle scene" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Node Dock" -msgstr "Riquadro dei nodi" +msgstr "Pannello dei nodi" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "FileSystem Dock" -msgstr "Riquadro del FileSystem" +msgstr "Pannello del file system" #: editor/editor_feature_profile.cpp -#, fuzzy msgid "Import Dock" -msgstr "Riquadro d'importazione" +msgstr "Pannello d'importazione" #: editor/editor_feature_profile.cpp msgid "Erase profile '%s'? (no undo)" @@ -1954,7 +1955,7 @@ msgstr "Commuta la visibilità dei file nascosti" #: editor/editor_file_dialog.cpp msgid "Toggle Favorite" -msgstr "Commuta preferito" +msgstr "Commuta lo stato di preferito" #: editor/editor_file_dialog.cpp msgid "Toggle Mode" @@ -2237,11 +2238,11 @@ msgstr "%s/s" #: editor/editor_network_profiler.cpp msgid "Down" -msgstr "Giù" +msgstr "In entrata" #: editor/editor_network_profiler.cpp msgid "Up" -msgstr "Su" +msgstr "In uscita" #: editor/editor_network_profiler.cpp editor/editor_node.cpp msgid "Node" @@ -2278,7 +2279,7 @@ msgstr "OK" #: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp msgid "Error saving resource!" -msgstr "Errore nel salvataggio della risorsa!" +msgstr "Errore durante il salvataggio della risorsa!" #: editor/editor_node.cpp msgid "" @@ -2298,7 +2299,7 @@ msgstr "Impossibile aprire il file in scrittura:" #: editor/editor_node.cpp msgid "Requested file format unknown:" -msgstr "Formato file richiesto sconosciuto:" +msgstr "Formato del file richiesto sconosciuto:" #: editor/editor_node.cpp msgid "Error while saving." @@ -2328,7 +2329,7 @@ msgstr "Errore durante il caricamento di \"%s\"." #: editor/editor_node.cpp msgid "Saving Scene" -msgstr "Salvataggio scena" +msgstr "Salvando la scena" #: editor/editor_node.cpp msgid "Analyzing" @@ -2336,7 +2337,7 @@ msgstr "Analizzando" #: editor/editor_node.cpp msgid "Creating Thumbnail" -msgstr "Creazione miniature" +msgstr "Creando la miniatura" #: editor/editor_node.cpp msgid "This operation can't be done without a tree root." @@ -2362,11 +2363,11 @@ msgstr "" #: editor/editor_node.cpp editor/scene_tree_dock.cpp msgid "Can't overwrite scene that is still open!" -msgstr "Impossibile sovrascrivere una scena che è ancora aperta!" +msgstr "Impossibile sovrascrivere una scena ancora aperta!" #: editor/editor_node.cpp msgid "Can't load MeshLibrary for merging!" -msgstr "Impossibile caricare MeshLibrary per l'unione!" +msgstr "Impossibile caricare la MeshLibrary per l'unione!" #: editor/editor_node.cpp msgid "Error saving MeshLibrary!" @@ -2374,7 +2375,7 @@ msgstr "Errore nel salvataggio della MeshLibrary!" #: editor/editor_node.cpp msgid "Can't load TileSet for merging!" -msgstr "Impossibile caricare TileSet per unione!" +msgstr "Impossibile caricare il TileSet per unione!" #: editor/editor_node.cpp msgid "Error saving TileSet!" @@ -2385,9 +2386,9 @@ msgid "" "An error occurred while trying to save the editor layout.\n" "Make sure the editor's user data path is writable." msgstr "" -"Si è verificato un errore mentre si stava provando a salvare il layout " -"dell'editor.\n" -"Assicurati che il percorso dati dell'editor dell'utente sia scrivibile." +"Si è verificato un errore durante un tentativo di salvataggio della " +"disposizione dell'editor.\n" +"Assicurarsi che il percorso dei dati dell'editor dell'utente sia scrivibile." #: editor/editor_node.cpp msgid "" @@ -2395,9 +2396,9 @@ msgid "" "To restore the Default layout to its base settings, use the Delete Layout " "option and delete the Default layout." msgstr "" -"Layout predefinito dell'editor sovrascritto.\n" -"Per ripristinare il layout predefinito alle impostazioni di base, usare " -"l'opzione elimina layout ed eliminare il layout predefinito." +"Disposzione predefinita dell'editor sovrascritta.\n" +"Per ripristinare la disposizione predefinita alle sue impostazioni di base, " +"usare l'opzione elimina layout ed eliminare la disposizione predefinita." #: editor/editor_node.cpp msgid "Layout name not found!" @@ -2405,7 +2406,7 @@ msgstr "Nome della disposizione non trovato!" #: editor/editor_node.cpp msgid "Restored the Default layout to its base settings." -msgstr "Ripristinato il layout default alle impostazioni base." +msgstr "Ripristinata la disposzione predefinita alle sue impostazioni di base." #: editor/editor_node.cpp msgid "" @@ -2415,8 +2416,8 @@ msgid "" msgstr "" "Questa risorsa appartiene a una scena che è stata importata, di conseguenza " "non è modificabile.\n" -"Si consiglia di leggere la documentazione riguardante l'importazione delle " -"scene per comprendere al meglio questo workflow." +"Si prega di leggere la documentazione relativa all'importazione delle scene " +"per capire meglio questa prassi." #: editor/editor_node.cpp msgid "" @@ -2424,15 +2425,15 @@ msgid "" "Changes to it won't be kept when saving the current scene." msgstr "" "Questa risorsa appartiene a una scena istanziata o ereditata.\n" -"Le modifiche ad essa non verranno mantenute salvando la scena corrente." +"Essa perderà qualsiasi modifica al salvataggio della scena corrente." #: editor/editor_node.cpp msgid "" "This resource was imported, so it's not editable. Change its settings in the " "import panel and then re-import." msgstr "" -"Questa risorsa è stata importata, non è quindi modificabile. Modificane le " -"impostazioni nel pannello di importazione e re-importala." +"Questa risorsa è stata importata e non è quindi modificabile. Modificare le " +"sue impostazioni nel pannello d'importazione e re-importarla." #: editor/editor_node.cpp msgid "" @@ -2441,11 +2442,10 @@ msgid "" "Please read the documentation relevant to importing scenes to better " "understand this workflow." msgstr "" -"Questa scena è stata importata, pertanto i cambiamenti ad essa non verranno " -"mantenuti.\n" -"Istanziarla o ereditarla permetterà di modificarla.\n" -"Si consiglia di leggere la documentazione relativa all'importazione delle " -"scene per comprendere meglio questo workflow." +"Questa scena è stata importata, perciò qualsiasi sua modifica verrà persa.\n" +"Per modificarla, Istanziarla o ereditarla.\n" +"Si prega di leggere la documentazione relativa all'importazione delle scene " +"per capire meglio questa prassi." #: editor/editor_node.cpp msgid "" @@ -2453,10 +2453,9 @@ msgid "" "Please read the documentation relevant to debugging to better understand " "this workflow." msgstr "" -"Questa risorsa appartiene a una scena che è stata importata, di conseguenza " -"non è modificabile.\n" -"Si consiglia di leggere la documentazione riguardante l'importazione delle " -"scene per comprendere al meglio questo workflow." +"Questo è un oggetto remoto, perciò qualsiasi sua modifica verrà persa.\n" +"Si prega di leggere la documentazione relativa al debug per capire meglio " +"questa prassi." #: editor/editor_node.cpp msgid "There is no defined scene to run." @@ -2472,19 +2471,19 @@ msgstr "Impossibile avviare il sottoprocesso!" #: editor/editor_node.cpp editor/filesystem_dock.cpp msgid "Open Scene" -msgstr "Apri scena" +msgstr "Apri una scena" #: editor/editor_node.cpp msgid "Open Base Scene" -msgstr "Apri scena di base" +msgstr "Apri una scena di base" #: editor/editor_node.cpp msgid "Quick Open..." -msgstr "Apri scena rapidamente…" +msgstr "Apri rapidamente…" #: editor/editor_node.cpp msgid "Quick Open Scene..." -msgstr "Apri scena rapidamente…" +msgstr "Apri una scena rapidamente…" #: editor/editor_node.cpp msgid "Quick Open Script..." @@ -2500,7 +2499,7 @@ msgstr "Salvare le modifiche a \"%s\" prima di chiudere?" #: editor/editor_node.cpp msgid "Saved %s modified resource(s)." -msgstr "Salvata(e) %s risorsa(e) modificata(e)." +msgstr "Salvate %s risorse modificate." #: editor/editor_node.cpp msgid "A root node is required to save the scene." @@ -2508,7 +2507,7 @@ msgstr "È necessario un nodo radice per salvare la scena." #: editor/editor_node.cpp msgid "Save Scene As..." -msgstr "Salva scena come…" +msgstr "Salva la scena come…" #: editor/editor_node.cpp editor/scene_tree_dock.cpp msgid "This operation can't be done without a scene." @@ -2516,7 +2515,7 @@ msgstr "Questa operazione non può essere eseguita senza una scena." #: editor/editor_node.cpp msgid "Export Mesh Library" -msgstr "Esporta libreria di Mesh" +msgstr "Esporta una libreria di Mesh" #: editor/editor_node.cpp msgid "This operation can't be done without a root node." @@ -2524,7 +2523,7 @@ msgstr "Questa operazione non può essere eseguita senza un nodo radice." #: editor/editor_node.cpp msgid "Export Tile Set" -msgstr "Esporta Tile Set" +msgstr "Esporta una collezione di tasselli" #: editor/editor_node.cpp msgid "This operation can't be done without a selected node." @@ -2540,19 +2539,19 @@ msgstr "Impossibile ricaricare una scena che non è mai stata salvata." #: editor/editor_node.cpp msgid "Reload Saved Scene" -msgstr "Ricarica scena salvata" +msgstr "Ricarica la scena salvata" #: editor/editor_node.cpp msgid "" "The current scene has unsaved changes.\n" "Reload the saved scene anyway? This action cannot be undone." msgstr "" -"La scena attuale ha dei cambiamenti non salvati.\n" +"La scena attuale ha delle modifiche non salvate.\n" "Ricaricare comunque la scena salvata? Questa azione non può essere annullata." #: editor/editor_node.cpp msgid "Quick Run Scene..." -msgstr "Esegui scena rapidamente…" +msgstr "Esegui la scena rapidamente…" #: editor/editor_node.cpp msgid "Quit" @@ -2568,7 +2567,7 @@ msgstr "Uscire dall'editor?" #: editor/editor_node.cpp msgid "Open Project Manager?" -msgstr "Aprire il gestore dei progetti?" +msgstr "Aprire il gestore di progetti?" #: editor/editor_node.cpp msgid "Save & Quit" @@ -2581,7 +2580,7 @@ msgstr "Salvare le modifiche alle scene seguenti prima di uscire?" #: editor/editor_node.cpp msgid "Save changes the following scene(s) before opening Project Manager?" msgstr "" -"Salvare le modifiche alle scene seguenti prima di aprire il gestore dei " +"Salvare le modifiche alle scene seguenti prima di aprire il gestore di " "progetti?" #: editor/editor_node.cpp @@ -2589,16 +2588,16 @@ msgid "" "This option is deprecated. Situations where refresh must be forced are now " "considered a bug. Please report." msgstr "" -"Questa opzione è deprecata. Situazioni in cui si è obbligati a ricaricare " -"sono ora considerate errori. Si prega di segnalarlo." +"Questa opzione è deprecata. Le situazioni in cui si è obbligati a ricaricare " +"sono ora considerate falle. Si prega di segnalarle." #: editor/editor_node.cpp msgid "Pick a Main Scene" -msgstr "Scegli una scena principale" +msgstr "Scegliere una scena principale" #: editor/editor_node.cpp msgid "Close Scene" -msgstr "Chiudi scena" +msgstr "Chiudi la scena" #: editor/editor_node.cpp msgid "Reopen Closed Scene" @@ -2607,13 +2606,12 @@ msgstr "Riapri la scena chiusa" #: editor/editor_node.cpp msgid "Unable to enable addon plugin at: '%s' parsing of config failed." msgstr "" -"Impossibile abilitare il componente aggiuntivo in: \"%s\" lettura della " -"configurazione fallita." +"Impossibile abilitare l'estensione in \"%s\". Lettura della configurazione " +"fallita." #: editor/editor_node.cpp msgid "Unable to find script field for addon plugin at: '%s'." -msgstr "" -"Impossibile trovare il campo script per il plugin addon in posizione: \"%s\"." +msgstr "Impossibile trovare il campo dello script per l'estensione in: \"%s\"." #: editor/editor_node.cpp msgid "Unable to load addon script from path: '%s'." @@ -2635,8 +2633,8 @@ msgstr "" msgid "" "Unable to load addon script from path: '%s' Base type is not EditorPlugin." msgstr "" -"Impossibile caricare uno script aggiuntivo dal percorso: La tipologia di " -"base di \"%s\" non è EditorPlugin." +"Impossibile caricare uno script di estensione dal percorso: il tipo base di " +"\"%s\" non è EditorPlugin." #: editor/editor_node.cpp msgid "Unable to load addon script from path: '%s' Script is not in tool mode." @@ -2720,15 +2718,15 @@ msgstr "Mostra nel filesystem" #: editor/editor_node.cpp msgid "Play This Scene" -msgstr "Esegui Scena" +msgstr "Esegui questa scena" #: editor/editor_node.cpp msgid "Close Tab" -msgstr "Chiudi scheda" +msgstr "Chiudi la scheda" #: editor/editor_node.cpp msgid "Undo Close Tab" -msgstr "Annulla Chiusura Tab" +msgstr "Annulla la chiusura di una scheda" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Close Other Tabs" @@ -2736,15 +2734,15 @@ msgstr "Chiudi le altre schede" #: editor/editor_node.cpp msgid "Close Tabs to the Right" -msgstr "Chiudi le Schede a Destra" +msgstr "Chiudi le schede a destra" #: editor/editor_node.cpp msgid "Close All Tabs" -msgstr "Chiudi Tutte le Schede" +msgstr "Chiudi tutte le schede" #: editor/editor_node.cpp msgid "Switch Scene Tab" -msgstr "Cambia Tab di Scena" +msgstr "Cambia la scheda di una scena" #: editor/editor_node.cpp msgid "%d more files or folders" @@ -2760,7 +2758,7 @@ msgstr "%d altri file" #: editor/editor_node.cpp msgid "Dock Position" -msgstr "Posizione Dock" +msgstr "Posizione del pannello" #: editor/editor_node.cpp msgid "Distraction Free Mode" @@ -2768,11 +2766,11 @@ msgstr "Modalità senza distrazioni" #: editor/editor_node.cpp msgid "Toggle distraction-free mode." -msgstr "Commuta modalità senza distrazioni." +msgstr "Commuta la modalità senza distrazioni." #: editor/editor_node.cpp msgid "Add a new scene." -msgstr "Aggiungi nuova scena." +msgstr "Aggiungi una nuova scena." #: editor/editor_node.cpp msgid "Scene" @@ -2780,11 +2778,11 @@ msgstr "Scena" #: editor/editor_node.cpp msgid "Go to previously opened scene." -msgstr "Vai alla scena precedentemente aperta." +msgstr "Va alla scena precedentemente aperta." #: editor/editor_node.cpp msgid "Copy Text" -msgstr "Copia Testo" +msgstr "Copia il testo" #: editor/editor_node.cpp msgid "Next tab" @@ -2796,7 +2794,7 @@ msgstr "Scheda precedente" #: editor/editor_node.cpp msgid "Filter Files..." -msgstr "Filtra file..." +msgstr "Filtra i file..." #: editor/editor_node.cpp msgid "Operations with scene files." @@ -2812,15 +2810,15 @@ msgstr "Nuova scena ereditata..." #: editor/editor_node.cpp msgid "Open Scene..." -msgstr "Apri scena..." +msgstr "Apri una scena..." #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp msgid "Open Recent" -msgstr "Apri recente" +msgstr "Apri una scena recente" #: editor/editor_node.cpp msgid "Save Scene" -msgstr "Salva scena" +msgstr "Salva la scena" #: editor/editor_node.cpp msgid "Save All Scenes" @@ -2832,7 +2830,7 @@ msgstr "Converti in..." #: editor/editor_node.cpp msgid "MeshLibrary..." -msgstr "Libreria delle Mesh..." +msgstr "MeshLibrary..." #: editor/editor_node.cpp msgid "TileSet..." @@ -2859,19 +2857,19 @@ msgstr "Progetto" #: editor/editor_node.cpp msgid "Project Settings..." -msgstr "Impostazioni progetto…" +msgstr "Impostazioni del progetto…" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "Version Control" -msgstr "Controllo Versione" +msgstr "Controllo della versione" #: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp msgid "Set Up Version Control" -msgstr "Imposta Controllo Versione" +msgstr "Imposta il controllo della versione" #: editor/editor_node.cpp msgid "Shut Down Version Control" -msgstr "Arresta Controllo Versione" +msgstr "Arresta il controllo della versione" #: editor/editor_node.cpp msgid "Export..." @@ -2879,7 +2877,7 @@ msgstr "Esporta..." #: editor/editor_node.cpp msgid "Install Android Build Template..." -msgstr "Installa il Modello di Costruzione di Android…" +msgstr "Installa il modello di costruzione per Android…" #: editor/editor_node.cpp msgid "Open Project Data Folder" @@ -2891,11 +2889,11 @@ msgstr "Strumenti" #: editor/editor_node.cpp msgid "Orphan Resource Explorer..." -msgstr "Explorer Risorse Orfane…" +msgstr "Explorer di risorse orfane…" #: editor/editor_node.cpp msgid "Quit to Project List" -msgstr "Esci e torna alla lista progetti" +msgstr "Esci e torna alla lista dei progetti" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/project_export.cpp @@ -2904,7 +2902,7 @@ msgstr "Debug" #: editor/editor_node.cpp msgid "Deploy with Remote Debug" -msgstr "Distribuisci con Debug remoto" +msgstr "Distribuisci con debug remoto" #: editor/editor_node.cpp msgid "" @@ -2915,16 +2913,16 @@ msgid "" "mobile device).\n" "You don't need to enable it to use the GDScript debugger locally." msgstr "" -"Quando questa opzione è abilitata, usare il deploy one-click farà tentare " -"l'eseguibile di connettersi all'indirizzo IP di questo computer permettendo " -"il debug del progetto in esecuzione .\n" -"L'intesa di questa opzione è quella di essere usata per il debug remoto " -"(normalmente un dispositivo mobile).\n" -"Non c'è bisogno di abilitarla se utilizzi il debugger GDScript normale." +"Quando questa opzione è abilitata, usare il rilascio in un click farà " +"tentare all'eseguibile di connettersi all'indirizzo IP di questo computer " +"permettendo il debug del progetto in esecuzione.\n" +"Questa opzione è intesa per essere usata per il debug remoto (solitamente " +"con un dispositivo mobile).\n" +"Non c'è bisogno di abilitarla se si usa il debugger per GDScript in locale." #: editor/editor_node.cpp msgid "Small Deploy with Network Filesystem" -msgstr "Small Deploy con Filesystem della rete" +msgstr "Rilascio piccolo con un filesystem di rete" #: editor/editor_node.cpp msgid "" @@ -2935,11 +2933,11 @@ msgid "" "On Android, deploying will use the USB cable for faster performance. This " "option speeds up testing for projects with large assets." msgstr "" -"Quando questa impostazione è abilitata, usare il deploy one-click per " -"Android esporterà soltanto un eseguibile senza i dati del progetto.\n" -"Il filesystem sarà provvisto dal progetto dell'editor nella rete.\n" -"Su Android, il deploy userà il cavo USB per performance migliori. Questa " -"impostazione rende i progetti con asset pesanti più veloci." +"Quando questa impostazione è abilitata, il rilascio in un click per Android " +"esporterà un eseguibile senza i dati del progetto.\n" +"Il filesystem verrà provvisto dall'editor attraverso la rete.\n" +"Su Android, esso userà il cavo USB per ottenere delle prestazioni migliori. " +"Questa impostazione rende più veloci i progetti con risorse pesanti." #: editor/editor_node.cpp msgid "Visible Collision Shapes" @@ -2950,24 +2948,24 @@ msgid "" "When this option is enabled, collision shapes and raycast nodes (for 2D and " "3D) will be visible in the running project." msgstr "" -"Quando questa opzione è abilitata, le forme di collisione ed i nodi raycast " -"(per il 2D e 3D) sarrano visibili nel progetto in esecuzione." +"Quando questa opzione è abilitata, le forme di collisione e i nodi RayCast " +"(sia 2D che 3D) sarrano visibili nel progetto in esecuzione." #: editor/editor_node.cpp msgid "Visible Navigation" -msgstr "Navigazione Visibile" +msgstr "Navigazione visibile" #: editor/editor_node.cpp msgid "" "When this option is enabled, navigation meshes and polygons will be visible " "in the running project." msgstr "" -"Quando questa opzione è abilitata, le mesh di navigazione ed i poligoni " +"Quando questa opzione è abilitata, le mesh di navigazione e i poligoni " "saranno visibili nel progetto in esecuzione." #: editor/editor_node.cpp msgid "Synchronize Scene Changes" -msgstr "Sincronizza Cambi Scena" +msgstr "Sincronizza i cambi della scena" #: editor/editor_node.cpp msgid "" @@ -2977,8 +2975,8 @@ msgid "" "filesystem option is enabled." msgstr "" "Quando questa opzione è abilitata, ogni modifica fatta alla scena " -"nell'editor sarà replicata nel progetto in esecuzione.\n" -"Quando usata in remoto su un dispositivo, si può aumentare l'efficacia " +"nell'editor verrà replicata nel progetto in esecuzione.\n" +"Quando usata in remoto su un dispositivo, essa risulta più efficiente " "abilitando l'opzione \"network filesystem\"." #: editor/editor_node.cpp @@ -2992,10 +2990,10 @@ msgid "" "When used remotely on a device, this is more efficient when the network " "filesystem option is enabled." msgstr "" -"Quando questa opzione è abilitata, qualsiasi script salvato sarà ricaricato " +"Quando questa opzione è abilitata, qualsiasi script salvato verrà ricaricato " "nel progetto in esecuzione.\n" -"Quando usato in remoto su un dispositivo, si potrà aumentarne l'efficacia " -"abilitando anche l'opzione \"network filesystem\"." +"Quando usato in remoto su un dispositivo, essa risulta più efficate " +"abilitando l'opzione \"network filesystem\"." #: editor/editor_node.cpp editor/script_create_dialog.cpp msgid "Editor" @@ -3003,40 +3001,42 @@ msgstr "Editor" #: editor/editor_node.cpp msgid "Editor Settings..." -msgstr "Impostazioni editor…" +msgstr "Impostazioni dell'editor…" #: editor/editor_node.cpp msgid "Editor Layout" msgstr "Disposizione dell'editor" #: editor/editor_node.cpp +#, fuzzy msgid "Take Screenshot" msgstr "Acquisisci una schermata" #: editor/editor_node.cpp +#, fuzzy msgid "Screenshots are stored in the Editor Data/Settings Folder." msgstr "" "Gli screenshot vengono memorizzati nella cartella Data/Settings dell'editor." #: editor/editor_node.cpp msgid "Toggle Fullscreen" -msgstr "Abilita/Disabilita modalità a schermo intero" +msgstr "Commuta la modalità a schermo intero" #: editor/editor_node.cpp msgid "Toggle System Console" -msgstr "Abilita/Disabilita la console di sistema" +msgstr "Commuta la console di sistema" #: editor/editor_node.cpp msgid "Open Editor Data/Settings Folder" -msgstr "Apri cartella dati/impostazioni editor" +msgstr "Apri cartella dei dati/impostazioni editor" #: editor/editor_node.cpp msgid "Open Editor Data Folder" -msgstr "Apri la Cartella dei Dati dell'Editor" +msgstr "Apri la cartella dei dati dell'editor" #: editor/editor_node.cpp msgid "Open Editor Settings Folder" -msgstr "Apri cartella impostazioni editor" +msgstr "Apri la cartella delle impostazioni editor" #: editor/editor_node.cpp msgid "Manage Editor Features..." @@ -3044,7 +3044,7 @@ msgstr "Gestisci le funzionalità dell'editor…" #: editor/editor_node.cpp msgid "Manage Export Templates..." -msgstr "Gestisci Modello d'Esportazione…" +msgstr "Gestisci i modelli d'esportazione…" #: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp msgid "Help" @@ -3052,6 +3052,7 @@ msgstr "Aiuto" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/plugins/shader_editor_plugin.cpp +#, fuzzy msgid "Online Docs" msgstr "Documentazione online" @@ -3065,7 +3066,7 @@ msgstr "Segnala un problema" #: editor/editor_node.cpp msgid "Send Docs Feedback" -msgstr "Valuta documentazione" +msgstr "Valuta la documentazione" #: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp msgid "Community" @@ -3077,7 +3078,7 @@ msgstr "Informazioni su Godot" #: editor/editor_node.cpp msgid "Support Godot Development" -msgstr "Supporta lo Sviluppo di Godot" +msgstr "Supporta lo sviluppo di Godot" #: editor/editor_node.cpp msgid "Play the project." @@ -3101,19 +3102,19 @@ msgstr "Ferma la scena." #: editor/editor_node.cpp msgid "Play the edited scene." -msgstr "Esegui la scena in modifica." +msgstr "Esegui la scena modificata." #: editor/editor_node.cpp msgid "Play Scene" -msgstr "Esegui scena" +msgstr "Esegui la scena" #: editor/editor_node.cpp msgid "Play custom scene" -msgstr "Esegui scena personalizzata" +msgstr "Avvia una scena personalizzata" #: editor/editor_node.cpp msgid "Play Custom Scene" -msgstr "Avvia scena personalizzata" +msgstr "Avvia una scena personalizzata" #: editor/editor_node.cpp msgid "Changing the video driver requires restarting the editor." @@ -3134,11 +3135,11 @@ msgstr "Aggiorna continuamente" #: editor/editor_node.cpp msgid "Update When Changed" -msgstr "Aggiorna quando modificato" +msgstr "Aggiorna quando modificata" #: editor/editor_node.cpp msgid "Hide Update Spinner" -msgstr "Disabilita l'icona girevole di aggiornamento" +msgstr "Nascondi la rotella di aggiornamento" #: editor/editor_node.cpp msgid "FileSystem" @@ -3150,7 +3151,7 @@ msgstr "Ispettore" #: editor/editor_node.cpp msgid "Expand Bottom Panel" -msgstr "Espandi Pannello Inferiore" +msgstr "Espandi il pannello inferiore" #: editor/editor_node.cpp msgid "Output" @@ -3161,9 +3162,10 @@ msgid "Don't Save" msgstr "Non salvare" #: editor/editor_node.cpp +#, fuzzy msgid "Android build template is missing, please install relevant templates." msgstr "" -"Modello build di Android non è presente, si prega di installare i modelli " +"Modello di costruzione di Android mancante, si prega di installare i modelli " "rilevanti." #: editor/editor_node.cpp @@ -3180,14 +3182,14 @@ msgid "" "the \"Use Custom Build\" option should be enabled in the Android export " "preset." msgstr "" -"Questo predisporrà il progetto per le build personalizzate per Android " -"installando i template sorgente in \"res://android/build\".\n" -"Potrai allora applicare le modifiche e costruire il tuo APK personalizzato " -"durante l'esportazione (aggiungere moduli, cambiare l'AndroidManifest.xml, " -"eccetera).\n" -"Nota che per creare delle build personalizzate, invece di usare gli APK pre-" -"costruiti, l'opzione \"Use Custom Build\" va attivata nella preimpostazione " -"d'esportazione per Android." +"Questo predisporrà il progetto alle costruzioni personalizzate per Android " +"installando il modello di sorgente in \"res://android/build\".\n" +"Sarà allora possibile applicare delle modifiche e costruire un APK " +"personalizzato durante l'esportazione (aggiungere moduli, cambiare " +"l'AndroidManifest.xml, eccetera).\n" +"Va notato che per creare delle costruzioni personalizzate, invece di usare " +"gli APK pre-costruiti, va attivata l'opzione \"Use Custom Build\" nella " +"preimpostazione d'esportazione per Android." #: editor/editor_node.cpp msgid "" @@ -3196,18 +3198,18 @@ msgid "" "Remove the \"res://android/build\" directory manually before attempting this " "operation again." msgstr "" -"Il template della build Android è già installato in questo progetto e non " -"verrà sovrascritto.\n" -"Rimuovi manualmente la cartella \"res://android/build\" prima di ritentare " +"Il modello di costruzione per Android è già installato in questo progetto e " +"non verrà sovrascritto.\n" +"Rimuovere manualmente la cartella \"res://android/build\" prima di ritentare " "questa operazione." #: editor/editor_node.cpp msgid "Import Templates From ZIP File" -msgstr "Importa Template Da File ZIP" +msgstr "Importa i modelli da un file ZIP" #: editor/editor_node.cpp msgid "Template Package" -msgstr "Pacchetto Template" +msgstr "Pacchetto di modelli" #: editor/editor_node.cpp msgid "Export Library" @@ -3297,11 +3299,11 @@ msgstr "Script Principale:" #: editor/editor_plugin_settings.cpp msgid "Edit Plugin" -msgstr "Modifica Plugin" +msgstr "Modifica estensione" #: editor/editor_plugin_settings.cpp msgid "Installed Plugins:" -msgstr "Plugins Installati:" +msgstr "Estensioni installate:" #: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp msgid "Update" @@ -3927,7 +3929,7 @@ msgstr "Riscansiona il Filesystem" #: editor/filesystem_dock.cpp msgid "Toggle Split Mode" -msgstr "Attiva/disattiva la modalità Split" +msgstr "Commuta la modalità divisa" #: editor/filesystem_dock.cpp msgid "Search files" @@ -4242,7 +4244,7 @@ msgstr "Copia parametri" #: editor/inspector_dock.cpp msgid "Edit Resource Clipboard" -msgstr "Modifica Appunti Risorse" +msgstr "Modifica gli appunti delle risorse" #: editor/inspector_dock.cpp msgid "Copy Resource" @@ -4306,15 +4308,15 @@ msgstr "Seleziona un singolo nodo per eliminare i suoi segnali e gruppi." #: editor/plugin_config_dialog.cpp msgid "Edit a Plugin" -msgstr "Modifica un Plugin" +msgstr "Modifica un'estensione" #: editor/plugin_config_dialog.cpp msgid "Create a Plugin" -msgstr "Crea un Plugin" +msgstr "Crea un'estensione" #: editor/plugin_config_dialog.cpp msgid "Plugin Name:" -msgstr "Nome Plugin:" +msgstr "Nome dell'estensione:" #: editor/plugin_config_dialog.cpp msgid "Subfolder:" @@ -4454,7 +4456,7 @@ msgstr "" #: editor/plugins/animation_blend_space_1d_editor.cpp #: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp msgid "Enable snap and show grid." -msgstr "Attiva lo snap e mostra la griglia." +msgstr "Abilita lo scatto e mostra la griglia." #: editor/plugins/animation_blend_space_1d_editor.cpp #: editor/plugins/animation_blend_space_2d_editor.cpp @@ -4508,7 +4510,7 @@ msgstr "Non esistono triangoli, non può quindi aver luogo alcun blending." #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Toggle Auto Triangles" -msgstr "Attiva Triangolazione Automatica" +msgstr "Attiva la triangolazione automatica" #: editor/plugins/animation_blend_space_2d_editor.cpp msgid "Create triangles by connecting points." @@ -4580,7 +4582,7 @@ msgstr "Elimina Nodo(i)" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Toggle Filter On/Off" -msgstr "Attiva/Disattiva il Filtro" +msgstr "Commuta il filtro" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Change Filter" @@ -4609,11 +4611,11 @@ msgstr "" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Anim Clips" -msgstr "Clip d'animazione" +msgstr "Segmenti d'animazione" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Audio Clips" -msgstr "Clip Audio" +msgstr "Segmenti audio" #: editor/plugins/animation_blend_tree_editor_plugin.cpp msgid "Functions" @@ -4640,7 +4642,7 @@ msgstr "Abilita filtraggio" #: editor/plugins/animation_player_editor_plugin.cpp msgid "Toggle Autoplay" -msgstr "Abilità Autoplay" +msgstr "Commuta la riproduzione automatica" #: editor/plugins/animation_player_editor_plugin.cpp msgid "New Animation Name:" @@ -4927,8 +4929,8 @@ msgstr "Rimuovi il nodo o la transizione selezionati." #: editor/plugins/animation_state_machine_editor.cpp msgid "Toggle autoplay this animation on start, restart or seek to zero." msgstr "" -"Attiva/disattiva la riproduzione automatica di questa animazione all'avvio, " -"riavvio, o il riavvolgimento a zero." +"Commuta la riproduzione automatica di questa animazione all'avvio, riavvio, " +"o il riavvolgimento a zero." #: editor/plugins/animation_state_machine_editor.cpp msgid "Set the end animation. This is useful for sub-transitions." @@ -5249,7 +5251,7 @@ msgstr "Importa…" #: editor/plugins/asset_library_editor_plugin.cpp msgid "Plugins..." -msgstr "Plugins…" +msgstr "Estensioni…" #: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp msgid "Sort:" @@ -5342,12 +5344,13 @@ msgid "Preview" msgstr "Anteprima" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Configure Snap" -msgstr "Configura Snap" +msgstr "Configura lo scatto" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Grid Offset:" -msgstr "Offset Griglia:" +msgstr "Scostamento della griglia:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Grid Step:" @@ -5363,7 +5366,7 @@ msgstr "passi" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotation Offset:" -msgstr "Offset Rotazione:" +msgstr "Scostamento della rotazione:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotation Step:" @@ -5371,7 +5374,7 @@ msgstr "Passo di rotazione:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Scale Step:" -msgstr "Passo di scala:" +msgstr "Passo della scala:" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Move Vertical Guide" @@ -5402,8 +5405,9 @@ msgid "Create Horizontal and Vertical Guides" msgstr "Crea Guide Orizzontali e Verticali" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)" -msgstr "Imposta Pivot Offset CanvasItem \"%s\" a (%d, %d)" +msgstr "Imposta lo scostamento del Pivot del CanvasItem \"%s\" a (%d, %d)" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Rotate %d CanvasItems" @@ -5677,73 +5681,90 @@ msgid "Ruler Mode" msgstr "Modalità righello" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Toggle smart snapping." -msgstr "Abilita snapping intelligente." +msgstr "Commuta lo scatto intelligente." #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Use Smart Snap" -msgstr "Usa lo Snap intelligente" +msgstr "Usa lo scatto intelligente" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Toggle grid snapping." -msgstr "Abilita/Disabilita snapping magnetico." +msgstr "Commuta la griglia magnetica." #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Use Grid Snap" -msgstr "Usa Griglia Magnetica" +msgstr "Usa la griglia magnetica" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snapping Options" -msgstr "Opzioni di Snapping" +msgstr "Opzioni dello scatto" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Use Rotation Snap" -msgstr "Usa lo Snap di Rotazione" +msgstr "Scatta la rotazione" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Use Scale Snap" -msgstr "Usa lo snap con scala" +msgstr "Scatta la scala" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap Relative" -msgstr "Snap Relativo" +msgstr "Scatti relativi" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Use Pixel Snap" -msgstr "Usa Pixel Snap" +msgstr "Scatta sui pixel" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Smart Snapping" -msgstr "Snapping intelligente" +msgstr "Scatto intelligente" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Configure Snap..." -msgstr "Configura Snap..." +msgstr "Configura gli scatti..." #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap to Parent" -msgstr "Snap al Genitore" +msgstr "Scatta sul genitore" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap to Node Anchor" -msgstr "Snap ad ancora del nodo" +msgstr "Scatta sull'ancora dei nodi" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap to Node Sides" -msgstr "Snap sui lati del nodo" +msgstr "Scatta sui lati dei nodi" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap to Node Center" -msgstr "Snap al centro del nodo" +msgstr "Scatta sul centro dei nodi" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap to Other Nodes" -msgstr "Snap ad altri nodi" +msgstr "Scatta sugli altri nodi" #: editor/plugins/canvas_item_editor_plugin.cpp +#, fuzzy msgid "Snap to Guides" -msgstr "Snap alle guide" +msgstr "Scatta sulle guide" #: editor/plugins/canvas_item_editor_plugin.cpp #: editor/plugins/spatial_editor_plugin.cpp @@ -6026,6 +6047,7 @@ msgid "Ease Out" msgstr "Ease Out" #: editor/plugins/curve_editor_plugin.cpp +#, fuzzy msgid "Smoothstep" msgstr "Graduale" @@ -6067,7 +6089,7 @@ msgstr "Rimuovi Punto" #: editor/plugins/curve_editor_plugin.cpp msgid "Toggle Curve Linear Tangent" -msgstr "Abilita Tangente di Curva Lineare" +msgstr "Commuta la Tangente di Curva Lineare" #: editor/plugins/curve_editor_plugin.cpp msgid "Hold Shift to edit tangents individually" @@ -6805,11 +6827,11 @@ msgstr "Impostazioni griglia" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Snap" -msgstr "Snap" +msgstr "Scatto" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Enable Snap" -msgstr "Abilita Snap" +msgstr "Abilita lo scatto" #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Grid" @@ -6862,7 +6884,7 @@ msgstr "Elimina risorsa" #: editor/plugins/resource_preloader_editor_plugin.cpp msgid "Resource clipboard is empty!" -msgstr "La clipboard delle risorse è vuota!" +msgstr "Gli appunti delle risorse sono vuoti!" #: editor/plugins/resource_preloader_editor_plugin.cpp msgid "Paste Resource" @@ -7005,7 +7027,7 @@ msgstr "Filtra gli script" #: editor/plugins/script_editor_plugin.cpp msgid "Toggle alphabetical sorting of the method list." -msgstr "Abilita/Disabilita l'ordinamento alfabetico della lista dei metodi." +msgstr "Commuta l'ordinamento alfabetico della lista dei metodi." #: editor/plugins/script_editor_plugin.cpp msgid "Filter methods" @@ -7106,11 +7128,11 @@ msgstr "Cerca" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Step Into" -msgstr "Passo dentro all'istruzione" +msgstr "Fai un passo all'interno" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Step Over" -msgstr "Passo successivo" +msgstr "Fai un passo" #: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp msgid "Break" @@ -7277,7 +7299,7 @@ msgstr "Indenta a destra" #: editor/plugins/script_text_editor.cpp msgid "Toggle Comment" -msgstr "Attiva/Disattiva Commento" +msgstr "Commuta i commenti" #: editor/plugins/script_text_editor.cpp msgid "Fold/Unfold Line" @@ -7329,7 +7351,7 @@ msgstr "Aiuto contestuale" #: editor/plugins/script_text_editor.cpp msgid "Toggle Bookmark" -msgstr "Abilita/Disabilita i segnalibri" +msgstr "Commuta i segnalibri" #: editor/plugins/script_text_editor.cpp msgid "Go to Next Bookmark" @@ -7354,7 +7376,7 @@ msgstr "Vai alla linea..." #: editor/plugins/script_text_editor.cpp #: modules/visual_script/visual_script_editor.cpp msgid "Toggle Breakpoint" -msgstr "Attiva/Disattiva Punto D'Interruzione" +msgstr "Commuta la riga corrente come punto d'interruzione" #: editor/plugins/script_text_editor.cpp msgid "Remove All Breakpoints" @@ -7661,12 +7683,11 @@ msgid "View Rotation Locked" msgstr "Rotazione Vista Bloccata" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "" "To zoom further, change the camera's clipping planes (View -> Settings...)" msgstr "" -"Per maggiore zoom, cambia i piani del clip della videocamera (Vista -> " -"Impostazioni)" +"Per un maggiore ingrandimento, cambia i piani del clip della videocamera " +"(Vista -> Impostazioni...)" #: editor/plugins/spatial_editor_plugin.cpp msgid "" @@ -7697,12 +7718,15 @@ msgstr "" "(\"raggi X\")." #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Snap Nodes To Floor" -msgstr "Sposta i Nodi sul Pavimento" +msgstr "Scatta i nodi sul pavimento" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Couldn't find a solid floor to snap the selection to." -msgstr "Non si è trovato un pavimento solido al quale agganciare la selezione." +msgstr "" +"Impossibile trovare un pavimento solido sul quale scattare la selezione." #: editor/plugins/spatial_editor_plugin.cpp msgid "" @@ -7719,8 +7743,9 @@ msgid "Use Local Space" msgstr "Usa Spazio Locale" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Use Snap" -msgstr "Usa Snap" +msgstr "Scatta" #: editor/plugins/spatial_editor_plugin.cpp msgid "Bottom View" @@ -7763,8 +7788,9 @@ msgid "Focus Selection" msgstr "Centra la Selezione" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Toggle Freelook" -msgstr "Abilita/Disabilita Vista libera" +msgstr "Commuta la vista libera" #: editor/plugins/spatial_editor_plugin.cpp #: editor/plugins/visual_shader_editor_plugin.cpp @@ -7772,8 +7798,9 @@ msgid "Transform" msgstr "Trasforma" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Snap Object to Floor" -msgstr "Posa l'oggetto sul suolo" +msgstr "Scatta l'oggetto sul suolo" #: editor/plugins/spatial_editor_plugin.cpp msgid "Transform Dialog..." @@ -7821,20 +7848,24 @@ msgid "Settings..." msgstr "Impostazioni…" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Snap Settings" -msgstr "Impostazioni Snap" +msgstr "Impostazioni dello scatto" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Translate Snap:" -msgstr "Trasla Snap:" +msgstr "Scatto della traslazione:" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Rotate Snap (deg.):" -msgstr "Snap Rotazione (gradi):" +msgstr "Scatto della rotazione (gradi):" #: editor/plugins/spatial_editor_plugin.cpp +#, fuzzy msgid "Scale Snap (%):" -msgstr "Scala Snap (%):" +msgstr "Scatto della scala (%):" #: editor/plugins/spatial_editor_plugin.cpp msgid "Viewport Settings" @@ -8004,7 +8035,7 @@ msgstr "ERRORE: Impossibile caricare la risorsa frame!" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Resource clipboard is empty or not a texture!" -msgstr "Clipboard risorse vuota o non è una texture!" +msgstr "Gli appunti delle risorse sono vuoti o non una texture!" #: editor/plugins/sprite_frames_editor_plugin.cpp msgid "Paste Frame" @@ -8104,7 +8135,7 @@ msgstr "Imposta Margine" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Snap Mode:" -msgstr "Modalità Snap:" +msgstr "Modalità dello scatto:" #: editor/plugins/texture_region_editor_plugin.cpp #: scene/resources/visual_shader.cpp @@ -8112,12 +8143,14 @@ msgid "None" msgstr "Nessuno" #: editor/plugins/texture_region_editor_plugin.cpp +#, fuzzy msgid "Pixel Snap" -msgstr "Snap a Pixel" +msgstr "Scatto sui pixel" #: editor/plugins/texture_region_editor_plugin.cpp +#, fuzzy msgid "Grid Snap" -msgstr "Snap Griglia" +msgstr "Scatto sulla griglia" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Auto Slice" @@ -8125,7 +8158,7 @@ msgstr "Auto Divisione" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Offset:" -msgstr "Offset:" +msgstr "Scostamento:" #: editor/plugins/texture_region_editor_plugin.cpp msgid "Step:" @@ -8184,8 +8217,9 @@ msgid "Create From Current Editor Theme" msgstr "Crea da Tema Editor corrente" #: editor/plugins/theme_editor_plugin.cpp +#, fuzzy msgid "Toggle Button" -msgstr "Attiva/Disattiva pulsante" +msgstr "Interruttore" #: editor/plugins/theme_editor_plugin.cpp msgid "Disabled Button" @@ -8536,7 +8570,7 @@ msgstr "Mantieni il poligono all'interno dell'area del rettangolo." #: editor/plugins/tile_set_editor_plugin.cpp msgid "Enable snap and show grid (configurable via the Inspector)." -msgstr "Abilita snap e mostra la griglia (configurabile dall'Inspector)." +msgstr "Abilita lo scatto e mostra la griglia (configurabile dall'ispettore)." #: editor/plugins/tile_set_editor_plugin.cpp msgid "Display Tile Names (Hold Alt Key)" @@ -10562,7 +10596,7 @@ msgstr "AutoLoad" #: editor/project_settings_editor.cpp msgid "Plugins" -msgstr "Plugins" +msgstr "Estensioni" #: editor/project_settings_editor.cpp msgid "Import Defaults" @@ -11075,9 +11109,9 @@ msgid "" "every time it updates.\n" "Switch back to the Local scene tree dock to improve performance." msgstr "" -"Se selezionato, il riquadro della scena remota farà ricaricare il progetto " +"Se selezionato, il pannello della scena remota farà ricaricare il progetto " "ogni volta che viene aggiornato.\n" -"Torna al riquadro della scena Locale per migliorare le prestazioni." +"Tornare al pannello della scena locale per migliorare le prestazioni." #: editor/scene_tree_dock.cpp msgid "Local" @@ -11089,7 +11123,7 @@ msgstr "Liberare ereditarietà ? (No Undo!)" #: editor/scene_tree_editor.cpp msgid "Toggle Visible" -msgstr "Attiva/Disattiva Visibilità " +msgstr "Commuta visibilità " #: editor/scene_tree_editor.cpp msgid "Unlock Node" @@ -11112,16 +11146,16 @@ msgid "" "Node has %s connection(s) and %s group(s).\n" "Click to show signals dock." msgstr "" -"Il nodo ha %s connessione/i e %s gruppo/i.\n" -"Clicca per mostrare il dock dei segnali." +"Il nodo ha %s connessioni e %s gruppi.\n" +"Cliccare per mostrare il pannello dei segnali." #: editor/scene_tree_editor.cpp msgid "" "Node has %s connection(s).\n" "Click to show signals dock." msgstr "" -"Il nodo ha %s connessione/i.\n" -"Clicca per mostrare il dock dei segnali." +"Il nodo ha %s connessioni.\n" +"Cliccare per mostrare il pannello dei segnali." #: editor/scene_tree_editor.cpp msgid "" @@ -11129,7 +11163,7 @@ msgid "" "Click to show groups dock." msgstr "" "Il nodo è in %s gruppi.\n" -"Clicca per mostrare il dock dei gruppi." +"Cliccare per mostrare il pannello dei gruppi." #: editor/scene_tree_editor.cpp msgid "Open Script:" @@ -11153,7 +11187,7 @@ msgstr "" #: editor/scene_tree_editor.cpp msgid "Toggle Visibility" -msgstr "Abilita Visibilità " +msgstr "Commuta visibilità " #: editor/scene_tree_editor.cpp msgid "" @@ -11689,20 +11723,22 @@ msgid "Grid Map" msgstr "Mappa di Griglia" #: modules/gridmap/grid_map_editor_plugin.cpp +#, fuzzy msgid "Snap View" -msgstr "Vista Snap" +msgstr "Scatta la vista" #: modules/gridmap/grid_map_editor_plugin.cpp +#, fuzzy msgid "Clip Disabled" msgstr "Clip Disabilitata" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Clip Above" -msgstr "Ritaglia Sopra" +msgstr "Taglia sopra" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Clip Below" -msgstr "Ritaglia Sotto" +msgstr "Taglia sotto" #: modules/gridmap/grid_map_editor_plugin.cpp msgid "Edit X Axis" @@ -12260,8 +12296,8 @@ msgstr "VariableSet non trovato nello script: " #: modules/visual_script/visual_script_nodes.cpp msgid "Custom node has no _step() method, can't process graph." msgstr "" -"Il nodo personalizzato non ha alcun metodo _step(), impossibile processare " -"il grafico." +"Il nodo personalizzato non ha alcun metodo _step(), impossibile elaborare il " +"grafico." #: modules/visual_script/visual_script_nodes.cpp msgid "" @@ -12329,11 +12365,23 @@ msgstr "" "dal menu Progetto." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Debug keystore non configurato nelle Impostazioni dell'Editor né nel preset." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Release keystore non configurato correttamente nel preset di esportazione." diff --git a/editor/translations/ja.po b/editor/translations/ja.po index b47b97b20e..85768d721a 100644 --- a/editor/translations/ja.po +++ b/editor/translations/ja.po @@ -1143,6 +1143,10 @@ msgstr "Dictionary 値ã®å¤‰æ›´" msgid "Thanks from the Godot community!" msgstr "Godot コミュニティより感è¬ã‚’ï¼" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot エンジンã«è²¢çŒ®ã—ãŸäººã€…" @@ -12202,10 +12206,22 @@ msgstr "" "ジェクト] メニューã‹ã‚‰ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¾ã™ã€‚" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "デãƒãƒƒã‚°ã‚ーストアãŒã‚¨ãƒ‡ã‚£ã‚¿è¨å®šã«ã‚‚プリセットã«ã‚‚è¨å®šã•れã¦ã„ã¾ã›ã‚“。" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "エクスãƒãƒ¼ãƒˆè¨å®šã«ã¦ãƒªãƒªãƒ¼ã‚¹ ã‚ーストアãŒèª¤ã£ã¦è¨å®šã•れã¦ã„ã¾ã™ã€‚" diff --git a/editor/translations/ka.po b/editor/translations/ka.po index 7c6f378627..ce5c6dc032 100644 --- a/editor/translations/ka.po +++ b/editor/translations/ka.po @@ -1162,6 +1162,10 @@ msgstr "ლექსიკáƒáƒœáƒ˜áƒ¡ მნიშვნელáƒáƒ‘ის შá msgid "Thanks from the Godot community!" msgstr "მáƒáƒ“ლáƒáƒ‘რGodot სáƒáƒ–áƒáƒ’áƒáƒ“áƒáƒ”ბისგáƒáƒœ!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot ძრáƒáƒ•ის ხელშემწყáƒáƒ‘ები" @@ -12073,10 +12077,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/km.po b/editor/translations/km.po index 21149c748f..ee77bab308 100644 --- a/editor/translations/km.po +++ b/editor/translations/km.po @@ -1082,6 +1082,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11685,10 +11689,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ko.po b/editor/translations/ko.po index cc41ee5d41..9224ef5e65 100644 --- a/editor/translations/ko.po +++ b/editor/translations/ko.po @@ -22,11 +22,12 @@ # Yongjin Jo <wnrhd114@gmail.com>, 2020. # Yungjoong Song <yungjoong.song@gmail.com>, 2020. # Henry LeRoux <henry.leroux@ocsbstudent.ca>, 2021. +# Postive_ Cloud <postive12@gmail.com>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-19 20:16+0000\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" "Last-Translator: Myeongjin Lee <aranet100@gmail.com>\n" "Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/" "godot/ko/>\n" @@ -35,7 +36,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -59,7 +60,7 @@ msgstr "표현ì‹ì˜ ìž…ë ¥ %i (ì „ë‹¬ë˜ì§€ 않ìŒ) ì´(ê°€) 올바르지 ì•ŠìŠ #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "ì¸ìŠ¤í„´ìŠ¤ê°€ null (ì „ë‹¬ë˜ì§€ 않ìŒ) ì´ë¯€ë¡œ self 를 ì‚¬ìš©í• ìˆ˜ 없습니다" +msgstr "ì¸ìŠ¤í„´ìŠ¤ê°€ null(ì „ë‹¬ë˜ì§€ 않ìŒ)ì´ë¯€ë¡œ self ëª…ë ¹ì–´ëŠ” ì‚¬ìš©í• ìˆ˜ 없습니다" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." @@ -1131,6 +1132,10 @@ msgstr "딕셔너리 ê°’ 변경" msgid "Thanks from the Godot community!" msgstr "Godot 커뮤니티ì—서 ê°ì‚¬ë“œë¦½ë‹ˆë‹¤!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "í´ë¦í•˜ì—¬ 복사합니다." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine 기여ìž" @@ -12115,10 +12120,26 @@ msgstr "" "하세요." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Debug Keystore, Debug User ë° Debug Password ì„¤ì •ì„ êµ¬ì„±í•˜ê±°ë‚˜ ê·¸ 중 ì–´ëŠ ê²ƒ" +"ë„ ì—†ì–´ì•¼ 합니다." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "Debug keystore를 편집기 ì„¤ì •ê³¼ í”„ë¦¬ì…‹ì— ì„¤ì •í•˜ì§€ 않았습니다." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Release Keystore, Release User ë° Release Password ì„¤ì •ì„ êµ¬ì„±í•˜ê±°ë‚˜ ê·¸ 중 ì–´" +"ëŠ ê²ƒë„ ì—†ì–´ì•¼ 합니다." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "내보내기 í”„ë¦¬ì…‹ì— ë°°í¬ keystorkeê°€ 잘못 ì„¤ì •ë˜ì–´ 있습니다." diff --git a/editor/translations/lt.po b/editor/translations/lt.po index b04d49c871..d4520d2d76 100644 --- a/editor/translations/lt.po +++ b/editor/translations/lt.po @@ -1123,6 +1123,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -12042,10 +12046,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/lv.po b/editor/translations/lv.po index f51c38c6b8..360b8bcb8f 100644 --- a/editor/translations/lv.po +++ b/editor/translations/lv.po @@ -1119,6 +1119,10 @@ msgstr "MainÄ«t VÄrdnÄ«cas VÄ“rtÄ«bu" msgid "Thanks from the Godot community!" msgstr "Paldies no Godot sabiedrÄ«bas!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot DzinÄ“ja ieguldÄ«tÄji" @@ -11846,10 +11850,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/mi.po b/editor/translations/mi.po index 6beaf559b3..17b666c0e6 100644 --- a/editor/translations/mi.po +++ b/editor/translations/mi.po @@ -1074,6 +1074,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11677,10 +11681,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/mk.po b/editor/translations/mk.po index 6cb5e626cb..0443bd589e 100644 --- a/editor/translations/mk.po +++ b/editor/translations/mk.po @@ -1081,6 +1081,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11684,10 +11688,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ml.po b/editor/translations/ml.po index 0b3a3e2f85..a25540d2cd 100644 --- a/editor/translations/ml.po +++ b/editor/translations/ml.po @@ -1084,6 +1084,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11695,10 +11699,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/mr.po b/editor/translations/mr.po index 7b2683f181..7e6f8f5cc5 100644 --- a/editor/translations/mr.po +++ b/editor/translations/mr.po @@ -1081,6 +1081,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11685,10 +11689,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ms.po b/editor/translations/ms.po index 0dc54a314a..82a4443b24 100644 --- a/editor/translations/ms.po +++ b/editor/translations/ms.po @@ -1124,6 +1124,10 @@ msgstr "Tukar Nilai Kamus" msgid "Thanks from the Godot community!" msgstr "Terima kasih dari komuniti Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Penyumbang Enjin Godot" @@ -12068,10 +12072,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/nb.po b/editor/translations/nb.po index 7d6077e69c..f040c4ca0e 100644 --- a/editor/translations/nb.po +++ b/editor/translations/nb.po @@ -1148,6 +1148,10 @@ msgstr "Endre listeverdi" msgid "Thanks from the Godot community!" msgstr "Takk fra Godot-samfunnet!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine sine bidragsytere" @@ -12577,10 +12581,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/nl.po b/editor/translations/nl.po index 41a5cf103a..616c3ae69a 100644 --- a/editor/translations/nl.po +++ b/editor/translations/nl.po @@ -50,7 +50,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-29 13:49+0000\n" +"PO-Revision-Date: 2021-06-05 08:32+0000\n" "Last-Translator: Stijn Hinlopen <f.a.hinlopen@gmail.com>\n" "Language-Team: Dutch <https://hosted.weblate.org/projects/godot-engine/godot/" "nl/>\n" @@ -1163,6 +1163,10 @@ msgstr "Waarde wijzigen" msgid "Thanks from the Godot community!" msgstr "Bedankt van de Godot gemeenschap!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine medewerkers" @@ -10497,7 +10501,7 @@ msgstr "Plugins" #: editor/project_settings_editor.cpp msgid "Import Defaults" -msgstr "Laad de standaard waarden" +msgstr "Import" #: editor/property_editor.cpp msgid "Preset..." @@ -10750,9 +10754,8 @@ msgid "Instance Child Scene" msgstr "Scène instantiëren" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "Can't paste root node into the same scene." -msgstr "Kan deze operatie niet uitvoeren op knopen uit een vreemde scène!" +msgstr "Kan de wortelknoop niet in dezelfde scène plakken." #: editor/scene_tree_dock.cpp msgid "Paste Node(s)" @@ -12259,10 +12262,22 @@ msgstr "" "projectmenu kan het geïnstalleerd worden." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "Debug Keystore is niet ingesteld of aanwezig in de Editor Settings." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "Release-Keystore is verkeerd ingesteld in de exportinstelingen." diff --git a/editor/translations/or.po b/editor/translations/or.po index e3b057e2c8..58214daf10 100644 --- a/editor/translations/or.po +++ b/editor/translations/or.po @@ -1080,6 +1080,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11683,10 +11687,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/pl.po b/editor/translations/pl.po index 6c3367a0ab..83d36da5bb 100644 --- a/editor/translations/pl.po +++ b/editor/translations/pl.po @@ -52,7 +52,7 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-19 20:16+0000\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" "Last-Translator: Tomek <kobewi4e@gmail.com>\n" "Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/" "godot/pl/>\n" @@ -62,7 +62,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -86,7 +86,7 @@ msgstr "NiewÅ‚aÅ›ciwe dane %i (nie przekazane) w wyrażeniu" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" msgstr "" -"self nie może być użyte, ponieważ instancja jest nullem (nie przekazano)" +"self nie może zostać użyte, ponieważ instancja jest nullem (nie przekazana)" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." @@ -1157,6 +1157,10 @@ msgstr "ZmieÅ„ wartość sÅ‚ownika" msgid "Thanks from the Godot community!" msgstr "PodziÄ™kowania od spoÅ‚ecznoÅ›ci Godota!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Kliknij, by skopiować." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Współtwórcy Godot Engine" @@ -12228,12 +12232,28 @@ msgstr "" "go z menu Projekt." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Albo ustawienia Debug Keystore, Debug User ORAZ Debug Password muszÄ… być " +"skonfigurowane, ALBO żadne z nich." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Debugowy keystore nieskonfigurowany w Ustawieniach Edytora ani w profilu " "eksportu." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Albo ustawienia Release Keystore, Release User ORAZ Release Password muszÄ… " +"być skonfigurowane, ALBO żadne z nich." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Wydaniowy keystore jest niepoprawnie skonfigurowany w profilu eksportu." diff --git a/editor/translations/pr.po b/editor/translations/pr.po index 8ad62171b2..e308deb01b 100644 --- a/editor/translations/pr.po +++ b/editor/translations/pr.po @@ -6,12 +6,13 @@ # Zion Nimchuk <zionnimchuk@gmail.com>, 2016-2017. # Allan Nordhøy <epost@anotheragency.no>, 2018. # David Fatheree <david.fathereewcchs@gmail.com>, 2020. +# Nathan Franke <natfra@pm.me>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2020-06-22 06:40+0000\n" -"Last-Translator: David Fatheree <david.fathereewcchs@gmail.com>\n" +"PO-Revision-Date: 2021-06-11 14:49+0000\n" +"Last-Translator: Nathan Franke <natfra@pm.me>\n" "Language-Team: Pirate <https://hosted.weblate.org/projects/godot-engine/" "godot/pr/>\n" "Language: pr\n" @@ -19,7 +20,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2-dev\n" +"X-Generator: Weblate 4.7-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -30,7 +31,7 @@ msgstr "" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "Expected a strin' o' length 1 (a character)." +msgstr "Expected a strin' o' length 1 (jus' a character)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp @@ -48,56 +49,55 @@ msgstr "" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." -msgstr "Yer index property name '%s' in node %s be walkin' th' plank!" +msgstr "Yer opera'r %s be usin' th' wrong grub, %s an' %s!" #: core/math/expression.cpp msgid "Invalid index of type %s for base type %s" -msgstr "Yer index property name '%s' in node %s be walkin' th' plank!" +msgstr "Yer index type %s o' node type %s be walkin' th' plank!" #: core/math/expression.cpp msgid "Invalid named index '%s' for base type %s" msgstr "" #: core/math/expression.cpp -#, fuzzy msgid "Invalid arguments to construct '%s'" -msgstr ": Evil argument of th' type: " +msgstr "Evil argument o' th' type '%s'" #: core/math/expression.cpp msgid "On call to '%s':" -msgstr "" +msgstr "O' th' call t' '%s':" #: core/ustring.cpp msgid "B" -msgstr "" +msgstr "' Barnacles" #: core/ustring.cpp msgid "KiB" -msgstr "" +msgstr "' Kilo-Barnacles" #: core/ustring.cpp msgid "MiB" -msgstr "" +msgstr "' Mega-Barnacles" #: core/ustring.cpp msgid "GiB" -msgstr "" +msgstr "' Giga-Barnacles" #: core/ustring.cpp msgid "TiB" -msgstr "" +msgstr "' Tera-Barnacles" #: core/ustring.cpp msgid "PiB" -msgstr "" +msgstr "' Peta-Barnacles" #: core/ustring.cpp msgid "EiB" -msgstr "" +msgstr "' Exa-Barnacles" #: editor/animation_bezier_editor.cpp msgid "Free" -msgstr "" +msgstr "O'en" #: editor/animation_bezier_editor.cpp msgid "Balanced" @@ -109,11 +109,11 @@ msgstr "See'in Double" #: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp msgid "Time:" -msgstr "" +msgstr "Sundial:" #: editor/animation_bezier_editor.cpp msgid "Value:" -msgstr "" +msgstr "Grub:" #: editor/animation_bezier_editor.cpp msgid "Insert Key Here" @@ -125,9 +125,8 @@ msgid "Duplicate Selected Key(s)" msgstr "Yar, Blow th' Selected Down!" #: editor/animation_bezier_editor.cpp -#, fuzzy msgid "Delete Selected Key(s)" -msgstr "Yar, Blow th' Selected Down!" +msgstr "Yar, Plunder th' Selected!" #: editor/animation_bezier_editor.cpp #, fuzzy @@ -1124,6 +1123,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -2137,7 +2140,7 @@ msgstr "" #: editor/editor_log.cpp msgid "Output:" -msgstr "" +msgstr "Cap'n's Log:" #: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp #, fuzzy @@ -2156,7 +2159,7 @@ msgstr "" #: editor/editor_log.cpp msgid "Clear Output" -msgstr "" +msgstr "Clear Cap'n's Log" #: editor/editor_network_profiler.cpp editor/editor_node.cpp #: editor/editor_profiler.cpp @@ -2781,7 +2784,7 @@ msgstr "" #: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp #: editor/project_export.cpp msgid "Debug" -msgstr "" +msgstr "Debuggin'" #: editor/editor_node.cpp msgid "Deploy with Remote Debug" @@ -3016,7 +3019,7 @@ msgstr "" #: editor/editor_node.cpp msgid "Output" -msgstr "" +msgstr "Cap'n's Log" #: editor/editor_node.cpp msgid "Don't Save" @@ -12124,10 +12127,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/pt.po b/editor/translations/pt.po index b164fc2f52..d2db134026 100644 --- a/editor/translations/pt.po +++ b/editor/translations/pt.po @@ -1130,6 +1130,10 @@ msgstr "Mudar o valor do dicionário" msgid "Thanks from the Godot community!" msgstr "Agradecimentos da Comunidade Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Contribuidores do Godot Engine" @@ -12196,12 +12200,24 @@ msgstr "" "menu Projeto." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Keystore de depuração não configurada nas Configurações do Editor e nem na " "predefinição." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Lançamento de keystore configurado incorretamente na predefinição exportada." diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po index 7bfa3e7b97..49a7b43571 100644 --- a/editor/translations/pt_BR.po +++ b/editor/translations/pt_BR.po @@ -88,7 +88,7 @@ # Lucas Araujo <lucassants2808@gmail.com>, 2020. # Sr Half <flavio05@outlook.com>, 2020. # Matheus Pesegoginski <pese.ek.tk@outlook.com>, 2020. -# DeeJayLSP <djlsplays@gmail.com>, 2020. +# DeeJayLSP <djlsplays@gmail.com>, 2020, 2021. # Anonymous <noreply@weblate.org>, 2020. # André Sousa <andrelvsousa@gmail.com>, 2020. # Kleyton Luiz de Sousa Vieira <kleytonluizdesouzavieira@gmail.com>, 2020. @@ -101,7 +101,7 @@ # Jairo Tuboi <tuboi.jairo@gmail.com>, 2020. # Felipe Fetter <felipetfetter@gmail.com>, 2020. # Rafael Henrique Capati <rhcapati@gmail.com>, 2020. -# NogardRyuu <nogardryuu@gmail.com>, 2020. +# NogardRyuu <nogardryuu@gmail.com>, 2020, 2021. # Elton <eltondeoliveira@outlook.com>, 2020. # ThiagoCTN <thiagocampostn@gmail.com>, 2020. # Alec Santos <alecsantos96@gmail.com>, 2020. @@ -116,12 +116,14 @@ # Gabriel Silveira <gabomfim99@gmail.com>, 2021. # Arthur Phillip D. Silva <artphil.dev@gmail.com>, 2021. # Gustavo HM 102 <gustavohm102@gmail.com>, 2021. +# Douglas Leão <djlsplays@gmail.com>, 2021. +# PauloFRs <paulofr1@hotmail.com>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: 2016-05-30\n" -"PO-Revision-Date: 2021-05-24 21:36+0000\n" -"Last-Translator: Gustavo HM 102 <gustavohm102@gmail.com>\n" +"PO-Revision-Date: 2021-06-29 08:04+0000\n" +"Last-Translator: PauloFRs <paulofr1@hotmail.com>\n" "Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/" "godot-engine/godot/pt_BR/>\n" "Language: pt_BR\n" @@ -129,7 +131,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7.1-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -152,7 +154,7 @@ msgstr "Entrada inválida %i (não passada) na expressão" #: core/math/expression.cpp msgid "self can't be used because instance is null (not passed)" -msgstr "self não pode ser usado porque a instância é nula (não passada)" +msgstr "self não pode ser usado porque sua instância é null (não passado)" #: core/math/expression.cpp msgid "Invalid operands to operator %s, %s and %s." @@ -775,7 +777,7 @@ msgstr "Mudar Deslocamento do InÃcio do Clip de Trilha de Audio" #: editor/animation_track_editor_plugins.cpp msgid "Change Audio Track Clip End Offset" -msgstr "Alterar deslocamento de fim do clipe de faixa de áudio" +msgstr "Alterar Deslocamento de Fim do Clipe de Faixa de Ãudio" #: editor/array_property_edit.cpp msgid "Resize Array" @@ -1143,8 +1145,8 @@ msgid "" "You can find the removed files in the system trash to restore them." msgstr "" "Remover arquivos selecionados do projeto? (irreversÃvel)\n" -"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso " -"seja necessário." +"Você pode encontrar os arquivos removidos na lixeira do sistema para " +"restaurá-los." #: editor/dependency_editor.cpp msgid "" @@ -1156,8 +1158,8 @@ msgstr "" "Os arquivos sendo removidos são requeridos por outros recursos para que " "funcionem.\n" "Removê-los mesmo assim? (irreversÃvel)\n" -"Você pode encontrar os arquivos removidos na lixeira e restaurá-los caso " -"necessário." +"Você pode encontrar os arquivos removidos na lixeira do sistema para " +"restaurá-los." #: editor/dependency_editor.cpp msgid "Cannot remove:" @@ -1227,6 +1229,10 @@ msgstr "Alterar Valor do Dicionário" msgid "Thanks from the Godot community!" msgstr "Agradecimentos da comunidade Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Clique para copiar." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Contribuidores da Godot Engine" @@ -1568,7 +1574,7 @@ msgstr "Renomear Autoload" #: editor/editor_autoload_settings.cpp msgid "Toggle AutoLoad Globals" -msgstr "Alternar Auto Carregamentos de Globais" +msgstr "Alternar Globais de AutoLoad" #: editor/editor_autoload_settings.cpp msgid "Move Autoload" @@ -1722,8 +1728,8 @@ msgid "" "Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. " "Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings." msgstr "" -"A plataforma de destino requer compactação de textura 'ETC2' ou 'PVRTC' para " -"GLES3. Ativar 'Importar Etc 2' ou 'Importar Pvrtc' nas Configurações do " +"A plataforma de destino requer compressão de textura 'ETC2' ou 'PVRTC' para " +"GLES3. Habilite 'Importar Etc 2' ou 'Importar Pvrtc' nas Configurações do " "Projeto." #: editor/editor_export.cpp @@ -1870,7 +1876,7 @@ msgstr "Importar" #: editor/editor_feature_profile.cpp editor/project_export.cpp msgid "Export" -msgstr "Exportar" +msgstr "Exportação" #: editor/editor_feature_profile.cpp msgid "Available Profiles:" @@ -1906,7 +1912,7 @@ msgstr "Gerenciar perfis de recurso do editor" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "Select Current Folder" -msgstr "Selecione a Pasta Atual" +msgstr "Selecionar a Pasta Atual" #: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp msgid "File Exists, Overwrite?" @@ -2073,7 +2079,7 @@ msgstr "(Re)Importando Assets" #: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Top" -msgstr "Cima" +msgstr "InÃcio" #: editor/editor_help.cpp msgid "Class:" @@ -3103,9 +3109,8 @@ msgid "About" msgstr "Sobre" #: editor/editor_node.cpp -#, fuzzy msgid "Support Godot Development" -msgstr "Apoie o desenvolvimento do Godot" +msgstr "Apoie o Desenvolvimento do Godot" #: editor/editor_node.cpp msgid "Play the project." @@ -3539,7 +3544,7 @@ msgstr "Não foi possÃvel instanciar o script:" #: editor/editor_run_script.cpp msgid "Did you forget the 'tool' keyword?" -msgstr "Você esqueceu da palavra-chave \"tool\"?" +msgstr "Você esqueceu da palavra-chave 'tool'?" #: editor/editor_run_script.cpp msgid "Couldn't run script:" @@ -5865,7 +5870,7 @@ msgstr "Máscara de Escala para inserir chaves." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Insert keys (based on mask)." -msgstr "Inserir Chaves (baseado na máscara)" +msgstr "Inserir Chaves (baseado na máscara)." #: editor/plugins/canvas_item_editor_plugin.cpp msgid "" @@ -5875,9 +5880,9 @@ msgid "" "Keys must be inserted manually for the first time." msgstr "" "Inserir chaves automaticamente quando os objetos são transladados, " -"rotacionados ou escalados (com base na máscara). \n" +"rotacionados ou escalados (com base na máscara).\n" "As chaves são adicionadas apenas à s faixas existentes, nenhuma nova trilha " -"será criada. \n" +"será criada.\n" "As chaves devem ser inseridas manualmente pela primeira vez." #: editor/plugins/canvas_item_editor_plugin.cpp @@ -6677,8 +6682,8 @@ msgid "" "Polygon 2D has internal vertices, so it can no longer be edited in the " "viewport." msgstr "" -"Polygon2D tem vértices internos, portanto não pode mais ser editado no " -"Viewport." +"Polygon2D tem vértices internos, portanto não pode mais ser editado na " +"viewport." #: editor/plugins/polygon_2d_editor_plugin.cpp msgid "Create Polygon & UV" @@ -7023,7 +7028,7 @@ msgstr "Alternar ordenação alfabética da lista de métodos." #: editor/plugins/script_editor_plugin.cpp msgid "Filter methods" -msgstr "Métodos de filtragem" +msgstr "Filtrar métodos" #: editor/plugins/script_editor_plugin.cpp msgid "Sort" @@ -7672,11 +7677,10 @@ msgid "View Rotation Locked" msgstr "Ver Rotação Bloqueada" #: editor/plugins/spatial_editor_plugin.cpp -#, fuzzy msgid "" "To zoom further, change the camera's clipping planes (View -> Settings...)" msgstr "" -"Para dar mais zoom, mude os planos de clipping da câmera (Visão -> " +"Para dar mais zoom, altere os planos de clipping da câmera (Visão -> " "Configurações...)" #: editor/plugins/spatial_editor_plugin.cpp @@ -9838,7 +9842,7 @@ msgstr "Compilado" #: editor/project_export.cpp msgid "Encrypted (Provide Key Below)" -msgstr "Criptografado (forneça chave abaixo)" +msgstr "Criptografado (Forneça Chave Abaixo)" #: editor/project_export.cpp msgid "Invalid Encryption Key (must be 64 characters long)" @@ -10239,7 +10243,7 @@ msgstr "" #: editor/project_settings_editor.cpp msgid "Key " -msgstr "Chave " +msgstr "Tecla " #: editor/project_settings_editor.cpp msgid "Joy Button" @@ -10251,7 +10255,7 @@ msgstr "Eixo do Joystick" #: editor/project_settings_editor.cpp msgid "Mouse Button" -msgstr "Botão do Mous" +msgstr "Botão do Mouse" #: editor/project_settings_editor.cpp msgid "" @@ -10291,7 +10295,7 @@ msgstr "Pressione uma Tecla..." #: editor/project_settings_editor.cpp msgid "Mouse Button Index:" -msgstr "Botão do Mouse:" +msgstr "Ãndice do Botão do Mouse:" #: editor/project_settings_editor.cpp msgid "Left Button" @@ -10551,7 +10555,7 @@ msgstr "Idiomas:" #: editor/project_settings_editor.cpp msgid "AutoLoad" -msgstr "O AutoLoad" +msgstr "AutoLoad" #: editor/project_settings_editor.cpp msgid "Plugins" @@ -11062,15 +11066,14 @@ msgid "Remote" msgstr "Remoto" #: editor/scene_tree_dock.cpp -#, fuzzy msgid "" "If selected, the Remote scene tree dock will cause the project to stutter " "every time it updates.\n" "Switch back to the Local scene tree dock to improve performance." msgstr "" "Se selecionado, o painel da árvore de cena Remota vai fazer o projeto travar " -"toda hora que atualizar.\n" -"Volta para o painel da árvore de cena Local para melhorar a performance." +"toda vez que atualizar.\n" +"Volte para o painel da árvore de cena Local para melhorar o desempenho." #: editor/scene_tree_dock.cpp msgid "Local" @@ -12322,12 +12325,28 @@ msgstr "" "através do menu Projeto." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"As configurações Debug Keystore, Debug User E Debug Password devem ser " +"configuradas OU nenhuma delas." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Porta-chaves de depuração não configurado nas Configurações do Editor e nem " "na predefinição." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"As configurações de Release Keystore, Release User AND Release Password " +"devem ser definidas OU nenhuma delas." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Keystore de liberação incorretamente configurada na predefinição de " diff --git a/editor/translations/ro.po b/editor/translations/ro.po index b86af89ae2..ec89b47e96 100644 --- a/editor/translations/ro.po +++ b/editor/translations/ro.po @@ -1127,6 +1127,10 @@ msgstr "SchimbaÅ£i Valoarea DicÅ£ionar" msgid "Thanks from the Godot community!" msgstr "MulÈ›umesc din partea comunităţii Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Contribuabili Motor Godot" @@ -12256,10 +12260,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ru.po b/editor/translations/ru.po index acf8b3caaf..0da9285077 100644 --- a/editor/translations/ru.po +++ b/editor/translations/ru.po @@ -94,11 +94,13 @@ # narrnika <narr13niki@gmail.com>, 2021. # nec-trou <darya.bilyalova@gmail.com>, 2021. # IindinAndEdresia <kapitan_pol@inbox.ru>, 2021. +# Bualma Show <appleaidar6@gmail.com>, 2021. +# enderlorde <madel.laboratories@gmail.com>, 2021. msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-21 11:33+0000\n" +"PO-Revision-Date: 2021-06-27 07:10+0000\n" "Last-Translator: Danil Alexeev <danil@alexeev.xyz>\n" "Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/" "godot/ru/>\n" @@ -108,7 +110,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7.1-dev\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -117,7 +119,7 @@ msgstr "Ðеверный параметр типа Ð´Ð»Ñ convert(), иÑÐ¿Ð¾Ð»Ñ #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp msgid "Expected a string of length 1 (a character)." -msgstr "ОжидалаÑÑŒ Ñтрока длиной 1 (Ñ‚.е. Ñимвол)." +msgstr "ОжидалаÑÑŒ Ñтрока длиной 1 (Ñ‚. е. 1 Ñимвол)." #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/mono/glue/gd_glue.cpp @@ -1204,6 +1206,10 @@ msgstr "Изменить значение ÑловарÑ" msgid "Thanks from the Godot community!" msgstr "СпаÑибо от ÑообщеÑтва Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Ðажмите, чтобы Ñкопировать." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Ðвторы Godot Engine" @@ -3149,7 +3155,7 @@ msgstr "ИнÑпектор" #: editor/editor_node.cpp msgid "Expand Bottom Panel" -msgstr "РаÑширить боковую панель" +msgstr "Развернуть нижнюю панель" #: editor/editor_node.cpp msgid "Output" @@ -5808,7 +5814,7 @@ msgstr "Кадрировать выбранное" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Preview Canvas Scale" -msgstr "ПредпроÑмотр Canvas Scale" +msgstr "ПредпроÑмотр маÑштаба холÑта" #: editor/plugins/canvas_item_editor_plugin.cpp msgid "Translation mask for inserting keys." @@ -8432,7 +8438,7 @@ msgstr "Приоритет" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Z Index" -msgstr "Положение по оÑи Z" +msgstr "Z-индекÑ" #: editor/plugins/tile_set_editor_plugin.cpp msgid "Region Mode" @@ -12278,12 +12284,28 @@ msgstr "" "Шаблон Ñборки Android не уÑтановлен в проекте. УÑтановите его в меню проекта." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"ЛИБО должны быть заданы наÑтройки Debug Keystore, Debug User И Debug " +"Password, ЛИБО ни одна из них." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Отладочное хранилище ключей не наÑтроено ни в наÑтройках редактора, ни в " "предуÑтановках." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"ЛИБО должны быть заданы наÑтройки Release Keystore, Release User И Release " +"Password, ЛИБО ни одна из них." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Хранилище ключей не наÑтроено ни в наÑтройках редактора, ни в предуÑтановках." diff --git a/editor/translations/si.po b/editor/translations/si.po index b62a68170b..89c1b2ffc8 100644 --- a/editor/translations/si.po +++ b/editor/translations/si.po @@ -1104,6 +1104,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11781,10 +11785,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/sk.po b/editor/translations/sk.po index c56b65ea9b..5d5b9cba9b 100644 --- a/editor/translations/sk.po +++ b/editor/translations/sk.po @@ -1114,6 +1114,10 @@ msgstr "ZmeniÅ¥ Hodnotu v SlovnÃku" msgid "Thanks from the Godot community!" msgstr "VÄaka z Godot komunity!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine prispievatelia" @@ -12154,10 +12158,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/sl.po b/editor/translations/sl.po index 534d8a8af8..2ac453123c 100644 --- a/editor/translations/sl.po +++ b/editor/translations/sl.po @@ -1171,6 +1171,10 @@ msgstr "Spremeni Slovarsko Vrednost" msgid "Thanks from the Godot community!" msgstr "Zahvaljujemo se vam iz skupnosti Godota!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine sodelovci" @@ -12537,10 +12541,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/sq.po b/editor/translations/sq.po index 9adfd21568..4409a6f48a 100644 --- a/editor/translations/sq.po +++ b/editor/translations/sq.po @@ -1112,6 +1112,10 @@ msgstr "Ndrysho Vlerën e Fjalorit" msgid "Thanks from the Godot community!" msgstr "Faleminderit nga komuniteti i Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Kontribuesit e Godot Engine" @@ -12137,10 +12141,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po index d839ee4d1b..3ba1c674a3 100644 --- a/editor/translations/sr_Cyrl.po +++ b/editor/translations/sr_Cyrl.po @@ -1226,6 +1226,10 @@ msgstr "Промени вредноÑÑ‚ речника" msgid "Thanks from the Godot community!" msgstr "Хвала од Godot заједнице!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine Ñарадници" @@ -13732,6 +13736,12 @@ msgstr "" "менија." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp #, fuzzy msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" @@ -13739,6 +13749,12 @@ msgstr "" "поÑтавкама." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp #, fuzzy msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po index bb42742181..fcab84a2bf 100644 --- a/editor/translations/sr_Latn.po +++ b/editor/translations/sr_Latn.po @@ -1112,6 +1112,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11873,10 +11877,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/sv.po b/editor/translations/sv.po index 073e2b0670..c5cad10f66 100644 --- a/editor/translations/sv.po +++ b/editor/translations/sv.po @@ -1132,6 +1132,10 @@ msgstr "Ändra Ordboksvärde" msgid "Thanks from the Godot community!" msgstr "Tack frÃ¥n Godot-gemenskapen!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine bidragare" @@ -12284,10 +12288,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/ta.po b/editor/translations/ta.po index ed08398eeb..c630966603 100644 --- a/editor/translations/ta.po +++ b/editor/translations/ta.po @@ -1108,6 +1108,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11781,10 +11785,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/te.po b/editor/translations/te.po index 62741d508d..f1d857b911 100644 --- a/editor/translations/te.po +++ b/editor/translations/te.po @@ -1083,6 +1083,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11687,10 +11691,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/th.po b/editor/translations/th.po index 3f01cae158..0edcf900b9 100644 --- a/editor/translations/th.po +++ b/editor/translations/th.po @@ -15,8 +15,8 @@ msgid "" msgstr "" "Project-Id-Version: Godot Engine editor\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-14 11:20+0000\n" -"Last-Translator: Kongfa Waroros <gongpha@hotmail.com>\n" +"PO-Revision-Date: 2021-06-07 23:43+0000\n" +"Last-Translator: Atirut Wattanamongkol <artjang301@gmail.com>\n" "Language-Team: Thai <https://hosted.weblate.org/projects/godot-engine/godot/" "th/>\n" "Language: th\n" @@ -1123,6 +1123,10 @@ msgstr "à¹à¸à¹‰à¹„ขค่าดิà¸à¸Šà¸±à¸™à¸™à¸²à¸£à¸µ" msgid "Thanks from the Godot community!" msgstr "ขà¸à¸‚à¸à¸šà¸„ุณจาà¸à¸Šà¸¸à¸¡à¸Šà¸™à¸œà¸¹à¹‰à¹ƒà¸Šà¹‰ Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "ผู้ช่วยพัฒนา Godot Engine" @@ -1956,7 +1960,7 @@ msgstr "มีà¸à¸²à¸£à¸™à¸³à¹€à¸‚้าไฟล์ %s หลายà¸à¸±à¸™ à #: editor/editor_file_system.cpp msgid "(Re)Importing Assets" -msgstr "นำเข้าทรัพยาà¸à¸£(à¸à¸µà¸à¸„รั้ง)" +msgstr "à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้าทรัพยาà¸à¸£(à¸à¸µà¸à¸„รั้ง)" #: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp msgid "Top" @@ -3465,7 +3469,7 @@ msgstr "à¸à¸³à¸¥à¸±à¸‡à¸„ลายเทมเพลตส่งà¸à¸à¸" #: editor/export_template_manager.cpp msgid "Importing:" -msgstr "นำเข้า:" +msgstr "à¸à¸³à¸¥à¸±à¸‡à¸™à¸³à¹€à¸‚้า:" #: editor/export_template_manager.cpp msgid "Error getting the list of mirrors." @@ -12005,10 +12009,22 @@ msgid "" msgstr "เทมเพลตà¸à¸²à¸£à¸ªà¸£à¹‰à¸²à¸‡à¸ªà¸³à¸«à¸£à¸±à¸šà¹à¸à¸™à¸”รà¸à¸¢à¸”์ไม่ถูà¸à¸•ิดตั้ง สามารถติดตั้งจาà¸à¹€à¸¡à¸™à¸¹à¹‚ปรเจà¸à¸•์" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "ดีบัภKeystore ไม่ได้ถูà¸à¸•ั้งไว้ในตั้งค่าขà¸à¸‡à¸•ัวà¹à¸à¹‰à¹„ขหรืà¸à¹ƒà¸™à¸žà¸£à¸µà¹€à¸‹à¹‡à¸•" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "Release keystore à¸à¸³à¸«à¸™à¸”ค่าไว้à¸à¸¢à¹ˆà¸²à¸‡à¹„ม่ถูà¸à¸•้à¸à¸‡à¹ƒà¸™à¸žà¸£à¸µà¹€à¸‹à¹‡à¸•สำหรับà¸à¸²à¸£à¸ªà¹ˆà¸‡à¸à¸à¸" diff --git a/editor/translations/tr.po b/editor/translations/tr.po index ae07c290e2..5892850caf 100644 --- a/editor/translations/tr.po +++ b/editor/translations/tr.po @@ -1171,6 +1171,10 @@ msgstr "Sözlükteki DeÄŸeri DeÄŸiÅŸtir" msgid "Thanks from the Godot community!" msgstr "Godot topluluÄŸundan teÅŸekkürler!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Oyun Motoru katkı saÄŸlayanlar" @@ -12230,12 +12234,24 @@ msgstr "" "Android derleme ÅŸablonu projede yüklü deÄŸil. Proje menüsünden yükleyin." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "Anahtar deposunda Hata Ayıklayıcı Ayarları'nda veya ön ayarda " "yapılandırılmamış." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "Dışa aktarma ön kümesinde yanlış yapılandırılan anahtar deposunu (keystore) " diff --git a/editor/translations/tt.po b/editor/translations/tt.po new file mode 100644 index 0000000000..c0d7e79447 --- /dev/null +++ b/editor/translations/tt.po @@ -0,0 +1,12508 @@ +# Tatar translation of the Godot Engine editor. +# Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. +# Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). +# This file is distributed under the same license as the Godot source code. +# +# Bualma Show <appleaidar6@gmail.com>, 2021. +msgid "" +msgstr "" +"Project-Id-Version: Godot Engine editor\n" +"PO-Revision-Date: 2021-06-07 23:43+0000\n" +"Last-Translator: Bualma Show <appleaidar6@gmail.com>\n" +"Language-Team: Tatar <https://hosted.weblate.org/projects/godot-engine/godot/" +"tt/>\n" +"Language: tt\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8-bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.7-dev\n" + +#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp +#: modules/visual_script/visual_script_builtin_funcs.cpp +msgid "Invalid type argument to convert(), use TYPE_* constants." +msgstr "convert() өчен ÑракÑыз аргумент төре, TYPE_ * тотрыклы кулланыгыз." + +#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp +msgid "Expected a string of length 1 (a character)." +msgstr "Озынлык Ñызык 1 (Ñгъни Ñимвол) көтелгән иде." + +#: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp +#: modules/mono/glue/gd_glue.cpp +#: modules/visual_script/visual_script_builtin_funcs.cpp +msgid "Not enough bytes for decoding bytes, or invalid format." +msgstr "" +"Байтларны декодациÑләү өчен байтлар җитәрлек түгел Ñки Ñ€Ó©Ñ…Ñәт ителми торган " +"формат." + +#: core/math/expression.cpp +msgid "Invalid input %i (not passed) in expression" +msgstr "" + +#: core/math/expression.cpp +msgid "self can't be used because instance is null (not passed)" +msgstr "" + +#: core/math/expression.cpp +msgid "Invalid operands to operator %s, %s and %s." +msgstr "" + +#: core/math/expression.cpp +msgid "Invalid index of type %s for base type %s" +msgstr "" + +#: core/math/expression.cpp +msgid "Invalid named index '%s' for base type %s" +msgstr "" + +#: core/math/expression.cpp +msgid "Invalid arguments to construct '%s'" +msgstr "" + +#: core/math/expression.cpp +msgid "On call to '%s':" +msgstr "" + +#: core/ustring.cpp +msgid "B" +msgstr "" + +#: core/ustring.cpp +msgid "KiB" +msgstr "" + +#: core/ustring.cpp +msgid "MiB" +msgstr "" + +#: core/ustring.cpp +msgid "GiB" +msgstr "" + +#: core/ustring.cpp +msgid "TiB" +msgstr "" + +#: core/ustring.cpp +msgid "PiB" +msgstr "" + +#: core/ustring.cpp +msgid "EiB" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Free" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Balanced" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Mirror" +msgstr "" + +#: editor/animation_bezier_editor.cpp editor/editor_profiler.cpp +msgid "Time:" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Value:" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Insert Key Here" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Duplicate Selected Key(s)" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Delete Selected Key(s)" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Add Bezier Point" +msgstr "" + +#: editor/animation_bezier_editor.cpp +msgid "Move Bezier Points" +msgstr "" + +#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp +msgid "Anim Duplicate Keys" +msgstr "" + +#: editor/animation_bezier_editor.cpp editor/animation_track_editor.cpp +msgid "Anim Delete Keys" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Change Keyframe Time" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Change Transition" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Change Transform" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Change Keyframe Value" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Change Call" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Multi Change Keyframe Time" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Multi Change Transition" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Multi Change Transform" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Multi Change Keyframe Value" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Multi Change Call" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Change Animation Length" +msgstr "" + +#: editor/animation_track_editor.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Change Animation Loop" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Property Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "3D Transform Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Call Method Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Bezier Curve Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Audio Playback Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation Playback Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation length (frames)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation length (seconds)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Add Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation Looping" +msgstr "" + +#: editor/animation_track_editor.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Functions:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Audio Clips:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Clips:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Change Track Path" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Toggle this track on/off." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Update Mode (How this property is set)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Interpolation Mode" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Loop Wrap Mode (Interpolate end with beginning on loop)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Remove this track." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Time (s): " +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Toggle Track Enabled" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Continuous" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Discrete" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Trigger" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Capture" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Nearest" +msgstr "" + +#: editor/animation_track_editor.cpp editor/plugins/curve_editor_plugin.cpp +#: editor/property_editor.cpp +msgid "Linear" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Cubic" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Clamp Loop Interp" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Wrap Loop Interp" +msgstr "" + +#: editor/animation_track_editor.cpp +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Insert Key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Duplicate Key(s)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Delete Key(s)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Change Animation Update Mode" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Change Animation Interpolation Mode" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Change Animation Loop Mode" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Remove Anim Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Create NEW track for %s and insert key?" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Create %d NEW tracks and insert keys?" +msgstr "" + +#: editor/animation_track_editor.cpp editor/create_dialog.cpp +#: editor/editor_audio_buses.cpp editor/editor_feature_profile.cpp +#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp +#: editor/plugins/abstract_polygon_2d_editor.cpp +#: editor/plugins/mesh_instance_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +#: editor/script_create_dialog.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Create" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Insert" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "AnimationPlayer can't animate itself, only other players." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Create & Insert" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Insert Track & Key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Insert Key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Change Animation Step" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Rearrange Tracks" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Transform tracks only apply to Spatial-based nodes." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "" +"Audio tracks can only point to nodes of type:\n" +"-AudioStreamPlayer\n" +"-AudioStreamPlayer2D\n" +"-AudioStreamPlayer3D" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation tracks can only point to AnimationPlayer nodes." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "An animation player can't animate itself, only other players." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Not possible to add a new track without a root" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Invalid track for Bezier (no suitable sub-properties)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Add Bezier Track" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Track path is invalid, so can't add a key." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Track is not of type Spatial, can't insert key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Add Transform Track Key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Add Track Key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Track path is invalid, so can't add a method key." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Add Method Track Key" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Method not found in object: " +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Move Keys" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Clipboard is empty" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Paste Tracks" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim Scale Keys" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "" +"This option does not work for Bezier editing, as it's only a single track." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "" +"This animation belongs to an imported scene, so changes to imported tracks " +"will not be saved.\n" +"\n" +"To enable the ability to add custom tracks, navigate to the scene's import " +"settings and set\n" +"\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks" +"\", then re-import.\n" +"Alternatively, use an import preset that imports animations to separate " +"files." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Warning: Editing imported animation" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Select an AnimationPlayer node to create and edit animations." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Only show tracks from nodes selected in tree." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Group tracks by node or display them as plain list." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Snap:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation step value." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Seconds" +msgstr "" + +#: editor/animation_track_editor.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "FPS" +msgstr "" + +#: editor/animation_track_editor.cpp editor/editor_properties.cpp +#: editor/plugins/polygon_2d_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp +#: editor/plugins/tile_set_editor_plugin.cpp editor/project_manager.cpp +#: editor/project_settings_editor.cpp editor/property_editor.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Edit" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Animation properties." +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Copy Tracks" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Scale Selection" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Scale From Cursor" +msgstr "" + +#: editor/animation_track_editor.cpp modules/gridmap/grid_map_editor_plugin.cpp +msgid "Duplicate Selection" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Duplicate Transposed" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Delete Selection" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Go to Next Step" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Go to Previous Step" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Optimize Animation" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Clean-Up Animation" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Pick the node that will be animated:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Use Bezier Curves" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Anim. Optimizer" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Max. Linear Error:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Max. Angular Error:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Max Optimizable Angle:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Optimize" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Remove invalid keys" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Remove unresolved and empty tracks" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Clean-up all animations" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Clean-Up Animation(s) (NO UNDO!)" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Clean-Up" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Scale Ratio:" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Select Tracks to Copy" +msgstr "" + +#: editor/animation_track_editor.cpp editor/editor_log.cpp +#: editor/editor_properties.cpp +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp +#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp +msgid "Copy" +msgstr "" + +#: editor/animation_track_editor.cpp +msgid "Select All/None" +msgstr "" + +#: editor/animation_track_editor_plugins.cpp +msgid "Add Audio Track Clip" +msgstr "" + +#: editor/animation_track_editor_plugins.cpp +msgid "Change Audio Track Clip Start Offset" +msgstr "" + +#: editor/animation_track_editor_plugins.cpp +msgid "Change Audio Track Clip End Offset" +msgstr "" + +#: editor/array_property_edit.cpp +msgid "Resize Array" +msgstr "" + +#: editor/array_property_edit.cpp +msgid "Change Array Value Type" +msgstr "" + +#: editor/array_property_edit.cpp +msgid "Change Array Value" +msgstr "" + +#: editor/code_editor.cpp +msgid "Go to Line" +msgstr "" + +#: editor/code_editor.cpp +msgid "Line Number:" +msgstr "" + +#: editor/code_editor.cpp +msgid "%d replaced." +msgstr "" + +#: editor/code_editor.cpp editor/editor_help.cpp +msgid "%d match." +msgstr "" + +#: editor/code_editor.cpp editor/editor_help.cpp +msgid "%d matches." +msgstr "" + +#: editor/code_editor.cpp editor/find_in_files.cpp +msgid "Match Case" +msgstr "" + +#: editor/code_editor.cpp editor/find_in_files.cpp +msgid "Whole Words" +msgstr "" + +#: editor/code_editor.cpp +msgid "Replace" +msgstr "" + +#: editor/code_editor.cpp +msgid "Replace All" +msgstr "" + +#: editor/code_editor.cpp +msgid "Selection Only" +msgstr "" + +#: editor/code_editor.cpp editor/plugins/script_text_editor.cpp +#: editor/plugins/text_editor.cpp +msgid "Standard" +msgstr "" + +#: editor/code_editor.cpp editor/plugins/script_editor_plugin.cpp +msgid "Toggle Scripts Panel" +msgstr "" + +#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/texture_region_editor_plugin.cpp +#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp +msgid "Zoom In" +msgstr "" + +#: editor/code_editor.cpp editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/texture_region_editor_plugin.cpp +#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp +msgid "Zoom Out" +msgstr "" + +#: editor/code_editor.cpp +msgid "Reset Zoom" +msgstr "" + +#: editor/code_editor.cpp +msgid "Warnings" +msgstr "" + +#: editor/code_editor.cpp +msgid "Line and column numbers." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Method in target node must be specified." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Method name must be a valid identifier." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "" +"Target method not found. Specify a valid method or attach a script to the " +"target node." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Connect to Node:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Connect to Script:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "From Signal:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Scene does not contain any script." +msgstr "" + +#: editor/connections_dialog.cpp editor/editor_autoload_settings.cpp +#: editor/groups_editor.cpp editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp +msgid "Add" +msgstr "" + +#: editor/connections_dialog.cpp editor/dependency_editor.cpp +#: editor/editor_feature_profile.cpp editor/groups_editor.cpp +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/plugins/theme_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp +#: editor/project_settings_editor.cpp +msgid "Remove" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Add Extra Call Argument:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Extra Call Arguments:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Receiver Method:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Advanced" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Deferred" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "" +"Defers the signal, storing it in a queue and only firing it at idle time." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Oneshot" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Disconnects the signal after its first emission." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Cannot connect signal" +msgstr "" + +#: editor/connections_dialog.cpp editor/dependency_editor.cpp +#: editor/export_template_manager.cpp editor/groups_editor.cpp +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +#: editor/plugins/version_control_editor_plugin.cpp editor/project_export.cpp +#: editor/project_settings_editor.cpp editor/property_editor.cpp +#: editor/run_settings_dialog.cpp editor/settings_config_dialog.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Close" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Connect" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Signal:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Connect '%s' to '%s'" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Disconnect '%s' from '%s'" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Disconnect all from signal: '%s'" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Connect..." +msgstr "" + +#: editor/connections_dialog.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Disconnect" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Connect a Signal to a Method" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Edit Connection:" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Are you sure you want to remove all connections from the \"%s\" signal?" +msgstr "" + +#: editor/connections_dialog.cpp editor/editor_help.cpp editor/node_dock.cpp +msgid "Signals" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Filter signals" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Are you sure you want to remove all connections from this signal?" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Disconnect All" +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Edit..." +msgstr "" + +#: editor/connections_dialog.cpp +msgid "Go To Method" +msgstr "" + +#: editor/create_dialog.cpp +msgid "Change %s Type" +msgstr "" + +#: editor/create_dialog.cpp editor/project_settings_editor.cpp +msgid "Change" +msgstr "" + +#: editor/create_dialog.cpp +msgid "Create New %s" +msgstr "" + +#: editor/create_dialog.cpp editor/editor_file_dialog.cpp +#: editor/filesystem_dock.cpp +msgid "Favorites:" +msgstr "" + +#: editor/create_dialog.cpp editor/editor_file_dialog.cpp +msgid "Recent:" +msgstr "" + +#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp +#: editor/property_selector.cpp editor/quick_open.cpp editor/rename_dialog.cpp +#: modules/visual_script/visual_script_property_selector.cpp +msgid "Search:" +msgstr "" + +#: editor/create_dialog.cpp editor/plugins/script_editor_plugin.cpp +#: editor/property_selector.cpp editor/quick_open.cpp +#: modules/visual_script/visual_script_property_selector.cpp +msgid "Matches:" +msgstr "" + +#: editor/create_dialog.cpp editor/editor_plugin_settings.cpp +#: editor/plugin_config_dialog.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp editor/property_selector.cpp +#: modules/visual_script/visual_script_property_selector.cpp +msgid "Description:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Search Replacement For:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Dependencies For:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "" +"Scene '%s' is currently being edited.\n" +"Changes will only take effect when reloaded." +msgstr "" + +#: editor/dependency_editor.cpp +msgid "" +"Resource '%s' is in use.\n" +"Changes will only take effect when reloaded." +msgstr "" + +#: editor/dependency_editor.cpp +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Dependencies" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Resource" +msgstr "" + +#: editor/dependency_editor.cpp editor/editor_autoload_settings.cpp +#: editor/project_manager.cpp editor/project_settings_editor.cpp +msgid "Path" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Dependencies:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Fix Broken" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Dependency Editor" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Search Replacement Resource:" +msgstr "" + +#: editor/dependency_editor.cpp editor/editor_file_dialog.cpp +#: editor/editor_help_search.cpp editor/editor_node.cpp +#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp +#: editor/property_selector.cpp editor/quick_open.cpp +#: editor/script_create_dialog.cpp +#: modules/visual_script/visual_script_property_selector.cpp +#: scene/gui/file_dialog.cpp +msgid "Open" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Owners Of:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "" +"Remove selected files from the project? (no undo)\n" +"You can find the removed files in the system trash to restore them." +msgstr "" + +#: editor/dependency_editor.cpp +msgid "" +"The files being removed are required by other resources in order for them to " +"work.\n" +"Remove them anyway? (no undo)\n" +"You can find the removed files in the system trash to restore them." +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Cannot remove:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Error loading:" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Load failed due to missing dependencies:" +msgstr "" + +#: editor/dependency_editor.cpp editor/editor_node.cpp +msgid "Open Anyway" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Which action should be taken?" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Fix Dependencies" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Errors loading!" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Permanently delete %d item(s)? (No undo!)" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Show Dependencies" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Orphan Resource Explorer" +msgstr "" + +#: editor/dependency_editor.cpp editor/editor_audio_buses.cpp +#: editor/editor_file_dialog.cpp editor/editor_node.cpp +#: editor/plugins/item_list_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp editor/project_export.cpp +#: editor/project_settings_editor.cpp editor/scene_tree_dock.cpp +msgid "Delete" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Owns" +msgstr "" + +#: editor/dependency_editor.cpp +msgid "Resources Without Explicit Ownership:" +msgstr "" + +#: editor/dictionary_property_edit.cpp +msgid "Change Dictionary Key" +msgstr "" + +#: editor/dictionary_property_edit.cpp +msgid "Change Dictionary Value" +msgstr "" + +#: editor/editor_about.cpp +msgid "Thanks from the Godot community!" +msgstr "" + +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + +#: editor/editor_about.cpp +msgid "Godot Engine contributors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Project Founders" +msgstr "" + +#: editor/editor_about.cpp +msgid "Lead Developer" +msgstr "" + +#. TRANSLATORS: This refers to a job title. +#. The trailing space is used to distinguish with the project list application, +#. you do not have to keep it in your translation. +#: editor/editor_about.cpp +msgid "Project Manager " +msgstr "" + +#: editor/editor_about.cpp +msgid "Developers" +msgstr "" + +#: editor/editor_about.cpp +msgid "Authors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Platinum Sponsors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Gold Sponsors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Silver Sponsors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Bronze Sponsors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Mini Sponsors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Gold Donors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Silver Donors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Bronze Donors" +msgstr "" + +#: editor/editor_about.cpp +msgid "Donors" +msgstr "" + +#: editor/editor_about.cpp +msgid "License" +msgstr "" + +#: editor/editor_about.cpp +msgid "Third-party Licenses" +msgstr "" + +#: editor/editor_about.cpp +msgid "" +"Godot Engine relies on a number of third-party free and open source " +"libraries, all compatible with the terms of its MIT license. The following " +"is an exhaustive list of all such third-party components with their " +"respective copyright statements and license terms." +msgstr "" + +#: editor/editor_about.cpp +msgid "All Components" +msgstr "" + +#: editor/editor_about.cpp +msgid "Components" +msgstr "" + +#: editor/editor_about.cpp +msgid "Licenses" +msgstr "" + +#: editor/editor_asset_installer.cpp editor/project_manager.cpp +msgid "Error opening package file, not in ZIP format." +msgstr "" + +#: editor/editor_asset_installer.cpp +msgid "%s (Already Exists)" +msgstr "" + +#: editor/editor_asset_installer.cpp +msgid "Uncompressing Assets" +msgstr "" + +#: editor/editor_asset_installer.cpp editor/project_manager.cpp +msgid "The following files failed extraction from package:" +msgstr "" + +#: editor/editor_asset_installer.cpp +msgid "And %s more files." +msgstr "" + +#: editor/editor_asset_installer.cpp editor/project_manager.cpp +msgid "Package installed successfully!" +msgstr "" + +#: editor/editor_asset_installer.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Success!" +msgstr "" + +#: editor/editor_asset_installer.cpp +msgid "Package Contents:" +msgstr "" + +#: editor/editor_asset_installer.cpp editor/editor_node.cpp +msgid "Install" +msgstr "" + +#: editor/editor_asset_installer.cpp +msgid "Package Installer" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Speakers" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Add Effect" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Rename Audio Bus" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Change Audio Bus Volume" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Toggle Audio Bus Solo" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Toggle Audio Bus Mute" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Toggle Audio Bus Bypass Effects" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Select Audio Bus Send" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Add Audio Bus Effect" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Move Bus Effect" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Delete Bus Effect" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Drag & drop to rearrange." +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Solo" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Mute" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Bypass" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Bus options" +msgstr "" + +#: editor/editor_audio_buses.cpp editor/filesystem_dock.cpp +#: editor/plugins/animation_player_editor_plugin.cpp editor/scene_tree_dock.cpp +msgid "Duplicate" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Reset Volume" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Delete Effect" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Audio" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Add Audio Bus" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Master bus can't be deleted!" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Delete Audio Bus" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Duplicate Audio Bus" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Reset Bus Volume" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Move Audio Bus" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Save Audio Bus Layout As..." +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Location for New Layout..." +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Open Audio Bus Layout" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "There is no '%s' file." +msgstr "" + +#: editor/editor_audio_buses.cpp editor/plugins/canvas_item_editor_plugin.cpp +msgid "Layout" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Invalid file, not an audio bus layout." +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Error saving file: %s" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Add Bus" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Add a new Audio Bus to this layout." +msgstr "" + +#: editor/editor_audio_buses.cpp editor/editor_properties.cpp +#: editor/plugins/animation_player_editor_plugin.cpp editor/property_editor.cpp +#: editor/script_create_dialog.cpp +msgid "Load" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Load an existing Bus Layout." +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Save As" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Save this Bus Layout to a file." +msgstr "" + +#: editor/editor_audio_buses.cpp editor/import_dock.cpp +msgid "Load Default" +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Load the default Bus Layout." +msgstr "" + +#: editor/editor_audio_buses.cpp +msgid "Create a new Bus Layout." +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Invalid name." +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Valid characters:" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Must not collide with an existing engine class name." +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Must not collide with an existing built-in type name." +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Must not collide with an existing global constant name." +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Keyword cannot be used as an autoload name." +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Autoload '%s' already exists!" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Rename Autoload" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Toggle AutoLoad Globals" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Move Autoload" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Remove Autoload" +msgstr "" + +#: editor/editor_autoload_settings.cpp editor/editor_plugin_settings.cpp +msgid "Enable" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Rearrange Autoloads" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Can't add autoload:" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Add AutoLoad" +msgstr "" + +#: editor/editor_autoload_settings.cpp editor/editor_file_dialog.cpp +#: editor/editor_plugin_settings.cpp +#: editor/plugins/animation_tree_editor_plugin.cpp +#: editor/script_create_dialog.cpp scene/gui/file_dialog.cpp +msgid "Path:" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Node Name:" +msgstr "" + +#: editor/editor_autoload_settings.cpp editor/editor_help_search.cpp +#: editor/editor_profiler.cpp editor/project_manager.cpp +#: editor/settings_config_dialog.cpp +msgid "Name" +msgstr "" + +#: editor/editor_autoload_settings.cpp +msgid "Singleton" +msgstr "" + +#: editor/editor_data.cpp editor/inspector_dock.cpp +msgid "Paste Params" +msgstr "" + +#: editor/editor_data.cpp +msgid "Updating Scene" +msgstr "" + +#: editor/editor_data.cpp +msgid "Storing local changes..." +msgstr "" + +#: editor/editor_data.cpp +msgid "Updating scene..." +msgstr "" + +#: editor/editor_data.cpp editor/editor_properties.cpp +msgid "[empty]" +msgstr "" + +#: editor/editor_data.cpp +msgid "[unsaved]" +msgstr "" + +#: editor/editor_dir_dialog.cpp +msgid "Please select a base directory first." +msgstr "" + +#: editor/editor_dir_dialog.cpp +msgid "Choose a Directory" +msgstr "" + +#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp +#: editor/filesystem_dock.cpp editor/project_manager.cpp +#: scene/gui/file_dialog.cpp +msgid "Create Folder" +msgstr "" + +#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp +#: editor/editor_plugin_settings.cpp editor/filesystem_dock.cpp +#: editor/plugins/theme_editor_plugin.cpp editor/project_export.cpp +#: modules/visual_script/visual_script_editor.cpp scene/gui/file_dialog.cpp +msgid "Name:" +msgstr "" + +#: editor/editor_dir_dialog.cpp editor/editor_file_dialog.cpp +#: editor/filesystem_dock.cpp scene/gui/file_dialog.cpp +msgid "Could not create folder." +msgstr "" + +#: editor/editor_dir_dialog.cpp +msgid "Choose" +msgstr "" + +#: editor/editor_export.cpp +msgid "Storing File:" +msgstr "" + +#: editor/editor_export.cpp +msgid "No export template found at the expected path:" +msgstr "" + +#: editor/editor_export.cpp +msgid "Packing" +msgstr "" + +#: editor/editor_export.cpp +msgid "" +"Target platform requires 'ETC' texture compression for GLES2. Enable 'Import " +"Etc' in Project Settings." +msgstr "" + +#: editor/editor_export.cpp +msgid "" +"Target platform requires 'ETC2' texture compression for GLES3. Enable " +"'Import Etc 2' in Project Settings." +msgstr "" + +#: editor/editor_export.cpp +msgid "" +"Target platform requires 'ETC' texture compression for the driver fallback " +"to GLES2.\n" +"Enable 'Import Etc' in Project Settings, or disable 'Driver Fallback " +"Enabled'." +msgstr "" + +#: editor/editor_export.cpp +msgid "" +"Target platform requires 'PVRTC' texture compression for GLES2. Enable " +"'Import Pvrtc' in Project Settings." +msgstr "" + +#: editor/editor_export.cpp +msgid "" +"Target platform requires 'ETC2' or 'PVRTC' texture compression for GLES3. " +"Enable 'Import Etc 2' or 'Import Pvrtc' in Project Settings." +msgstr "" + +#: editor/editor_export.cpp +msgid "" +"Target platform requires 'PVRTC' texture compression for the driver fallback " +"to GLES2.\n" +"Enable 'Import Pvrtc' in Project Settings, or disable 'Driver Fallback " +"Enabled'." +msgstr "" + +#: editor/editor_export.cpp platform/android/export/export.cpp +#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp +#: platform/osx/export/export.cpp platform/uwp/export/export.cpp +msgid "Custom debug template not found." +msgstr "" + +#: editor/editor_export.cpp platform/android/export/export.cpp +#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp +#: platform/osx/export/export.cpp platform/uwp/export/export.cpp +msgid "Custom release template not found." +msgstr "" + +#: editor/editor_export.cpp platform/javascript/export/export.cpp +msgid "Template file not found:" +msgstr "" + +#: editor/editor_export.cpp +msgid "On 32-bit exports the embedded PCK cannot be bigger than 4 GiB." +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "3D Editor" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Script Editor" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Asset Library" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Scene Tree Editing" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Node Dock" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "FileSystem Dock" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Import Dock" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Erase profile '%s'? (no undo)" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Profile must be a valid filename and must not contain '.'" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Profile with this name already exists." +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "(Editor Disabled, Properties Disabled)" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "(Properties Disabled)" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "(Editor Disabled)" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Class Options:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Enable Contextual Editor" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Enabled Properties:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Enabled Features:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Enabled Classes:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "File '%s' format is invalid, import aborted." +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "" +"Profile '%s' already exists. Remove it first before importing, import " +"aborted." +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Error saving profile to path: '%s'." +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Unset" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Current Profile:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Make Current" +msgstr "" + +#: editor/editor_feature_profile.cpp +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/version_control_editor_plugin.cpp +msgid "New" +msgstr "" + +#: editor/editor_feature_profile.cpp editor/editor_node.cpp +#: editor/project_manager.cpp +msgid "Import" +msgstr "" + +#: editor/editor_feature_profile.cpp editor/project_export.cpp +msgid "Export" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Available Profiles:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Class Options" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "New profile name:" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Erase Profile" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Godot Feature Profile" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Import Profile(s)" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Export Profile" +msgstr "" + +#: editor/editor_feature_profile.cpp +msgid "Manage Editor Feature Profiles" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Select Current Folder" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "File Exists, Overwrite?" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Select This Folder" +msgstr "" + +#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp +msgid "Copy Path" +msgstr "" + +#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp +msgid "Open in File Manager" +msgstr "" + +#: editor/editor_file_dialog.cpp editor/editor_node.cpp +#: editor/filesystem_dock.cpp editor/project_manager.cpp +msgid "Show in File Manager" +msgstr "" + +#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp +msgid "New Folder..." +msgstr "" + +#: editor/editor_file_dialog.cpp editor/find_in_files.cpp +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Refresh" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "All Recognized" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "All Files (*)" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Open a File" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Open File(s)" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Open a Directory" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Open a File or Directory" +msgstr "" + +#: editor/editor_file_dialog.cpp editor/editor_node.cpp +#: editor/editor_properties.cpp editor/import_defaults_editor.cpp +#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/script_editor_plugin.cpp scene/gui/file_dialog.cpp +msgid "Save" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Save a File" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Go Back" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Go Forward" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Go Up" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Toggle Hidden Files" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Toggle Favorite" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Toggle Mode" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Focus Path" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Move Favorite Up" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Move Favorite Down" +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Go to previous folder." +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "Go to next folder." +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Go to parent folder." +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Refresh files." +msgstr "" + +#: editor/editor_file_dialog.cpp +msgid "(Un)favorite current folder." +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Toggle the visibility of hidden files." +msgstr "" + +#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp +msgid "View items as a grid of thumbnails." +msgstr "" + +#: editor/editor_file_dialog.cpp editor/filesystem_dock.cpp +msgid "View items as a list." +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "Directories & Files:" +msgstr "" + +#: editor/editor_file_dialog.cpp editor/plugins/sprite_editor_plugin.cpp +#: editor/plugins/style_box_editor_plugin.cpp +#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp +msgid "Preview:" +msgstr "" + +#: editor/editor_file_dialog.cpp scene/gui/file_dialog.cpp +msgid "File:" +msgstr "" + +#: editor/editor_file_system.cpp +msgid "ScanSources" +msgstr "" + +#: editor/editor_file_system.cpp +msgid "" +"There are multiple importers for different types pointing to file %s, import " +"aborted" +msgstr "" + +#: editor/editor_file_system.cpp +msgid "(Re)Importing Assets" +msgstr "" + +#: editor/editor_help.cpp editor/plugins/spatial_editor_plugin.cpp +msgid "Top" +msgstr "" + +#: editor/editor_help.cpp +msgid "Class:" +msgstr "" + +#: editor/editor_help.cpp editor/scene_tree_editor.cpp +#: editor/script_create_dialog.cpp +msgid "Inherits:" +msgstr "" + +#: editor/editor_help.cpp +msgid "Inherited by:" +msgstr "" + +#: editor/editor_help.cpp +msgid "Description" +msgstr "" + +#: editor/editor_help.cpp +msgid "Online Tutorials" +msgstr "" + +#: editor/editor_help.cpp +msgid "Properties" +msgstr "" + +#: editor/editor_help.cpp +msgid "override:" +msgstr "" + +#: editor/editor_help.cpp +msgid "default:" +msgstr "" + +#: editor/editor_help.cpp +msgid "Methods" +msgstr "" + +#: editor/editor_help.cpp +msgid "Theme Properties" +msgstr "" + +#: editor/editor_help.cpp +msgid "Enumerations" +msgstr "" + +#: editor/editor_help.cpp +msgid "Constants" +msgstr "" + +#: editor/editor_help.cpp +msgid "Property Descriptions" +msgstr "" + +#: editor/editor_help.cpp +msgid "(value)" +msgstr "" + +#: editor/editor_help.cpp +msgid "" +"There is currently no description for this property. Please help us by " +"[color=$color][url=$url]contributing one[/url][/color]!" +msgstr "" + +#: editor/editor_help.cpp +msgid "Method Descriptions" +msgstr "" + +#: editor/editor_help.cpp +msgid "" +"There is currently no description for this method. Please help us by [color=" +"$color][url=$url]contributing one[/url][/color]!" +msgstr "" + +#: editor/editor_help_search.cpp editor/editor_node.cpp +#: editor/plugins/script_editor_plugin.cpp +msgid "Search Help" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Case Sensitive" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Show Hierarchy" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Display All" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Classes Only" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Methods Only" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Signals Only" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Constants Only" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Properties Only" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Theme Properties Only" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Member Type" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Class" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Method" +msgstr "" + +#: editor/editor_help_search.cpp editor/plugins/script_text_editor.cpp +msgid "Signal" +msgstr "" + +#: editor/editor_help_search.cpp editor/plugins/theme_editor_plugin.cpp +msgid "Constant" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Property" +msgstr "" + +#: editor/editor_help_search.cpp +msgid "Theme Property" +msgstr "" + +#: editor/editor_inspector.cpp editor/project_settings_editor.cpp +msgid "Property:" +msgstr "" + +#: editor/editor_inspector.cpp +msgid "Set" +msgstr "" + +#: editor/editor_inspector.cpp +msgid "Set Multiple:" +msgstr "" + +#: editor/editor_log.cpp +msgid "Output:" +msgstr "" + +#: editor/editor_log.cpp editor/plugins/tile_map_editor_plugin.cpp +msgid "Copy Selection" +msgstr "" + +#: editor/editor_log.cpp editor/editor_network_profiler.cpp +#: editor/editor_profiler.cpp editor/editor_properties.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/property_editor.cpp editor/scene_tree_dock.cpp +#: editor/script_editor_debugger.cpp +#: modules/gdnative/gdnative_library_editor_plugin.cpp scene/gui/line_edit.cpp +#: scene/gui/text_edit.cpp +msgid "Clear" +msgstr "" + +#: editor/editor_log.cpp +msgid "Clear Output" +msgstr "" + +#: editor/editor_network_profiler.cpp editor/editor_node.cpp +#: editor/editor_profiler.cpp +msgid "Stop" +msgstr "" + +#: editor/editor_network_profiler.cpp editor/editor_profiler.cpp +#: editor/plugins/animation_state_machine_editor.cpp editor/rename_dialog.cpp +msgid "Start" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "%s/s" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "Down" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "Up" +msgstr "" + +#: editor/editor_network_profiler.cpp editor/editor_node.cpp +msgid "Node" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "Incoming RPC" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "Incoming RSET" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "Outgoing RPC" +msgstr "" + +#: editor/editor_network_profiler.cpp +msgid "Outgoing RSET" +msgstr "" + +#: editor/editor_node.cpp editor/project_manager.cpp +msgid "New Window" +msgstr "" + +#: editor/editor_node.cpp +msgid "Imported resources can't be saved." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +#: scene/gui/dialogs.cpp +msgid "OK" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Error saving resource!" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This resource can't be saved because it does not belong to the edited scene. " +"Make it unique first." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Save Resource As..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Can't open file for writing:" +msgstr "" + +#: editor/editor_node.cpp +msgid "Requested file format unknown:" +msgstr "" + +#: editor/editor_node.cpp +msgid "Error while saving." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +msgid "Can't open '%s'. The file could have been moved or deleted." +msgstr "" + +#: editor/editor_node.cpp +msgid "Error while parsing '%s'." +msgstr "" + +#: editor/editor_node.cpp +msgid "Unexpected end of file '%s'." +msgstr "" + +#: editor/editor_node.cpp +msgid "Missing '%s' or its dependencies." +msgstr "" + +#: editor/editor_node.cpp +msgid "Error while loading '%s'." +msgstr "" + +#: editor/editor_node.cpp +msgid "Saving Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Analyzing" +msgstr "" + +#: editor/editor_node.cpp +msgid "Creating Thumbnail" +msgstr "" + +#: editor/editor_node.cpp +msgid "This operation can't be done without a tree root." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This scene can't be saved because there is a cyclic instancing inclusion.\n" +"Please resolve it and then attempt to save again." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Couldn't save scene. Likely dependencies (instances or inheritance) couldn't " +"be satisfied." +msgstr "" + +#: editor/editor_node.cpp editor/scene_tree_dock.cpp +msgid "Can't overwrite scene that is still open!" +msgstr "" + +#: editor/editor_node.cpp +msgid "Can't load MeshLibrary for merging!" +msgstr "" + +#: editor/editor_node.cpp +msgid "Error saving MeshLibrary!" +msgstr "" + +#: editor/editor_node.cpp +msgid "Can't load TileSet for merging!" +msgstr "" + +#: editor/editor_node.cpp +msgid "Error saving TileSet!" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"An error occurred while trying to save the editor layout.\n" +"Make sure the editor's user data path is writable." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Default editor layout overridden.\n" +"To restore the Default layout to its base settings, use the Delete Layout " +"option and delete the Default layout." +msgstr "" + +#: editor/editor_node.cpp +msgid "Layout name not found!" +msgstr "" + +#: editor/editor_node.cpp +msgid "Restored the Default layout to its base settings." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This resource belongs to a scene that was imported, so it's not editable.\n" +"Please read the documentation relevant to importing scenes to better " +"understand this workflow." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This resource belongs to a scene that was instanced or inherited.\n" +"Changes to it won't be kept when saving the current scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This resource was imported, so it's not editable. Change its settings in the " +"import panel and then re-import." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This scene was imported, so changes to it won't be kept.\n" +"Instancing it or inheriting will allow making changes to it.\n" +"Please read the documentation relevant to importing scenes to better " +"understand this workflow." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This is a remote object, so changes to it won't be kept.\n" +"Please read the documentation relevant to debugging to better understand " +"this workflow." +msgstr "" + +#: editor/editor_node.cpp +msgid "There is no defined scene to run." +msgstr "" + +#: editor/editor_node.cpp +msgid "Save scene before running..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Could not start subprocess!" +msgstr "" + +#: editor/editor_node.cpp editor/filesystem_dock.cpp +msgid "Open Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Base Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Quick Open..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Quick Open Scene..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Quick Open Script..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Save & Close" +msgstr "" + +#: editor/editor_node.cpp +msgid "Save changes to '%s' before closing?" +msgstr "" + +#: editor/editor_node.cpp +msgid "Saved %s modified resource(s)." +msgstr "" + +#: editor/editor_node.cpp +msgid "A root node is required to save the scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "Save Scene As..." +msgstr "" + +#: editor/editor_node.cpp editor/scene_tree_dock.cpp +msgid "This operation can't be done without a scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "Export Mesh Library" +msgstr "" + +#: editor/editor_node.cpp +msgid "This operation can't be done without a root node." +msgstr "" + +#: editor/editor_node.cpp +msgid "Export Tile Set" +msgstr "" + +#: editor/editor_node.cpp +msgid "This operation can't be done without a selected node." +msgstr "" + +#: editor/editor_node.cpp +msgid "Current scene not saved. Open anyway?" +msgstr "" + +#: editor/editor_node.cpp +msgid "Can't reload a scene that was never saved." +msgstr "" + +#: editor/editor_node.cpp +msgid "Reload Saved Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"The current scene has unsaved changes.\n" +"Reload the saved scene anyway? This action cannot be undone." +msgstr "" + +#: editor/editor_node.cpp +msgid "Quick Run Scene..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Quit" +msgstr "" + +#: editor/editor_node.cpp +msgid "Yes" +msgstr "" + +#: editor/editor_node.cpp +msgid "Exit the editor?" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Project Manager?" +msgstr "" + +#: editor/editor_node.cpp +msgid "Save & Quit" +msgstr "" + +#: editor/editor_node.cpp +msgid "Save changes to the following scene(s) before quitting?" +msgstr "" + +#: editor/editor_node.cpp +msgid "Save changes the following scene(s) before opening Project Manager?" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This option is deprecated. Situations where refresh must be forced are now " +"considered a bug. Please report." +msgstr "" + +#: editor/editor_node.cpp +msgid "Pick a Main Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Close Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Reopen Closed Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Unable to enable addon plugin at: '%s' parsing of config failed." +msgstr "" + +#: editor/editor_node.cpp +msgid "Unable to find script field for addon plugin at: '%s'." +msgstr "" + +#: editor/editor_node.cpp +msgid "Unable to load addon script from path: '%s'." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Unable to load addon script from path: '%s'. This might be due to a code " +"error in that script.\n" +"Disabling the addon at '%s' to prevent further errors." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Unable to load addon script from path: '%s' Base type is not EditorPlugin." +msgstr "" + +#: editor/editor_node.cpp +msgid "Unable to load addon script from path: '%s' Script is not in tool mode." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Scene '%s' was automatically imported, so it can't be modified.\n" +"To make changes to it, a new inherited scene can be created." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Error loading scene, it must be inside the project path. Use 'Import' to " +"open the scene, then save it inside the project path." +msgstr "" + +#: editor/editor_node.cpp +msgid "Scene '%s' has broken dependencies:" +msgstr "" + +#: editor/editor_node.cpp +msgid "Clear Recent Scenes" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"No main scene has ever been defined, select one?\n" +"You can change it later in \"Project Settings\" under the 'application' " +"category." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Selected scene '%s' does not exist, select a valid one?\n" +"You can change it later in \"Project Settings\" under the 'application' " +"category." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"Selected scene '%s' is not a scene file, select a valid one?\n" +"You can change it later in \"Project Settings\" under the 'application' " +"category." +msgstr "" + +#: editor/editor_node.cpp +msgid "Save Layout" +msgstr "" + +#: editor/editor_node.cpp +msgid "Delete Layout" +msgstr "" + +#: editor/editor_node.cpp editor/import_dock.cpp +#: editor/script_create_dialog.cpp +msgid "Default" +msgstr "" + +#: editor/editor_node.cpp editor/editor_properties.cpp +#: editor/plugins/script_editor_plugin.cpp editor/property_editor.cpp +msgid "Show in FileSystem" +msgstr "" + +#: editor/editor_node.cpp +msgid "Play This Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Close Tab" +msgstr "" + +#: editor/editor_node.cpp +msgid "Undo Close Tab" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +msgid "Close Other Tabs" +msgstr "" + +#: editor/editor_node.cpp +msgid "Close Tabs to the Right" +msgstr "" + +#: editor/editor_node.cpp +msgid "Close All Tabs" +msgstr "" + +#: editor/editor_node.cpp +msgid "Switch Scene Tab" +msgstr "" + +#: editor/editor_node.cpp +msgid "%d more files or folders" +msgstr "" + +#: editor/editor_node.cpp +msgid "%d more folders" +msgstr "" + +#: editor/editor_node.cpp +msgid "%d more files" +msgstr "" + +#: editor/editor_node.cpp +msgid "Dock Position" +msgstr "" + +#: editor/editor_node.cpp +msgid "Distraction Free Mode" +msgstr "" + +#: editor/editor_node.cpp +msgid "Toggle distraction-free mode." +msgstr "" + +#: editor/editor_node.cpp +msgid "Add a new scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Go to previously opened scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "Copy Text" +msgstr "" + +#: editor/editor_node.cpp +msgid "Next tab" +msgstr "" + +#: editor/editor_node.cpp +msgid "Previous tab" +msgstr "" + +#: editor/editor_node.cpp +msgid "Filter Files..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Operations with scene files." +msgstr "" + +#: editor/editor_node.cpp +msgid "New Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "New Inherited Scene..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Scene..." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +msgid "Open Recent" +msgstr "" + +#: editor/editor_node.cpp +msgid "Save Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Save All Scenes" +msgstr "" + +#: editor/editor_node.cpp +msgid "Convert To..." +msgstr "" + +#: editor/editor_node.cpp +msgid "MeshLibrary..." +msgstr "" + +#: editor/editor_node.cpp +msgid "TileSet..." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp +#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp +msgid "Undo" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_text_editor.cpp +#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp +msgid "Redo" +msgstr "" + +#: editor/editor_node.cpp +msgid "Miscellaneous project or scene-wide tools." +msgstr "" + +#: editor/editor_node.cpp editor/project_manager.cpp +#: editor/script_create_dialog.cpp +msgid "Project" +msgstr "" + +#: editor/editor_node.cpp +msgid "Project Settings..." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp +msgid "Version Control" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp +msgid "Set Up Version Control" +msgstr "" + +#: editor/editor_node.cpp +msgid "Shut Down Version Control" +msgstr "" + +#: editor/editor_node.cpp +msgid "Export..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Install Android Build Template..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Project Data Folder" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/tile_set_editor_plugin.cpp +msgid "Tools" +msgstr "" + +#: editor/editor_node.cpp +msgid "Orphan Resource Explorer..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Quit to Project List" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +#: editor/project_export.cpp +msgid "Debug" +msgstr "" + +#: editor/editor_node.cpp +msgid "Deploy with Remote Debug" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"When this option is enabled, using one-click deploy will make the executable " +"attempt to connect to this computer's IP so the running project can be " +"debugged.\n" +"This option is intended to be used for remote debugging (typically with a " +"mobile device).\n" +"You don't need to enable it to use the GDScript debugger locally." +msgstr "" + +#: editor/editor_node.cpp +msgid "Small Deploy with Network Filesystem" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"When this option is enabled, using one-click deploy for Android will only " +"export an executable without the project data.\n" +"The filesystem will be provided from the project by the editor over the " +"network.\n" +"On Android, deploying will use the USB cable for faster performance. This " +"option speeds up testing for projects with large assets." +msgstr "" + +#: editor/editor_node.cpp +msgid "Visible Collision Shapes" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"When this option is enabled, collision shapes and raycast nodes (for 2D and " +"3D) will be visible in the running project." +msgstr "" + +#: editor/editor_node.cpp +msgid "Visible Navigation" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"When this option is enabled, navigation meshes and polygons will be visible " +"in the running project." +msgstr "" + +#: editor/editor_node.cpp +msgid "Synchronize Scene Changes" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"When this option is enabled, any changes made to the scene in the editor " +"will be replicated in the running project.\n" +"When used remotely on a device, this is more efficient when the network " +"filesystem option is enabled." +msgstr "" + +#: editor/editor_node.cpp +msgid "Synchronize Script Changes" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"When this option is enabled, any script that is saved will be reloaded in " +"the running project.\n" +"When used remotely on a device, this is more efficient when the network " +"filesystem option is enabled." +msgstr "" + +#: editor/editor_node.cpp editor/script_create_dialog.cpp +msgid "Editor" +msgstr "" + +#: editor/editor_node.cpp +msgid "Editor Settings..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Editor Layout" +msgstr "" + +#: editor/editor_node.cpp +msgid "Take Screenshot" +msgstr "" + +#: editor/editor_node.cpp +msgid "Screenshots are stored in the Editor Data/Settings Folder." +msgstr "" + +#: editor/editor_node.cpp +msgid "Toggle Fullscreen" +msgstr "" + +#: editor/editor_node.cpp +msgid "Toggle System Console" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Editor Data/Settings Folder" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Editor Data Folder" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Editor Settings Folder" +msgstr "" + +#: editor/editor_node.cpp +msgid "Manage Editor Features..." +msgstr "" + +#: editor/editor_node.cpp +msgid "Manage Export Templates..." +msgstr "" + +#: editor/editor_node.cpp editor/plugins/shader_editor_plugin.cpp +msgid "Help" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +#: editor/plugins/shader_editor_plugin.cpp +msgid "Online Docs" +msgstr "" + +#: editor/editor_node.cpp +msgid "Q&A" +msgstr "" + +#: editor/editor_node.cpp +msgid "Report a Bug" +msgstr "" + +#: editor/editor_node.cpp +msgid "Send Docs Feedback" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/asset_library_editor_plugin.cpp +msgid "Community" +msgstr "Җәмәгать" + +#: editor/editor_node.cpp +msgid "About" +msgstr "" + +#: editor/editor_node.cpp +msgid "Support Godot Development" +msgstr "" + +#: editor/editor_node.cpp +msgid "Play the project." +msgstr "" + +#: editor/editor_node.cpp +msgid "Play" +msgstr "" + +#: editor/editor_node.cpp +msgid "Pause the scene execution for debugging." +msgstr "" + +#: editor/editor_node.cpp +msgid "Pause Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Stop the scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "Play the edited scene." +msgstr "" + +#: editor/editor_node.cpp +msgid "Play Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Play custom scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Play Custom Scene" +msgstr "" + +#: editor/editor_node.cpp +msgid "Changing the video driver requires restarting the editor." +msgstr "" + +#: editor/editor_node.cpp editor/project_settings_editor.cpp +#: editor/settings_config_dialog.cpp +msgid "Save & Restart" +msgstr "" + +#: editor/editor_node.cpp +msgid "Spins when the editor window redraws." +msgstr "" + +#: editor/editor_node.cpp +msgid "Update Continuously" +msgstr "" + +#: editor/editor_node.cpp +msgid "Update When Changed" +msgstr "" + +#: editor/editor_node.cpp +msgid "Hide Update Spinner" +msgstr "" + +#: editor/editor_node.cpp +msgid "FileSystem" +msgstr "" + +#: editor/editor_node.cpp +msgid "Inspector" +msgstr "" + +#: editor/editor_node.cpp +msgid "Expand Bottom Panel" +msgstr "" + +#: editor/editor_node.cpp +msgid "Output" +msgstr "" + +#: editor/editor_node.cpp +msgid "Don't Save" +msgstr "" + +#: editor/editor_node.cpp +msgid "Android build template is missing, please install relevant templates." +msgstr "" + +#: editor/editor_node.cpp +msgid "Manage Templates" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"This will set up your project for custom Android builds by installing the " +"source template to \"res://android/build\".\n" +"You can then apply modifications and build your own custom APK on export " +"(adding modules, changing the AndroidManifest.xml, etc.).\n" +"Note that in order to make custom builds instead of using pre-built APKs, " +"the \"Use Custom Build\" option should be enabled in the Android export " +"preset." +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"The Android build template is already installed in this project and it won't " +"be overwritten.\n" +"Remove the \"res://android/build\" directory manually before attempting this " +"operation again." +msgstr "" + +#: editor/editor_node.cpp +msgid "Import Templates From ZIP File" +msgstr "" + +#: editor/editor_node.cpp +msgid "Template Package" +msgstr "" + +#: editor/editor_node.cpp +msgid "Export Library" +msgstr "" + +#: editor/editor_node.cpp +msgid "Merge With Existing" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open & Run a Script" +msgstr "" + +#: editor/editor_node.cpp +msgid "" +"The following files are newer on disk.\n" +"What action should be taken?" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +#: editor/plugins/shader_editor_plugin.cpp +msgid "Reload" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/script_editor_plugin.cpp +#: editor/plugins/shader_editor_plugin.cpp +msgid "Resave" +msgstr "" + +#: editor/editor_node.cpp +msgid "New Inherited" +msgstr "" + +#: editor/editor_node.cpp +msgid "Load Errors" +msgstr "" + +#: editor/editor_node.cpp editor/plugins/tile_map_editor_plugin.cpp +msgid "Select" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open 2D Editor" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open 3D Editor" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open Script Editor" +msgstr "" + +#: editor/editor_node.cpp editor/project_manager.cpp +msgid "Open Asset Library" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open the next Editor" +msgstr "" + +#: editor/editor_node.cpp +msgid "Open the previous Editor" +msgstr "" + +#: editor/editor_node.h +msgid "Warning!" +msgstr "" + +#: editor/editor_path.cpp +msgid "No sub-resources found." +msgstr "" + +#: editor/editor_plugin.cpp +msgid "Creating Mesh Previews" +msgstr "" + +#: editor/editor_plugin.cpp +msgid "Thumbnail..." +msgstr "" + +#: editor/editor_plugin_settings.cpp +msgid "Main Script:" +msgstr "" + +#: editor/editor_plugin_settings.cpp +msgid "Edit Plugin" +msgstr "" + +#: editor/editor_plugin_settings.cpp +msgid "Installed Plugins:" +msgstr "" + +#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp +msgid "Update" +msgstr "" + +#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Version:" +msgstr "" + +#: editor/editor_plugin_settings.cpp editor/plugin_config_dialog.cpp +msgid "Author:" +msgstr "" + +#: editor/editor_plugin_settings.cpp +msgid "Status:" +msgstr "" + +#: editor/editor_plugin_settings.cpp +msgid "Edit:" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Measure:" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Frame Time (sec)" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Average Time (sec)" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Frame %" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Physics Frame %" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Inclusive" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Self" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Frame #:" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Time" +msgstr "" + +#: editor/editor_profiler.cpp +msgid "Calls" +msgstr "" + +#: editor/editor_properties.cpp +msgid "Edit Text:" +msgstr "" + +#: editor/editor_properties.cpp editor/script_create_dialog.cpp +msgid "On" +msgstr "" + +#: editor/editor_properties.cpp +msgid "Layer" +msgstr "" + +#: editor/editor_properties.cpp +msgid "Bit %d, value %d" +msgstr "" + +#: editor/editor_properties.cpp +msgid "[Empty]" +msgstr "" + +#: editor/editor_properties.cpp editor/plugins/root_motion_editor_plugin.cpp +msgid "Assign..." +msgstr "" + +#: editor/editor_properties.cpp +msgid "Invalid RID" +msgstr "" + +#: editor/editor_properties.cpp +msgid "" +"The selected resource (%s) does not match any type expected for this " +"property (%s)." +msgstr "" + +#: editor/editor_properties.cpp +msgid "" +"Can't create a ViewportTexture on resources saved as a file.\n" +"Resource needs to belong to a scene." +msgstr "" + +#: editor/editor_properties.cpp +msgid "" +"Can't create a ViewportTexture on this resource because it's not set as " +"local to scene.\n" +"Please switch on the 'local to scene' property on it (and all resources " +"containing it up to a node)." +msgstr "" + +#: editor/editor_properties.cpp editor/property_editor.cpp +msgid "Pick a Viewport" +msgstr "" + +#: editor/editor_properties.cpp editor/property_editor.cpp +msgid "New Script" +msgstr "" + +#: editor/editor_properties.cpp editor/scene_tree_dock.cpp +msgid "Extend Script" +msgstr "" + +#: editor/editor_properties.cpp editor/property_editor.cpp +msgid "New %s" +msgstr "" + +#: editor/editor_properties.cpp editor/property_editor.cpp +msgid "Make Unique" +msgstr "" + +#: editor/editor_properties.cpp +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/animation_state_machine_editor.cpp +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +#: editor/plugins/tile_map_editor_plugin.cpp editor/property_editor.cpp +#: editor/scene_tree_dock.cpp scene/gui/line_edit.cpp scene/gui/text_edit.cpp +msgid "Paste" +msgstr "" + +#: editor/editor_properties.cpp editor/property_editor.cpp +msgid "Convert To %s" +msgstr "" + +#: editor/editor_properties.cpp editor/property_editor.cpp +msgid "Selected node is not a Viewport!" +msgstr "" + +#: editor/editor_properties_array_dict.cpp +msgid "Size: " +msgstr "" + +#: editor/editor_properties_array_dict.cpp +msgid "Page: " +msgstr "" + +#: editor/editor_properties_array_dict.cpp +#: editor/plugins/theme_editor_plugin.cpp +msgid "Remove Item" +msgstr "" + +#: editor/editor_properties_array_dict.cpp +msgid "New Key:" +msgstr "" + +#: editor/editor_properties_array_dict.cpp +msgid "New Value:" +msgstr "" + +#: editor/editor_properties_array_dict.cpp +msgid "Add Key/Value Pair" +msgstr "" + +#: editor/editor_run_native.cpp +msgid "" +"No runnable export preset found for this platform.\n" +"Please add a runnable preset in the Export menu or define an existing preset " +"as runnable." +msgstr "" + +#: editor/editor_run_script.cpp +msgid "Write your logic in the _run() method." +msgstr "" + +#: editor/editor_run_script.cpp +msgid "There is an edited scene already." +msgstr "" + +#: editor/editor_run_script.cpp +msgid "Couldn't instance script:" +msgstr "" + +#: editor/editor_run_script.cpp +msgid "Did you forget the 'tool' keyword?" +msgstr "" + +#: editor/editor_run_script.cpp +msgid "Couldn't run script:" +msgstr "" + +#: editor/editor_run_script.cpp +msgid "Did you forget the '_run' method?" +msgstr "" + +#: editor/editor_spin_slider.cpp +msgid "Hold Ctrl to round to integers. Hold Shift for more precise changes." +msgstr "" + +#: editor/editor_sub_scene.cpp +msgid "Select Node(s) to Import" +msgstr "" + +#: editor/editor_sub_scene.cpp editor/project_manager.cpp +msgid "Browse" +msgstr "" + +#: editor/editor_sub_scene.cpp +msgid "Scene Path:" +msgstr "" + +#: editor/editor_sub_scene.cpp +msgid "Import From Node:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Redownload" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Uninstall" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "(Installed)" +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Download" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Official export templates aren't available for development builds." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "(Missing)" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "(Current)" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Retrieving mirrors, please wait..." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Remove template version '%s'?" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Can't open export templates zip." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Invalid version.txt format inside templates: %s." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "No version.txt found inside templates." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Error creating path for templates:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Extracting Export Templates" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Importing:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Error getting the list of mirrors." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Error parsing JSON of mirror list. Please report this issue!" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "" +"No download links found for this version. Direct download is only available " +"for official releases." +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Can't resolve." +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Can't connect." +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "No response." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Request Failed." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Redirect Loop." +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Failed:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Download Complete." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Cannot remove temporary file:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "" +"Templates installation failed.\n" +"The problematic templates archives can be found at '%s'." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Error requesting URL:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Connecting to Mirror..." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Disconnected" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Resolving" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Can't Resolve" +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Connecting..." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Can't Connect" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Connected" +msgstr "" + +#: editor/export_template_manager.cpp +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Requesting..." +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Downloading" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Connection Error" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "SSL Handshake Error" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Uncompressing Android Build Sources" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Current Version:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Installed Versions:" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Install From File" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Remove Template" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Select Template File" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Godot Export Templates" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Export Template Manager" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Download Templates" +msgstr "" + +#: editor/export_template_manager.cpp +msgid "Select mirror from list: (Shift+Click: Open in Browser)" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Favorites" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Status: Import of file failed. Please fix file and reimport manually." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "" +"Importing has been disabled for this file, so it can't be opened for editing." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Cannot move/rename resources root." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Cannot move a folder into itself." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Error moving:" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Error duplicating:" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Unable to update dependencies:" +msgstr "" + +#: editor/filesystem_dock.cpp editor/scene_tree_editor.cpp +msgid "No name provided." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Provided name contains invalid characters." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "A file or folder with this name already exists." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Name contains invalid characters." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "" +"The following files or folders conflict with items in the target location " +"'%s':\n" +"\n" +"%s\n" +"\n" +"Do you wish to overwrite them?" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Renaming file:" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Renaming folder:" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Duplicating file:" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Duplicating folder:" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "New Inherited Scene" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Set As Main Scene" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Open Scenes" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Instance" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Add to Favorites" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Remove from Favorites" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Edit Dependencies..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "View Owners..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move To..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "New Scene..." +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp +msgid "New Script..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "New Resource..." +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp +#: editor/script_editor_debugger.cpp +msgid "Expand All" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/visual_shader_editor_plugin.cpp +#: editor/script_editor_debugger.cpp +msgid "Collapse All" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Duplicate..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move to Trash" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +msgid "Rename..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Previous Folder/File" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Next Folder/File" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Re-Scan Filesystem" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Toggle Split Mode" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Search files" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "" +"Scanning Files,\n" +"Please Wait..." +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Move" +msgstr "" + +#: editor/filesystem_dock.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/project_manager.cpp editor/rename_dialog.cpp +#: editor/scene_tree_dock.cpp +msgid "Rename" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Overwrite" +msgstr "" + +#: editor/filesystem_dock.cpp +msgid "Create Scene" +msgstr "" + +#: editor/filesystem_dock.cpp editor/plugins/script_editor_plugin.cpp +msgid "Create Script" +msgstr "" + +#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp +msgid "Find in Files" +msgstr "" + +#: editor/find_in_files.cpp +msgid "Find:" +msgstr "" + +#: editor/find_in_files.cpp +msgid "Folder:" +msgstr "" + +#: editor/find_in_files.cpp +msgid "Filters:" +msgstr "" + +#: editor/find_in_files.cpp +msgid "" +"Include the files with the following extensions. Add or remove them in " +"ProjectSettings." +msgstr "" + +#: editor/find_in_files.cpp editor/plugins/script_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +msgid "Find..." +msgstr "" + +#: editor/find_in_files.cpp editor/plugins/script_text_editor.cpp +msgid "Replace..." +msgstr "" + +#: editor/find_in_files.cpp editor/progress_dialog.cpp scene/gui/dialogs.cpp +msgid "Cancel" +msgstr "" + +#: editor/find_in_files.cpp +msgid "Find: " +msgstr "" + +#: editor/find_in_files.cpp +msgid "Replace: " +msgstr "" + +#: editor/find_in_files.cpp +msgid "Replace all (no undo)" +msgstr "" + +#: editor/find_in_files.cpp +msgid "Searching..." +msgstr "" + +#: editor/find_in_files.cpp +msgid "%d match in %d file." +msgstr "" + +#: editor/find_in_files.cpp +msgid "%d matches in %d file." +msgstr "" + +#: editor/find_in_files.cpp +msgid "%d matches in %d files." +msgstr "" + +#: editor/groups_editor.cpp +msgid "Add to Group" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Remove from Group" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Group name already exists." +msgstr "" + +#: editor/groups_editor.cpp +msgid "Invalid group name." +msgstr "" + +#: editor/groups_editor.cpp +msgid "Rename Group" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Delete Group" +msgstr "" + +#: editor/groups_editor.cpp editor/node_dock.cpp +msgid "Groups" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Nodes Not in Group" +msgstr "" + +#: editor/groups_editor.cpp editor/scene_tree_dock.cpp +#: editor/scene_tree_editor.cpp +msgid "Filter nodes" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Nodes in Group" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Empty groups will be automatically removed." +msgstr "" + +#: editor/groups_editor.cpp +msgid "Group Editor" +msgstr "" + +#: editor/groups_editor.cpp +msgid "Manage Groups" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import as Single Scene" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Animations" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Materials" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Objects" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Objects+Materials" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Objects+Animations" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Materials+Animations" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import with Separate Objects+Materials+Animations" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import as Multiple Scenes" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Import as Multiple Scenes+Materials" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "Import Scene" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Importing Scene..." +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Generating Lightmaps" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Generating for Mesh: " +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Running Custom Script..." +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Couldn't load post-import script:" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Invalid/broken script for post-import (check console):" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Error running post-import script:" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Did you return a Node-derived object in the `post_import()` method?" +msgstr "" + +#: editor/import/resource_importer_scene.cpp +msgid "Saving..." +msgstr "" + +#: editor/import_defaults_editor.cpp +msgid "Select Importer" +msgstr "" + +#: editor/import_defaults_editor.cpp +msgid "Importer:" +msgstr "" + +#: editor/import_defaults_editor.cpp +msgid "Reset to Defaults" +msgstr "" + +#: editor/import_dock.cpp +msgid "Keep File (No Import)" +msgstr "" + +#: editor/import_dock.cpp +msgid "%d Files" +msgstr "" + +#: editor/import_dock.cpp +msgid "Set as Default for '%s'" +msgstr "" + +#: editor/import_dock.cpp +msgid "Clear Default for '%s'" +msgstr "" + +#: editor/import_dock.cpp +msgid "Import As:" +msgstr "" + +#: editor/import_dock.cpp +msgid "Preset" +msgstr "" + +#: editor/import_dock.cpp +msgid "Reimport" +msgstr "" + +#: editor/import_dock.cpp +msgid "Save Scenes, Re-Import, and Restart" +msgstr "" + +#: editor/import_dock.cpp +msgid "Changing the type of an imported file requires editor restart." +msgstr "" + +#: editor/import_dock.cpp +msgid "" +"WARNING: Assets exist that use this resource, they may stop loading properly." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Failed to load resource." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Expand All Properties" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Collapse All Properties" +msgstr "" + +#: editor/inspector_dock.cpp editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/script_editor_plugin.cpp +msgid "Save As..." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Copy Params" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Edit Resource Clipboard" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Copy Resource" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Make Built-In" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Make Sub-Resources Unique" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Open in Help" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Create a new resource in memory and edit it." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Load an existing resource from disk and edit it." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Save the currently edited resource." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Go to the previous edited object in history." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Go to the next edited object in history." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "History of recently edited objects." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Object properties." +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Filter properties" +msgstr "" + +#: editor/inspector_dock.cpp +msgid "Changes may be lost!" +msgstr "" + +#: editor/multi_node_edit.cpp +msgid "MultiNode Set" +msgstr "" + +#: editor/node_dock.cpp +msgid "Select a single node to edit its signals and groups." +msgstr "" + +#: editor/plugin_config_dialog.cpp +msgid "Edit a Plugin" +msgstr "" + +#: editor/plugin_config_dialog.cpp +msgid "Create a Plugin" +msgstr "" + +#: editor/plugin_config_dialog.cpp +msgid "Plugin Name:" +msgstr "" + +#: editor/plugin_config_dialog.cpp +msgid "Subfolder:" +msgstr "" + +#: editor/plugin_config_dialog.cpp editor/script_create_dialog.cpp +msgid "Language:" +msgstr "" + +#: editor/plugin_config_dialog.cpp +msgid "Script Name:" +msgstr "" + +#: editor/plugin_config_dialog.cpp +msgid "Activate now?" +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Create Polygon" +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Create points." +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +msgid "" +"Edit points.\n" +"LMB: Move Point\n" +"RMB: Erase Point" +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +#: editor/plugins/animation_blend_space_1d_editor.cpp +msgid "Erase points." +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +msgid "Edit Polygon" +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +msgid "Insert Point" +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +msgid "Edit Polygon (Remove Point)" +msgstr "" + +#: editor/plugins/abstract_polygon_2d_editor.cpp +msgid "Remove Polygon And Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/animation_state_machine_editor.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Add Animation" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Load..." +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Move Node Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +msgid "Change BlendSpace1D Limits" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +msgid "Change BlendSpace1D Labels" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_state_machine_editor.cpp +msgid "This type of node can't be used. Only root nodes are allowed." +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Add Node Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Add Animation Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +msgid "Remove BlendSpace1D Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +msgid "Move BlendSpace1D Node Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/animation_state_machine_editor.cpp +msgid "" +"AnimationTree is inactive.\n" +"Activate to enable playback, check node warnings if activation fails." +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Set the blending position within the space" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Select and move points, create points with RMB." +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp scene/gui/graph_edit.cpp +msgid "Enable snap and show grid." +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Point" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Open Editor" +msgstr "" + +#: editor/plugins/animation_blend_space_1d_editor.cpp +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Open Animation Node" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Triangle already exists." +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Add Triangle" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Change BlendSpace2D Limits" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Change BlendSpace2D Labels" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Remove BlendSpace2D Point" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Remove BlendSpace2D Triangle" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "BlendSpace2D does not belong to an AnimationTree node." +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "No triangles exist, so no blending can take place." +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Toggle Auto Triangles" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Create triangles by connecting points." +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Erase points and triangles." +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +msgid "Generate blend triangles automatically (instead of manually)" +msgstr "" + +#: editor/plugins/animation_blend_space_2d_editor.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend:" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Parameter Changed" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Edit Filters" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Output node can't be added to the blend tree." +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Add Node to BlendTree" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Node Moved" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Unable to connect, port may be in use or connection may be invalid." +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Nodes Connected" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Nodes Disconnected" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Set Animation" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Delete Node" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/scene_tree_dock.cpp +msgid "Delete Node(s)" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Toggle Filter On/Off" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Change Filter" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "No animation player set, so unable to retrieve track names." +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Player path set is invalid, so unable to retrieve track names." +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/root_motion_editor_plugin.cpp +msgid "" +"Animation player has no valid root node path, so unable to retrieve track " +"names." +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Anim Clips" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Audio Clips" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Functions" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Node Renamed" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Add Node..." +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +#: editor/plugins/root_motion_editor_plugin.cpp +msgid "Edit Filtered Tracks:" +msgstr "" + +#: editor/plugins/animation_blend_tree_editor_plugin.cpp +msgid "Enable Filtering" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Toggle Autoplay" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "New Animation Name:" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "New Anim" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Change Animation Name:" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Delete Animation?" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Remove Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Invalid animation name!" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Animation name already exists!" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Rename Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Blend Next Changed" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Change Blend Time" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Load Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Duplicate Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "No animation to copy!" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "No animation resource on clipboard!" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Pasted Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Paste Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "No animation to edit!" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Play selected animation backwards from current pos. (A)" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Play selected animation backwards from end. (Shift+A)" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Stop animation playback. (S)" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Play selected animation from start. (Shift+D)" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Play selected animation from current pos. (D)" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Animation position (in seconds)." +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Scale animation playback globally for the node." +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Animation Tools" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Edit Transitions..." +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Open in Inspector" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Display list of animations in player." +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Autoplay on Load" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Enable Onion Skinning" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Onion Skinning Options" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Directions" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Past" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Future" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Depth" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "1 step" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "2 steps" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "3 steps" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Differences Only" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Force White Modulate" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Include Gizmos (3D)" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Pin AnimationPlayer" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Create New Animation" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Animation Name:" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp editor/property_editor.cpp +msgid "Error!" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Blend Times:" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Next (Auto Queue):" +msgstr "" + +#: editor/plugins/animation_player_editor_plugin.cpp +msgid "Cross-Animation Blend Times" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Move Node" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Transition exists!" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Add Transition" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Node" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "End" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Immediate" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Sync" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "At End" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Travel" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Start and end nodes are needed for a sub-transition." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "No playback resource set at path: %s." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Node Removed" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Transition Removed" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Set Start Node (Autoplay)" +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "" +"Select and move nodes.\n" +"RMB to add new nodes.\n" +"Shift+LMB to create connections." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Create new nodes." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Connect nodes." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Remove selected node or transition." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Toggle autoplay this animation on start, restart or seek to zero." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Set the end animation. This is useful for sub-transitions." +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Transition: " +msgstr "" + +#: editor/plugins/animation_state_machine_editor.cpp +msgid "Play Mode:" +msgstr "" + +#: editor/plugins/animation_tree_editor_plugin.cpp +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "AnimationTree" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "New name:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Scale:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Fade In (s):" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Fade Out (s):" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Mix" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Auto Restart:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Restart (s):" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Random Restart (s):" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Start!" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Amount:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend 0:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend 1:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "X-Fade Time (s):" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Current:" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Input" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Clear Auto-Advance" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Set Auto-Advance" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Delete Input" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Animation tree is valid." +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Animation tree is invalid." +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Animation Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "OneShot Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Mix Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend2 Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend3 Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Blend4 Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "TimeScale Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "TimeSeek Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Transition Node" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Import Animations..." +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Edit Node Filters" +msgstr "" + +#: editor/plugins/animation_tree_player_editor_plugin.cpp +msgid "Filters..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Contents:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "View Files" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Connection error, please try again." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Can't connect to host:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "No response from host:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Can't resolve hostname:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Request failed, return code:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Request failed." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Cannot save response to:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Write error." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Request failed, too many redirects" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Redirect loop." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Request failed, timeout" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Timeout." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Bad download hash, assuming file has been tampered with." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Expected:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Got:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Failed SHA-256 hash check" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Asset Download Error:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Downloading (%s / %s)..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Downloading..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Resolving..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Error making request" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Idle" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Install..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Retry" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Download Error" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Download for this asset is already in progress!" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Recently Updated" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Least Recently Updated" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Name (A-Z)" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Name (Z-A)" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "License (A-Z)" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "License (Z-A)" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "First" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Previous" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Next" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Last" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "All" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "No results for \"%s\"." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Import..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Plugins..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp editor/project_manager.cpp +msgid "Sort:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Category:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Site:" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Support" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Official" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Testing" +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Loading..." +msgstr "" + +#: editor/plugins/asset_library_editor_plugin.cpp +msgid "Assets ZIP File" +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "" +"Can't determine a save path for lightmap images.\n" +"Save your scene and try again." +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "" +"No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake " +"Light' flag is on." +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "Failed creating lightmap images, make sure path is writable." +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "Failed determining lightmap size. Maximum lightmap size too small?" +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "" +"Some mesh is invalid. Make sure the UV2 channel values are contained within " +"the [0.0,1.0] square region." +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "" +"Godot editor was built without ray tracing support, lightmaps can't be baked." +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "Bake Lightmaps" +msgstr "" + +#: editor/plugins/baked_lightmap_editor_plugin.cpp +msgid "Select lightmap bake file:" +msgstr "" + +#: editor/plugins/camera_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Preview" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Configure Snap" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Grid Offset:" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Grid Step:" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Primary Line Every:" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "steps" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Rotation Offset:" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Rotation Step:" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Scale Step:" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Move Vertical Guide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Create Vertical Guide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Remove Vertical Guide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Move Horizontal Guide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Create Horizontal Guide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Remove Horizontal Guide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Create Horizontal and Vertical Guides" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Set CanvasItem \"%s\" Pivot Offset to (%d, %d)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Rotate %d CanvasItems" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Rotate CanvasItem \"%s\" to %d degrees" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Move CanvasItem \"%s\" Anchor" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Scale Node2D \"%s\" to (%s, %s)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Resize Control \"%s\" to (%d, %d)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Scale %d CanvasItems" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Scale CanvasItem \"%s\" to (%s, %s)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Move %d CanvasItems" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Move CanvasItem \"%s\" to (%d, %d)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "" +"Children of containers have their anchors and margins values overridden by " +"their parent." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Presets for the anchors and margins values of a Control node." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "" +"When active, moving Control nodes changes their anchors instead of their " +"margins." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Top Left" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Top Right" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Bottom Right" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Bottom Left" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Center Left" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Center Top" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Center Right" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Center Bottom" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Center" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Left Wide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Top Wide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Right Wide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Bottom Wide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "VCenter Wide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "HCenter Wide" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Full Rect" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Keep Ratio" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Anchors only" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Change Anchors and Margins" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Change Anchors" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"Game Camera Override\n" +"Overrides game camera with editor viewport camera." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"Game Camera Override\n" +"No game instance running." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Lock Selected" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Unlock Selected" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Group Selected" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Ungroup Selected" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Paste Pose" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Clear Guides" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Create Custom Bone(s) from Node(s)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Clear Bones" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Make IK Chain" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Clear IK Chain" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "" +"Warning: Children of a container get their position and size determined only " +"by their parent." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/texture_region_editor_plugin.cpp +#: editor/plugins/tile_set_editor_plugin.cpp scene/gui/graph_edit.cpp +msgid "Zoom Reset" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Select Mode" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Drag: Rotate" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Alt+Drag: Move" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Press 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving)." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Alt+RMB: Depth list selection" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Move Mode" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rotate Mode" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Scale Mode" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"Show a list of all objects at the position clicked\n" +"(same as Alt+RMB in select mode)." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Click to change object's rotation pivot." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Pan Mode" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Ruler Mode" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Toggle smart snapping." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Use Smart Snap" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Toggle grid snapping." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Use Grid Snap" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snapping Options" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Use Rotation Snap" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Use Scale Snap" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap Relative" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Use Pixel Snap" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Smart Snapping" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Configure Snap..." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap to Parent" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap to Node Anchor" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap to Node Sides" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap to Node Center" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap to Other Nodes" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Snap to Guides" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Lock the selected object in place (can't be moved)." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Unlock the selected object (can be moved)." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Makes sure the object's children are not selectable." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Restores the object's children's ability to be selected." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Skeleton Options" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Bones" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Make Custom Bone(s) from Node(s)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Clear Custom Bones" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Always Show Grid" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Helpers" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Rulers" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Guides" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Origin" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Viewport" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Show Group And Lock Icons" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Center Selection" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Frame Selection" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Preview Canvas Scale" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Translation mask for inserting keys." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Rotation mask for inserting keys." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Scale mask for inserting keys." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Insert keys (based on mask)." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "" +"Auto insert keys when objects are translated, rotated or scaled (based on " +"mask).\n" +"Keys are only added to existing tracks, no new tracks will be created.\n" +"Keys must be inserted manually for the first time." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Auto Insert Key" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Animation Key and Pose Options" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Insert Key (Existing Tracks)" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Copy Pose" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Clear Pose" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Multiply grid step by 2" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Divide grid step by 2" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Pan View" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Add %s" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Adding %s..." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Cannot instantiate multiple nodes without root." +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp +msgid "Create Node" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp +msgid "Error instancing scene from %s" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "Change Default Type" +msgstr "" + +#: editor/plugins/canvas_item_editor_plugin.cpp +msgid "" +"Drag & drop + Shift : Add node as sibling\n" +"Drag & drop + Alt : Change node type" +msgstr "" + +#: editor/plugins/collision_polygon_editor_plugin.cpp +msgid "Create Polygon3D" +msgstr "" + +#: editor/plugins/collision_polygon_editor_plugin.cpp +msgid "Edit Poly" +msgstr "" + +#: editor/plugins/collision_polygon_editor_plugin.cpp +msgid "Edit Poly (Remove Point)" +msgstr "" + +#: editor/plugins/collision_shape_2d_editor_plugin.cpp +msgid "Set Handle" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Load Emission Mask" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/cpu_particles_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +msgid "Restart" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Clear Emission Mask" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +msgid "Particles" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Generated Point Count:" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Emission Mask" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Solid Pixels" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Border Pixels" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Directed Border Pixels" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Capture from Pixel" +msgstr "" + +#: editor/plugins/cpu_particles_2d_editor_plugin.cpp +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Emission Colors" +msgstr "" + +#: editor/plugins/cpu_particles_editor_plugin.cpp +msgid "CPUParticles" +msgstr "" + +#: editor/plugins/cpu_particles_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +msgid "Create Emission Points From Mesh" +msgstr "" + +#: editor/plugins/cpu_particles_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +msgid "Create Emission Points From Node" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Flat 0" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Flat 1" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp +msgid "Ease In" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp editor/property_editor.cpp +msgid "Ease Out" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Smoothstep" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Modify Curve Point" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Modify Curve Tangent" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Load Curve Preset" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Add Point" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Remove Point" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Left Linear" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Right Linear" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Load Preset" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Remove Curve Point" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Toggle Curve Linear Tangent" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Hold Shift to edit tangents individually" +msgstr "" + +#: editor/plugins/curve_editor_plugin.cpp +msgid "Right click to add point" +msgstr "" + +#: editor/plugins/gi_probe_editor_plugin.cpp +msgid "Bake GI Probe" +msgstr "" + +#: editor/plugins/gradient_editor_plugin.cpp +msgid "Gradient Edited" +msgstr "" + +#: editor/plugins/item_list_editor_plugin.cpp +msgid "Item %d" +msgstr "" + +#: editor/plugins/item_list_editor_plugin.cpp +msgid "Items" +msgstr "" + +#: editor/plugins/item_list_editor_plugin.cpp +msgid "Item List Editor" +msgstr "" + +#: editor/plugins/light_occluder_2d_editor_plugin.cpp +msgid "Create Occluder Polygon" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Mesh is empty!" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Couldn't create a Trimesh collision shape." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Static Trimesh Body" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "This doesn't work on scene root!" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Trimesh Static Shape" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Can't create a single convex collision shape for the scene root." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Couldn't create a single convex collision shape." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Single Convex Shape" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Can't create multiple convex collision shapes for the scene root." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Couldn't create any collision shapes." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Multiple Convex Shapes" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Navigation Mesh" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Contained Mesh is not of type ArrayMesh." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "UV Unwrap failed, mesh may not be manifold?" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "No mesh to debug." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Model has no UV in this layer" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "MeshInstance lacks a Mesh!" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Mesh has not surface to create outlines from!" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Mesh primitive type is not PRIMITIVE_TRIANGLES!" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Could not create outline!" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Outline" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Mesh" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Trimesh Static Body" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "" +"Creates a StaticBody and assigns a polygon-based collision shape to it " +"automatically.\n" +"This is the most accurate (but slowest) option for collision detection." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Trimesh Collision Sibling" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "" +"Creates a polygon-based collision shape.\n" +"This is the most accurate (but slowest) option for collision detection." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Single Convex Collision Sibling" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "" +"Creates a single convex collision shape.\n" +"This is the fastest (but least accurate) option for collision detection." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Multiple Convex Collision Siblings" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "" +"Creates a polygon-based collision shape.\n" +"This is a performance middle-ground between the two above options." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Outline Mesh..." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "" +"Creates a static outline mesh. The outline mesh will have its normals " +"flipped automatically.\n" +"This can be used instead of the SpatialMaterial Grow property when using " +"that property isn't possible." +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "View UV1" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "View UV2" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Unwrap UV2 for Lightmap/AO" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Create Outline Mesh" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "Outline Size:" +msgstr "" + +#: editor/plugins/mesh_instance_editor_plugin.cpp +msgid "UV Channel Debug" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "Remove item %d?" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "" +"Update from existing scene?:\n" +"%s" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "Mesh Library" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +#: editor/plugins/theme_editor_plugin.cpp +msgid "Add Item" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "Remove Selected Item" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "Import from Scene" +msgstr "" + +#: editor/plugins/mesh_library_editor_plugin.cpp +msgid "Update from Scene" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "No mesh source specified (and no MultiMesh set in node)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "No mesh source specified (and MultiMesh contains no Mesh)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Mesh source is invalid (invalid path)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Mesh source is invalid (not a MeshInstance)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Mesh source is invalid (contains no Mesh resource)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "No surface source specified." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Surface source is invalid (invalid path)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Surface source is invalid (no geometry)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Surface source is invalid (no faces)." +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Select a Source Mesh:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Select a Target Surface:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Populate Surface" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Populate MultiMesh" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Target Surface:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Source Mesh:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "X-Axis" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Y-Axis" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Z-Axis" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Mesh Up Axis:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Random Rotation:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Random Tilt:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Random Scale:" +msgstr "" + +#: editor/plugins/multimesh_editor_plugin.cpp +msgid "Populate" +msgstr "" + +#: editor/plugins/navigation_polygon_editor_plugin.cpp +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create Navigation Polygon" +msgstr "" + +#: editor/plugins/particles_2d_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +msgid "Convert to CPUParticles" +msgstr "" + +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Generating Visibility Rect" +msgstr "" + +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Generate Visibility Rect" +msgstr "" + +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Can only set point into a ParticlesMaterial process material" +msgstr "" + +#: editor/plugins/particles_2d_editor_plugin.cpp +msgid "Convert to CPUParticles2D" +msgstr "" + +#: editor/plugins/particles_2d_editor_plugin.cpp +#: editor/plugins/particles_editor_plugin.cpp +msgid "Generation Time (sec):" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "The geometry's faces don't contain any area." +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "The geometry doesn't contain any faces." +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "\"%s\" doesn't inherit from Spatial." +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "\"%s\" doesn't contain geometry." +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "\"%s\" doesn't contain face geometry." +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Create Emitter" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Emission Points:" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Surface Points" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Surface Points+Normal (Directed)" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Volume" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Emission Source: " +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "A processor material of type 'ParticlesMaterial' is required." +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Generating AABB" +msgstr "" + +#: editor/plugins/particles_editor_plugin.cpp +msgid "Generate Visibility AABB" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Remove Point from Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Remove Out-Control from Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Remove In-Control from Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Add Point to Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Split Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Move Point in Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Move In-Control in Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Move Out-Control in Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Select Points" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Shift+Drag: Select Control Points" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Click: Add Point" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Left Click: Split Segment (in curve)" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Right Click: Delete Point" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +msgid "Select Control Points (Shift+Drag)" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Add Point (in empty space)" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Delete Point" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Close Curve" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp editor/plugins/theme_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_export.cpp +msgid "Options" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Mirror Handle Angles" +msgstr "" + +#: editor/plugins/path_2d_editor_plugin.cpp +#: editor/plugins/path_editor_plugin.cpp +msgid "Mirror Handle Lengths" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Curve Point #" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Set Curve Point Position" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Set Curve In Position" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Set Curve Out Position" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Split Path" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Remove Path Point" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Remove Out-Control Point" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Remove In-Control Point" +msgstr "" + +#: editor/plugins/path_editor_plugin.cpp +msgid "Split Segment (in curve)" +msgstr "" + +#: editor/plugins/physical_bone_plugin.cpp +msgid "Move Joint" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "" +"The skeleton property of the Polygon2D does not point to a Skeleton2D node" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Sync Bones" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "" +"No texture in this polygon.\n" +"Set a texture to be able to edit UV." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Create UV Map" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "" +"Polygon 2D has internal vertices, so it can no longer be edited in the " +"viewport." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Create Polygon & UV" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Create Internal Vertex" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Remove Internal Vertex" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Invalid Polygon (need 3 different vertices)" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Add Custom Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Remove Custom Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Transform UV Map" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Transform Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Paint Bone Weights" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Open Polygon 2D UV editor." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Polygon 2D UV Editor" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "UV" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Points" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Polygons" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Bones" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Move Points" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Command: Rotate" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Shift: Move All" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Shift+Command: Scale" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Ctrl: Rotate" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Shift+Ctrl: Scale" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Move Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Rotate Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Scale Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Create a custom polygon. Enables custom polygon rendering." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "" +"Remove a custom polygon. If none remain, custom polygon rendering is " +"disabled." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Paint weights with specified intensity." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Unpaint weights with specified intensity." +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Radius:" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Copy Polygon to UV" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Copy UV to Polygon" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Clear UV" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Grid Settings" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Snap" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Enable Snap" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Grid" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Show Grid" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Configure Grid:" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Grid Offset X:" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Grid Offset Y:" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Grid Step X:" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Grid Step Y:" +msgstr "" + +#: editor/plugins/polygon_2d_editor_plugin.cpp +msgid "Sync Bones to Polygon" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "ERROR: Couldn't load resource!" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "Add Resource" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "Rename Resource" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Delete Resource" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "Resource clipboard is empty!" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "Paste Resource" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/scene_tree_editor.cpp +msgid "Instance:" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/plugins/theme_editor_plugin.cpp editor/project_settings_editor.cpp +#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Type:" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +#: editor/scene_tree_dock.cpp editor/scene_tree_editor.cpp +msgid "Open in Editor" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "Load Resource" +msgstr "" + +#: editor/plugins/resource_preloader_editor_plugin.cpp +msgid "ResourcePreloader" +msgstr "" + +#: editor/plugins/root_motion_editor_plugin.cpp +msgid "AnimationTree has no path set to an AnimationPlayer" +msgstr "" + +#: editor/plugins/root_motion_editor_plugin.cpp +msgid "Path to AnimationPlayer is invalid" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Clear Recent Files" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Close and save changes?" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error writing TextFile:" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Could not load file at:" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error saving file!" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error while saving theme." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error Saving" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error importing theme." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error Importing" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "New Text File..." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Open File" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Save File As..." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Can't obtain the script for running." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Script failed reloading, check console for errors." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Script is not in tool mode, will not be able to run." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "" +"To run this script, it must inherit EditorScript and be set to tool mode." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Import Theme" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error while saving theme" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Error saving" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Save Theme As..." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "%s Class Reference" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +msgid "Find Next" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +msgid "Find Previous" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Filter scripts" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Toggle alphabetical sorting of the method list." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Filter methods" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Sort" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Move Up" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Move Down" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Next script" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Previous script" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "File" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Open..." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Reopen Closed Script" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Save All" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Soft Reload Script" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Copy Script Path" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "History Previous" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "History Next" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/theme_editor_plugin.cpp +msgid "Theme" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Import Theme..." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Reload Theme" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Save Theme" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Close All" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Close Docs" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp +msgid "Run" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +#: editor/plugins/script_text_editor.cpp +#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp editor/project_manager.cpp +#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp +msgid "Search" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp +msgid "Step Into" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp +msgid "Step Over" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp +msgid "Break" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp +#: editor/script_editor_debugger.cpp +msgid "Continue" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Keep Debugger Open" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Debug with External Editor" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Open Godot online documentation." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Search the reference documentation." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Go to previous edited document." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Go to next edited document." +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Discard" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "" +"The following files are newer on disk.\n" +"What action should be taken?:" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp editor/script_editor_debugger.cpp +msgid "Debugger" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Search Results" +msgstr "" + +#: editor/plugins/script_editor_plugin.cpp +msgid "Clear Recent Scripts" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Connections to method:" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/script_editor_debugger.cpp +msgid "Source" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Target" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "" +"Missing connected method '%s' for signal '%s' from node '%s' to node '%s'." +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "[Ignore]" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Line" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Function" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Only resources from filesystem can be dropped." +msgstr "" + +#: editor/plugins/script_text_editor.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Can't drop nodes because script '%s' is not used in this scene." +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Lookup Symbol" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Pick Color" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp +msgid "Convert Case" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp +msgid "Uppercase" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp +msgid "Lowercase" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp +msgid "Capitalize" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/plugins/text_editor.cpp +msgid "Syntax Highlighter" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp +msgid "Bookmarks" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Breakpoints" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +#: editor/plugins/shader_editor_plugin.cpp editor/plugins/text_editor.cpp +msgid "Go To" +msgstr "" + +#: editor/plugins/script_text_editor.cpp editor/scene_tree_dock.cpp +#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp +msgid "Cut" +msgstr "" + +#: editor/plugins/script_text_editor.cpp scene/gui/line_edit.cpp +#: scene/gui/text_edit.cpp +msgid "Select All" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Delete Line" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Indent Left" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Indent Right" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Toggle Comment" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Fold/Unfold Line" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Fold All Lines" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Unfold All Lines" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Clone Down" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Complete Symbol" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Evaluate Selection" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Trim Trailing Whitespace" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Convert Indent to Spaces" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Convert Indent to Tabs" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Auto Indent" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Find in Files..." +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Contextual Help" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Toggle Bookmark" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Next Bookmark" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Previous Bookmark" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Remove All Bookmarks" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Function..." +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Line..." +msgstr "" + +#: editor/plugins/script_text_editor.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Toggle Breakpoint" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Remove All Breakpoints" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Next Breakpoint" +msgstr "" + +#: editor/plugins/script_text_editor.cpp +msgid "Go to Previous Breakpoint" +msgstr "" + +#: editor/plugins/shader_editor_plugin.cpp +msgid "" +"This shader has been modified on on disk.\n" +"What action should be taken?" +msgstr "" + +#: editor/plugins/shader_editor_plugin.cpp +msgid "Shader" +msgstr "" + +#: editor/plugins/skeleton_2d_editor_plugin.cpp +msgid "This skeleton has no bones, create some children Bone2D nodes." +msgstr "" + +#: editor/plugins/skeleton_2d_editor_plugin.cpp +msgid "Create Rest Pose from Bones" +msgstr "" + +#: editor/plugins/skeleton_2d_editor_plugin.cpp +msgid "Set Rest Pose to Bones" +msgstr "" + +#: editor/plugins/skeleton_2d_editor_plugin.cpp +msgid "Skeleton2D" +msgstr "" + +#: editor/plugins/skeleton_2d_editor_plugin.cpp +msgid "Make Rest Pose (From Bones)" +msgstr "" + +#: editor/plugins/skeleton_2d_editor_plugin.cpp +msgid "Set Bones to Rest Pose" +msgstr "" + +#: editor/plugins/skeleton_editor_plugin.cpp +msgid "Create physical bones" +msgstr "" + +#: editor/plugins/skeleton_editor_plugin.cpp +msgid "Skeleton" +msgstr "" + +#: editor/plugins/skeleton_editor_plugin.cpp +msgid "Create physical skeleton" +msgstr "" + +#: editor/plugins/skeleton_ik_editor_plugin.cpp +msgid "Play IK" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Orthogonal" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Perspective" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Transform Aborted." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "X-Axis Transform." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Y-Axis Transform." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Z-Axis Transform." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Plane Transform." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Scaling: " +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Translating: " +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rotating %s degrees." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Keying is disabled (no key inserted)." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Animation Key Inserted." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Pitch" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Yaw" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Size" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Objects Drawn" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Material Changes" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Shader Changes" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Surface Changes" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Draw Calls" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Vertices" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Top View." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Bottom View." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Bottom" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Left View." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Left" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Right View." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Right" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Front View." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Front" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rear View." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rear" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Align Transform with View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Align Rotation with View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp +msgid "No parent to instance a child at." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp editor/scene_tree_dock.cpp +msgid "This operation requires a single selected node." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Auto Orthogonal Enabled" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Lock View Rotation" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Display Normal" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Display Wireframe" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Display Overdraw" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Display Unshaded" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Environment" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Gizmos" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Information" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View FPS" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Half Resolution" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Audio Listener" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Enable Doppler" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Cinematic Preview" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Not available when using the GLES2 renderer." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Left" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Right" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Forward" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Backwards" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Up" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Down" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Speed Modifier" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Freelook Slow Modifier" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Rotation Locked" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"To zoom further, change the camera's clipping planes (View -> Settings...)" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"Note: The FPS value displayed is the editor's framerate.\n" +"It cannot be used as a reliable indication of in-game performance." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "XForm Dialog" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"Click to toggle between visibility states.\n" +"\n" +"Open eye: Gizmo is visible.\n" +"Closed eye: Gizmo is hidden.\n" +"Half-open eye: Gizmo is also visible through opaque surfaces (\"x-ray\")." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Snap Nodes To Floor" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Couldn't find a solid floor to snap the selection to." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "" +"Drag: Rotate\n" +"Alt+Drag: Move\n" +"Alt+RMB: Depth list selection" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Use Local Space" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Use Snap" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Bottom View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Top View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rear View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Front View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Left View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Right View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Switch Perspective/Orthogonal View" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Insert Animation Key" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Focus Origin" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Focus Selection" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Toggle Freelook" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Transform" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Snap Object to Floor" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Transform Dialog..." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "1 Viewport" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "2 Viewports" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "2 Viewports (Alt)" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "3 Viewports" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "3 Viewports (Alt)" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "4 Viewports" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Gizmos" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Origin" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Grid" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Settings..." +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Snap Settings" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Translate Snap:" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rotate Snap (deg.):" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Scale Snap (%):" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Viewport Settings" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Perspective FOV (deg.):" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Z-Near:" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "View Z-Far:" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Transform Change" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Translate:" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Rotate (deg.):" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Scale (ratio):" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Transform Type" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Pre" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Post" +msgstr "" + +#: editor/plugins/spatial_editor_plugin.cpp +msgid "Nameless gizmo" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Create Mesh2D" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Mesh2D Preview" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Create Polygon2D" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Polygon2D Preview" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Create CollisionPolygon2D" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "CollisionPolygon2D Preview" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Create LightOccluder2D" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "LightOccluder2D Preview" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Sprite is empty!" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Can't convert a sprite using animation frames to mesh." +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Invalid geometry, can't replace by mesh." +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Convert to Mesh2D" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Invalid geometry, can't create polygon." +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Convert to Polygon2D" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Invalid geometry, can't create collision polygon." +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Create CollisionPolygon2D Sibling" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Invalid geometry, can't create light occluder." +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Create LightOccluder2D Sibling" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Sprite" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Simplification: " +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Shrink (Pixels): " +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Grow (Pixels): " +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Update Preview" +msgstr "" + +#: editor/plugins/sprite_editor_plugin.cpp +msgid "Settings:" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "No Frames Selected" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Add %d Frame(s)" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Add Frame" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Unable to load images" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "ERROR: Couldn't load frame resource!" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Resource clipboard is empty or not a texture!" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Paste Frame" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Add Empty" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Change Animation FPS" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "(empty)" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Move Frame" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Animations:" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "New Animation" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Speed:" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Loop" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Animation Frames:" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Add a Texture from File" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Add Frames from a Sprite Sheet" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Insert Empty (Before)" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Insert Empty (After)" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Move (Before)" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Move (After)" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Select Frames" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Horizontal:" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Vertical:" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Select/Clear All Frames" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "Create Frames from Sprite Sheet" +msgstr "" + +#: editor/plugins/sprite_frames_editor_plugin.cpp +msgid "SpriteFrames" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Set Region Rect" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Set Margin" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Snap Mode:" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +#: scene/resources/visual_shader.cpp +msgid "None" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Pixel Snap" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Grid Snap" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Auto Slice" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Offset:" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Step:" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "Sep.:" +msgstr "" + +#: editor/plugins/texture_region_editor_plugin.cpp +msgid "TextureRegion" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Add All Items" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Add All" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Remove All Items" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp editor/project_manager.cpp +msgid "Remove All" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Edit Theme" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Theme editing menu." +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Add Class Items" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Remove Class Items" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Create Empty Template" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Create Empty Editor Template" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Create From Current Editor Theme" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Toggle Button" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Disabled Button" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Disabled Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Check Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Checked Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Radio Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Checked Radio Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Named Sep." +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Submenu" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Subitem 1" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Subitem 2" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Has" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Many" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Disabled LineEdit" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Tab 1" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Tab 2" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Tab 3" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Editable Item" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Subtree" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Has,Many,Options" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Data Type:" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Icon" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp editor/rename_dialog.cpp +msgid "Style" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Font" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Color" +msgstr "" + +#: editor/plugins/theme_editor_plugin.cpp +msgid "Theme File" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Erase Selection" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Fix Invalid Tiles" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cut Selection" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Paint TileMap" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Line Draw" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Rectangle Paint" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Bucket Fill" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Erase TileMap" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Find Tile" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Transpose" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Disable Autotile" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Enable Priority" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Filter tiles" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Give a TileSet resource to this TileMap to use its tiles." +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Paint Tile" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "" +"Shift+LMB: Line Draw\n" +"Shift+Command+LMB: Rectangle Paint" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "" +"Shift+LMB: Line Draw\n" +"Shift+Ctrl+LMB: Rectangle Paint" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Pick Tile" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Rotate Left" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Rotate Right" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Flip Horizontally" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Flip Vertically" +msgstr "" + +#: editor/plugins/tile_map_editor_plugin.cpp +msgid "Clear Transform" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Add Texture(s) to TileSet." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove selected Texture from TileSet." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create from Scene" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Merge from Scene" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "New Single Tile" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "New Autotile" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "New Atlas" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Next Coordinate" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Select the next shape, subtile, or Tile." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Previous Coordinate" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Select the previous shape, subtile, or Tile." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Region" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Collision" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Occlusion" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Navigation" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Bitmask" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Priority" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Z Index" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Region Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Collision Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Occlusion Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Navigation Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Bitmask Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Priority Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Icon Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Z Index Mode" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Copy bitmask." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Paste bitmask." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Erase bitmask." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create a new rectangle." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "New Rectangle" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create a new polygon." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "New Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Delete Selected Shape" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Keep polygon inside region Rect." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Enable snap and show grid (configurable via the Inspector)." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Display Tile Names (Hold Alt Key)" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"Add or select a texture on the left panel to edit the tiles bound to it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove selected texture? This will remove all tiles which use it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "You haven't selected a texture to remove." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create from scene? This will overwrite all current tiles." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Merge from scene?" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove Texture" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "%s file(s) were not added because was already on the list." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"Drag handles to edit Rect.\n" +"Click on another Tile to edit it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Delete selected Rect." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"Select current edited sub-tile.\n" +"Click on another Tile to edit it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Delete polygon." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"LMB: Set bit on.\n" +"RMB: Set bit off.\n" +"Shift+LMB: Set wildcard bit.\n" +"Click on another Tile to edit it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"Select sub-tile to use as icon, this will be also used on invalid autotile " +"bindings.\n" +"Click on another Tile to edit it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"Select sub-tile to change its priority.\n" +"Click on another Tile to edit it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "" +"Select sub-tile to change its z index.\n" +"Click on another Tile to edit it." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Set Tile Region" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create Tile" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Set Tile Icon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Edit Tile Bitmask" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Edit Collision Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Edit Occlusion Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Edit Navigation Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Paste Tile Bitmask" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Clear Tile Bitmask" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Make Polygon Concave" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Make Polygon Convex" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove Tile" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove Collision Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove Occlusion Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Remove Navigation Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Edit Tile Priority" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Edit Tile Z Index" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Make Convex" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Make Concave" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create Collision Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "Create Occlusion Polygon" +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "This property can't be changed." +msgstr "" + +#: editor/plugins/tile_set_editor_plugin.cpp +msgid "TileSet" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "No VCS addons are available." +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Error" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "No files added to stage" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Commit" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "VCS Addon is not initialized" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Version Control System" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Initialize" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Staging area" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Detect new changes" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Changes" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Modified" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Renamed" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Deleted" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Typechange" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Stage Selected" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Stage All" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Commit Changes" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +#: modules/gdnative/gdnative_library_singleton_editor.cpp +msgid "Status" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "View file diffs before committing them to the latest version" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "No file diff is active" +msgstr "" + +#: editor/plugins/version_control_editor_plugin.cpp +msgid "Detect changes in file diff" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "(GLES3 only)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Add Output" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Scalar" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Vector" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Boolean" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Sampler" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Add input port" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Add output port" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Change input port type" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Change output port type" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Change input port name" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Change output port name" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Remove input port" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Remove output port" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Set expression" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Resize VisualShader node" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Set Uniform Name" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Set Input Default Port" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Add Node to Visual Shader" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Node(s) Moved" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Duplicate Nodes" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +#: modules/visual_script/visual_script_editor.cpp +msgid "Paste Nodes" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Delete Nodes" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Visual Shader Input Type Changed" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "UniformRef Name Changed" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Vertex" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Fragment" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Light" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Show resulted shader code." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Create Shader Node" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Color function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Color operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Grayscale function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Converts HSV vector to RGB equivalent." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Converts RGB vector to HSV equivalent." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Sepia function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Burn operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Darken operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Difference operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Dodge operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "HardLight operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Lighten operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Overlay operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Screen operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "SoftLight operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Color constant." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Color uniform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the boolean result of the %s comparison between two parameters." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Equal (==)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Greater Than (>)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Greater Than or Equal (>=)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns an associated vector if the provided scalars are equal, greater or " +"less." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns the boolean result of the comparison between INF and a scalar " +"parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns the boolean result of the comparison between NaN and a scalar " +"parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Less Than (<)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Less Than or Equal (<=)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Not Equal (!=)" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns an associated vector if the provided boolean value is true or false." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns an associated scalar if the provided boolean value is true or false." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the boolean result of the comparison between two parameters." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns the boolean result of the comparison between INF (or NaN) and a " +"scalar parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Boolean constant." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Boolean uniform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for all shader modes." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Input parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for vertex and fragment shader modes." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for fragment and light shader modes." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for fragment shader mode." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for light shader mode." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for vertex shader mode." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "'%s' input parameter for vertex and fragment shader mode." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Scalar function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Scalar operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "E constant (2.718282). Represents the base of the natural logarithm." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Epsilon constant (0.00001). Smallest possible scalar number." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Phi constant (1.618034). Golden ratio." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Pi/4 constant (0.785398) or 45 degrees." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Pi/2 constant (1.570796) or 90 degrees." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Pi constant (3.141593) or 180 degrees." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Tau constant (6.283185) or 360 degrees." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Sqrt2 constant (1.414214). Square root of 2." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the absolute value of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the arc-cosine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the inverse hyperbolic cosine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the arc-sine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the inverse hyperbolic sine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the arc-tangent of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the arc-tangent of the parameters." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the inverse hyperbolic tangent of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Finds the nearest integer that is greater than or equal to the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Constrains a value to lie between two further values." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the cosine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the hyperbolic cosine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Converts a quantity in radians to degrees." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Base-e Exponential." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Base-2 Exponential." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Finds the nearest integer less than or equal to the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Computes the fractional part of the argument." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the inverse of the square root of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Natural logarithm." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Base-2 logarithm." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the greater of two values." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the lesser of two values." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Linear interpolation between two scalars." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the opposite value of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "1.0 - scalar" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns the value of the first parameter raised to the power of the second." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Converts a quantity in degrees to radians." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "1.0 / scalar" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Finds the nearest integer to the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Finds the nearest even integer to the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Clamps the value between 0.0 and 1.0." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Extracts the sign of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the sine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the hyperbolic sine of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the square root of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n" +"\n" +"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than " +"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 " +"using Hermite polynomials." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Step function( scalar(edge), scalar(x) ).\n" +"\n" +"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the tangent of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the hyperbolic tangent of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Finds the truncated value of the parameter." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Adds scalar to scalar." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Divides scalar by scalar." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Multiplies scalar by scalar." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the remainder of the two scalars." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Subtracts scalar from scalar." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Scalar constant." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Scalar uniform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Perform the cubic texture lookup." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Perform the texture lookup." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Cubic texture uniform lookup." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "2D texture uniform lookup." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "2D texture uniform lookup with triplanar." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Transform function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Calculate the outer product of a pair of vectors.\n" +"\n" +"OuterProduct treats the first parameter 'c' as a column vector (matrix with " +"one column) and the second parameter 'r' as a row vector (matrix with one " +"row) and does a linear algebraic matrix multiply 'c * r', yielding a matrix " +"whose number of rows is the number of components in 'c' and whose number of " +"columns is the number of components in 'r'." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Composes transform from four vectors." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Decomposes transform to four vectors." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the determinant of a transform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the inverse of a transform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the transpose of a transform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Multiplies transform by transform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Multiplies vector by transform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Transform constant." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Transform uniform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Vector function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Vector operator." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Composes vector from three scalars." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Decomposes vector to three scalars." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the cross product of two vectors." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the distance between two points." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the dot product of two vectors." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns the vector that points in the same direction as a reference vector. " +"The function has three vector parameters : N, the vector to orient, I, the " +"incident vector, and Nref, the reference vector. If the dot product of I and " +"Nref is smaller than zero the return value is N. Otherwise -N is returned." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the length of a vector." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Linear interpolation between two vectors." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Linear interpolation between two vectors using scalar." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Calculates the normalize product of vector." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "1.0 - vector" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "1.0 / vector" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns the vector that points in the direction of reflection ( a : incident " +"vector, b : normal vector )." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the vector that points in the direction of refraction." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n" +"\n" +"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than " +"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 " +"using Hermite polynomials." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n" +"\n" +"Returns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than " +"'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 " +"using Hermite polynomials." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Step function( vector(edge), vector(x) ).\n" +"\n" +"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Step function( scalar(edge), vector(x) ).\n" +"\n" +"Returns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Adds vector to vector." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Divides vector by vector." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Multiplies vector by vector." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Returns the remainder of the two vectors." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Subtracts vector from vector." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Vector constant." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Vector uniform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Custom Godot Shader Language expression, with custom amount of input and " +"output ports. This is a direct injection of code into the vertex/fragment/" +"light function, do not use it to write the function declarations inside." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Returns falloff based on the dot product of surface normal and view " +"direction of camera (pass associated inputs to it)." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"Custom Godot Shader Language expression, which is placed on top of the " +"resulted shader. You can place various function definitions inside and call " +"it later in the Expressions. You can also declare varyings, uniforms and " +"constants." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "A reference to an existing uniform." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "(Fragment/Light mode only) Scalar derivative function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "(Fragment/Light mode only) Vector derivative function." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"(Fragment/Light mode only) (Vector) Derivative in 'x' using local " +"differencing." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"(Fragment/Light mode only) (Scalar) Derivative in 'x' using local " +"differencing." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"(Fragment/Light mode only) (Vector) Derivative in 'y' using local " +"differencing." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"(Fragment/Light mode only) (Scalar) Derivative in 'y' using local " +"differencing." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"(Fragment/Light mode only) (Vector) Sum of absolute derivative in 'x' and " +"'y'." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "" +"(Fragment/Light mode only) (Scalar) Sum of absolute derivative in 'x' and " +"'y'." +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "VisualShader" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Edit Visual Property" +msgstr "" + +#: editor/plugins/visual_shader_editor_plugin.cpp +msgid "Visual Shader Mode Changed" +msgstr "" + +#: editor/project_export.cpp +msgid "Runnable" +msgstr "" + +#: editor/project_export.cpp +msgid "Delete preset '%s'?" +msgstr "" + +#: editor/project_export.cpp +msgid "" +"Failed to export the project for platform '%s'.\n" +"Export templates seem to be missing or invalid." +msgstr "" + +#: editor/project_export.cpp +msgid "" +"Failed to export the project for platform '%s'.\n" +"This might be due to a configuration issue in the export preset or your " +"export settings." +msgstr "" + +#: editor/project_export.cpp +msgid "Release" +msgstr "" + +#: editor/project_export.cpp +msgid "Exporting All" +msgstr "" + +#: editor/project_export.cpp +msgid "The given export path doesn't exist:" +msgstr "" + +#: editor/project_export.cpp +msgid "Export templates for this platform are missing/corrupted:" +msgstr "" + +#: editor/project_export.cpp +msgid "Presets" +msgstr "" + +#: editor/project_export.cpp editor/project_settings_editor.cpp +msgid "Add..." +msgstr "" + +#: editor/project_export.cpp +msgid "" +"If checked, the preset will be available for use in one-click deploy.\n" +"Only one preset per platform may be marked as runnable." +msgstr "" + +#: editor/project_export.cpp +msgid "Export Path" +msgstr "" + +#: editor/project_export.cpp +msgid "Resources" +msgstr "" + +#: editor/project_export.cpp +msgid "Export all resources in the project" +msgstr "" + +#: editor/project_export.cpp +msgid "Export selected scenes (and dependencies)" +msgstr "" + +#: editor/project_export.cpp +msgid "Export selected resources (and dependencies)" +msgstr "" + +#: editor/project_export.cpp +msgid "Export Mode:" +msgstr "" + +#: editor/project_export.cpp +msgid "Resources to export:" +msgstr "" + +#: editor/project_export.cpp +msgid "" +"Filters to export non-resource files/folders\n" +"(comma-separated, e.g: *.json, *.txt, docs/*)" +msgstr "" + +#: editor/project_export.cpp +msgid "" +"Filters to exclude files/folders from project\n" +"(comma-separated, e.g: *.json, *.txt, docs/*)" +msgstr "" + +#: editor/project_export.cpp +msgid "Features" +msgstr "" + +#: editor/project_export.cpp +msgid "Custom (comma-separated):" +msgstr "" + +#: editor/project_export.cpp +msgid "Feature List:" +msgstr "" + +#: editor/project_export.cpp +msgid "Script" +msgstr "" + +#: editor/project_export.cpp +msgid "Script Export Mode:" +msgstr "" + +#: editor/project_export.cpp +msgid "Text" +msgstr "" + +#: editor/project_export.cpp +msgid "Compiled" +msgstr "" + +#: editor/project_export.cpp +msgid "Encrypted (Provide Key Below)" +msgstr "" + +#: editor/project_export.cpp +msgid "Invalid Encryption Key (must be 64 characters long)" +msgstr "" + +#: editor/project_export.cpp +msgid "Script Encryption Key (256-bits as hex):" +msgstr "" + +#: editor/project_export.cpp +msgid "Export PCK/Zip" +msgstr "" + +#: editor/project_export.cpp +msgid "Export Project" +msgstr "" + +#: editor/project_export.cpp +msgid "Export mode?" +msgstr "" + +#: editor/project_export.cpp +msgid "Export All" +msgstr "" + +#: editor/project_export.cpp editor/project_manager.cpp +msgid "ZIP File" +msgstr "" + +#: editor/project_export.cpp +msgid "Godot Game Pack" +msgstr "" + +#: editor/project_export.cpp +msgid "Export templates for this platform are missing:" +msgstr "" + +#: editor/project_export.cpp +msgid "Manage Export Templates" +msgstr "" + +#: editor/project_export.cpp +msgid "Export With Debug" +msgstr "" + +#: editor/project_manager.cpp +msgid "The path specified doesn't exist." +msgstr "" + +#: editor/project_manager.cpp +msgid "Error opening package file (it's not in ZIP format)." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Invalid \".zip\" project file; it doesn't contain a \"project.godot\" file." +msgstr "" + +#: editor/project_manager.cpp +msgid "Please choose an empty folder." +msgstr "" + +#: editor/project_manager.cpp +msgid "Please choose a \"project.godot\" or \".zip\" file." +msgstr "" + +#: editor/project_manager.cpp +msgid "This directory already contains a Godot project." +msgstr "" + +#: editor/project_manager.cpp +msgid "New Game Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Imported Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Invalid Project Name." +msgstr "" + +#: editor/project_manager.cpp +msgid "Couldn't create folder." +msgstr "" + +#: editor/project_manager.cpp +msgid "There is already a folder in this path with the specified name." +msgstr "" + +#: editor/project_manager.cpp +msgid "It would be a good idea to name your project." +msgstr "" + +#: editor/project_manager.cpp +msgid "Invalid project path (changed anything?)." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Couldn't load project.godot in project path (error %d). It may be missing or " +"corrupted." +msgstr "" + +#: editor/project_manager.cpp +msgid "Couldn't edit project.godot in project path." +msgstr "" + +#: editor/project_manager.cpp +msgid "Couldn't create project.godot in project path." +msgstr "" + +#: editor/project_manager.cpp +msgid "Rename Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Import Existing Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Import & Edit" +msgstr "" + +#: editor/project_manager.cpp +msgid "Create New Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Create & Edit" +msgstr "" + +#: editor/project_manager.cpp +msgid "Install Project:" +msgstr "" + +#: editor/project_manager.cpp +msgid "Install & Edit" +msgstr "" + +#: editor/project_manager.cpp +msgid "Project Name:" +msgstr "" + +#: editor/project_manager.cpp +msgid "Project Path:" +msgstr "" + +#: editor/project_manager.cpp +msgid "Project Installation Path:" +msgstr "" + +#: editor/project_manager.cpp +msgid "Renderer:" +msgstr "" + +#: editor/project_manager.cpp +msgid "OpenGL ES 3.0" +msgstr "" + +#: editor/project_manager.cpp +msgid "Not supported by your GPU drivers." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Higher visual quality\n" +"All features available\n" +"Incompatible with older hardware\n" +"Not recommended for web games" +msgstr "" + +#: editor/project_manager.cpp +msgid "OpenGL ES 2.0" +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Lower visual quality\n" +"Some features not available\n" +"Works on most hardware\n" +"Recommended for web games" +msgstr "" + +#: editor/project_manager.cpp +msgid "Renderer can be changed later, but scenes may need to be adjusted." +msgstr "" + +#: editor/project_manager.cpp +msgid "Unnamed Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Missing Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Error: Project is missing on the filesystem." +msgstr "" + +#: editor/project_manager.cpp +msgid "Can't open project at '%s'." +msgstr "" + +#: editor/project_manager.cpp +msgid "Are you sure to open more than one project?" +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"The following project settings file does not specify the version of Godot " +"through which it was created.\n" +"\n" +"%s\n" +"\n" +"If you proceed with opening it, it will be converted to Godot's current " +"configuration file format.\n" +"Warning: You won't be able to open the project with previous versions of the " +"engine anymore." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"The following project settings file was generated by an older engine " +"version, and needs to be converted for this version:\n" +"\n" +"%s\n" +"\n" +"Do you want to convert it?\n" +"Warning: You won't be able to open the project with previous versions of the " +"engine anymore." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"The project settings were created by a newer engine version, whose settings " +"are not compatible with this version." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Can't run project: no main scene defined.\n" +"Please edit the project and set the main scene in the Project Settings under " +"the \"Application\" category." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Can't run project: Assets need to be imported.\n" +"Please edit the project to trigger the initial import." +msgstr "" + +#: editor/project_manager.cpp +msgid "Are you sure to run %d projects at once?" +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Remove %d projects from the list?\n" +"The project folders' contents won't be modified." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Remove this project from the list?\n" +"The project folder's contents won't be modified." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Remove all missing projects from the list?\n" +"The project folders' contents won't be modified." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Language changed.\n" +"The interface will update after restarting the editor or project manager." +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"Are you sure to scan %s folders for existing Godot projects?\n" +"This could take a while." +msgstr "" + +#. TRANSLATORS: This refers to the application where users manage their Godot projects. +#: editor/project_manager.cpp +msgid "Project Manager" +msgstr "" + +#: editor/project_manager.cpp +msgid "Projects" +msgstr "" + +#: editor/project_manager.cpp +msgid "Loading, please wait..." +msgstr "" + +#: editor/project_manager.cpp +msgid "Last Modified" +msgstr "" + +#: editor/project_manager.cpp +msgid "Scan" +msgstr "" + +#: editor/project_manager.cpp +msgid "Select a Folder to Scan" +msgstr "" + +#: editor/project_manager.cpp +msgid "New Project" +msgstr "" + +#: editor/project_manager.cpp +msgid "Remove Missing" +msgstr "" + +#: editor/project_manager.cpp +msgid "Templates" +msgstr "" + +#: editor/project_manager.cpp +msgid "Restart Now" +msgstr "" + +#: editor/project_manager.cpp +msgid "Can't run project" +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"You currently don't have any projects.\n" +"Would you like to explore official example projects in the Asset Library?" +msgstr "" + +#: editor/project_manager.cpp +msgid "" +"The search box filters projects by name and last path component.\n" +"To filter projects by name and full path, the query must contain at least " +"one `/` character." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Key " +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Joy Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Joy Axis" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Mouse Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "" +"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or " +"'\"'" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "An action with the name '%s' already exists." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Rename Input Action Event" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Change Action deadzone" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Add Input Action Event" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "All Devices" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Device" +msgstr "" + +#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp +msgid "Press a Key..." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Mouse Button Index:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Left Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Right Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Middle Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Wheel Up Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Wheel Down Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Wheel Left Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Wheel Right Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "X Button 1" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "X Button 2" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Joypad Axis Index:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Axis" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Joypad Button Index:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Erase Input Action" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Erase Input Action Event" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Add Event" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Button" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Left Button." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Right Button." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Middle Button." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Wheel Up." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Wheel Down." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Add Global Property" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Select a setting item first!" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "No property '%s' exists." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Setting '%s' is internal, and it can't be deleted." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Delete Item" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "" +"Invalid action name. It cannot be empty nor contain '/', ':', '=', '\\' or " +"'\"'." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Add Input Action" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Error saving settings." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Settings saved OK." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Moved Input Action Event" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Override for Feature" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Add Translation" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Remove Translation" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Add Remapped Path" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Resource Remap Add Remap" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Change Resource Remap Language" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Remove Resource Remap" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Remove Resource Remap Option" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Changed Locale Filter" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Changed Locale Filter Mode" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Project Settings (project.godot)" +msgstr "" + +#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp +msgid "General" +msgstr "Төп" + +#: editor/project_settings_editor.cpp +msgid "Override For..." +msgstr "" + +#: editor/project_settings_editor.cpp editor/settings_config_dialog.cpp +msgid "The editor must be restarted for changes to take effect." +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Input Map" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Action:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Action" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Deadzone" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Device:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Index:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Localization" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Translations" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Translations:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Remaps" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Resources:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Remaps by Locale:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Locale" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Locales Filter" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Show All Locales" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Show Selected Locales Only" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Filter mode:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Locales:" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "AutoLoad" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Plugins" +msgstr "" + +#: editor/project_settings_editor.cpp +msgid "Import Defaults" +msgstr "" + +#: editor/property_editor.cpp +msgid "Preset..." +msgstr "" + +#: editor/property_editor.cpp +msgid "Zero" +msgstr "" + +#: editor/property_editor.cpp +msgid "Easing In-Out" +msgstr "" + +#: editor/property_editor.cpp +msgid "Easing Out-In" +msgstr "" + +#: editor/property_editor.cpp +msgid "File..." +msgstr "" + +#: editor/property_editor.cpp +msgid "Dir..." +msgstr "" + +#: editor/property_editor.cpp +msgid "Assign" +msgstr "" + +#: editor/property_editor.cpp +msgid "Select Node" +msgstr "" + +#: editor/property_editor.cpp +msgid "Error loading file: Not a resource!" +msgstr "" + +#: editor/property_editor.cpp +msgid "Pick a Node" +msgstr "" + +#: editor/property_editor.cpp +msgid "Bit %d, val %d." +msgstr "" + +#: editor/property_selector.cpp +msgid "Select Property" +msgstr "" + +#: editor/property_selector.cpp +msgid "Select Virtual Method" +msgstr "" + +#: editor/property_selector.cpp +msgid "Select Method" +msgstr "" + +#: editor/rename_dialog.cpp editor/scene_tree_dock.cpp +msgid "Batch Rename" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Replace:" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Prefix:" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Suffix:" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Use Regular Expressions" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Advanced Options" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Substitute" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Node name" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Node's parent name, if available" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Node type" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Current scene name" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Root node name" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "" +"Sequential integer counter.\n" +"Compare counter options." +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Per-level Counter" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "If set, the counter restarts for each group of child nodes." +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Initial value for the counter" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Step" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Amount by which counter is incremented for each node" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Padding" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "" +"Minimum number of digits for the counter.\n" +"Missing digits are padded with leading zeros." +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Post-Process" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Keep" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "PascalCase to snake_case" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "snake_case to PascalCase" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Case" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "To Lowercase" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "To Uppercase" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Reset" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "Regular Expression Error:" +msgstr "" + +#: editor/rename_dialog.cpp +msgid "At character %s" +msgstr "" + +#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp +msgid "Reparent Node" +msgstr "" + +#: editor/reparent_dialog.cpp +msgid "Reparent Location (Select new Parent):" +msgstr "" + +#: editor/reparent_dialog.cpp +msgid "Keep Global Transform" +msgstr "" + +#: editor/reparent_dialog.cpp editor/scene_tree_dock.cpp +msgid "Reparent" +msgstr "" + +#: editor/run_settings_dialog.cpp +msgid "Run Mode:" +msgstr "" + +#: editor/run_settings_dialog.cpp +msgid "Current Scene" +msgstr "" + +#: editor/run_settings_dialog.cpp +msgid "Main Scene" +msgstr "" + +#: editor/run_settings_dialog.cpp +msgid "Main Scene Arguments:" +msgstr "" + +#: editor/run_settings_dialog.cpp +msgid "Scene Run Settings" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "No parent to instance the scenes at." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Error loading scene from %s" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"Cannot instance the scene '%s' because the current scene exists within one " +"of its nodes." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Instance Scene(s)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Replace with Branch Scene" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Instance Child Scene" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Can't paste root node into the same scene." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Paste Node(s)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Detach Script" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "This operation can't be done on the tree root." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Move Node In Parent" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Move Nodes In Parent" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Duplicate Node(s)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Can't reparent nodes in inherited scenes, order of nodes can't change." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Node must belong to the edited scene to become root." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Instantiated scenes can't become root" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Make node as Root" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Delete %d nodes and any children?" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Delete %d nodes?" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Delete the root node \"%s\"?" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Delete node \"%s\" and its children?" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Delete node \"%s\"?" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Can not perform with the root node." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "This operation can't be done on instanced scenes." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Save New Scene As..." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"Disabling \"editable_instance\" will cause all properties of the node to be " +"reverted to their default." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"Enabling \"Load As Placeholder\" will disable \"Editable Children\" and " +"cause all properties of the node to be reverted to their default." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Make Local" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "New Scene Root" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Create Root Node:" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "2D Scene" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "3D Scene" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "User Interface" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Other Node" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Can't operate on nodes from a foreign scene!" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Can't operate on nodes the current scene inherits from!" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Attach Script" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Cut Node(s)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Remove Node(s)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Change type of node(s)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"Couldn't save new scene. Likely dependencies (instances) couldn't be " +"satisfied." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Error saving scene." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Error duplicating scene to save it." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Sub-Resources" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Clear Inheritance" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Editable Children" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Load As Placeholder" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Open Documentation" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"Cannot attach a script: there are no languages registered.\n" +"This is probably because this editor was built with all language modules " +"disabled." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Add Child Node" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Expand/Collapse All" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Change Type" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Reparent to New Node" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Make Scene Root" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Merge From Scene" +msgstr "" + +#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp +msgid "Save Branch as Scene" +msgstr "" + +#: editor/scene_tree_dock.cpp editor/script_editor_debugger.cpp +msgid "Copy Node Path" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Delete (No Confirm)" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Add/Create a New Node." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"Instance a scene file as a Node. Creates an inherited scene if no root node " +"exists." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Attach a new or existing script to the selected node." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Detach the script from the selected node." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Remote" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "" +"If selected, the Remote scene tree dock will cause the project to stutter " +"every time it updates.\n" +"Switch back to the Local scene tree dock to improve performance." +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Local" +msgstr "" + +#: editor/scene_tree_dock.cpp +msgid "Clear Inheritance? (No Undo!)" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Toggle Visible" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Unlock Node" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Button Group" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "(Connecting From)" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Node configuration warning:" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "" +"Node has %s connection(s) and %s group(s).\n" +"Click to show signals dock." +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "" +"Node has %s connection(s).\n" +"Click to show signals dock." +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "" +"Node is in %s group(s).\n" +"Click to show groups dock." +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Open Script:" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "" +"Node is locked.\n" +"Click to unlock it." +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "" +"Children are not selectable.\n" +"Click to make selectable." +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Toggle Visibility" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "" +"AnimationPlayer is pinned.\n" +"Click to unpin." +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Invalid node name, the following characters are not allowed:" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Rename Node" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Scene Tree (Nodes):" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Node Configuration Warning!" +msgstr "" + +#: editor/scene_tree_editor.cpp +msgid "Select a Node" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Path is empty." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Filename is empty." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Path is not local." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Invalid base path." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "A directory with the same name exists." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "File does not exist." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Invalid extension." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Wrong extension chosen." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Error loading template '%s'" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Error - Could not create script in filesystem." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Error loading script from %s" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Overrides" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "N/A" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Open Script / Choose Location" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Open Script" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "File exists, it will be reused." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Invalid path." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Invalid class name." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Invalid inherited parent name or path." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Script path/name is valid." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Allowed: a-z, A-Z, 0-9, _ and ." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Built-in script (into scene file)." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Will create a new script file." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Will load an existing script file." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Script file already exists." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "" +"Note: Built-in scripts have some limitations and can't be edited using an " +"external editor." +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Class Name:" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Template:" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Built-in Script:" +msgstr "" + +#: editor/script_create_dialog.cpp +msgid "Attach Node Script" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Remote " +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Bytes:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Warning:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Error:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "C++ Error" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "C++ Error:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "C++ Source" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Source:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "C++ Source:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Stack Trace" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Errors" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Child process connected." +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Copy Error" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Video RAM" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Skip Breakpoints" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Inspect Previous Instance" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Inspect Next Instance" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Stack Frames" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Profiler" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Network Profiler" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Monitor" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Value" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Monitors" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Pick one or more items from the list to display the graph." +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "List of Video Memory Usage by Resource:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Total:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Export list to a CSV file" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Resource Path" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Type" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Format" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Usage" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Misc" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Clicked Control:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Clicked Control Type:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Live Edit Root:" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Set From Tree" +msgstr "" + +#: editor/script_editor_debugger.cpp +msgid "Export measures as CSV" +msgstr "" + +#: editor/settings_config_dialog.cpp +msgid "Erase Shortcut" +msgstr "" + +#: editor/settings_config_dialog.cpp +msgid "Restore Shortcut" +msgstr "" + +#: editor/settings_config_dialog.cpp +msgid "Change Shortcut" +msgstr "" + +#: editor/settings_config_dialog.cpp +msgid "Editor Settings" +msgstr "" + +#: editor/settings_config_dialog.cpp +msgid "Shortcuts" +msgstr "" + +#: editor/settings_config_dialog.cpp +msgid "Binding" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Light Radius" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change AudioStreamPlayer3D Emission Angle" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Camera FOV" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Camera Size" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Notifier AABB" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Particles AABB" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Probe Extents" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp +msgid "Change Sphere Shape Radius" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp +msgid "Change Box Shape Extents" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Capsule Shape Radius" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Capsule Shape Height" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Cylinder Shape Radius" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Cylinder Shape Height" +msgstr "" + +#: editor/spatial_editor_gizmos.cpp +msgid "Change Ray Shape Length" +msgstr "" + +#: modules/csg/csg_gizmos.cpp +msgid "Change Cylinder Radius" +msgstr "" + +#: modules/csg/csg_gizmos.cpp +msgid "Change Cylinder Height" +msgstr "" + +#: modules/csg/csg_gizmos.cpp +msgid "Change Torus Inner Radius" +msgstr "" + +#: modules/csg/csg_gizmos.cpp +msgid "Change Torus Outer Radius" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Select the dynamic library for this entry" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Select dependencies of the library for this entry" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Remove current entry" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Double click to create a new entry" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Platform:" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Platform" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Dynamic Library" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "Add an architecture entry" +msgstr "" + +#: modules/gdnative/gdnative_library_editor_plugin.cpp +msgid "GDNativeLibrary" +msgstr "" + +#: modules/gdnative/gdnative_library_singleton_editor.cpp +msgid "Enabled GDNative Singleton" +msgstr "" + +#: modules/gdnative/gdnative_library_singleton_editor.cpp +msgid "Disabled GDNative Singleton" +msgstr "" + +#: modules/gdnative/gdnative_library_singleton_editor.cpp +msgid "Library" +msgstr "" + +#: modules/gdnative/gdnative_library_singleton_editor.cpp +msgid "Libraries: " +msgstr "" + +#: modules/gdnative/register_types.cpp +msgid "GDNative" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Step argument is zero!" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Not a script with an instance" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Not based on a script" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Not based on a resource file" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Invalid instance dictionary format (missing @path)" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Invalid instance dictionary format (can't load script at @path)" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Invalid instance dictionary format (invalid script at @path)" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Invalid instance dictionary (invalid subclasses)" +msgstr "" + +#: modules/gdscript/gdscript_functions.cpp +msgid "Object can't provide a length." +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Next Plane" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Previous Plane" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Plane:" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Next Floor" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Previous Floor" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Floor:" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "GridMap Delete Selection" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "GridMap Fill Selection" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "GridMap Paste Selection" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "GridMap Paint" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Grid Map" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Snap View" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Clip Disabled" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Clip Above" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Clip Below" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Edit X Axis" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Edit Y Axis" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Edit Z Axis" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Rotate X" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Rotate Y" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Rotate Z" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Back Rotate X" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Back Rotate Y" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Back Rotate Z" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Cursor Clear Rotation" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Paste Selects" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Clear Selection" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Fill Selection" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "GridMap Settings" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Pick Distance:" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Filter meshes" +msgstr "" + +#: modules/gridmap/grid_map_editor_plugin.cpp +msgid "Give a MeshLibrary resource to this GridMap to use its meshes." +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Begin Bake" +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Preparing data structures" +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Generate buffers" +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Direct lighting" +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Indirect lighting" +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Post processing" +msgstr "" + +#: modules/lightmapper_cpu/lightmapper_cpu.cpp +msgid "Plotting lightmaps" +msgstr "" + +#: modules/mono/csharp_script.cpp +msgid "Class name can't be a reserved keyword" +msgstr "" + +#: modules/mono/mono_gd/gd_mono_utils.cpp +msgid "End of inner exception stack trace" +msgstr "" + +#: modules/recast/navigation_mesh_editor_plugin.cpp +msgid "Bake NavMesh" +msgstr "" + +#: modules/recast/navigation_mesh_editor_plugin.cpp +msgid "Clear the navigation mesh." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Setting up Configuration..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Calculating grid size..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Creating heightfield..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Marking walkable triangles..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Constructing compact heightfield..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Eroding walkable area..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Partitioning..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Creating contours..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Creating polymesh..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Converting to native navigation mesh..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Navigation Mesh Generator Setup:" +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Parsing Geometry..." +msgstr "" + +#: modules/recast/navigation_mesh_generator.cpp +msgid "Done!" +msgstr "" + +#: modules/visual_script/visual_script.cpp +msgid "" +"A node yielded without working memory, please read the docs on how to yield " +"properly!" +msgstr "" + +#: modules/visual_script/visual_script.cpp +msgid "" +"Node yielded, but did not return a function state in the first working " +"memory." +msgstr "" + +#: modules/visual_script/visual_script.cpp +msgid "" +"Return value must be assigned to first element of node working memory! Fix " +"your node please." +msgstr "" + +#: modules/visual_script/visual_script.cpp +msgid "Node returned an invalid sequence output: " +msgstr "" + +#: modules/visual_script/visual_script.cpp +msgid "Found sequence bit but not the node in the stack, report bug!" +msgstr "" + +#: modules/visual_script/visual_script.cpp +msgid "Stack overflow with stack depth: " +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Signal Arguments" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Argument Type" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Argument name" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Set Variable Default Value" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Set Variable Type" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Input Port" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Output Port" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Override an existing built-in function." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Create a new function." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Variables:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Create a new variable." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Signals:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Create a new signal." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Name is not a valid identifier:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Name already in use by another func/var/signal:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Rename Function" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Rename Variable" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Rename Signal" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Function" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Delete input port" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Variable" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Signal" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove Input Port" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove Output Port" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Expression" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove VisualScript Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Duplicate VisualScript Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Hold %s to drop a Getter. Hold Shift to drop a generic signature." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Hold %s to drop a simple reference to the node." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Hold Ctrl to drop a simple reference to the node." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Hold %s to drop a Variable Setter." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Hold Ctrl to drop a Variable Setter." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Preload Node" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Node(s) From Tree" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "" +"Can't drop properties because script '%s' is not used in this scene.\n" +"Drop holding 'Shift' to just copy the signature." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Getter Property" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Setter Property" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Base Type" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Move Node(s)" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove VisualScript Node" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Connect Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Disconnect Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Connect Node Data" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Connect Node Sequence" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Script already has function '%s'" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Input Value" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Resize Comment" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Can't copy the function node." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Clipboard is empty!" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Paste VisualScript Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Can't create function with a function node." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Can't create function of nodes from nodes of multiple functions." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Select at least one node with sequence port." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Try to only have one sequence input in selection." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Create Function" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove Function" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove Variable" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Editing Variable:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Remove Signal" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Editing Signal:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Make Tool:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Members:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Change Base Type:" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Nodes..." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Add Function..." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "function_name" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Select or create a function to edit its graph." +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Delete Selected" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Find Node Type" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Copy Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Cut Nodes" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Make Function" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Refresh Graph" +msgstr "" + +#: modules/visual_script/visual_script_editor.cpp +msgid "Edit Member" +msgstr "" + +#: modules/visual_script/visual_script_flow_control.cpp +msgid "Input type not iterable: " +msgstr "" + +#: modules/visual_script/visual_script_flow_control.cpp +msgid "Iterator became invalid" +msgstr "" + +#: modules/visual_script/visual_script_flow_control.cpp +msgid "Iterator became invalid: " +msgstr "" + +#: modules/visual_script/visual_script_func_nodes.cpp +msgid "Invalid index property name." +msgstr "" + +#: modules/visual_script/visual_script_func_nodes.cpp +msgid "Base object is not a Node!" +msgstr "" + +#: modules/visual_script/visual_script_func_nodes.cpp +msgid "Path does not lead Node!" +msgstr "" + +#: modules/visual_script/visual_script_func_nodes.cpp +msgid "Invalid index property name '%s' in node %s." +msgstr "" + +#: modules/visual_script/visual_script_nodes.cpp +msgid ": Invalid argument of type: " +msgstr "" + +#: modules/visual_script/visual_script_nodes.cpp +msgid ": Invalid arguments: " +msgstr "" + +#: modules/visual_script/visual_script_nodes.cpp +msgid "VariableGet not found in script: " +msgstr "" + +#: modules/visual_script/visual_script_nodes.cpp +msgid "VariableSet not found in script: " +msgstr "" + +#: modules/visual_script/visual_script_nodes.cpp +msgid "Custom node has no _step() method, can't process graph." +msgstr "" + +#: modules/visual_script/visual_script_nodes.cpp +msgid "" +"Invalid return value from _step(), must be integer (seq out), or string " +"(error)." +msgstr "" + +#: modules/visual_script/visual_script_property_selector.cpp +msgid "Search VisualScript" +msgstr "" + +#: modules/visual_script/visual_script_property_selector.cpp +msgid "Get %s" +msgstr "" + +#: modules/visual_script/visual_script_property_selector.cpp +msgid "Set %s" +msgstr "" + +#: platform/android/export/export.cpp +msgid "Package name is missing." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Package segments must be of non-zero length." +msgstr "" + +#: platform/android/export/export.cpp +msgid "The character '%s' is not allowed in Android application package names." +msgstr "" + +#: platform/android/export/export.cpp +msgid "A digit cannot be the first character in a package segment." +msgstr "" + +#: platform/android/export/export.cpp +msgid "The character '%s' cannot be the first character in a package segment." +msgstr "" + +#: platform/android/export/export.cpp +msgid "The package must have at least one '.' separator." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Select device from the list" +msgstr "" + +#: platform/android/export/export.cpp +msgid "Unable to find the 'apksigner' tool." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Android build template not installed in the project. Install it from the " +"Project menu." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Debug keystore not configured in the Editor Settings nor in the preset." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Release keystore incorrectly configured in the export preset." +msgstr "" + +#: platform/android/export/export.cpp +msgid "A valid Android SDK path is required in Editor Settings." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Invalid Android SDK path in Editor Settings." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Missing 'platform-tools' directory!" +msgstr "" + +#: platform/android/export/export.cpp +msgid "Unable to find Android SDK platform-tools' adb command." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Please check in the Android SDK directory specified in Editor Settings." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Missing 'build-tools' directory!" +msgstr "" + +#: platform/android/export/export.cpp +msgid "Unable to find Android SDK build-tools' apksigner command." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Invalid public key for APK expansion." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Invalid package name:" +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Invalid \"GodotPaymentV3\" module included in the \"android/modules\" " +"project setting (changed in Godot 3.2.2).\n" +msgstr "" + +#: platform/android/export/export.cpp +msgid "\"Use Custom Build\" must be enabled to use the plugins." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR" +"\"." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"." +msgstr "" + +#: platform/android/export/export.cpp +msgid "\"Export AAB\" is only valid when \"Use Custom Build\" is enabled." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Invalid filename! Android App Bundle requires the *.aab extension." +msgstr "" + +#: platform/android/export/export.cpp +msgid "APK Expansion not compatible with Android App Bundle." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Invalid filename! Android APK requires the *.apk extension." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Trying to build from a custom built template, but no version info for it " +"exists. Please reinstall from the 'Project' menu." +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Android build version mismatch:\n" +" Template installed: %s\n" +" Godot Version: %s\n" +"Please reinstall Android build template from 'Project' menu." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Building Android Project (gradle)" +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Building of Android project failed, check output for the error.\n" +"Alternatively visit docs.godotengine.org for Android build documentation." +msgstr "" + +#: platform/android/export/export.cpp +msgid "Moving output" +msgstr "" + +#: platform/android/export/export.cpp +msgid "" +"Unable to copy and rename export file, check gradle project directory for " +"outputs." +msgstr "" + +#: platform/iphone/export/export.cpp +msgid "Identifier is missing." +msgstr "" + +#: platform/iphone/export/export.cpp +msgid "The character '%s' is not allowed in Identifier." +msgstr "" + +#: platform/iphone/export/export.cpp +msgid "App Store Team ID not specified - cannot configure the project." +msgstr "" + +#: platform/iphone/export/export.cpp +msgid "Invalid Identifier:" +msgstr "" + +#: platform/iphone/export/export.cpp +msgid "Required icon is not specified in the preset." +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Stop HTTP Server" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Run in Browser" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Run exported HTML in the system's default browser." +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Could not write file:" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Could not open template for export:" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Invalid export template:" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Could not read custom HTML shell:" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Could not read boot splash image file:" +msgstr "" + +#: platform/javascript/export/export.cpp +msgid "Using default boot splash image." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid package short name." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid package unique name." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid package publisher display name." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid product GUID." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid publisher GUID." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid background color." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid Store Logo image dimensions (should be 50x50)." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid square 44x44 logo image dimensions (should be 44x44)." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid square 71x71 logo image dimensions (should be 71x71)." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid square 150x150 logo image dimensions (should be 150x150)." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid square 310x310 logo image dimensions (should be 310x310)." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid wide 310x150 logo image dimensions (should be 310x150)." +msgstr "" + +#: platform/uwp/export/export.cpp +msgid "Invalid splash screen image dimensions (should be 620x300)." +msgstr "" + +#: scene/2d/animated_sprite.cpp +msgid "" +"A SpriteFrames resource must be created or set in the \"Frames\" property in " +"order for AnimatedSprite to display frames." +msgstr "" + +#: scene/2d/canvas_modulate.cpp +msgid "" +"Only one visible CanvasModulate is allowed per scene (or set of instanced " +"scenes). The first created one will work, while the rest will be ignored." +msgstr "" + +#: scene/2d/collision_object_2d.cpp +msgid "" +"This node has no shape, so it can't collide or interact with other objects.\n" +"Consider adding a CollisionShape2D or CollisionPolygon2D as a child to " +"define its shape." +msgstr "" + +#: scene/2d/collision_polygon_2d.cpp +msgid "" +"CollisionPolygon2D only serves to provide a collision shape to a " +"CollisionObject2D derived node. Please only use it as a child of Area2D, " +"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape." +msgstr "" + +#: scene/2d/collision_polygon_2d.cpp +msgid "An empty CollisionPolygon2D has no effect on collision." +msgstr "" + +#: scene/2d/collision_polygon_2d.cpp +msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode." +msgstr "" + +#: scene/2d/collision_polygon_2d.cpp +msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode." +msgstr "" + +#: scene/2d/collision_shape_2d.cpp +msgid "" +"CollisionShape2D only serves to provide a collision shape to a " +"CollisionObject2D derived node. Please only use it as a child of Area2D, " +"StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape." +msgstr "" + +#: scene/2d/collision_shape_2d.cpp +msgid "" +"A shape must be provided for CollisionShape2D to function. Please create a " +"shape resource for it!" +msgstr "" + +#: scene/2d/collision_shape_2d.cpp +msgid "" +"Polygon-based shapes are not meant be used nor edited directly through the " +"CollisionShape2D node. Please use the CollisionPolygon2D node instead." +msgstr "" + +#: scene/2d/cpu_particles_2d.cpp +msgid "" +"CPUParticles2D animation requires the usage of a CanvasItemMaterial with " +"\"Particles Animation\" enabled." +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node B must be a PhysicsBody2D" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Joint is not connected to two PhysicsBody2Ds" +msgstr "" + +#: scene/2d/joints_2d.cpp +msgid "Node A and Node B must be different PhysicsBody2Ds" +msgstr "" + +#: scene/2d/light_2d.cpp +msgid "" +"A texture with the shape of the light must be supplied to the \"Texture\" " +"property." +msgstr "" + +#: scene/2d/light_occluder_2d.cpp +msgid "" +"An occluder polygon must be set (or drawn) for this occluder to take effect." +msgstr "" + +#: scene/2d/light_occluder_2d.cpp +msgid "The occluder polygon for this occluder is empty. Please draw a polygon." +msgstr "" + +#: scene/2d/navigation_polygon.cpp +msgid "" +"A NavigationPolygon resource must be set or created for this node to work. " +"Please set a property or draw a polygon." +msgstr "" + +#: scene/2d/navigation_polygon.cpp +msgid "" +"NavigationPolygonInstance must be a child or grandchild to a Navigation2D " +"node. It only provides navigation data." +msgstr "" + +#: scene/2d/parallax_layer.cpp +msgid "" +"ParallaxLayer node only works when set as child of a ParallaxBackground node." +msgstr "" + +#: scene/2d/particles_2d.cpp +msgid "" +"GPU-based particles are not supported by the GLES2 video driver.\n" +"Use the CPUParticles2D node instead. You can use the \"Convert to " +"CPUParticles\" option for this purpose." +msgstr "" + +#: scene/2d/particles_2d.cpp scene/3d/particles.cpp +msgid "" +"A material to process the particles is not assigned, so no behavior is " +"imprinted." +msgstr "" + +#: scene/2d/particles_2d.cpp +msgid "" +"Particles2D animation requires the usage of a CanvasItemMaterial with " +"\"Particles Animation\" enabled." +msgstr "" + +#: scene/2d/path_2d.cpp +msgid "PathFollow2D only works when set as a child of a Path2D node." +msgstr "" + +#: scene/2d/physics_body_2d.cpp +msgid "" +"Size changes to RigidBody2D (in character or rigid modes) will be overridden " +"by the physics engine when running.\n" +"Change the size in children collision shapes instead." +msgstr "" + +#: scene/2d/remote_transform_2d.cpp +msgid "Path property must point to a valid Node2D node to work." +msgstr "" + +#: scene/2d/skeleton_2d.cpp +msgid "This Bone2D chain should end at a Skeleton2D node." +msgstr "" + +#: scene/2d/skeleton_2d.cpp +msgid "A Bone2D only works with a Skeleton2D or another Bone2D as parent node." +msgstr "" + +#: scene/2d/skeleton_2d.cpp +msgid "" +"This bone lacks a proper REST pose. Go to the Skeleton2D node and set one." +msgstr "" + +#: scene/2d/tile_map.cpp +msgid "" +"TileMap with Use Parent on needs a parent CollisionObject2D to give shapes " +"to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, " +"KinematicBody2D, etc. to give them a shape." +msgstr "" + +#: scene/2d/visibility_notifier_2d.cpp +msgid "" +"VisibilityEnabler2D works best when used with the edited scene root directly " +"as parent." +msgstr "" + +#: scene/3d/arvr_nodes.cpp +msgid "ARVRCamera must have an ARVROrigin node as its parent." +msgstr "" + +#: scene/3d/arvr_nodes.cpp +msgid "ARVRController must have an ARVROrigin node as its parent." +msgstr "" + +#: scene/3d/arvr_nodes.cpp +msgid "" +"The controller ID must not be 0 or this controller won't be bound to an " +"actual controller." +msgstr "" + +#: scene/3d/arvr_nodes.cpp +msgid "ARVRAnchor must have an ARVROrigin node as its parent." +msgstr "" + +#: scene/3d/arvr_nodes.cpp +msgid "" +"The anchor ID must not be 0 or this anchor won't be bound to an actual " +"anchor." +msgstr "" + +#: scene/3d/arvr_nodes.cpp +msgid "ARVROrigin requires an ARVRCamera child node." +msgstr "" + +#: scene/3d/baked_lightmap.cpp +msgid "Finding meshes and lights" +msgstr "" + +#: scene/3d/baked_lightmap.cpp +msgid "Preparing geometry (%d/%d)" +msgstr "" + +#: scene/3d/baked_lightmap.cpp +msgid "Preparing environment" +msgstr "" + +#: scene/3d/baked_lightmap.cpp +msgid "Generating capture" +msgstr "" + +#: scene/3d/baked_lightmap.cpp +msgid "Saving lightmaps" +msgstr "" + +#: scene/3d/baked_lightmap.cpp +msgid "Done" +msgstr "" + +#: scene/3d/collision_object.cpp +msgid "" +"This node has no shape, so it can't collide or interact with other objects.\n" +"Consider adding a CollisionShape or CollisionPolygon as a child to define " +"its shape." +msgstr "" + +#: scene/3d/collision_polygon.cpp +msgid "" +"CollisionPolygon only serves to provide a collision shape to a " +"CollisionObject derived node. Please only use it as a child of Area, " +"StaticBody, RigidBody, KinematicBody, etc. to give them a shape." +msgstr "" + +#: scene/3d/collision_polygon.cpp +msgid "An empty CollisionPolygon has no effect on collision." +msgstr "" + +#: scene/3d/collision_shape.cpp +msgid "" +"CollisionShape only serves to provide a collision shape to a CollisionObject " +"derived node. Please only use it as a child of Area, StaticBody, RigidBody, " +"KinematicBody, etc. to give them a shape." +msgstr "" + +#: scene/3d/collision_shape.cpp +msgid "" +"A shape must be provided for CollisionShape to function. Please create a " +"shape resource for it." +msgstr "" + +#: scene/3d/collision_shape.cpp +msgid "" +"Plane shapes don't work well and will be removed in future versions. Please " +"don't use them." +msgstr "" + +#: scene/3d/collision_shape.cpp +msgid "" +"ConcavePolygonShape doesn't support RigidBody in another mode than static." +msgstr "" + +#: scene/3d/cpu_particles.cpp +msgid "Nothing is visible because no mesh has been assigned." +msgstr "" + +#: scene/3d/cpu_particles.cpp +msgid "" +"CPUParticles animation requires the usage of a SpatialMaterial whose " +"Billboard Mode is set to \"Particle Billboard\"." +msgstr "" + +#: scene/3d/gi_probe.cpp +msgid "Plotting Meshes" +msgstr "" + +#: scene/3d/gi_probe.cpp +msgid "Finishing Plot" +msgstr "" + +#: scene/3d/gi_probe.cpp +msgid "" +"GIProbes are not supported by the GLES2 video driver.\n" +"Use a BakedLightmap instead." +msgstr "" + +#: scene/3d/light.cpp +msgid "A SpotLight with an angle wider than 90 degrees cannot cast shadows." +msgstr "" + +#: scene/3d/navigation_mesh.cpp +msgid "A NavigationMesh resource must be set or created for this node to work." +msgstr "" + +#: scene/3d/navigation_mesh.cpp +msgid "" +"NavigationMeshInstance must be a child or grandchild to a Navigation node. " +"It only provides navigation data." +msgstr "" + +#: scene/3d/particles.cpp +msgid "" +"GPU-based particles are not supported by the GLES2 video driver.\n" +"Use the CPUParticles node instead. You can use the \"Convert to CPUParticles" +"\" option for this purpose." +msgstr "" + +#: scene/3d/particles.cpp +msgid "" +"Nothing is visible because meshes have not been assigned to draw passes." +msgstr "" + +#: scene/3d/particles.cpp +msgid "" +"Particles animation requires the usage of a SpatialMaterial whose Billboard " +"Mode is set to \"Particle Billboard\"." +msgstr "" + +#: scene/3d/path.cpp +msgid "PathFollow only works when set as a child of a Path node." +msgstr "" + +#: scene/3d/path.cpp +msgid "" +"PathFollow's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its " +"parent Path's Curve resource." +msgstr "" + +#: scene/3d/physics_body.cpp +msgid "" +"Size changes to RigidBody (in character or rigid modes) will be overridden " +"by the physics engine when running.\n" +"Change the size in children collision shapes instead." +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node B must be a PhysicsBody" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Joint is not connected to any PhysicsBodies" +msgstr "" + +#: scene/3d/physics_joint.cpp +msgid "Node A and Node B must be different PhysicsBodies" +msgstr "" + +#: scene/3d/remote_transform.cpp +msgid "" +"The \"Remote Path\" property must point to a valid Spatial or Spatial-" +"derived node to work." +msgstr "" + +#: scene/3d/soft_body.cpp +msgid "This body will be ignored until you set a mesh." +msgstr "" + +#: scene/3d/soft_body.cpp +msgid "" +"Size changes to SoftBody will be overridden by the physics engine when " +"running.\n" +"Change the size in children collision shapes instead." +msgstr "" + +#: scene/3d/sprite_3d.cpp +msgid "" +"A SpriteFrames resource must be created or set in the \"Frames\" property in " +"order for AnimatedSprite3D to display frames." +msgstr "" + +#: scene/3d/vehicle_body.cpp +msgid "" +"VehicleWheel serves to provide a wheel system to a VehicleBody. Please use " +"it as a child of a VehicleBody." +msgstr "" + +#: scene/3d/world_environment.cpp +msgid "" +"WorldEnvironment requires its \"Environment\" property to contain an " +"Environment to have a visible effect." +msgstr "" + +#: scene/3d/world_environment.cpp +msgid "" +"Only one WorldEnvironment is allowed per scene (or set of instanced scenes)." +msgstr "" + +#: scene/3d/world_environment.cpp +msgid "" +"This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set " +"this environment's Background Mode to Canvas (for 2D scenes)." +msgstr "" + +#: scene/animation/animation_blend_tree.cpp +msgid "On BlendTree node '%s', animation not found: '%s'" +msgstr "" + +#: scene/animation/animation_blend_tree.cpp +msgid "Animation not found: '%s'" +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "In node '%s', invalid animation: '%s'." +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "Invalid animation: '%s'." +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "Nothing connected to input '%s' of node '%s'." +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "No root AnimationNode for the graph is set." +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "Path to an AnimationPlayer node containing animations is not set." +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "Path set for AnimationPlayer does not lead to an AnimationPlayer node." +msgstr "" + +#: scene/animation/animation_tree.cpp +msgid "The AnimationPlayer root node is not a valid node." +msgstr "" + +#: scene/animation/animation_tree_player.cpp +msgid "This node has been deprecated. Use AnimationTree instead." +msgstr "" + +#: scene/gui/color_picker.cpp +msgid "" +"Color: #%s\n" +"LMB: Set color\n" +"RMB: Remove preset" +msgstr "" + +#: scene/gui/color_picker.cpp +msgid "Pick a color from the editor window." +msgstr "" + +#: scene/gui/color_picker.cpp +msgid "HSV" +msgstr "" + +#: scene/gui/color_picker.cpp +msgid "Raw" +msgstr "" + +#: scene/gui/color_picker.cpp +msgid "Switch between hexadecimal and code values." +msgstr "" + +#: scene/gui/color_picker.cpp +msgid "Add current color as a preset." +msgstr "" + +#: scene/gui/container.cpp +msgid "" +"Container by itself serves no purpose unless a script configures its " +"children placement behavior.\n" +"If you don't intend to add a script, use a plain Control node instead." +msgstr "" + +#: scene/gui/control.cpp +msgid "" +"The Hint Tooltip won't be displayed as the control's Mouse Filter is set to " +"\"Ignore\". To solve this, set the Mouse Filter to \"Stop\" or \"Pass\"." +msgstr "" + +#: scene/gui/dialogs.cpp +msgid "Alert!" +msgstr "" + +#: scene/gui/dialogs.cpp +msgid "Please Confirm..." +msgstr "" + +#: scene/gui/file_dialog.cpp +msgid "Must use a valid extension." +msgstr "" + +#: scene/gui/graph_edit.cpp +msgid "Enable grid minimap." +msgstr "" + +#: scene/gui/popup.cpp +msgid "" +"Popups will hide by default unless you call popup() or any of the popup*() " +"functions. Making them visible for editing is fine, but they will hide upon " +"running." +msgstr "" + +#: scene/gui/range.cpp +msgid "If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0." +msgstr "" + +#: scene/gui/scroll_container.cpp +msgid "" +"ScrollContainer is intended to work with a single child control.\n" +"Use a container as child (VBox, HBox, etc.), or a Control and set the custom " +"minimum size manually." +msgstr "" + +#: scene/gui/tree.cpp +msgid "(Other)" +msgstr "" + +#: scene/main/scene_tree.cpp +msgid "" +"Default Environment as specified in Project Settings (Rendering -> " +"Environment -> Default Environment) could not be loaded." +msgstr "" + +#: scene/main/viewport.cpp +msgid "" +"This viewport is not set as render target. If you intend for it to display " +"its contents directly to the screen, make it a child of a Control so it can " +"obtain a size. Otherwise, make it a RenderTarget and assign its internal " +"texture to some node for display." +msgstr "" + +#: scene/main/viewport.cpp +msgid "Viewport size must be greater than 0 to render anything." +msgstr "" + +#: scene/resources/visual_shader_nodes.cpp +msgid "" +"The sampler port is connected but not used. Consider changing the source to " +"'SamplerPort'." +msgstr "" + +#: scene/resources/visual_shader_nodes.cpp +msgid "Invalid source for preview." +msgstr "" + +#: scene/resources/visual_shader_nodes.cpp +msgid "Invalid source for shader." +msgstr "" + +#: scene/resources/visual_shader_nodes.cpp +msgid "Invalid comparison function for that type." +msgstr "" + +#: servers/visual/shader_language.cpp +msgid "Assignment to function." +msgstr "" + +#: servers/visual/shader_language.cpp +msgid "Assignment to uniform." +msgstr "" + +#: servers/visual/shader_language.cpp +msgid "Varyings can only be assigned in vertex function." +msgstr "" + +#: servers/visual/shader_language.cpp +msgid "Constants cannot be modified." +msgstr "" diff --git a/editor/translations/tzm.po b/editor/translations/tzm.po index c06fa4f106..629220c426 100644 --- a/editor/translations/tzm.po +++ b/editor/translations/tzm.po @@ -1081,6 +1081,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11684,10 +11688,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/uk.po b/editor/translations/uk.po index 52a125fc02..5f0fe3d721 100644 --- a/editor/translations/uk.po +++ b/editor/translations/uk.po @@ -20,7 +20,7 @@ msgid "" msgstr "" "Project-Id-Version: Ukrainian (Godot Engine)\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2021-05-18 14:51+0000\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" "Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/" "godot/uk/>\n" @@ -30,7 +30,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1135,6 +1135,10 @@ msgstr "Змінити Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñловника" msgid "Thanks from the Godot community!" msgstr "СпаÑибі від Ñпільноти Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "Клацніть, щоб Ñкопіювати." + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Ðвтори Ñ€ÑƒÑˆÑ–Ñ Godot" @@ -12236,12 +12240,28 @@ msgstr "" "допомогою меню «Проєкт»." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" +"Має бути налаштовано діагноÑтику Ñховища ключів, діагноÑтику кориÑтувача ÐБО " +"діагноÑтику Ð¿Ð°Ñ€Ð¾Ð»Ñ ÐБО не налаштовано діагноÑтику жодного з цих компонентів." + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" "ÐÑ– у параметрах редактора, ні у шаблоні не налаштовано діагноÑтичне Ñховище " "ключів." #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Має бути налаштовано параметри Ñховища ключів випуÑку, кориÑтувача випуÑку Ñ– " +"Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð²Ð¸Ð¿ÑƒÑку або не налаштовано жоден з цих параметрів." + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" "У шаблоні екÑÐ¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð½ÐµÐ¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ð¾ налаштовано Ñховище ключів випуÑку." diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po index 19e41bb657..3af1eac2ef 100644 --- a/editor/translations/ur_PK.po +++ b/editor/translations/ur_PK.po @@ -1101,6 +1101,10 @@ msgstr "" msgid "Thanks from the Godot community!" msgstr "" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "" @@ -11992,10 +11996,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/vi.po b/editor/translations/vi.po index c532ba4f50..8a34f898b8 100644 --- a/editor/translations/vi.po +++ b/editor/translations/vi.po @@ -1124,6 +1124,10 @@ msgstr "Äổi giá trị từ Ä‘iển" msgid "Thanks from the Godot community!" msgstr "Cảm Æ¡n từ cá»™ng đồng Godot!" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Cá nhân đóng góp cá»§a Godot Engine" @@ -12098,10 +12102,22 @@ msgstr "" "Dá»± Ãn." #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po index b65b62655e..6994841e78 100644 --- a/editor/translations/zh_CN.po +++ b/editor/translations/zh_CN.po @@ -83,7 +83,7 @@ msgid "" msgstr "" "Project-Id-Version: Chinese (Simplified) (Godot Engine)\n" "POT-Creation-Date: 2018-01-20 12:15+0200\n" -"PO-Revision-Date: 2021-05-29 13:49+0000\n" +"PO-Revision-Date: 2021-06-20 13:35+0000\n" "Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n" "Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/" "godot-engine/godot/zh_Hans/>\n" @@ -92,7 +92,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.7-dev\n" +"X-Generator: Weblate 4.7\n" #: core/math/expression.cpp modules/gdscript/gdscript_functions.cpp #: modules/visual_script/visual_script_builtin_funcs.cpp @@ -1177,6 +1177,10 @@ msgstr "改å˜å—典值" msgid "Thanks from the Godot community!" msgstr "Godot ç¤¾åŒºæ„Ÿè°¢ä½ ï¼" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "点击å¤åˆ¶ã€‚" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine 贡献者" @@ -12036,10 +12040,23 @@ msgid "" msgstr "未在项目ä¸å®‰è£… Android 构建模æ¿ã€‚从项目èœå•安装它。" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "Debug Keystoreã€Debug Userã€Debug Password 必须全部填写或者全部留空。" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "未在编辑器设置或预设ä¸é…置调试密钥库。" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" +"Release Keystoreã€Release Userã€Release Password 必须全部填写或者全部留空。" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "用于å‘布的密钥å˜å‚¨åœ¨å¯¼å‡ºé¢„è®¾ä¸æœªè¢«æ£ç¡®è®¾ç½®ã€‚" diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po index 0e5af962b5..eee6eb62b7 100644 --- a/editor/translations/zh_HK.po +++ b/editor/translations/zh_HK.po @@ -1155,6 +1155,10 @@ msgstr "動畫變化數值" msgid "Thanks from the Godot community!" msgstr "Godot社å€çš„æ„Ÿè¬ï¼" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine è²¢ç»è€…" @@ -12508,10 +12512,22 @@ msgid "" msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "" diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po index 255f31dfbc..7aee72ee43 100644 --- a/editor/translations/zh_TW.po +++ b/editor/translations/zh_TW.po @@ -1123,6 +1123,10 @@ msgstr "改變å—典值" msgid "Thanks from the Godot community!" msgstr "Godot 社群感è¬ä½ ï¼" +#: editor/editor_about.cpp editor/editor_node.cpp editor/project_manager.cpp +msgid "Click to copy." +msgstr "" + #: editor/editor_about.cpp msgid "Godot Engine contributors" msgstr "Godot Engine è²¢ç»è€…" @@ -11982,10 +11986,22 @@ msgid "" msgstr "尚未於專案ä¸å®‰è£ Android 建置樣æ¿ã€‚請先於專案目錄ä¸é€²è¡Œå®‰è£ã€‚" #: platform/android/export/export.cpp +msgid "" +"Either Debug Keystore, Debug User AND Debug Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Debug keystore not configured in the Editor Settings nor in the preset." msgstr "尚未於編輯器è¨å®šæˆ–é è¨è¨å®šä¸è¨å®šé‡‘鑰儲å˜å€ (Keystore)。" #: platform/android/export/export.cpp +msgid "" +"Either Release Keystore, Release User AND Release Password settings must be " +"configured OR none of them." +msgstr "" + +#: platform/android/export/export.cpp msgid "Release keystore incorrectly configured in the export preset." msgstr "發行金鑰儲å˜å€ä¸ä¸æ£ç¢ºä¹‹çµ„æ…‹è¨å®šè‡³åŒ¯å‡ºé è¨è¨å®šã€‚" diff --git a/main/main.cpp b/main/main.cpp index d67761db55..1ab36701ff 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -34,8 +34,10 @@ #include "core/core_string_names.h" #include "core/crypto/crypto.h" #include "core/debugger/engine_debugger.h" +#include "core/extension/extension_api_dump.h" #include "core/input/input.h" #include "core/input/input_map.h" +#include "core/io/dir_access.h" #include "core/io/file_access_network.h" #include "core/io/file_access_pack.h" #include "core/io/file_access_zip.h" @@ -43,8 +45,8 @@ #include "core/io/ip.h" #include "core/io/resource_loader.h" #include "core/object/message_queue.h" -#include "core/os/dir_access.h" #include "core/os/os.h" +#include "core/os/time.h" #include "core/register_core_types.h" #include "core/string/translation.h" #include "core/version.h" @@ -101,6 +103,7 @@ static InputMap *input_map = nullptr; static TranslationServer *translation_server = nullptr; static Performance *performance = nullptr; static PackedData *packed_data = nullptr; +static Time *time_singleton = nullptr; #ifdef MINIZIP_ENABLED static ZipArchive *zip_packed_data = nullptr; #endif @@ -135,6 +138,7 @@ static int audio_driver_idx = -1; static bool single_window = false; static bool editor = false; static bool project_manager = false; +static bool cmdline_tool = false; static String locale; static bool show_help = false; static bool auto_quit = false; @@ -147,9 +151,9 @@ static bool auto_build_solutions = false; static DisplayServer::WindowMode window_mode = DisplayServer::WINDOW_MODE_WINDOWED; static DisplayServer::ScreenOrientation window_orientation = DisplayServer::SCREEN_LANDSCAPE; +static DisplayServer::VSyncMode window_vsync_mode = DisplayServer::VSYNC_ENABLED; static uint32_t window_flags = 0; static Size2i window_size = Size2i(1024, 600); -static bool window_vsync_via_compositor = false; static int init_screen = -1; static bool init_fullscreen = false; @@ -171,7 +175,9 @@ static int frame_delay = 0; static bool disable_render_loop = false; static int fixed_fps = -1; static bool print_fps = false; - +#ifdef TOOLS_ENABLED +static bool dump_extension_api = false; +#endif bool profile_gpu = false; /* Helper methods */ @@ -183,6 +189,10 @@ bool Main::is_project_manager() { return project_manager; } +bool Main::is_cmdline_tool() { + return cmdline_tool; +} + static String unescape_cmdline(const String &p_str) { return p_str.replace("%20", " "); } @@ -328,8 +338,6 @@ void Main::print_help(const char *p_binary) { OS::get_singleton()->print(" --position <X>,<Y> Request window position.\n"); OS::get_singleton()->print(" --low-dpi Force low-DPI mode (macOS and Windows only).\n"); OS::get_singleton()->print(" --no-window Disable window creation (Windows only). Useful together with --script.\n"); - OS::get_singleton()->print(" --enable-vsync-via-compositor When vsync is enabled, vsync via the OS' window compositor (Windows only).\n"); - OS::get_singleton()->print(" --disable-vsync-via-compositor Disable vsync via the OS' window compositor (Windows only).\n"); OS::get_singleton()->print(" --single-window Use a single window (no separate subwindows).\n"); OS::get_singleton()->print(" --tablet-driver Pen tablet input driver.\n"); OS::get_singleton()->print("\n"); @@ -399,6 +407,8 @@ Error Main::test_setup() { translation_server = memnew(TranslationServer); + register_core_extensions(); + // From `Main::setup2()`. preregister_module_types(); preregister_server_types(); @@ -532,6 +542,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph MAIN_PRINT("Main: Initialize Globals"); input_map = memnew(InputMap); + time_singleton = memnew(Time); globals = memnew(ProjectSettings); register_core_settings(); //here globals are present @@ -586,11 +597,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph Vector<String> breakpoints; bool use_custom_res = true; bool force_res = false; - bool saw_vsync_via_compositor_override = false; #ifdef TOOLS_ENABLED bool found_project = false; #endif - bool use_vsync = false; packed_data = PackedData::get_singleton(); if (!packed_data) { @@ -812,12 +821,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "--no-window") { // disable window creation (Windows only) OS::get_singleton()->set_no_window_mode(true); - } else if (I->get() == "--enable-vsync-via-compositor") { - window_vsync_via_compositor = true; - saw_vsync_via_compositor_override = true; - } else if (I->get() == "--disable-vsync-via-compositor") { - window_vsync_via_compositor = false; - saw_vsync_via_compositor_override = true; #endif } else if (I->get() == "--profiling") { // enable profiling @@ -878,18 +881,31 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph auto_build_solutions = true; editor = true; -#ifdef DEBUG_METHODS_ENABLED + cmdline_tool = true; + } else if (I->get() == "--gdnative-generate-json-api" || I->get() == "--gdnative-generate-json-builtin-api") { // Register as an editor instance to use low-end fallback if relevant. editor = true; + cmdline_tool = true; // We still pass it to the main arguments since the argument handling itself is not done in this function main_args.push_back(I->get()); -#endif + } else if (I->get() == "--dump-extension-api") { + // Register as an editor instance to use low-end fallback if relevant. + editor = true; + cmdline_tool = true; + dump_extension_api = true; + print_line("dump extension?"); + main_args.push_back(I->get()); } else if (I->get() == "--export" || I->get() == "--export-debug" || I->get() == "--export-pack") { // Export project - + // Actually handling is done in start(). editor = true; + cmdline_tool = true; + main_args.push_back(I->get()); + } else if (I->get() == "--doctool") { + // Actually handling is done in start(). + cmdline_tool = true; main_args.push_back(I->get()); #endif } else if (I->get() == "--path") { // set path of project to start or edit @@ -1122,8 +1138,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } if (!project_manager && !editor) { - // Determine if the project manager should be requested - project_manager = main_args.size() == 0 && !found_project; + // If we didn't find a project, we fall back to the project manager. + project_manager = !found_project && !cmdline_tool; } #endif @@ -1183,6 +1199,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->set_cmdline(execpath, main_args); + register_core_extensions(); //before display + GLOBAL_DEF("rendering/driver/driver_name", "Vulkan"); ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name", PropertyInfo(Variant::STRING, @@ -1259,19 +1277,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", false); } - use_vsync = GLOBAL_DEF_RST("display/window/vsync/use_vsync", true); - OS::get_singleton()->_use_vsync = use_vsync; - - if (!saw_vsync_via_compositor_override) { - // If one of the command line options to enable/disable vsync via the - // window compositor ("--enable-vsync-via-compositor" or - // "--disable-vsync-via-compositor") was present then it overrides the - // project setting. - window_vsync_via_compositor = GLOBAL_DEF("display/window/vsync/vsync_via_compositor", false); - } - - OS::get_singleton()->_vsync_via_compositor = window_vsync_via_compositor; - /* todo restore OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false); video_mode.layered = GLOBAL_DEF("display/window/per_pixel_transparency/enabled", false); @@ -1329,17 +1334,19 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph { window_orientation = DisplayServer::ScreenOrientation(int(GLOBAL_DEF_BASIC("display/window/handheld/orientation", DisplayServer::ScreenOrientation::SCREEN_LANDSCAPE))); } - + { + window_vsync_mode = DisplayServer::VSyncMode(int(GLOBAL_DEF("display/window/vsync/vsync_mode", DisplayServer::VSyncMode::VSYNC_ENABLED))); + } Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF_BASIC("physics/common/physics_fps", 60)); ProjectSettings::get_singleton()->set_custom_property_info("physics/common/physics_fps", PropertyInfo(Variant::INT, "physics/common/physics_fps", - PROPERTY_HINT_RANGE, "1,120,1,or_greater")); + PROPERTY_HINT_RANGE, "1,1000,1")); Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5)); Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0)); ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps", PropertyInfo(Variant::INT, "debug/settings/fps/force_fps", - PROPERTY_HINT_RANGE, "0,120,1,or_greater")); + PROPERTY_HINT_RANGE, "0,1000,1")); GLOBAL_DEF("debug/settings/stdout/print_fps", false); GLOBAL_DEF("debug/settings/stdout/verbose_stdout", false); @@ -1402,6 +1409,9 @@ error: if (input_map) { memdelete(input_map); } + if (time_singleton) { + memdelete(time_singleton); + } if (translation_server) { memdelete(translation_server); } @@ -1446,8 +1456,8 @@ Error Main::setup2(Thread::ID p_main_tid_override) { #endif #ifdef TOOLS_ENABLED - if (editor || project_manager) { - EditorNode::register_editor_paths(project_manager); + if (editor || project_manager || cmdline_tool) { + EditorPaths::create(); } #endif @@ -1519,14 +1529,14 @@ Error Main::setup2(Thread::ID p_main_tid_override) { String rendering_driver; // temp broken Error err; - display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_flags, window_size, err); + display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err); if (err != OK || display_server == nullptr) { //ok i guess we can't use this display server, try other ones for (int i = 0; i < DisplayServer::get_create_function_count(); i++) { if (i == display_driver_idx) { continue; //don't try the same twice } - display_server = DisplayServer::create(i, rendering_driver, window_mode, window_flags, window_size, err); + display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err); if (err == OK && display_server != nullptr) { break; } @@ -1571,7 +1581,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { print_verbose("Using \"" + tablet_driver + "\" pen tablet driver..."); - /* Initialize Visual Server */ + /* Initialize Rendering Server */ rendering_server = memnew(RenderingServerDefault(OS::get_singleton()->get_render_thread_mode() == OS::RENDER_SEPARATE_THREAD)); @@ -1651,7 +1661,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) { boot_logo_path = boot_logo_path.strip_edges(); if (boot_logo_path != String()) { - boot_logo.instance(); + boot_logo.instantiate(); Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo); if (load_err) { ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash."); @@ -1822,13 +1832,13 @@ bool Main::start() { ERR_FAIL_COND_V(!_start_success, false); bool hasicon = false; - String doc_tool_path; String positional_arg; String game_path; String script; bool check_only = false; #ifdef TOOLS_ENABLED + String doc_tool_path; bool doc_base = true; String _export_preset; bool export_debug = false; @@ -1838,8 +1848,9 @@ bool Main::start() { main_timer_sync.init(OS::get_singleton()->get_ticks_usec()); List<String> args = OS::get_singleton()->get_cmdline_args(); - // parameters that do not have an argument to the right for (int i = 0; i < args.size(); i++) { + // First check parameters that do not have an argument to the right. + // Doctest Unit Testing Handler // Designed to override and pass arguments to the unit test handler. if (args[i] == "--check-only") { @@ -1869,7 +1880,7 @@ bool Main::start() { game_path = args[i]; } } - //parameters that have an argument to the right + // Then parameters that have an argument to the right. else if (i < (args.size() - 1)) { bool parsed_pair = true; if (args[i] == "-s" || args[i] == "--script") { @@ -1901,16 +1912,19 @@ bool Main::start() { if (parsed_pair) { i++; } - } else if (args[i] == "--doctool") { - // Handle case where no path is given to --doctool. + } +#ifdef TOOLS_ENABLED + // Handle case where no path is given to --doctool. + else if (args[i] == "--doctool") { doc_tool_path = "."; } +#endif } #ifdef TOOLS_ENABLED if (doc_tool_path != "") { - Engine::get_singleton()->set_editor_hint( - true); // Needed to instance editor-only classes for their default values + // Needed to instance editor-only classes for their default values + Engine::get_singleton()->set_editor_hint(true); { DirAccessRef da = DirAccess::open(doc_tool_path); @@ -1983,16 +1997,30 @@ bool Main::start() { return false; } + if (dump_extension_api) { + NativeExtensionAPIDump::generate_extension_json_file("extension_api.json"); + return false; + } #endif if (script == "" && game_path == "" && String(GLOBAL_GET("application/run/main_scene")) != "") { game_path = GLOBAL_GET("application/run/main_scene"); } +#ifdef TOOLS_ENABLED + if (!editor && !project_manager && !cmdline_tool && script == "" && game_path == "") { + // If we end up here, it means we didn't manage to detect what we want to run. + // Let's throw an error gently. The code leading to this is pretty brittle so + // this might end up triggered by valid usage, in which case we'll have to + // fine-tune further. + ERR_FAIL_V_MSG(false, "Couldn't detect whether to run the editor, the project manager or a specific project. Aborting."); + } +#endif + MainLoop *main_loop = nullptr; if (editor) { main_loop = memnew(SceneTree); - }; + } String main_loop_type = GLOBAL_DEF("application/run/main_loop_type", "SceneTree"); if (script != "") { @@ -2006,9 +2034,9 @@ bool Main::start() { return false; } - if (script_res->can_instance()) { + if (script_res->can_instantiate()) { StringName instance_type = script_res->get_instance_base_type(); - Object *obj = ClassDB::instance(instance_type); + Object *obj = ClassDB::instantiate(instance_type); MainLoop *script_loop = Object::cast_to<MainLoop>(obj); if (!script_loop) { if (obj) { @@ -2029,7 +2057,7 @@ bool Main::start() { String script_path = ScriptServer::get_global_class_path(main_loop_type); Ref<Script> script_res = ResourceLoader::load(script_path); StringName script_base = ScriptServer::get_global_class_native_base(main_loop_type); - Object *obj = ClassDB::instance(script_base); + Object *obj = ClassDB::instantiate(script_base); MainLoop *script_loop = Object::cast_to<MainLoop>(obj); if (!script_loop) { if (obj) { @@ -2052,7 +2080,7 @@ bool Main::start() { DisplayServer::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type); return false; } else { - Object *ml = ClassDB::instance(main_loop_type); + Object *ml = ClassDB::instantiate(main_loop_type); ERR_FAIL_COND_V_MSG(!ml, false, "Can't instance MainLoop type."); main_loop = Object::cast_to<MainLoop>(ml); @@ -2109,14 +2137,14 @@ bool Main::start() { Node *n = nullptr; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; - n = ps->instance(); + n = ps->instantiate(); } else if (res->is_class("Script")) { Ref<Script> script_res = res; StringName ibt = script_res->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_CONTINUE_MSG(obj == nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + @@ -2319,7 +2347,7 @@ bool Main::start() { Node *scene = nullptr; Ref<PackedScene> scenedata = ResourceLoader::load(local_game_path); if (scenedata.is_valid()) { - scene = scenedata->instance(); + scene = scenedata->instantiate(); } ERR_FAIL_COND_V_MSG(!scene, false, "Failed loading scene: " + local_game_path); @@ -2344,7 +2372,7 @@ bool Main::start() { String iconpath = GLOBAL_DEF("application/config/icon", "Variant()"); if ((iconpath != "") && (!hasicon)) { Ref<Image> icon; - icon.instance(); + icon.instantiate(); if (ImageLoader::load_image(iconpath, icon) == OK) { DisplayServer::get_singleton()->set_icon(icon); hasicon = true; @@ -2354,14 +2382,13 @@ bool Main::start() { } #ifdef TOOLS_ENABLED - if (project_manager || (script == "" && game_path == "" && !editor)) { + if (project_manager) { Engine::get_singleton()->set_editor_hint(true); ProjectManager *pmanager = memnew(ProjectManager); ProgressDialog *progress_dialog = memnew(ProgressDialog); pmanager->add_child(progress_dialog); sml->get_root()->add_child(pmanager); DisplayServer::get_singleton()->set_context(DisplayServer::CONTEXT_PROJECTMAN); - project_manager = true; } if (project_manager || editor) { @@ -2373,10 +2400,8 @@ bool Main::start() { } // Load SSL Certificates from Editor Settings (or builtin) - Crypto::load_default_certificates(EditorSettings::get_singleton()->get_setting( - "network/ssl/editor_ssl_certificates") - . - operator String()); + Crypto::load_default_certificates( + EditorSettings::get_singleton()->get_setting("network/ssl/editor_ssl_certificates").operator String()); } #endif } @@ -2667,6 +2692,9 @@ void Main::cleanup(bool p_force) { if (input_map) { memdelete(input_map); } + if (time_singleton) { + memdelete(time_singleton); + } if (translation_server) { memdelete(translation_server); } diff --git a/main/main.h b/main/main.h index f4fff6b97e..84077137ba 100644 --- a/main/main.h +++ b/main/main.h @@ -45,6 +45,7 @@ class Main { public: static bool is_project_manager(); + static bool is_cmdline_tool(); static int test_entrypoint(int argc, char *argv[], bool &tests_need_run); static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true); static Error setup2(Thread::ID p_main_tid_override = 0); diff --git a/main/performance.cpp b/main/performance.cpp index a2e53f2ee2..9f5be7b8c4 100644 --- a/main/performance.cpp +++ b/main/performance.cpp @@ -60,16 +60,12 @@ void Performance::_bind_methods() { BIND_ENUM_CONSTANT(OBJECT_RESOURCE_COUNT); BIND_ENUM_CONSTANT(OBJECT_NODE_COUNT); BIND_ENUM_CONSTANT(OBJECT_ORPHAN_NODE_COUNT); - BIND_ENUM_CONSTANT(RENDER_OBJECTS_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_VERTICES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_MATERIAL_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_SHADER_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_SURFACE_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_DRAW_CALLS_IN_FRAME); + BIND_ENUM_CONSTANT(RENDER_TOTAL_OBJECTS_IN_FRAME); + BIND_ENUM_CONSTANT(RENDER_TOTAL_PRIMITIVES_IN_FRAME); + BIND_ENUM_CONSTANT(RENDER_TOTAL_DRAW_CALLS_IN_FRAME); BIND_ENUM_CONSTANT(RENDER_VIDEO_MEM_USED); BIND_ENUM_CONSTANT(RENDER_TEXTURE_MEM_USED); - BIND_ENUM_CONSTANT(RENDER_VERTEX_MEM_USED); - BIND_ENUM_CONSTANT(RENDER_USAGE_VIDEO_MEM_TOTAL); + BIND_ENUM_CONSTANT(RENDER_BUFFER_MEM_USED); BIND_ENUM_CONSTANT(PHYSICS_2D_ACTIVE_OBJECTS); BIND_ENUM_CONSTANT(PHYSICS_2D_COLLISION_PAIRS); BIND_ENUM_CONSTANT(PHYSICS_2D_ISLAND_COUNT); @@ -103,16 +99,12 @@ String Performance::get_monitor_name(Monitor p_monitor) const { "object/resources", "object/nodes", "object/orphan_nodes", - "raster/objects_drawn", - "raster/vertices_drawn", - "raster/mat_changes", - "raster/shader_changes", - "raster/surface_changes", - "raster/draw_calls", + "raster/total_objects_drawn", + "raster/total_primitives_drawn", + "raster/total_draw_calls", "video/video_mem", "video/texture_mem", - "video/vertex_mem", - "video/video_mem_max", + "video/buffer_mem", "physics_2d/active_objects", "physics_2d/collision_pairs", "physics_2d/islands", @@ -148,26 +140,18 @@ float Performance::get_monitor(Monitor p_monitor) const { return _get_node_count(); case OBJECT_ORPHAN_NODE_COUNT: return Node::orphan_node_count; - case RENDER_OBJECTS_IN_FRAME: - return RS::get_singleton()->get_render_info(RS::INFO_OBJECTS_IN_FRAME); - case RENDER_VERTICES_IN_FRAME: - return RS::get_singleton()->get_render_info(RS::INFO_VERTICES_IN_FRAME); - case RENDER_MATERIAL_CHANGES_IN_FRAME: - return RS::get_singleton()->get_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME); - case RENDER_SHADER_CHANGES_IN_FRAME: - return RS::get_singleton()->get_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME); - case RENDER_SURFACE_CHANGES_IN_FRAME: - return RS::get_singleton()->get_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME); - case RENDER_DRAW_CALLS_IN_FRAME: - return RS::get_singleton()->get_render_info(RS::INFO_DRAW_CALLS_IN_FRAME); + case RENDER_TOTAL_OBJECTS_IN_FRAME: + return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME); + case RENDER_TOTAL_PRIMITIVES_IN_FRAME: + return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME); + case RENDER_TOTAL_DRAW_CALLS_IN_FRAME: + return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME); case RENDER_VIDEO_MEM_USED: - return RS::get_singleton()->get_render_info(RS::INFO_VIDEO_MEM_USED); + return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_VIDEO_MEM_USED); case RENDER_TEXTURE_MEM_USED: - return RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED); - case RENDER_VERTEX_MEM_USED: - return RS::get_singleton()->get_render_info(RS::INFO_VERTEX_MEM_USED); - case RENDER_USAGE_VIDEO_MEM_TOTAL: - return RS::get_singleton()->get_render_info(RS::INFO_USAGE_VIDEO_MEM_TOTAL); + return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_TEXTURE_MEM_USED); + case RENDER_BUFFER_MEM_USED: + return RS::get_singleton()->get_rendering_info(RS::RENDERING_INFO_BUFFER_MEM_USED); case PHYSICS_2D_ACTIVE_OBJECTS: return PhysicsServer2D::get_singleton()->get_process_info(PhysicsServer2D::INFO_ACTIVE_OBJECTS); case PHYSICS_2D_COLLISION_PAIRS: @@ -207,10 +191,6 @@ Performance::MonitorType Performance::get_monitor_type(Monitor p_monitor) const MONITOR_TYPE_QUANTITY, MONITOR_TYPE_QUANTITY, MONITOR_TYPE_QUANTITY, - MONITOR_TYPE_QUANTITY, - MONITOR_TYPE_QUANTITY, - MONITOR_TYPE_QUANTITY, - MONITOR_TYPE_MEMORY, MONITOR_TYPE_MEMORY, MONITOR_TYPE_MEMORY, MONITOR_TYPE_MEMORY, diff --git a/main/performance.h b/main/performance.h index 122e5a4f9a..174b3500d1 100644 --- a/main/performance.h +++ b/main/performance.h @@ -73,16 +73,12 @@ public: OBJECT_RESOURCE_COUNT, OBJECT_NODE_COUNT, OBJECT_ORPHAN_NODE_COUNT, - RENDER_OBJECTS_IN_FRAME, - RENDER_VERTICES_IN_FRAME, - RENDER_MATERIAL_CHANGES_IN_FRAME, - RENDER_SHADER_CHANGES_IN_FRAME, - RENDER_SURFACE_CHANGES_IN_FRAME, - RENDER_DRAW_CALLS_IN_FRAME, + RENDER_TOTAL_OBJECTS_IN_FRAME, + RENDER_TOTAL_PRIMITIVES_IN_FRAME, + RENDER_TOTAL_DRAW_CALLS_IN_FRAME, RENDER_VIDEO_MEM_USED, RENDER_TEXTURE_MEM_USED, - RENDER_VERTEX_MEM_USED, - RENDER_USAGE_VIDEO_MEM_TOTAL, + RENDER_BUFFER_MEM_USED, PHYSICS_2D_ACTIVE_OBJECTS, PHYSICS_2D_COLLISION_PAIRS, PHYSICS_2D_ISLAND_COUNT, diff --git a/misc/dist/linux/godot.6 b/misc/dist/linux/godot.6 index 4140094813..3e5bdefdce 100644 --- a/misc/dist/linux/godot.6 +++ b/misc/dist/linux/godot.6 @@ -85,12 +85,6 @@ Force low\-DPI mode (macOS and Windows only). .TP \fB\-\-no\-window\fR Disable window creation (Windows only). Useful together with \fB\-\-script\fR. -.TP -\fB\-\-enable\-vsync\-via\-compositor\fR -When vsync is enabled, vsync via the OS' window compositor (Windows only). -.TP -\fB\-\-disable\-vsync\-via\-compositor\fR -Disable vsync via the OS' window compositor (Windows only). .SS "Debug options:" .TP \fB\-d\fR, \fB\-\-debug\fR diff --git a/misc/dist/linux/org.godotengine.Godot.xml b/misc/dist/linux/org.godotengine.Godot.xml index 2f647f71a6..e51179cd61 100644 --- a/misc/dist/linux/org.godotengine.Godot.xml +++ b/misc/dist/linux/org.godotengine.Godot.xml @@ -21,6 +21,12 @@ <glob pattern="*.escn"/> </mime-type> + <mime-type type="application/x-godot-shader"> + <comment>Godot Engine shader</comment> + <icon name="x-godot-shader" /> + <glob pattern="*.gdshader"/> + </mime-type> + <mime-type type="application/x-gdscript"> <comment>GDScript script</comment> <icon name="x-gdscript" /> diff --git a/misc/dist/osx_template.app/Contents/Info.plist b/misc/dist/osx_template.app/Contents/Info.plist index aad24935d0..8e221df946 100644 --- a/misc/dist/osx_template.app/Contents/Info.plist +++ b/misc/dist/osx_template.app/Contents/Info.plist @@ -36,6 +36,8 @@ </array> <key>NSPrincipalClass</key> <string>NSApplication</string> + <key>LSApplicationCategoryType</key> + <string>public.app-category.$app_category</string> <key>LSMinimumSystemVersion</key> <string>10.12</string> <key>LSMinimumSystemVersionByArchitecture</key> diff --git a/misc/dist/osx_tools.app/Contents/Info.plist b/misc/dist/osx_tools.app/Contents/Info.plist index 1c682f339f..8e70d4c203 100644 --- a/misc/dist/osx_tools.app/Contents/Info.plist +++ b/misc/dist/osx_tools.app/Contents/Info.plist @@ -38,6 +38,8 @@ </array> <key>NSPrincipalClass</key> <string>NSApplication</string> + <key>LSApplicationCategoryType</key> + <string>public.app-category.developer-tools</string> <key>LSMinimumSystemVersion</key> <string>10.12</string> <key>LSMinimumSystemVersionByArchitecture</key> diff --git a/misc/dist/shell/_godot.zsh-completion b/misc/dist/shell/_godot.zsh-completion index 8e14240b53..b29746bfc4 100644 --- a/misc/dist/shell/_godot.zsh-completion +++ b/misc/dist/shell/_godot.zsh-completion @@ -51,8 +51,6 @@ _arguments \ '--position[request window position]:position in X,Y format' \ '--low-dpi[force low-DPI mode (macOS and Windows only)]' \ '--no-window[disable window creation (Windows only), useful together with --script]' \ - "--enable-vsync-via-compositor[when Vsync is enabled, Vsync via the OS' window compositor (Windows only)]" \ - "--disable-vsync-via-compositor[disable Vsync via the OS' window compositor (Windows only)]" \ '(-d --debug)'{-d,--debug}'[debug (local stdout debugger)]' \ '(-b --breakpoints)'{-b,--breakpoints}'[specify the breakpoint list as source::line comma-separated pairs, no spaces (use %20 instead)]:breakpoint list' \ '--profiling[enable profiling in the script debugger]' \ diff --git a/misc/dist/shell/godot.bash-completion b/misc/dist/shell/godot.bash-completion index 14f2be37b1..03861e43f8 100644 --- a/misc/dist/shell/godot.bash-completion +++ b/misc/dist/shell/godot.bash-completion @@ -54,8 +54,6 @@ _complete_godot_options() { --position --low-dpi --no-window ---enable-vsync-via-compositor ---disable-vsync-via-compositor --debug --breakpoints --profiling diff --git a/misc/dist/shell/godot.fish b/misc/dist/shell/godot.fish index a485a1dcdb..1367665bbc 100644 --- a/misc/dist/shell/godot.fish +++ b/misc/dist/shell/godot.fish @@ -61,8 +61,6 @@ complete -c godot -l resolution -d "Request window resolution" -x complete -c godot -l position -d "Request window position" -x complete -c godot -l low-dpi -d "Force low-DPI mode (macOS and Windows only)" complete -c godot -l no-window -d "Disable window creation (Windows only), useful together with --script" -complete -c godot -l enable-vsync-via-compositor -d "When Vsync is enabled, Vsync via the OS' window compositor (Windows only)" -complete -c godot -l disable-vsync-via-compositor -d "Disable Vsync via the OS' window compositor (Windows only)" # Debug options: complete -c godot -s d -l debug -d "Debug (local stdout debugger)" diff --git a/misc/hooks/canonicalize_filename.sh b/misc/hooks/canonicalize_filename.sh index 5eecabf5bc..5fcae6ee70 100755 --- a/misc/hooks/canonicalize_filename.sh +++ b/misc/hooks/canonicalize_filename.sh @@ -13,7 +13,7 @@ # There should be no need to change anything below this line. # Canonicalize by recursively following every symlink in every component of the -# specified filename. This should reproduce the results of the GNU version of +# specified filename. This should reproduce the results of the GNU version of # readlink with the -f option. # # Reference: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format index 2dac8e9a55..81bc412944 100755 --- a/misc/hooks/pre-commit-clang-format +++ b/misc/hooks/pre-commit-clang-format @@ -76,7 +76,8 @@ fi # To get consistent formatting, we recommend contributors to use the same # clang-format version as CI. -RECOMMENDED_CLANG_FORMAT_MAJOR="11" +RECOMMENDED_CLANG_FORMAT_MAJOR_MIN="11" +RECOMMENDED_CLANG_FORMAT_MAJOR_MAX="12" if [ ! -x "$CLANG_FORMAT" ] ; then message="Error: clang-format executable not found. Please install clang-format $RECOMMENDED_CLANG_FORMAT_MAJOR.x.x." @@ -106,8 +107,8 @@ fi CLANG_FORMAT_VERSION="$(clang-format --version | sed "s/[^0-9\.]*\([0-9\.]*\).*/\1/")" CLANG_FORMAT_MAJOR="$(echo "$CLANG_FORMAT_VERSION" | cut -d. -f1)" -if [ "$CLANG_FORMAT_MAJOR" != "$RECOMMENDED_CLANG_FORMAT_MAJOR" ]; then - echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected $RECOMMENDED_CLANG_FORMAT_MAJOR.x.x)." +if [[ "$CLANG_FORMAT_MAJOR" -lt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MIN" || "$CLANG_FORMAT_MAJOR" -gt "$RECOMMENDED_CLANG_FORMAT_MAJOR_MAX" ]]; then + echo "Warning: Your clang-format binary is the wrong version ($CLANG_FORMAT_VERSION, expected between $RECOMMENDED_CLANG_FORMAT_MAJOR_MIN.x.x and $RECOMMENDED_CLANG_FORMAT_MAJOR_MAX.x.x)." echo " Consider upgrading or downgrading clang-format as formatting may not be applied correctly." fi diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index 772ac87dbf..23639a4f2f 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -260,7 +260,7 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) { }; }; - image.instance(); + image.instantiate(); image->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); return image; diff --git a/modules/basis_universal/texture_basisu.cpp b/modules/basis_universal/texture_basisu.cpp index 6a5f6313c4..9e917420ce 100644 --- a/modules/basis_universal/texture_basisu.cpp +++ b/modules/basis_universal/texture_basisu.cpp @@ -130,7 +130,7 @@ void TextureBasisU::set_basisu_data(const Vector<uint8_t>& p_data) { }; Ref<Image> img; - img.instance(); + img.instantiate(); img->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); RenderingServer::get_singleton()->texture_allocate(texture, tex_size.x, tex_size.y, 0, img->get_format(), RS::TEXTURE_TYPE_2D, flags); diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp index 27b49a6609..171895ed24 100644 --- a/modules/bmp/image_loader_bmp.cpp +++ b/modules/bmp/image_loader_bmp.cpp @@ -298,7 +298,7 @@ static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) { Error open_memfile_error = memfile.open_custom(p_bmp, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer."); Ref<Image> img; - img.instance(); + img.instantiate(); Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image."); return img; diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp index e601884486..e07be14c5b 100644 --- a/modules/bullet/bullet_physics_server.cpp +++ b/modules/bullet/bullet_physics_server.cpp @@ -268,7 +268,7 @@ PhysicsServer3D::AreaSpaceOverrideMode BulletPhysicsServer3D::area_get_space_ove return area->get_spOv_mode(); } -void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) { +void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) { AreaBullet *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -288,7 +288,7 @@ void BulletPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_sh area->set_shape(p_shape_idx, shape); } -void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) { +void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) { AreaBullet *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -309,9 +309,9 @@ RID BulletPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const { return area->get_shape(p_shape_idx)->get_self(); } -Transform BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const { +Transform3D BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const { AreaBullet *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform()); + ERR_FAIL_COND_V(!area, Transform3D()); return area->get_shape_transform(p_shape_idx); } @@ -382,15 +382,15 @@ Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param) } } -void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform &p_transform) { +void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform3D &p_transform) { AreaBullet *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); area->set_transform(p_transform); } -Transform BulletPhysicsServer3D::area_get_transform(RID p_area) const { +Transform3D BulletPhysicsServer3D::area_get_transform(RID p_area) const { AreaBullet *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform()); + ERR_FAIL_COND_V(!area, Transform3D()); return area->get_transform(); } @@ -484,7 +484,7 @@ PhysicsServer3D::BodyMode BulletPhysicsServer3D::body_get_mode(RID p_body) const return body->get_mode(); } -void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) { +void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -504,7 +504,7 @@ void BulletPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_sh body->set_shape(p_shape_idx, shape); } -void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) { +void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -527,9 +527,9 @@ RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const { return shape->get_self(); } -Transform BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const { +Transform3D BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Transform()); + ERR_FAIL_COND_V(!body, Transform3D()); return body->get_shape_transform(p_shape_idx); } @@ -842,7 +842,7 @@ PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_bod return BulletPhysicsDirectBodyState3D::get_singleton(body); } -bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -850,7 +850,7 @@ bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform &p_from return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); } -int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { +int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { RigidBodyBullet *body = rigid_body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, 0); ERR_FAIL_COND_V(!body->get_space(), 0); @@ -990,7 +990,7 @@ Variant BulletPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state return Variant(); } -void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform &p_transform) { +void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform3D &p_transform) { SoftBodyBullet *body = soft_body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -1205,7 +1205,7 @@ Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const { return pin_joint->getPivotInB(); } -RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) { +RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); @@ -1277,7 +1277,7 @@ bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_f return hinge_joint->get_flag(p_flag); } -RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); @@ -1313,7 +1313,7 @@ real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointPar return slider_joint->get_param(p_param); } -RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); @@ -1347,7 +1347,7 @@ real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJ return coneTwist_joint->get_param(p_param); } -RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A); ERR_FAIL_COND_V(!body_A, RID()); JointAssertSpace(body_A, "A", RID()); diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h index de0379c873..d34d619ba2 100644 --- a/modules/bullet/bullet_physics_server.h +++ b/modules/bullet/bullet_physics_server.h @@ -134,12 +134,12 @@ public: virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) override; virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const override; - virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override; + virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override; virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) override; - virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) override; + virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) override; virtual int area_get_shape_count(RID p_area) const override; virtual RID area_get_shape(RID p_area, int p_shape_idx) const override; - virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const override; + virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const override; virtual void area_remove_shape(RID p_area, int p_shape_idx) override; virtual void area_clear_shapes(RID p_area) override; virtual void area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) override; @@ -153,8 +153,8 @@ public: virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) override; virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override; - virtual void area_set_transform(RID p_area, const Transform &p_transform) override; - virtual Transform area_get_transform(RID p_area) const override; + virtual void area_set_transform(RID p_area, const Transform3D &p_transform) override; + virtual Transform3D area_get_transform(RID p_area) const override; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override; virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override; @@ -166,7 +166,7 @@ public: /* RIGID BODY API */ - virtual RID body_create(BodyMode p_mode = BODY_MODE_RIGID, bool p_init_sleeping = false) override; + virtual RID body_create(BodyMode p_mode = BODY_MODE_DYNAMIC, bool p_init_sleeping = false) override; virtual void body_set_space(RID p_body, RID p_space) override; virtual RID body_get_space(RID p_body) const override; @@ -174,14 +174,14 @@ public: virtual void body_set_mode(RID p_body, BodyMode p_mode) override; virtual BodyMode body_get_mode(RID p_body) const override; - virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override; + virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override; // Not supported, Please remove and add new shape virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override; - virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) override; + virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) override; virtual int body_get_shape_count(RID p_body) const override; virtual RID body_get_shape(RID p_body, int p_shape_idx) const override; - virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const override; + virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const override; virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override; @@ -253,8 +253,8 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; + virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; /* SOFT BODY API */ @@ -283,7 +283,7 @@ public: virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override; /// Special function. This function has bad performance - virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override; + virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override; @@ -333,7 +333,7 @@ public: virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override; virtual Vector3 pin_joint_get_local_b(RID p_joint) const override; - virtual RID joint_create_hinge(RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) override; + virtual RID joint_create_hinge(RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) override; virtual RID joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override; virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override; @@ -343,19 +343,19 @@ public: virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override; /// Reference frame is A - virtual RID joint_create_slider(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; + virtual RID joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override; virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override; /// Reference frame is A - virtual RID joint_create_cone_twist(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; + virtual RID joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override; virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override; /// Reference frame is A - virtual RID joint_create_generic_6dof(RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; + virtual RID joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) override; virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) override; diff --git a/modules/bullet/bullet_types_converter.cpp b/modules/bullet/bullet_types_converter.cpp index 19d4816372..01461767bd 100644 --- a/modules/bullet/bullet_types_converter.cpp +++ b/modules/bullet/bullet_types_converter.cpp @@ -59,7 +59,7 @@ void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal) { INVERT_B_TO_G(inVal[2], outVal[2]); } -void B_TO_G(btTransform const &inVal, Transform &outVal) { +void B_TO_G(btTransform const &inVal, Transform3D &outVal) { B_TO_G(inVal.getBasis(), outVal.basis); B_TO_G(inVal.getOrigin(), outVal.origin); } @@ -89,7 +89,7 @@ void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal) { INVERT_G_TO_B(inVal[2], outVal[2]); } -void G_TO_B(Transform const &inVal, btTransform &outVal) { +void G_TO_B(Transform3D const &inVal, btTransform &outVal) { G_TO_B(inVal.basis, outVal.getBasis()); G_TO_B(inVal.origin, outVal.getOrigin()); } diff --git a/modules/bullet/bullet_types_converter.h b/modules/bullet/bullet_types_converter.h index ca9b7175dd..e184fe1769 100644 --- a/modules/bullet/bullet_types_converter.h +++ b/modules/bullet/bullet_types_converter.h @@ -32,7 +32,7 @@ #define BULLET_TYPES_CONVERTER_H #include "core/math/basis.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/typedefs.h" @@ -49,14 +49,14 @@ extern void B_TO_G(btVector3 const &inVal, Vector3 &outVal); extern void INVERT_B_TO_G(btVector3 const &inVal, Vector3 &outVal); extern void B_TO_G(btMatrix3x3 const &inVal, Basis &outVal); extern void INVERT_B_TO_G(btMatrix3x3 const &inVal, Basis &outVal); -extern void B_TO_G(btTransform const &inVal, Transform &outVal); +extern void B_TO_G(btTransform const &inVal, Transform3D &outVal); // Godot TO Bullet extern void G_TO_B(Vector3 const &inVal, btVector3 &outVal); extern void INVERT_G_TO_B(Vector3 const &inVal, btVector3 &outVal); extern void G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); extern void INVERT_G_TO_B(Basis const &inVal, btMatrix3x3 &outVal); -extern void G_TO_B(Transform const &inVal, btTransform &outVal); +extern void G_TO_B(Transform3D const &inVal, btTransform &outVal); extern void UNSCALE_BT_BASIS(btTransform &scaledBasis); #endif diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp index d9f5beb5a1..c45bd5bbc0 100644 --- a/modules/bullet/collision_object_bullet.cpp +++ b/modules/bullet/collision_object_bullet.cpp @@ -49,7 +49,7 @@ CollisionObjectBullet::ShapeWrapper::~ShapeWrapper() {} -void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform &p_transform) { +void CollisionObjectBullet::ShapeWrapper::set_transform(const Transform3D &p_transform) { G_TO_B(p_transform.get_basis().get_scale_abs(), scale); G_TO_B(p_transform, transform); UNSCALE_BT_BASIS(transform); @@ -193,7 +193,7 @@ int CollisionObjectBullet::get_godot_object_flags() const { return bt_collision_object->getUserIndex2(); } -void CollisionObjectBullet::set_transform(const Transform &p_global_transform) { +void CollisionObjectBullet::set_transform(const Transform3D &p_global_transform) { set_body_scale(p_global_transform.basis.get_scale_abs()); btTransform bt_transform; @@ -203,8 +203,8 @@ void CollisionObjectBullet::set_transform(const Transform &p_global_transform) { set_transform__bullet(bt_transform); } -Transform CollisionObjectBullet::get_transform() const { - Transform t; +Transform3D CollisionObjectBullet::get_transform() const { + Transform3D t; B_TO_G(get_transform__bullet(), t); t.basis.scale(body_scale); return t; @@ -230,7 +230,7 @@ RigidCollisionObjectBullet::~RigidCollisionObjectBullet() { } } -void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform &p_transform, bool p_disabled) { +void RigidCollisionObjectBullet::add_shape(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_disabled) { shapes.push_back(ShapeWrapper(p_shape, p_transform, !p_disabled)); p_shape->add_owner(this); reload_shapes(); @@ -296,7 +296,7 @@ void RigidCollisionObjectBullet::remove_all_shapes(bool p_permanentlyFromThisBod } } -void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform &p_transform) { +void RigidCollisionObjectBullet::set_shape_transform(int p_index, const Transform3D &p_transform) { ERR_FAIL_INDEX(p_index, get_shape_count()); shapes.write[p_index].set_transform(p_transform); @@ -307,8 +307,8 @@ const btTransform &RigidCollisionObjectBullet::get_bt_shape_transform(int p_inde return shapes[p_index].transform; } -Transform RigidCollisionObjectBullet::get_shape_transform(int p_index) const { - Transform trs; +Transform3D RigidCollisionObjectBullet::get_shape_transform(int p_index) const { + Transform3D trs; B_TO_G(shapes[p_index].transform, trs); return trs; } diff --git a/modules/bullet/collision_object_bullet.h b/modules/bullet/collision_object_bullet.h index c8081a53f1..944ab89b87 100644 --- a/modules/bullet/collision_object_bullet.h +++ b/modules/bullet/collision_object_bullet.h @@ -31,7 +31,7 @@ #ifndef COLLISION_OBJECT_BULLET_H #define COLLISION_OBJECT_BULLET_H -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/object/class_db.h" #include "core/templates/vset.h" @@ -83,7 +83,7 @@ public: set_transform(p_transform); } - ShapeWrapper(ShapeBullet *p_shape, const Transform &p_transform, bool p_active) : + ShapeWrapper(ShapeBullet *p_shape, const Transform3D &p_transform, bool p_active) : shape(p_shape), active(p_active) { set_transform(p_transform); @@ -102,7 +102,7 @@ public: active = otherShape.active; } - void set_transform(const Transform &p_transform); + void set_transform(const Transform3D &p_transform); void set_transform(const btTransform &p_transform); btTransform get_adjusted_transform() const; @@ -202,8 +202,8 @@ public: void set_godot_object_flags(int flags); int get_godot_object_flags() const; - void set_transform(const Transform &p_global_transform); - Transform get_transform() const; + void set_transform(const Transform3D &p_global_transform); + Transform3D get_transform() const; virtual void set_transform__bullet(const btTransform &p_global_transform); virtual const btTransform &get_transform__bullet() const; @@ -225,7 +225,7 @@ public: _FORCE_INLINE_ btCollisionShape *get_main_shape() const { return mainShape; } - void add_shape(ShapeBullet *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false); + void add_shape(ShapeBullet *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false); void set_shape(int p_index, ShapeBullet *p_shape); int get_shape_count() const; @@ -238,10 +238,10 @@ public: void remove_shape_full(int p_index); void remove_all_shapes(bool p_permanentlyFromThisBody = false, bool p_force_not_reload = false); - void set_shape_transform(int p_index, const Transform &p_transform); + void set_shape_transform(int p_index, const Transform3D &p_transform); const btTransform &get_bt_shape_transform(int p_index) const; - Transform get_shape_transform(int p_index) const; + Transform3D get_shape_transform(int p_index) const; void set_shape_disabled(int p_index, bool p_disabled); bool is_shape_disabled(int p_index); diff --git a/modules/bullet/cone_twist_joint_bullet.cpp b/modules/bullet/cone_twist_joint_bullet.cpp index e785780c5b..34516d8b3b 100644 --- a/modules/bullet/cone_twist_joint_bullet.cpp +++ b/modules/bullet/cone_twist_joint_bullet.cpp @@ -40,16 +40,16 @@ @author AndreaCatania */ -ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame) : +ConeTwistJointBullet::ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : JointBullet() { - Transform scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(rbAFrame.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); btTransform btFrameA; G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(rbBFrame.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); btTransform btFrameB; diff --git a/modules/bullet/cone_twist_joint_bullet.h b/modules/bullet/cone_twist_joint_bullet.h index 7d6bafd292..7e51f7d644 100644 --- a/modules/bullet/cone_twist_joint_bullet.h +++ b/modules/bullet/cone_twist_joint_bullet.h @@ -43,7 +43,7 @@ class ConeTwistJointBullet : public JointBullet { class btConeTwistConstraint *coneConstraint; public: - ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &rbAFrame, const Transform &rbBFrame); + ConeTwistJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_CONE_TWIST; } diff --git a/modules/bullet/config.py b/modules/bullet/config.py index be7cf74f6f..83605f1f9b 100644 --- a/modules/bullet/config.py +++ b/modules/bullet/config.py @@ -1,6 +1,7 @@ def can_build(env, platform): # API Changed and bullet is disabled at the moment return False + # Later change to return not env["disable_3d"] def configure(env): diff --git a/modules/bullet/generic_6dof_joint_bullet.cpp b/modules/bullet/generic_6dof_joint_bullet.cpp index 43ad6c56d5..7e04d57b9d 100644 --- a/modules/bullet/generic_6dof_joint_bullet.cpp +++ b/modules/bullet/generic_6dof_joint_bullet.cpp @@ -40,7 +40,7 @@ @author AndreaCatania */ -Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) : +Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : JointBullet() { for (int i = 0; i < 3; i++) { for (int j = 0; j < PhysicsServer3D::G6DOF_JOINT_FLAG_MAX; j++) { @@ -48,7 +48,7 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu } } - Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); @@ -56,7 +56,7 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); @@ -71,30 +71,30 @@ Generic6DOFJointBullet::Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBu setup(sixDOFConstraint); } -Transform Generic6DOFJointBullet::getFrameOffsetA() const { +Transform3D Generic6DOFJointBullet::getFrameOffsetA() const { btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } -Transform Generic6DOFJointBullet::getFrameOffsetB() const { +Transform3D Generic6DOFJointBullet::getFrameOffsetB() const { btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } -Transform Generic6DOFJointBullet::getFrameOffsetA() { +Transform3D Generic6DOFJointBullet::getFrameOffsetA() { btTransform btTrs = sixDOFConstraint->getFrameOffsetA(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } -Transform Generic6DOFJointBullet::getFrameOffsetB() { +Transform3D Generic6DOFJointBullet::getFrameOffsetB() { btTransform btTrs = sixDOFConstraint->getFrameOffsetB(); - Transform gTrs; + Transform3D gTrs; B_TO_G(btTrs, gTrs); return gTrs; } diff --git a/modules/bullet/generic_6dof_joint_bullet.h b/modules/bullet/generic_6dof_joint_bullet.h index 62b8e85a81..00567e3085 100644 --- a/modules/bullet/generic_6dof_joint_bullet.h +++ b/modules/bullet/generic_6dof_joint_bullet.h @@ -48,14 +48,14 @@ class Generic6DOFJointBullet : public JointBullet { bool flags[3][PhysicsServer3D::G6DOF_JOINT_FLAG_MAX]; public: - Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB); + Generic6DOFJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_6DOF; } - Transform getFrameOffsetA() const; - Transform getFrameOffsetB() const; - Transform getFrameOffsetA(); - Transform getFrameOffsetB(); + Transform3D getFrameOffsetA() const; + Transform3D getFrameOffsetB() const; + Transform3D getFrameOffsetA(); + Transform3D getFrameOffsetB(); void set_linear_lower_limit(const Vector3 &linearLower); void set_linear_upper_limit(const Vector3 &linearUpper); diff --git a/modules/bullet/hinge_joint_bullet.cpp b/modules/bullet/hinge_joint_bullet.cpp index 4ceb98729f..b5fe50cf5f 100644 --- a/modules/bullet/hinge_joint_bullet.cpp +++ b/modules/bullet/hinge_joint_bullet.cpp @@ -40,16 +40,16 @@ @author AndreaCatania */ -HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB) : +HingeJointBullet::HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB) : JointBullet() { - Transform scaled_AFrame(frameA.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(frameA.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); btTransform btFrameA; G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(frameB.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(frameB.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); btTransform btFrameB; diff --git a/modules/bullet/hinge_joint_bullet.h b/modules/bullet/hinge_joint_bullet.h index 06a95be374..dd0f69ba68 100644 --- a/modules/bullet/hinge_joint_bullet.h +++ b/modules/bullet/hinge_joint_bullet.h @@ -41,7 +41,7 @@ class HingeJointBullet : public JointBullet { class btHingeConstraint *hingeConstraint; public: - HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameA, const Transform &frameB); + HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameA, const Transform3D &frameB); HingeJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_HINGE; } diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp index 675da1a597..ce39d4f0df 100644 --- a/modules/bullet/rigid_body_bullet.cpp +++ b/modules/bullet/rigid_body_bullet.cpp @@ -106,11 +106,11 @@ Vector3 BulletPhysicsDirectBodyState3D::get_angular_velocity() const { return body->get_angular_velocity(); } -void BulletPhysicsDirectBodyState3D::set_transform(const Transform &p_transform) { +void BulletPhysicsDirectBodyState3D::set_transform(const Transform3D &p_transform) { body->set_transform(p_transform); } -Transform BulletPhysicsDirectBodyState3D::get_transform() const { +Transform3D BulletPhysicsDirectBodyState3D::get_transform() const { return body->get_transform(); } @@ -268,7 +268,7 @@ RigidBodyBullet::RigidBodyBullet() : reload_shapes(); setupBulletCollisionObject(btBody); - set_mode(PhysicsServer3D::BODY_MODE_RIGID); + set_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); reload_axis_lock(); areasWhereIam.resize(maxAreasWhereIam); @@ -531,14 +531,14 @@ void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) { reload_axis_lock(); _internal_set_mass(0); break; - case PhysicsServer3D::BODY_MODE_RIGID: - mode = PhysicsServer3D::BODY_MODE_RIGID; + case PhysicsServer3D::BODY_MODE_DYNAMIC: + mode = PhysicsServer3D::BODY_MODE_DYNAMIC; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); break; - case PhysicsServer3D::BODY_MODE_CHARACTER: - mode = PhysicsServer3D::BODY_MODE_CHARACTER; + case PhysicsServer3D::MODE_DYNAMIC_LOCKED: + mode = PhysicsServer3D::MODE_DYNAMIC_LOCKED; reload_axis_lock(); _internal_set_mass(0 == mass ? 1 : mass); scratch_space_override_modificator(); @@ -711,7 +711,7 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { void RigidBodyBullet::reload_axis_lock() { btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)))); - if (PhysicsServer3D::BODY_MODE_CHARACTER == mode) { + if (PhysicsServer3D::MODE_DYNAMIC_LOCKED == mode) { /// When character angular is always locked btBody->setAngularFactor(btVector3(0., 0., 0.)); } else { @@ -1006,7 +1006,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { // Rigidbody is dynamic if and only if mass is non Zero, otherwise static const bool isDynamic = p_mass != 0.f; if (isDynamic) { - if (PhysicsServer3D::BODY_MODE_RIGID != mode && PhysicsServer3D::BODY_MODE_CHARACTER != mode) { + if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LOCKED != mode) { return; } @@ -1015,7 +1015,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) { mainShape->calculateLocalInertia(p_mass, localInertia); } - if (PhysicsServer3D::BODY_MODE_RIGID == mode) { + if (PhysicsServer3D::BODY_MODE_DYNAMIC == mode) { btBody->setCollisionFlags(clearedCurrentFlags); // Just set the flags without Kin and Static } else { btBody->setCollisionFlags(clearedCurrentFlags | btCollisionObject::CF_CHARACTER_OBJECT); diff --git a/modules/bullet/rigid_body_bullet.h b/modules/bullet/rigid_body_bullet.h index 843ff4a7af..606df7134b 100644 --- a/modules/bullet/rigid_body_bullet.h +++ b/modules/bullet/rigid_body_bullet.h @@ -107,8 +107,8 @@ public: virtual void set_angular_velocity(const Vector3 &p_velocity) override; virtual Vector3 get_angular_velocity() const override; - virtual void set_transform(const Transform &p_transform) override; - virtual Transform get_transform() const override; + virtual void set_transform(const Transform3D &p_transform) override; + virtual Transform3D get_transform() const override; virtual void add_central_force(const Vector3 &p_force) override; virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override; diff --git a/modules/bullet/slider_joint_bullet.cpp b/modules/bullet/slider_joint_bullet.cpp index 45c892851b..1d83118468 100644 --- a/modules/bullet/slider_joint_bullet.cpp +++ b/modules/bullet/slider_joint_bullet.cpp @@ -40,16 +40,16 @@ @author AndreaCatania */ -SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB) : +SliderJointBullet::SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : JointBullet() { - Transform scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); + Transform3D scaled_AFrame(frameInA.scaled(rbA->get_body_scale())); scaled_AFrame.basis.rotref_posscale_decomposition(scaled_AFrame.basis); btTransform btFrameA; G_TO_B(scaled_AFrame, btFrameA); if (rbB) { - Transform scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); + Transform3D scaled_BFrame(frameInB.scaled(rbB->get_body_scale())); scaled_BFrame.basis.rotref_posscale_decomposition(scaled_BFrame.basis); btTransform btFrameB; @@ -70,44 +70,44 @@ const RigidBodyBullet *SliderJointBullet::getRigidBodyB() const { return static_cast<RigidBodyBullet *>(sliderConstraint->getRigidBodyB().getUserPointer()); } -const Transform SliderJointBullet::getCalculatedTransformA() const { +const Transform3D SliderJointBullet::getCalculatedTransformA() const { btTransform btTransform = sliderConstraint->getCalculatedTransformA(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -const Transform SliderJointBullet::getCalculatedTransformB() const { +const Transform3D SliderJointBullet::getCalculatedTransformB() const { btTransform btTransform = sliderConstraint->getCalculatedTransformB(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -const Transform SliderJointBullet::getFrameOffsetA() const { +const Transform3D SliderJointBullet::getFrameOffsetA() const { btTransform btTransform = sliderConstraint->getFrameOffsetA(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -const Transform SliderJointBullet::getFrameOffsetB() const { +const Transform3D SliderJointBullet::getFrameOffsetB() const { btTransform btTransform = sliderConstraint->getFrameOffsetB(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -Transform SliderJointBullet::getFrameOffsetA() { +Transform3D SliderJointBullet::getFrameOffsetA() { btTransform btTransform = sliderConstraint->getFrameOffsetA(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } -Transform SliderJointBullet::getFrameOffsetB() { +Transform3D SliderJointBullet::getFrameOffsetB() { btTransform btTransform = sliderConstraint->getFrameOffsetB(); - Transform gTrans; + Transform3D gTrans; B_TO_G(btTransform, gTrans); return gTrans; } diff --git a/modules/bullet/slider_joint_bullet.h b/modules/bullet/slider_joint_bullet.h index 90964671c2..0c93558449 100644 --- a/modules/bullet/slider_joint_bullet.h +++ b/modules/bullet/slider_joint_bullet.h @@ -44,18 +44,18 @@ class SliderJointBullet : public JointBullet { public: /// Reference frame is A - SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform &frameInA, const Transform &frameInB); + SliderJointBullet(RigidBodyBullet *rbA, RigidBodyBullet *rbB, const Transform3D &frameInA, const Transform3D &frameInB); virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_SLIDER; } const RigidBodyBullet *getRigidBodyA() const; const RigidBodyBullet *getRigidBodyB() const; - const Transform getCalculatedTransformA() const; - const Transform getCalculatedTransformB() const; - const Transform getFrameOffsetA() const; - const Transform getFrameOffsetB() const; - Transform getFrameOffsetA(); - Transform getFrameOffsetB(); + const Transform3D getCalculatedTransformA() const; + const Transform3D getCalculatedTransformB() const; + const Transform3D getFrameOffsetA() const; + const Transform3D getFrameOffsetB() const; + Transform3D getFrameOffsetA(); + Transform3D getFrameOffsetB(); real_t getLowerLinLimit() const; void setLowerLinLimit(real_t lowerLimit); real_t getUpperLinLimit() const; diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp index 2c8727baf2..bbbb0e7851 100644 --- a/modules/bullet/soft_body_bullet.cpp +++ b/modules/bullet/soft_body_bullet.cpp @@ -136,7 +136,7 @@ void SoftBodyBullet::destroy_soft_body() { bt_soft_body = nullptr; } -void SoftBodyBullet::set_soft_transform(const Transform &p_transform) { +void SoftBodyBullet::set_soft_transform(const Transform3D &p_transform) { reset_all_node_positions(); move_all_nodes(p_transform); } @@ -159,7 +159,7 @@ AABB SoftBodyBullet::get_bounds() const { return aabb; } -void SoftBodyBullet::move_all_nodes(const Transform &p_transform) { +void SoftBodyBullet::move_all_nodes(const Transform3D &p_transform) { if (!bt_soft_body) { return; } diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h index 87023b2517..63708b57a7 100644 --- a/modules/bullet/soft_body_bullet.h +++ b/modules/bullet/soft_body_bullet.h @@ -104,11 +104,11 @@ public: void destroy_soft_body(); // Special function. This function has bad performance - void set_soft_transform(const Transform &p_transform); + void set_soft_transform(const Transform3D &p_transform); AABB get_bounds() const; - void move_all_nodes(const Transform &p_transform); + void move_all_nodes(const Transform3D &p_transform); void set_node_position(int node_index, const Vector3 &p_global_position); void set_node_position(int node_index, const btVector3 &p_global_position); void get_node_position(int node_index, Vector3 &r_position) const; diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index bdaec4a09e..33dd9ef56d 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -117,7 +117,7 @@ bool BulletPhysicsDirectSpaceState::intersect_ray(const Vector3 &p_from, const V } } -int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return 0; } @@ -152,7 +152,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { +bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { r_closest_safe = 0.0f; r_closest_unsafe = 0.0f; btVector3 bt_motion; @@ -214,7 +214,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf } /// Returns the list of contacts pairs in this order: Local contact, other body contact -bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return false; } @@ -250,7 +250,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform & return btQuery.m_count; } -bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape); ERR_FAIL_COND_V(!shape, false); @@ -445,7 +445,7 @@ real_t SpaceBullet::get_param(PhysicsServer3D::SpaceParameter p_param) { case PhysicsServer3D::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: default: - WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned."); + WARN_PRINT("The SpaceBullet doesn't support this get parameter (" + itos(p_param) + "), 0 is returned."); return 0.f; } } @@ -908,7 +908,7 @@ static Ref<StandardMaterial3D> red_mat; static Ref<StandardMaterial3D> blue_mat; #endif -bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { #if debug_test_motion /// Yes I know this is not good, but I've used it as fast debugging hack. /// I'm leaving it here just for speedup the other eventual debugs @@ -1062,7 +1062,7 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform &p_f return has_penetration; } -int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { +int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { btTransform body_transform; G_TO_B(p_transform, body_transform); UNSCALE_BT_BASIS(body_transform); diff --git a/modules/bullet/space_bullet.h b/modules/bullet/space_bullet.h index 87aa2b9e93..36d0538e6b 100644 --- a/modules/bullet/space_bullet.h +++ b/modules/bullet/space_bullet.h @@ -78,11 +78,11 @@ public: virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &r_closest_safe, real_t &r_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; /// Returns the list of contacts pairs in this order: Local contact, other body contact - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; }; @@ -188,8 +188,8 @@ public: real_t get_linear_damp() const { return linear_damp; } real_t get_angular_damp() const { return angular_damp; } - bool test_body_motion(RigidBodyBullet *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); - int test_ray_separation(RigidBodyBullet *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); + bool test_body_motion(RigidBodyBullet *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); + int test_ray_separation(RigidBodyBullet *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); private: void create_empty_world(bool p_create_soft_world); diff --git a/modules/camera/camera_osx.mm b/modules/camera/camera_osx.mm index 9b59b68075..6bc56add20 100644 --- a/modules/camera/camera_osx.mm +++ b/modules/camera/camera_osx.mm @@ -162,7 +162,7 @@ uint8_t *w = img_data[0].ptrw(); memcpy(w, dataY, new_width * new_height); - img[0].instance(); + img[0].instantiate(); img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]); } @@ -181,7 +181,7 @@ memcpy(w, dataCbCr, 2 * new_width * new_height); ///TODO GLES2 doesn't support FORMAT_RG8, need to do some form of conversion - img[1].instance(); + img[1].instantiate(); img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]); } @@ -341,7 +341,7 @@ void CameraOSX::update_feeds() { if (!found) { Ref<CameraFeedOSX> newfeed; - newfeed.instance(); + newfeed.instantiate(); newfeed->set_device(device); // assume display camera so inverse diff --git a/modules/csg/config.py b/modules/csg/config.py index 9106cbceca..3991b846f9 100644 --- a/modules/csg/config.py +++ b/modules/csg/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 7387842259..5a37486568 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -265,7 +265,7 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector< _regen_face_aabbs(); } -void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform &p_xform) { +void CSGBrush::copy_from(const CSGBrush &p_brush, const Transform3D &p_xform) { faces = p_brush.faces; materials = p_brush.materials; diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 3fbed66e5c..c872860486 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -33,10 +33,10 @@ #include "core/math/aabb.h" #include "core/math/plane.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/list.h" #include "core/templates/map.h" #include "core/templates/oa_hash_map.h" @@ -60,7 +60,7 @@ struct CSGBrush { // Create a brush from faces. void build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces); - void copy_from(const CSGBrush &p_brush, const Transform &p_xform); + void copy_from(const CSGBrush &p_brush, const Transform3D &p_xform); }; struct CSGBrushOperation { @@ -165,8 +165,8 @@ struct CSGBrushOperation { Vector<Vertex2D> vertices; Vector<Face2D> faces; Plane plane; - Transform to_2D; - Transform to_3D; + Transform3D to_2D; + Transform3D to_3D; float vertex_snap2 = 0.0; inline int _get_point_idx(const Vector2 &p_point); diff --git a/modules/csg/csg_gizmos.cpp b/modules/csg/csg_gizmos.cpp index 8a46dcca65..37a7d96de5 100644 --- a/modules/csg/csg_gizmos.cpp +++ b/modules/csg/csg_gizmos.cpp @@ -99,9 +99,9 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(EditorNode3DGizmo *p_gizmo, int void CSGShape3DGizmoPlugin::set_handle(EditorNode3DGizmo *p_gizmo, int p_idx, Camera3D *p_camera, const Point2 &p_point) { CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_spatial_node()); - Transform gt = cs->get_global_transform(); + Transform3D gt = cs->get_global_transform(); //gt.orthonormalize(); - Transform gi = gt.affine_inverse(); + Transform3D gi = gt.affine_inverse(); Vector3 ray_from = p_camera->project_ray_origin(p_point); Vector3 ray_dir = p_camera->project_ray_normal(p_point); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 67dfdfb5eb..fd8b213293 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -44,7 +44,7 @@ void CSGShape3D::set_use_collision(bool p_enable) { } if (use_collision) { - root_collision_shape.instance(); + root_collision_shape.instantiate(); root_collision_instance = PhysicsServer3D::get_singleton()->body_create(); PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); @@ -411,7 +411,7 @@ void CSGShape3D::_update_shape() { } } - root_mesh.instance(); + root_mesh.instantiate(); //create surfaces for (int i = 0; i < surfaces.size(); i++) { @@ -498,7 +498,7 @@ void CSGShape3D::_notification(int p_what) { } if (use_collision && is_root_shape()) { - root_collision_shape.instance(); + root_collision_shape.instantiate(); root_collision_instance = PhysicsServer3D::get_singleton()->body_create(); PhysicsServer3D::get_singleton()->body_set_mode(root_collision_instance, PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_state(root_collision_instance, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); @@ -578,7 +578,7 @@ Array CSGShape3D::get_meshes() const { if (root_mesh.is_valid()) { Array arr; arr.resize(2); - arr[0] = Transform(); + arr[0] = Transform3D(); arr[1] = root_mesh; return arr; } @@ -868,7 +868,7 @@ void CSGMesh3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &CSGMesh3D::get_material); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGMesh3D::set_mesh(const Ref<Mesh> &p_mesh) { @@ -1027,7 +1027,7 @@ void CSGSphere3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGSphere3D::set_radius(const float p_radius) { @@ -1197,7 +1197,7 @@ void CSGBox3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &CSGBox3D::get_material); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGBox3D::set_size(const Vector3 &p_size) { @@ -1373,12 +1373,12 @@ void CSGCylinder3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGCylinder3D::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGCylinder3D::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_radius", "get_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_radius", "get_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cone"), "set_cone", "is_cone"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGCylinder3D::set_radius(const float p_radius) { @@ -1592,12 +1592,12 @@ void CSGTorus3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_smooth_faces", "smooth_faces"), &CSGTorus3D::set_smooth_faces); ClassDB::bind_method(D_METHOD("get_smooth_faces"), &CSGTorus3D::get_smooth_faces); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_outer_radius", "get_outer_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_inner_radius", "get_inner_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_outer_radius", "get_outer_radius"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_sides", "get_sides"); ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_sides", "get_ring_sides"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); } void CSGTorus3D::set_inner_radius(const float p_inner_radius) { @@ -1978,13 +1978,13 @@ CSGBrush *CSGPolygon3D::_build_brush() { float u1 = 0.0; float u2 = path_continuous_u ? 0.0 : 1.0; - Transform path_to_this; + Transform3D path_to_this; if (!path_local) { // center on paths origin path_to_this = get_global_transform().affine_inverse() * path->get_global_transform(); } - Transform prev_xf; + Transform3D prev_xf; Vector3 lookat_dir; @@ -2006,7 +2006,7 @@ CSGBrush *CSGPolygon3D::_build_brush() { ofs = 0.0; } - Transform xf; + Transform3D xf; xf.origin = curve->interpolate_baked(ofs); Vector3 local_dir; @@ -2158,13 +2158,13 @@ void CSGPolygon3D::_notification(int p_what) { void CSGPolygon3D::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("spin") && mode != MODE_SPIN) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("path") && mode != MODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "depth" && mode != MODE_DEPTH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } CSGShape3D::_validate_property(property); @@ -2224,17 +2224,17 @@ void CSGPolygon3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Depth,Spin,Path"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_depth", "get_depth"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees"); ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_EXP_RANGE, "0.001,1000.0,0.001,or_greater"), "set_path_interval", "get_path_interval"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater,exp"), "set_path_interval", "get_path_interval"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "StandardMaterial3D,ShaderMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); BIND_ENUM_CONSTANT(MODE_DEPTH); BIND_ENUM_CONSTANT(MODE_SPIN); diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml index b1d0454b76..5bb1c4e75b 100644 --- a/modules/csg/doc_classes/CSGBox3D.xml +++ b/modules/csg/doc_classes/CSGBox3D.xml @@ -14,7 +14,7 @@ <member name="material" type="Material" setter="set_material" getter="get_material"> The material used to render the box. </member> - <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3( 2, 2, 2 )"> + <member name="size" type="Vector3" setter="set_size" getter="get_size" default="Vector3(2, 2, 2)"> The box's width, height and depth. </member> </members> diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml index c55fa0983e..4f29786779 100644 --- a/modules/csg/doc_classes/CSGPolygon3D.xml +++ b/modules/csg/doc_classes/CSGPolygon3D.xml @@ -38,7 +38,7 @@ <member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation"> The method by which each slice is rotated along the path when [member mode] is [constant MODE_PATH]. </member> - <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array( 0, 0, 0, 1, 1, 1, 1, 0 )"> + <member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)"> Point array that defines the shape that we'll extrude. </member> <member name="smooth_faces" type="bool" setter="set_smooth_faces" getter="get_smooth_faces" default="false"> diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index dac556c7f1..01ec46e707 100644 --- a/modules/csg/doc_classes/CSGShape3D.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -31,7 +31,7 @@ <return type="Array"> </return> <description> - Returns an [Array] with two elements, the first is the [Transform] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape. + Returns an [Array] with two elements, the first is the [Transform3D] of this node and the second is the root [Mesh] of this node. Only works when this node is the root shape. </description> </method> <method name="is_root_shape" qualifiers="const"> diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp index 1444d33171..60282c3f36 100644 --- a/modules/dds/register_types.cpp +++ b/modules/dds/register_types.cpp @@ -35,7 +35,7 @@ static Ref<ResourceFormatDDS> resource_loader_dds; void register_dds_types() { - resource_loader_dds.instance(); + resource_loader_dds.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_dds); } diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp index 2fef576b77..fced61a600 100644 --- a/modules/dds/texture_loader_dds.cpp +++ b/modules/dds/texture_loader_dds.cpp @@ -30,7 +30,7 @@ #include "texture_loader_dds.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #define PF_FOURCC(s) ((uint32_t)(((s)[3] << 24U) | ((s)[2] << 16U) | ((s)[1] << 8U) | ((s)[0]))) diff --git a/modules/enet/config.py b/modules/enet/config.py index 5fd343c75d..3662b2d94e 100644 --- a/modules/enet/config.py +++ b/modules/enet/config.py @@ -8,7 +8,7 @@ def configure(env): def get_doc_classes(): return [ - "NetworkedMultiplayerENet", + "ENetMultiplayerPeer", ] diff --git a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml index 271cb03c9f..5b2c72dce4 100644 --- a/modules/enet/doc_classes/NetworkedMultiplayerENet.xml +++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="ENetMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> PacketPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library. </brief_description> <description> - A PacketPeer implementation that should be passed to [member SceneTree.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals. + A PacketPeer implementation that should be passed to [member MultiplayerAPI.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals. ENet's purpose is to provide a relatively thin, simple and robust network communication layer on top of UDP (User Datagram Protocol). [b]Note:[/b] ENet only uses UDP, not TCP. When forwarding the server port to make your server accessible on the public Internet, you only need to forward the server port in UDP. You can use the [UPNP] class to try to forward the server port automatically when starting the server. </description> @@ -36,7 +36,7 @@ <argument index="4" name="local_port" type="int" default="0"> </argument> <description> - Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. + Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]local_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques. </description> </method> <method name="create_server"> @@ -51,7 +51,7 @@ <argument index="3" name="out_bandwidth" type="int" default="0"> </argument> <description> - Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. + Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this ENetMultiplayerPeer instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created. </description> </method> <method name="disconnect_peer"> @@ -150,12 +150,12 @@ </methods> <members> <member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false"> - Enforce ordered packets when using [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system. + Enforce ordered packets when using [constant MultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant MultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system. </member> <member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count" default="3"> The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per-channel basis. This is done to combat latency and reduces ordering restrictions on packets. The delivery status of a packet in one channel won't stall the delivery of other packets in another channel. </member> - <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="NetworkedMultiplayerENet.CompressionMode" default="0"> + <member name="compression_mode" type="int" setter="set_compression_mode" getter="get_compression_mode" enum="ENetMultiplayerPeer.CompressionMode" default="0"> The compression method used for network packets. These have different tradeoffs of compression speed versus bandwidth, you may need to test which one works best for your use case if you use compression at all. </member> <member name="dtls_verify" type="bool" setter="set_dtls_verify_enabled" getter="is_dtls_verify_enabled" default="true"> @@ -168,7 +168,7 @@ <member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1"> Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels: one for reliable packets, and one for unreliable packets. The channel [code]0[/code] is reserved and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data. See [member channel_count] for more information about ENet channels. </member> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> <member name="use_dtls" type="bool" setter="set_dtls_enabled" getter="is_dtls_enabled" default="false"> When enabled, the client or server created by this peer, will use [PacketPeerDTLS] instead of raw UDP sockets for communicating with the remote peer. This will make the communication encrypted with DTLS at the cost of higher resource usage and potentially larger packet size. Note: When creating a DTLS server, make sure you setup the key/certificate pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS clients, have a look at the [member dtls_verify] option, and configure the certificate accordingly via [method set_dtls_certificate]. diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/enet_multiplayer_peer.cpp index 9491373013..a9726426ad 100644 --- a/modules/enet/networked_multiplayer_enet.cpp +++ b/modules/enet/enet_multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_enet.cpp */ +/* enet_multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,45 +28,45 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "networked_multiplayer_enet.h" +#include "enet_multiplayer_peer.h" #include "core/io/ip.h" #include "core/io/marshalls.h" #include "core/os/os.h" -void NetworkedMultiplayerENet::set_transfer_mode(TransferMode p_mode) { +void ENetMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } -NetworkedMultiplayerPeer::TransferMode NetworkedMultiplayerENet::get_transfer_mode() const { +MultiplayerPeer::TransferMode ENetMultiplayerPeer::get_transfer_mode() const { return transfer_mode; } -void NetworkedMultiplayerENet::set_target_peer(int p_peer) { +void ENetMultiplayerPeer::set_target_peer(int p_peer) { target_peer = p_peer; } -int NetworkedMultiplayerENet::get_packet_peer() const { +int ENetMultiplayerPeer::get_packet_peer() const { ERR_FAIL_COND_V_MSG(!active, 1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, 1); return incoming_packets.front()->get().from; } -int NetworkedMultiplayerENet::get_packet_channel() const { +int ENetMultiplayerPeer::get_packet_channel() const { ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(incoming_packets.size() == 0, -1); return incoming_packets.front()->get().channel; } -int NetworkedMultiplayerENet::get_last_packet_channel() const { +int ENetMultiplayerPeer::get_last_packet_channel() const { ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V(!current_packet.packet, -1); return current_packet.channel; } -Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { +Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) { ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive)."); @@ -115,7 +115,7 @@ Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int connection_status = CONNECTION_CONNECTED; return OK; } -Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) { +Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) { ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active."); ERR_FAIL_COND_V_MSG(p_port < 1 || p_port > 65535, ERR_INVALID_PARAMETER, "The remote port number must be between 1 and 65535 (inclusive)."); ERR_FAIL_COND_V_MSG(p_local_port < 0 || p_local_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive)."); @@ -199,7 +199,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por return OK; } -void NetworkedMultiplayerENet::poll() { +void ENetMultiplayerPeer::poll() { ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); _pop_current_packet(); @@ -362,7 +362,10 @@ void NetworkedMultiplayerENet::poll() { // To myself and only myself incoming_packets.push_back(packet); } else if (!server_relay) { - // No other destination is allowed when server is not relaying + // When relaying is disabled, other destinations will only be processed by the server. + if (target == 0 || target < -1) { + incoming_packets.push_back(packet); + } continue; } else if (target == 0) { // Re-send to everyone but sender :| @@ -423,13 +426,13 @@ void NetworkedMultiplayerENet::poll() { } } -bool NetworkedMultiplayerENet::is_server() const { +bool ENetMultiplayerPeer::is_server() const { ERR_FAIL_COND_V_MSG(!active, false, "The multiplayer instance isn't currently active."); return server; } -void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) { +void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) { ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); _pop_current_packet(); @@ -460,7 +463,7 @@ void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) { connection_status = CONNECTION_DISCONNECTED; } -void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { +void ENetMultiplayerPeer::disconnect_peer(int p_peer, bool now) { ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_MSG(!is_server(), "Can't disconnect a peer when not acting as a server."); ERR_FAIL_COND_MSG(!peer_map.has(p_peer), vformat("Peer ID %d not found in the list of peers.", p_peer)); @@ -495,11 +498,11 @@ void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) { } } -int NetworkedMultiplayerENet::get_available_packet_count() const { +int ENetMultiplayerPeer::get_available_packet_count() const { return incoming_packets.size(); } -Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { +Error ENetMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { ERR_FAIL_COND_V_MSG(incoming_packets.size() == 0, ERR_UNAVAILABLE, "No incoming packets available."); _pop_current_packet(); @@ -513,7 +516,7 @@ Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buff return OK; } -Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer_size) { +Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V_MSG(!active, ERR_UNCONFIGURED, "The multiplayer instance isn't currently active."); ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client."); @@ -588,11 +591,11 @@ Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer return OK; } -int NetworkedMultiplayerENet::get_max_packet_size() const { +int ENetMultiplayerPeer::get_max_packet_size() const { return 1 << 24; // Anything is good } -void NetworkedMultiplayerENet::_pop_current_packet() { +void ENetMultiplayerPeer::_pop_current_packet() { if (current_packet.packet) { enet_packet_destroy(current_packet.packet); current_packet.packet = nullptr; @@ -601,11 +604,11 @@ void NetworkedMultiplayerENet::_pop_current_packet() { } } -NetworkedMultiplayerPeer::ConnectionStatus NetworkedMultiplayerENet::get_connection_status() const { +MultiplayerPeer::ConnectionStatus ENetMultiplayerPeer::get_connection_status() const { return connection_status; } -uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { +uint32_t ENetMultiplayerPeer::_gen_unique_id() const { uint32_t hash = 0; while (hash == 0 || hash == 1) { @@ -626,12 +629,12 @@ uint32_t NetworkedMultiplayerENet::_gen_unique_id() const { return hash; } -int NetworkedMultiplayerENet::get_unique_id() const { +int ENetMultiplayerPeer::get_unique_id() const { ERR_FAIL_COND_V_MSG(!active, 0, "The multiplayer instance isn't currently active."); return unique_id; } -void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) { +void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enable) { refuse_connections = p_enable; #ifdef GODOT_ENET if (active) { @@ -640,20 +643,20 @@ void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) { #endif } -bool NetworkedMultiplayerENet::is_refusing_new_connections() const { +bool ENetMultiplayerPeer::is_refusing_new_connections() const { return refuse_connections; } -void NetworkedMultiplayerENet::set_compression_mode(CompressionMode p_mode) { +void ENetMultiplayerPeer::set_compression_mode(CompressionMode p_mode) { compression_mode = p_mode; } -NetworkedMultiplayerENet::CompressionMode NetworkedMultiplayerENet::get_compression_mode() const { +ENetMultiplayerPeer::CompressionMode ENetMultiplayerPeer::get_compression_mode() const { return compression_mode; } -size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet *)(context); +size_t ENetMultiplayerPeer::enet_compress(void *context, const ENetBuffer *inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 *outData, size_t outLimit) { + ENetMultiplayerPeer *enet = (ENetMultiplayerPeer *)(context); if (size_t(enet->src_compressor_mem.size()) < inLimit) { enet->src_compressor_mem.resize(inLimit); @@ -706,8 +709,8 @@ size_t NetworkedMultiplayerENet::enet_compress(void *context, const ENetBuffer * return ret; } -size_t NetworkedMultiplayerENet::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { - NetworkedMultiplayerENet *enet = (NetworkedMultiplayerENet *)(context); +size_t ENetMultiplayerPeer::enet_decompress(void *context, const enet_uint8 *inData, size_t inLimit, enet_uint8 *outData, size_t outLimit) { + ENetMultiplayerPeer *enet = (ENetMultiplayerPeer *)(context); int ret = -1; switch (enet->compression_mode) { case COMPRESS_FASTLZ: { @@ -729,7 +732,7 @@ size_t NetworkedMultiplayerENet::enet_decompress(void *context, const enet_uint8 } } -void NetworkedMultiplayerENet::_setup_compressor() { +void ENetMultiplayerPeer::_setup_compressor() { switch (compression_mode) { case COMPRESS_NONE: { enet_host_compress(host, nullptr); @@ -745,11 +748,11 @@ void NetworkedMultiplayerENet::_setup_compressor() { } } -void NetworkedMultiplayerENet::enet_compressor_destroy(void *context) { +void ENetMultiplayerPeer::enet_compressor_destroy(void *context) { // Nothing to do } -IPAddress NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const { +IPAddress ENetMultiplayerPeer::get_peer_address(int p_peer_id) const { ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IPAddress(), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IPAddress(), "Can't get the address of peers other than the server (ID -1) when acting as a client."); ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IPAddress(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); @@ -764,7 +767,7 @@ IPAddress NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const { return out; } -int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const { +int ENetMultiplayerPeer::get_peer_port(int p_peer_id) const { ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), 0, vformat("Peer ID %d not found in the list of peers.", p_peer_id)); ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, 0, "Can't get the address of peers other than the server (ID -1) when acting as a client."); ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); @@ -775,12 +778,12 @@ int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const { #endif } -int NetworkedMultiplayerENet::get_local_port() const { +int ENetMultiplayerPeer::get_local_port() const { ERR_FAIL_COND_V_MSG(!active || !host, 0, "The multiplayer instance isn't currently active."); return host->address.port; } -void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) { +void ENetMultiplayerPeer::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) { ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id)); ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client."); ERR_FAIL_COND_MSG(peer_map[p_peer_id] == nullptr, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id)); @@ -788,73 +791,73 @@ void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_lim enet_peer_timeout(peer_map[p_peer_id], p_timeout_limit, p_timeout_min, p_timeout_max); } -void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) { +void ENetMultiplayerPeer::set_transfer_channel(int p_channel) { ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel)); ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, vformat("The channel %d is reserved.", SYSCH_CONFIG)); transfer_channel = p_channel; } -int NetworkedMultiplayerENet::get_transfer_channel() const { +int ENetMultiplayerPeer::get_transfer_channel() const { return transfer_channel; } -void NetworkedMultiplayerENet::set_channel_count(int p_channel) { +void ENetMultiplayerPeer::set_channel_count(int p_channel) { ERR_FAIL_COND_MSG(active, "The channel count can't be set while the multiplayer instance is active."); ERR_FAIL_COND_MSG(p_channel < SYSCH_MAX, vformat("The channel count must be greater than or equal to %d to account for reserved channels (got %d).", SYSCH_MAX, p_channel)); channel_count = p_channel; } -int NetworkedMultiplayerENet::get_channel_count() const { +int ENetMultiplayerPeer::get_channel_count() const { return channel_count; } -void NetworkedMultiplayerENet::set_always_ordered(bool p_ordered) { +void ENetMultiplayerPeer::set_always_ordered(bool p_ordered) { always_ordered = p_ordered; } -bool NetworkedMultiplayerENet::is_always_ordered() const { +bool ENetMultiplayerPeer::is_always_ordered() const { return always_ordered; } -void NetworkedMultiplayerENet::set_server_relay_enabled(bool p_enabled) { +void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) { ERR_FAIL_COND_MSG(active, "Server relaying can't be toggled while the multiplayer instance is active."); server_relay = p_enabled; } -bool NetworkedMultiplayerENet::is_server_relay_enabled() const { +bool ENetMultiplayerPeer::is_server_relay_enabled() const { return server_relay; } -void NetworkedMultiplayerENet::_bind_methods() { - ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100)); - ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &NetworkedMultiplayerENet::set_compression_mode); - ClassDB::bind_method(D_METHOD("get_compression_mode"), &NetworkedMultiplayerENet::get_compression_mode); - ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &NetworkedMultiplayerENet::set_bind_ip); - ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_enabled); - ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &NetworkedMultiplayerENet::is_dtls_enabled); - ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &NetworkedMultiplayerENet::set_dtls_key); - ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &NetworkedMultiplayerENet::set_dtls_certificate); - ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_verify_enabled); - ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled); - ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address); - ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port); - ClassDB::bind_method(D_METHOD("get_local_port"), &NetworkedMultiplayerENet::get_local_port); - ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout); - - ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel); - ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &NetworkedMultiplayerENet::get_last_packet_channel); - ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &NetworkedMultiplayerENet::set_transfer_channel); - ClassDB::bind_method(D_METHOD("get_transfer_channel"), &NetworkedMultiplayerENet::get_transfer_channel); - ClassDB::bind_method(D_METHOD("set_channel_count", "channels"), &NetworkedMultiplayerENet::set_channel_count); - ClassDB::bind_method(D_METHOD("get_channel_count"), &NetworkedMultiplayerENet::get_channel_count); - ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &NetworkedMultiplayerENet::set_always_ordered); - ClassDB::bind_method(D_METHOD("is_always_ordered"), &NetworkedMultiplayerENet::is_always_ordered); - ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &NetworkedMultiplayerENet::set_server_relay_enabled); - ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &NetworkedMultiplayerENet::is_server_relay_enabled); +void ENetMultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &ENetMultiplayerPeer::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "local_port"), &ENetMultiplayerPeer::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &ENetMultiplayerPeer::close_connection, DEFVAL(100)); + ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &ENetMultiplayerPeer::disconnect_peer, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_compression_mode", "mode"), &ENetMultiplayerPeer::set_compression_mode); + ClassDB::bind_method(D_METHOD("get_compression_mode"), &ENetMultiplayerPeer::get_compression_mode); + ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &ENetMultiplayerPeer::set_bind_ip); + ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &ENetMultiplayerPeer::set_dtls_enabled); + ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &ENetMultiplayerPeer::is_dtls_enabled); + ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &ENetMultiplayerPeer::set_dtls_key); + ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &ENetMultiplayerPeer::set_dtls_certificate); + ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &ENetMultiplayerPeer::set_dtls_verify_enabled); + ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &ENetMultiplayerPeer::is_dtls_verify_enabled); + ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &ENetMultiplayerPeer::get_peer_address); + ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &ENetMultiplayerPeer::get_peer_port); + ClassDB::bind_method(D_METHOD("get_local_port"), &ENetMultiplayerPeer::get_local_port); + ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &ENetMultiplayerPeer::set_peer_timeout); + + ClassDB::bind_method(D_METHOD("get_packet_channel"), &ENetMultiplayerPeer::get_packet_channel); + ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &ENetMultiplayerPeer::get_last_packet_channel); + ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &ENetMultiplayerPeer::set_transfer_channel); + ClassDB::bind_method(D_METHOD("get_transfer_channel"), &ENetMultiplayerPeer::get_transfer_channel); + ClassDB::bind_method(D_METHOD("set_channel_count", "channels"), &ENetMultiplayerPeer::set_channel_count); + ClassDB::bind_method(D_METHOD("get_channel_count"), &ENetMultiplayerPeer::get_channel_count); + ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &ENetMultiplayerPeer::set_always_ordered); + ClassDB::bind_method(D_METHOD("is_always_ordered"), &ENetMultiplayerPeer::is_always_ordered); + ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &ENetMultiplayerPeer::set_server_relay_enabled); + ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &ENetMultiplayerPeer::is_server_relay_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "compression_mode", PROPERTY_HINT_ENUM, "None,Range Coder,FastLZ,ZLib,ZStd"), "set_compression_mode", "get_compression_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel"), "set_transfer_channel", "get_transfer_channel"); @@ -871,7 +874,7 @@ void NetworkedMultiplayerENet::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESS_ZSTD); } -NetworkedMultiplayerENet::NetworkedMultiplayerENet() { +ENetMultiplayerPeer::ENetMultiplayerPeer() { enet_compressor.context = this; enet_compressor.compress = enet_compress; enet_compressor.decompress = enet_decompress; @@ -880,7 +883,7 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() { bind_ip = IPAddress("*"); } -NetworkedMultiplayerENet::~NetworkedMultiplayerENet() { +ENetMultiplayerPeer::~ENetMultiplayerPeer() { if (active) { close_connection(); } @@ -888,36 +891,36 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet() { // Sets IP for ENet to bind when using create_server or create_client // if no IP is set, then ENet bind to ENET_HOST_ANY -void NetworkedMultiplayerENet::set_bind_ip(const IPAddress &p_ip) { +void ENetMultiplayerPeer::set_bind_ip(const IPAddress &p_ip) { ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip))); bind_ip = p_ip; } -void NetworkedMultiplayerENet::set_dtls_enabled(bool p_enabled) { +void ENetMultiplayerPeer::set_dtls_enabled(bool p_enabled) { ERR_FAIL_COND(active); dtls_enabled = p_enabled; } -bool NetworkedMultiplayerENet::is_dtls_enabled() const { +bool ENetMultiplayerPeer::is_dtls_enabled() const { return dtls_enabled; } -void NetworkedMultiplayerENet::set_dtls_verify_enabled(bool p_enabled) { +void ENetMultiplayerPeer::set_dtls_verify_enabled(bool p_enabled) { ERR_FAIL_COND(active); dtls_verify = p_enabled; } -bool NetworkedMultiplayerENet::is_dtls_verify_enabled() const { +bool ENetMultiplayerPeer::is_dtls_verify_enabled() const { return dtls_verify; } -void NetworkedMultiplayerENet::set_dtls_key(Ref<CryptoKey> p_key) { +void ENetMultiplayerPeer::set_dtls_key(Ref<CryptoKey> p_key) { ERR_FAIL_COND(active); dtls_key = p_key; } -void NetworkedMultiplayerENet::set_dtls_certificate(Ref<X509Certificate> p_cert) { +void ENetMultiplayerPeer::set_dtls_certificate(Ref<X509Certificate> p_cert) { ERR_FAIL_COND(active); dtls_cert = p_cert; } diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/enet_multiplayer_peer.h index 2d928859fa..e6d45eb16a 100644 --- a/modules/enet/networked_multiplayer_enet.h +++ b/modules/enet/enet_multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* networked_multiplayer_enet.h */ +/* enet_multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -33,12 +33,12 @@ #include "core/crypto/crypto.h" #include "core/io/compression.h" -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include <enet/enet.h> -class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer { - GDCLASS(NetworkedMultiplayerENet, NetworkedMultiplayerPeer); +class ENetMultiplayerPeer : public MultiplayerPeer { + GDCLASS(ENetMultiplayerPeer, MultiplayerPeer); public: enum CompressionMode { @@ -168,8 +168,8 @@ public: void set_server_relay_enabled(bool p_enabled); bool is_server_relay_enabled() const; - NetworkedMultiplayerENet(); - ~NetworkedMultiplayerENet(); + ENetMultiplayerPeer(); + ~ENetMultiplayerPeer(); void set_bind_ip(const IPAddress &p_ip); void set_dtls_enabled(bool p_enabled); @@ -180,6 +180,6 @@ public: void set_dtls_certificate(Ref<X509Certificate> p_cert); }; -VARIANT_ENUM_CAST(NetworkedMultiplayerENet::CompressionMode); +VARIANT_ENUM_CAST(ENetMultiplayerPeer::CompressionMode); #endif // NETWORKED_MULTIPLAYER_ENET_H diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp index 8da2d17e13..7a32903d76 100644 --- a/modules/enet/register_types.cpp +++ b/modules/enet/register_types.cpp @@ -30,7 +30,7 @@ #include "register_types.h" #include "core/error/error_macros.h" -#include "networked_multiplayer_enet.h" +#include "enet_multiplayer_peer.h" static bool enet_ok = false; @@ -41,7 +41,7 @@ void register_enet_types() { enet_ok = true; } - ClassDB::register_class<NetworkedMultiplayerENet>(); + ClassDB::register_class<ENetMultiplayerPeer>(); } void unregister_enet_types() { diff --git a/modules/fbx/README.md b/modules/fbx/README.md index 69a50d4bea..8eca4bd3c9 100644 --- a/modules/fbx/README.md +++ b/modules/fbx/README.md @@ -79,23 +79,23 @@ enum RotOrder { // references: ComputePivotTransform / run the calculation // This is the local pivot transform for the node, not the global transforms Transform ComputePivotTransform( - Transform chain[TransformationComp_MAXIMUM], - Transform &geometric_transform) { + Transform3D chain[TransformationComp_MAXIMUM], + Transform3D &geometric_transform) { // Maya pivots - Transform T = chain[TransformationComp_Translation]; - Transform Roff = chain[TransformationComp_RotationOffset]; - Transform Rp = chain[TransformationComp_RotationPivot]; - Transform Rpre = chain[TransformationComp_PreRotation]; - Transform R = chain[TransformationComp_Rotation]; - Transform Rpost = chain[TransformationComp_PostRotation]; - Transform Soff = chain[TransformationComp_ScalingOffset]; - Transform Sp = chain[TransformationComp_ScalingPivot]; - Transform S = chain[TransformationComp_Scaling]; + Transform3D T = chain[TransformationComp_Translation]; + Transform3D Roff = chain[TransformationComp_RotationOffset]; + Transform3D Rp = chain[TransformationComp_RotationPivot]; + Transform3D Rpre = chain[TransformationComp_PreRotation]; + Transform3D R = chain[TransformationComp_Rotation]; + Transform3D Rpost = chain[TransformationComp_PostRotation]; + Transform3D Soff = chain[TransformationComp_ScalingOffset]; + Transform3D Sp = chain[TransformationComp_ScalingPivot]; + Transform3D S = chain[TransformationComp_Scaling]; // 3DS Max Pivots - Transform OT = chain[TransformationComp_GeometricTranslation]; - Transform OR = chain[TransformationComp_GeometricRotation]; - Transform OS = chain[TransformationComp_GeometricScaling]; + Transform3D OT = chain[TransformationComp_GeometricTranslation]; + Transform3D OR = chain[TransformationComp_GeometricRotation]; + Transform3D OS = chain[TransformationComp_GeometricScaling]; // Calculate 3DS max pivot transform - use geometric space (e.g doesn't effect children nodes only the current node) geometric_transform = OT * OR * OS; diff --git a/modules/fbx/data/fbx_bone.h b/modules/fbx/data/fbx_bone.h index efba147b89..83918ad1e2 100644 --- a/modules/fbx/data/fbx_bone.h +++ b/modules/fbx/data/fbx_bone.h @@ -38,7 +38,7 @@ struct PivotTransform; -struct FBXBone : public Reference { +struct FBXBone : public RefCounted { uint64_t parent_bone_id = 0; uint64_t bone_id = 0; diff --git a/modules/fbx/data/fbx_material.cpp b/modules/fbx/data/fbx_material.cpp index d54ac86e9f..cf5d70fa5b 100644 --- a/modules/fbx/data/fbx_material.cpp +++ b/modules/fbx/data/fbx_material.cpp @@ -160,7 +160,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { const String p_fbx_current_directory = state.path; Ref<StandardMaterial3D> spatial_material; - spatial_material.instance(); + spatial_material.instantiate(); // read the material file // is material two sided @@ -223,7 +223,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } else if (fbx_texture_data != nullptr && fbx_texture_data->Media() != nullptr && fbx_texture_data->Media()->IsEmbedded()) { // This is an embedded texture. Extract it. Ref<Image> image; - //image.instance(); // oooo double instance bug? why make Image::_png_blah call + //image.instantiate(); // oooo double instance bug? why make Image::_png_blah call const String extension = texture_name.get_extension().to_upper(); if (extension == "PNG") { @@ -256,7 +256,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } Ref<ImageTexture> image_texture; - image_texture.instance(); + image_texture.instantiate(); image_texture->create_from_image(image); texture = image_texture; @@ -324,7 +324,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { if (spatial_material.is_null()) { // Done here so if no data no material is created. - spatial_material.instance(); + spatial_material.instantiate(); } const FBXDocParser::TypedProperty<real_t> *real_value = dynamic_cast<const FBXDocParser::TypedProperty<real_t> *>(prop); @@ -420,7 +420,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } break; case PROPERTY_DESC_COAT_ROUGHNESS: { // meaning is that approx equal to zero is disabled not actually zero. ;) - if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) { + if (real_value && Math::is_zero_approx(real_value->Value())) { print_verbose("clearcoat real value: " + rtos(real_value->Value())); spatial_material->set_clearcoat_gloss(1.0 - real_value->Value()); } else { @@ -428,7 +428,7 @@ Ref<StandardMaterial3D> FBXMaterial::import_material(ImportState &state) { } } break; case PROPERTY_DESC_EMISSIVE: { - if (real_value && Math::is_equal_approx(real_value->Value(), 0.0f)) { + if (real_value && Math::is_zero_approx(real_value->Value())) { print_verbose("Emissive real value: " + rtos(real_value->Value())); spatial_material->set_emission_energy(real_value->Value()); } else if (vector_value && !vector_value->Value().is_equal_approx(Vector3(0, 0, 0))) { diff --git a/modules/fbx/data/fbx_material.h b/modules/fbx/data/fbx_material.h index 23310b8e1d..5fd4d9212b 100644 --- a/modules/fbx/data/fbx_material.h +++ b/modules/fbx/data/fbx_material.h @@ -33,10 +33,10 @@ #include "tools/import_utils.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" -struct FBXMaterial : public Reference { +struct FBXMaterial : public RefCounted { String material_name = String(); bool warning_non_pbr_material = false; FBXDocParser::Material *material = nullptr; @@ -266,7 +266,7 @@ struct FBXMaterial : public Reference { /* storing the texture properties like color */ template <class T> - struct TexturePropertyMapping : Reference { + struct TexturePropertyMapping : RefCounted { StandardMaterial3D::TextureParam map_mode = StandardMaterial3D::TextureParam::TEXTURE_ALBEDO; const T property = T(); }; diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp index 349bcaeeaa..0d33b8e7c6 100644 --- a/modules/fbx/data/fbx_mesh_data.cpp +++ b/modules/fbx/data/fbx_mesh_data.cpp @@ -211,7 +211,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s const int surface_id = polygon_surfaces[*polygon_id]; if (surfaces.has(surface_id) == false) { SurfaceData sd; - sd.surface_tool.instance(); + sd.surface_tool.instantiate(); sd.surface_tool->begin(Mesh::PRIMITIVE_TRIANGLES); if (surface_id < 0) { @@ -316,7 +316,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s Vector3 *normals_ptr = morph_data->normals.ptrw(); Ref<SurfaceTool> morph_st; - morph_st.instance(); + morph_st.instantiate(); morph_st->begin(Mesh::PRIMITIVE_TRIANGLES); for (unsigned int vi = 0; vi < surface->vertices_map.size(); vi += 1) { @@ -345,7 +345,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s // Phase 6. Compose the mesh and return it. Ref<EditorSceneImporterMesh> mesh; - mesh.instance(); + mesh.instantiate(); // Add blend shape info. for (const String *morph_name = morphs.next(nullptr); morph_name != nullptr; morph_name = morphs.next(morph_name)) { @@ -1126,8 +1126,8 @@ HashMap<int, R> FBXMeshData::extract_per_vertex_data( } const int vertex_index = get_vertex_from_polygon_vertex(p_mesh_indices, polygon_vertex_index); ERR_FAIL_COND_V_MSG(vertex_index < 0, (HashMap<int, R>()), "FBX file corrupted: #ERR8"); - ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9."); - ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10."); + ERR_FAIL_COND_V_MSG(vertex_index >= p_vertex_count, (HashMap<int, R>()), "FBX file seems corrupted: #ERR9."); + ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] < 0, (HashMap<int, R>()), "FBX file seems corrupted: #ERR10."); ERR_FAIL_COND_V_MSG(p_mapping_data.index[polygon_vertex_index] >= (int)p_mapping_data.data.size(), (HashMap<int, R>()), "FBX file seems corrupted: #ERR11."); aggregate_vertex_data[vertex_index].push_back({ polygon_id, p_mapping_data.data[p_mapping_data.index[polygon_vertex_index]] }); } diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h index c4eaa7d170..7486c5c59c 100644 --- a/modules/fbx/data/fbx_mesh_data.h +++ b/modules/fbx/data/fbx_mesh_data.h @@ -78,7 +78,7 @@ struct VertexData { }; // Caches mesh information and instantiates meshes for you using helper functions. -struct FBXMeshData : Reference { +struct FBXMeshData : RefCounted { struct MorphVertexData { // TODO we have only these?? /// Each element is a vertex. Not supposed to be void. diff --git a/modules/fbx/data/fbx_node.h b/modules/fbx/data/fbx_node.h index a6f62f3388..75461e397d 100644 --- a/modules/fbx/data/fbx_node.h +++ b/modules/fbx/data/fbx_node.h @@ -40,7 +40,7 @@ class Node3D; struct PivotTransform; -struct FBXNode : Reference, ModelAbstraction { +struct FBXNode : RefCounted, ModelAbstraction { uint64_t current_node_id = 0; String node_name = String(); Node3D *godot_node = nullptr; diff --git a/modules/fbx/data/fbx_skeleton.h b/modules/fbx/data/fbx_skeleton.h index df937cde49..b6103df949 100644 --- a/modules/fbx/data/fbx_skeleton.h +++ b/modules/fbx/data/fbx_skeleton.h @@ -35,14 +35,14 @@ #include "fbx_node.h" #include "model_abstraction.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "scene/3d/skeleton_3d.h" struct FBXNode; struct ImportState; struct FBXBone; -struct FBXSkeleton : Reference { +struct FBXSkeleton : RefCounted { Ref<FBXNode> fbx_node = Ref<FBXNode>(); Vector<Ref<FBXBone>> skeleton_bones = Vector<Ref<FBXBone>>(); Skeleton3D *skeleton = nullptr; diff --git a/modules/fbx/data/pivot_transform.cpp b/modules/fbx/data/pivot_transform.cpp index f4055c830f..4cf42257a4 100644 --- a/modules/fbx/data/pivot_transform.cpp +++ b/modules/fbx/data/pivot_transform.cpp @@ -90,7 +90,7 @@ void PivotTransform::ReadTransformChain() { if (ok) { geometric_rotation = ImportUtils::EulerToQuaternion(rot, ImportUtils::deg2rad(GeometricRotation)); } else { - geometric_rotation = Quat(); + geometric_rotation = Quaternion(); } const Vector3 &GeometricTranslation = ImportUtils::safe_import_vector3(FBXDocParser::PropertyGet<Vector3>(props, "GeometricTranslation", ok)); @@ -100,7 +100,7 @@ void PivotTransform::ReadTransformChain() { geometric_translation = Vector3(0, 0, 0); } - if (geometric_rotation != Quat()) { + if (geometric_rotation != Quaternion()) { print_error("geometric rotation is unsupported!"); //CRASH_COND(true); } @@ -116,8 +116,8 @@ void PivotTransform::ReadTransformChain() { } } -Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const { - Transform T, Roff, Rp, Soff, Sp, S; +Transform3D PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const { + Transform3D T, Roff, Rp, Soff, Sp, S; // Here I assume this is the operation which needs done. // Its WorldTransform * V @@ -132,29 +132,29 @@ Transform PivotTransform::ComputeLocalTransform(Vector3 p_translation, Quat p_ro // Scaling node S.scale(p_scaling); // Rotation pivots - Transform Rpre = Transform(pre_rotation); - Transform R = Transform(p_rotation); - Transform Rpost = Transform(post_rotation); + Transform3D Rpre = Transform3D(pre_rotation); + Transform3D R = Transform3D(p_rotation); + Transform3D Rpost = Transform3D(post_rotation); return T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); } -Transform PivotTransform::ComputeGlobalTransform(Transform t) const { +Transform3D PivotTransform::ComputeGlobalTransform(Transform3D t) const { Vector3 pos = t.origin; Vector3 scale = t.basis.get_scale(); - Quat rot = t.basis.get_rotation_quat(); + Quaternion rot = t.basis.get_rotation_quaternion(); return ComputeGlobalTransform(pos, rot, scale); } -Transform PivotTransform::ComputeLocalTransform(Transform t) const { +Transform3D PivotTransform::ComputeLocalTransform(Transform3D t) const { Vector3 pos = t.origin; Vector3 scale = t.basis.get_scale(); - Quat rot = t.basis.get_rotation_quat(); + Quaternion rot = t.basis.get_rotation_quaternion(); return ComputeLocalTransform(pos, rot, scale); } -Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const { - Transform T, Roff, Rp, Soff, Sp, S; +Transform3D PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const { + Transform3D T, Roff, Rp, Soff, Sp, S; // Here I assume this is the operation which needs done. // Its WorldTransform * V @@ -170,26 +170,26 @@ Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_r S.scale(p_scaling); // Rotation pivots - Transform Rpre = Transform(pre_rotation); - Transform R = Transform(p_rotation); - Transform Rpost = Transform(post_rotation); + Transform3D Rpre = Transform3D(pre_rotation); + Transform3D R = Transform3D(p_rotation); + Transform3D Rpost = Transform3D(post_rotation); - Transform parent_global_xform; - Transform parent_local_scaling_m; + Transform3D parent_global_xform; + Transform3D parent_local_scaling_m; if (parent_transform.is_valid()) { parent_global_xform = parent_transform->GlobalTransform; parent_local_scaling_m = parent_transform->Local_Scaling_Matrix; } - Transform local_rotation_m, parent_global_rotation_m; - Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat(); - parent_global_rotation_m.basis.set_quat(parent_global_rotation); + Transform3D local_rotation_m, parent_global_rotation_m; + Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion(); + parent_global_rotation_m.basis.set_quaternion(parent_global_rotation); local_rotation_m = Rpre * R * Rpost; - //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized()); + //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized()); - Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; + Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; Vector3 parent_translation = parent_global_xform.get_origin(); parent_shear_translation.origin = parent_translation; parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform; @@ -197,26 +197,26 @@ Transform PivotTransform::ComputeGlobalTransform(Vector3 p_translation, Quat p_r local_shear_scaling = S; // Inherit type handler - we don't care about T here, just reordering RSrs etc. - Transform global_rotation_scale; + Transform3D global_rotation_scale; if (inherit_type == FBXDocParser::Transform_RrSs) { global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_RSrs) { global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_Rrs) { - Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse(); + Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.affine_inverse(); global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling; } - Transform local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); - //Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin); + Transform3D local_transform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); + //Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); - ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform(), "Det == 0 prevented in scene file"); + ERR_FAIL_COND_V_MSG(local_transform.basis.determinant() == 0, Transform3D(), "Det == 0 prevented in scene file"); // manual hack to force SSC not to be compensated for - until we can handle it properly with tests return parent_global_xform * local_transform; } void PivotTransform::ComputePivotTransform() { - Transform T, Roff, Rp, Soff, Sp, S; + Transform3D T, Roff, Rp, Soff, Sp, S; // Here I assume this is the operation which needs done. // Its WorldTransform * V @@ -237,26 +237,26 @@ void PivotTransform::ComputePivotTransform() { Local_Scaling_Matrix = S; // copy for when node / child is looking for the value of this. // Rotation pivots - Transform Rpre = Transform(pre_rotation); - Transform R = Transform(rotation); - Transform Rpost = Transform(post_rotation); + Transform3D Rpre = Transform3D(pre_rotation); + Transform3D R = Transform3D(rotation); + Transform3D Rpost = Transform3D(post_rotation); - Transform parent_global_xform; - Transform parent_local_scaling_m; + Transform3D parent_global_xform; + Transform3D parent_local_scaling_m; if (parent_transform.is_valid()) { parent_global_xform = parent_transform->GlobalTransform; parent_local_scaling_m = parent_transform->Local_Scaling_Matrix; } - Transform local_rotation_m, parent_global_rotation_m; - Quat parent_global_rotation = parent_global_xform.basis.get_rotation_quat(); - parent_global_rotation_m.basis.set_quat(parent_global_rotation); + Transform3D local_rotation_m, parent_global_rotation_m; + Quaternion parent_global_rotation = parent_global_xform.basis.get_rotation_quaternion(); + parent_global_rotation_m.basis.set_quaternion(parent_global_rotation); local_rotation_m = Rpre * R * Rpost; - //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quat().normalized()); + //Basis parent_global_rotation = Basis(parent_global_xform.get_basis().get_rotation_quaternion().normalized()); - Transform local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; + Transform3D local_shear_scaling, parent_shear_scaling, parent_shear_rotation, parent_shear_translation; Vector3 parent_translation = parent_global_xform.get_origin(); parent_shear_translation.origin = parent_translation; parent_shear_rotation = parent_shear_translation.affine_inverse() * parent_global_xform; @@ -264,24 +264,24 @@ void PivotTransform::ComputePivotTransform() { local_shear_scaling = S; // Inherit type handler - we don't care about T here, just reordering RSrs etc. - Transform global_rotation_scale; + Transform3D global_rotation_scale; if (inherit_type == FBXDocParser::Transform_RrSs) { global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_shear_scaling * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_RSrs) { global_rotation_scale = parent_global_rotation_m * parent_shear_scaling * local_rotation_m * local_shear_scaling; } else if (inherit_type == FBXDocParser::Transform_Rrs) { - Transform parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse(); + Transform3D parent_global_shear_m_noLocal = parent_shear_scaling * parent_local_scaling_m.inverse(); global_rotation_scale = parent_global_rotation_m * local_rotation_m * parent_global_shear_m_noLocal * local_shear_scaling; } - LocalTransform = Transform(); + LocalTransform = Transform3D(); LocalTransform = T * Roff * Rp * Rpre * R * Rpost.affine_inverse() * Rp.affine_inverse() * Soff * Sp * S * Sp.affine_inverse(); ERR_FAIL_COND_MSG(LocalTransform.basis.determinant() == 0, "invalid scale reset"); - Transform local_translation_pivoted = Transform(Basis(), LocalTransform.origin); - GlobalTransform = Transform(); + Transform3D local_translation_pivoted = Transform3D(Basis(), LocalTransform.origin); + GlobalTransform = Transform3D(); //GlobalTransform = parent_global_xform * LocalTransform; - Transform global_origin = Transform(Basis(), parent_translation); + Transform3D global_origin = Transform3D(Basis(), parent_translation); GlobalTransform = (global_origin * local_translation_pivoted) * global_rotation_scale; ImportUtils::debug_xform("local xform calculation", LocalTransform); diff --git a/modules/fbx/data/pivot_transform.h b/modules/fbx/data/pivot_transform.h index 9996027870..099b268075 100644 --- a/modules/fbx/data/pivot_transform.h +++ b/modules/fbx/data/pivot_transform.h @@ -31,8 +31,8 @@ #ifndef PIVOT_TRANSFORM_H #define PIVOT_TRANSFORM_H -#include "core/math/transform.h" -#include "core/object/reference.h" +#include "core/math/transform_3d.h" +#include "core/object/ref_counted.h" #include "model_abstraction.h" @@ -55,13 +55,13 @@ enum TransformationComp { TransformationComp_MAXIMUM }; // Abstract away pivot data so its simpler to handle -struct PivotTransform : Reference, ModelAbstraction { +struct PivotTransform : RefCounted, ModelAbstraction { // at the end we want to keep geometric_ everything, post and pre rotation // these are used during animation data processing / keyframe ingestion the rest can be simplified down / out. - Quat pre_rotation = Quat(); - Quat post_rotation = Quat(); - Quat rotation = Quat(); - Quat geometric_rotation = Quat(); + Quaternion pre_rotation = Quaternion(); + Quaternion post_rotation = Quaternion(); + Quaternion rotation = Quaternion(); + Quaternion geometric_rotation = Quaternion(); Vector3 rotation_pivot = Vector3(); Vector3 rotation_offset = Vector3(); Vector3 scaling_offset = Vector3(1.0, 1.0, 1.0); @@ -85,10 +85,10 @@ struct PivotTransform : Reference, ModelAbstraction { print_verbose("raw post_rotation " + raw_post_rotation * (180 / Math_PI)); } - Transform ComputeGlobalTransform(Transform t) const; - Transform ComputeLocalTransform(Transform t) const; - Transform ComputeGlobalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const; - Transform ComputeLocalTransform(Vector3 p_translation, Quat p_rotation, Vector3 p_scaling) const; + Transform3D ComputeGlobalTransform(Transform3D t) const; + Transform3D ComputeLocalTransform(Transform3D t) const; + Transform3D ComputeGlobalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const; + Transform3D ComputeLocalTransform(Vector3 p_translation, Quaternion p_rotation, Vector3 p_scaling) const; /* Extract into xforms and calculate once */ void ComputePivotTransform(); @@ -105,10 +105,10 @@ struct PivotTransform : Reference, ModelAbstraction { //Transform chain[TransformationComp_MAXIMUM]; // cached for later use - Transform GlobalTransform = Transform(); - Transform LocalTransform = Transform(); - Transform Local_Scaling_Matrix = Transform(); // used for inherit type. - Transform GeometricTransform = Transform(); // 3DS max only + Transform3D GlobalTransform = Transform3D(); + Transform3D LocalTransform = Transform3D(); + Transform3D Local_Scaling_Matrix = Transform3D(); // used for inherit type. + Transform3D GeometricTransform = Transform3D(); // 3DS max only FBXDocParser::TransformInheritance inherit_type = FBXDocParser::TransformInheritance_MAX; // maya fbx requires this - sorry <3 }; diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp index f60277f60a..e3f36ef3e3 100644 --- a/modules/fbx/editor_scene_importer_fbx.cpp +++ b/modules/fbx/editor_scene_importer_fbx.cpp @@ -258,24 +258,24 @@ struct EditorSceneImporterAssetImportInterpolate { //thank you for existing, partial specialization template <> -struct EditorSceneImporterAssetImportInterpolate<Quat> { - Quat lerp(const Quat &a, const Quat &b, float c) const { - ERR_FAIL_COND_V(!a.is_normalized(), Quat()); - ERR_FAIL_COND_V(!b.is_normalized(), Quat()); +struct EditorSceneImporterAssetImportInterpolate<Quaternion> { + Quaternion lerp(const Quaternion &a, const Quaternion &b, float c) const { + ERR_FAIL_COND_V(!a.is_normalized(), Quaternion()); + ERR_FAIL_COND_V(!b.is_normalized(), Quaternion()); return a.slerp(b, c).normalized(); } - Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, float c) { - ERR_FAIL_COND_V(!p1.is_normalized(), Quat()); - ERR_FAIL_COND_V(!p2.is_normalized(), Quat()); + Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, float c) { + ERR_FAIL_COND_V(!p1.is_normalized(), Quaternion()); + ERR_FAIL_COND_V(!p2.is_normalized(), Quaternion()); return p1.slerp(p2, c).normalized(); } - Quat bezier(Quat start, Quat control_1, Quat control_2, Quat end, float t) { - ERR_FAIL_COND_V(!start.is_normalized(), Quat()); - ERR_FAIL_COND_V(!end.is_normalized(), Quat()); + Quaternion bezier(Quaternion start, Quaternion control_1, Quaternion control_2, Quaternion end, float t) { + ERR_FAIL_COND_V(!start.is_normalized(), Quaternion()); + ERR_FAIL_COND_V(!end.is_normalized(), Quaternion()); return start.slerp(end, t).normalized(); } @@ -373,7 +373,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( scene_root->add_child(state.root); state.root->set_owner(scene_root); - state.fbx_root_node.instance(); + state.fbx_root_node.instantiate(); state.fbx_root_node->godot_node = state.root; // Size relative to cm. @@ -389,11 +389,11 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // Enabled by default. state.enable_animation_import = true; Ref<FBXNode> root_node; - root_node.instance(); + root_node.instantiate(); // make sure fake noFBXDocParser::PropertyPtr ptrde always has a transform too ;) Ref<PivotTransform> pivot_transform; - pivot_transform.instance(); + pivot_transform.instantiate(); root_node->pivot_transform = pivot_transform; root_node->node_name = "root node"; root_node->current_node_id = 0; @@ -479,7 +479,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( if (state.renderer_mesh_data.has(mesh_id)) { mesh_vertex_data = state.renderer_mesh_data[mesh_id]; } else { - mesh_vertex_data.instance(); + mesh_vertex_data.instantiate(); state.renderer_mesh_data.insert(mesh_id, mesh_vertex_data); } @@ -535,7 +535,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( ERR_CONTINUE_MSG(!mat, "Could not convert fbx material by id: " + itos(material_id)); Ref<FBXMaterial> material; - material.instance(); + material.instantiate(); material->set_imported_material(mat); Ref<StandardMaterial3D> godot_material = material->import_material(state); @@ -575,7 +575,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( if (state.skeleton_map.has(armature_id)) { fbx_skeleton_inst = state.skeleton_map[armature_id]; } else { - fbx_skeleton_inst.instance(); + fbx_skeleton_inst.instantiate(); state.skeleton_map.insert(armature_id, fbx_skeleton_inst); } @@ -650,7 +650,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( if (state.renderer_mesh_data.has(mesh_id)) { mesh_data_precached = state.renderer_mesh_data[mesh_id]; } else { - mesh_data_precached.instance(); + mesh_data_precached.instantiate(); state.renderer_mesh_data.insert(mesh_id, mesh_data_precached); } @@ -735,7 +735,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( Ref<Skin> skin; if (!state.MeshSkins.has(mesh_id)) { print_verbose("Created new skin"); - skin.instance(); + skin.instantiate(); state.MeshSkins.insert(mesh_id, skin); } else { print_verbose("Grabbed skin"); @@ -848,7 +848,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } Ref<Animation> animation; - animation.instance(); + animation.instantiate(); animation->set_name(animation_name); animation->set_length(duration); @@ -888,7 +888,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // we need to know what object the curves are for. // we need the target ID and the target name for the track reduction. - FBXDocParser::Model::RotOrder quat_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ; + FBXDocParser::Model::RotOrder quaternion_rotation_order = FBXDocParser::Model::RotOrder_EulerXYZ; // T:: R:: S:: Visible:: Custom:: for (const FBXDocParser::AnimationCurveNode *curve_node : node_list) { @@ -910,7 +910,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( continue; } else { //print_verbose("[doc] applied rotation order: " + itos(target->RotationOrder())); - quat_rotation_order = target->RotationOrder(); + quaternion_rotation_order = target->RotationOrder(); } uint64_t target_id = target->ID(); @@ -1011,7 +1011,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // track count is 5. // next track id is 5. const uint64_t target_id = track->key(); - int track_idx = animation->add_track(Animation::TYPE_TRANSFORM); + int track_idx = animation->add_track(Animation::TYPE_TRANSFORM3D); // animation->track_set_path(track_idx, node_path); Ref<FBXBone> bone; @@ -1023,7 +1023,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( bone = state.fbx_bone_map[target_id]; } - Transform target_transform; + Transform3D target_transform; if (state.fbx_target_map.has(target_id)) { Ref<FBXNode> node_ref = state.fbx_target_map[target_id]; @@ -1086,7 +1086,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( Vector<float> pos_times; Vector<Vector3> scale_values; Vector<float> scale_times; - Vector<Quat> rot_values; + Vector<Quaternion> rot_values; Vector<float> rot_times; double max_duration = 0; @@ -1122,8 +1122,8 @@ Node3D *EditorSceneImporterFBX::_generate_scene( bool got_pre = false; bool got_post = false; - Quat post_rotation; - Quat pre_rotation; + Quaternion post_rotation; + Quaternion pre_rotation; // Rotation matrix const Vector3 &PreRotation = FBXDocParser::PropertyGet<Vector3>(props, "PreRotation", got_pre); @@ -1137,24 +1137,24 @@ Node3D *EditorSceneImporterFBX::_generate_scene( post_rotation = ImportUtils::EulerToQuaternion(rot_order, ImportUtils::deg2rad(PostRotation)); } - Quat lastQuat = Quat(); + Quaternion lastQuaternion = Quaternion(); for (std::pair<int64_t, Vector3> rotation_key : rotation_keys.keyframes) { double animation_track_time = CONVERT_FBX_TIME(rotation_key.first); //print_verbose("euler rotation key: " + rotation_key.second); - Quat rot_key_value = ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_key.second)); + Quaternion rot_key_value = ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_key.second)); - if (lastQuat != Quat() && rot_key_value.dot(lastQuat) < 0) { + if (lastQuaternion != Quaternion() && rot_key_value.dot(lastQuaternion) < 0) { rot_key_value.x = -rot_key_value.x; rot_key_value.y = -rot_key_value.y; rot_key_value.z = -rot_key_value.z; rot_key_value.w = -rot_key_value.w; } // pre_post rotation possibly could fix orientation - Quat final_rotation = pre_rotation * rot_key_value * post_rotation; + Quaternion final_rotation = pre_rotation * rot_key_value * post_rotation; - lastQuat = final_rotation; + lastQuaternion = final_rotation; if (animation_track_time > max_duration) { max_duration = animation_track_time; @@ -1165,7 +1165,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } bool valid_rest = false; - Transform bone_rest; + Transform3D bone_rest; int skeleton_bone = -1; if (state.fbx_bone_map.has(target_id)) { if (bone.is_valid() && bone->fbx_skeleton.is_valid()) { @@ -1182,13 +1182,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } const Vector3 def_pos = translation_keys.has_default ? (translation_keys.default_value * state.scale) : bone_rest.origin; - const Quat def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quat_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quat(); + const Quaternion def_rot = rotation_keys.has_default ? ImportUtils::EulerToQuaternion(quaternion_rotation_order, ImportUtils::deg2rad(rotation_keys.default_value)) : bone_rest.basis.get_rotation_quaternion(); const Vector3 def_scale = scale_keys.has_default ? scale_keys.default_value : bone_rest.basis.get_scale(); print_verbose("track defaults: p(" + def_pos + ") s(" + def_scale + ") r(" + def_rot + ")"); while (true) { Vector3 pos = def_pos; - Quat rot = def_rot; + Quaternion rot = def_rot; Vector3 scale = def_scale; if (pos_values.size()) { @@ -1197,7 +1197,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene( } if (rot_values.size()) { - rot = _interpolate_track<Quat>(rot_times, rot_values, time, + rot = _interpolate_track<Quaternion>(rot_times, rot_values, time, AssetImportAnimation::INTERP_LINEAR); } @@ -1208,13 +1208,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene( // node animations must also include pivots if (skeleton_bone >= 0) { - Transform xform = Transform(); - xform.basis.set_quat_scale(rot, scale); + Transform3D xform = Transform3D(); + xform.basis.set_quaternion_scale(rot, scale); xform.origin = pos; - const Transform t = bone_rest.affine_inverse() * xform; + const Transform3D t = bone_rest.affine_inverse() * xform; // populate this again - rot = t.basis.get_rotation_quat(); + rot = t.basis.get_rotation_quaternion(); rot.normalize(); scale = t.basis.get_scale(); pos = t.origin; @@ -1312,7 +1312,7 @@ void EditorSceneImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone, // declare our bone element reference (invalid, unless we create a bone in this step) // this lets us pass valid armature information into children objects and this is why we moved this up here - // previously this was created .instanced() on the same line. + // previously this was created .instantiated() on the same line. Ref<FBXBone> bone_element; if (model != nullptr) { @@ -1324,7 +1324,7 @@ void EditorSceneImporterFBX::BuildDocumentBones(Ref<FBXBone> p_parent_bone, ERR_FAIL_COND_MSG(state.fbx_bone_map.has(limb_node->ID()), "[serious] duplicate LimbNode detected"); bool parent_is_bone = state.fbx_bone_map.find(p_id); - bone_element.instance(); + bone_element.instantiate(); // used to build the bone hierarchy in the skeleton bone_element->parent_bone_id = parent_is_bone ? p_id : 0; @@ -1404,12 +1404,12 @@ void EditorSceneImporterFBX::BuildDocumentNodes( uint64_t current_node_id = model->ID(); Ref<FBXNode> new_node; - new_node.instance(); + new_node.instantiate(); new_node->current_node_id = current_node_id; new_node->node_name = ImportUtils::FBXNodeToName(model->Name()); Ref<PivotTransform> fbx_transform; - fbx_transform.instance(); + fbx_transform.instantiate(); fbx_transform->set_parent(parent_transform); fbx_transform->set_model(model); fbx_transform->debug_pivot_xform("name: " + new_node->node_name); diff --git a/modules/fbx/fbx_parser/FBXDeformer.cpp b/modules/fbx/fbx_parser/FBXDeformer.cpp index 039718ae15..4220ba62a7 100644 --- a/modules/fbx/fbx_parser/FBXDeformer.cpp +++ b/modules/fbx/fbx_parser/FBXDeformer.cpp @@ -78,7 +78,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXMeshGeometry.h" #include "FBXParser.h" #include "core/math/math_funcs.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include <iostream> diff --git a/modules/fbx/fbx_parser/FBXDocument.h b/modules/fbx/fbx_parser/FBXDocument.h index e01e0471aa..885ff8fca4 100644 --- a/modules/fbx/fbx_parser/FBXDocument.h +++ b/modules/fbx/fbx_parser/FBXDocument.h @@ -37,7 +37,7 @@ #include "FBXCommon.h" #include "FBXParser.h" #include "FBXProperties.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" #include "core/string/print_string.h" @@ -242,13 +242,13 @@ public: return target_id; } - Transform GetBindPose() const { + Transform3D GetBindPose() const { return transform; } private: uint64_t target_id = 0; - Transform transform; + Transform3D transform; }; /** DOM base class for FBX cameras attached to a node */ @@ -905,11 +905,11 @@ public: } /** */ - const Transform &GetTransform() const { + const Transform3D &GetTransform() const { return transform; } - const Transform &TransformLink() const { + const Transform3D &TransformLink() const { return transformLink; } @@ -917,7 +917,7 @@ public: return node; } - const Transform &TransformAssociateModel() const { + const Transform3D &TransformAssociateModel() const { return transformAssociateModel; } @@ -941,9 +941,9 @@ private: std::vector<float> weights; std::vector<unsigned int> indices; - Transform transform; - Transform transformLink; - Transform transformAssociateModel; + Transform3D transform; + Transform3D transformLink; + Transform3D transformAssociateModel; SkinLinkMode link_mode; bool valid_transformAssociateModel = false; const Model *node = nullptr; diff --git a/modules/fbx/fbx_parser/FBXParser.cpp b/modules/fbx/fbx_parser/FBXParser.cpp index 98435b5c0f..a92b23f4ee 100644 --- a/modules/fbx/fbx_parser/FBXParser.cpp +++ b/modules/fbx/fbx_parser/FBXParser.cpp @@ -82,7 +82,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXParser.h" #include "FBXTokenizer.h" #include "core/math/math_defs.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector3.h" #include "core/string/print_string.h" @@ -1157,7 +1157,7 @@ void ParseVectorDataArray(std::vector<int64_t> &out, const ElementPtr el) { } // ------------------------------------------------------------------------------------------------ -Transform ReadMatrix(const ElementPtr element) { +Transform3D ReadMatrix(const ElementPtr element) { std::vector<float> values; ParseVectorDataArray(values, element); @@ -1167,12 +1167,12 @@ Transform ReadMatrix(const ElementPtr element) { // clean values to prevent any IBM damage on inverse() / affine_inverse() for (float &value : values) { - if (::Math::is_equal_approx(0, value)) { + if (::Math::is_zero_approx(value)) { value = 0; } } - Transform xform; + Transform3D xform; Basis basis; basis.set( diff --git a/modules/fbx/fbx_parser/FBXParser.h b/modules/fbx/fbx_parser/FBXParser.h index 8b248e8791..93836c2205 100644 --- a/modules/fbx/fbx_parser/FBXParser.h +++ b/modules/fbx/fbx_parser/FBXParser.h @@ -81,7 +81,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <memory> #include "core/math/color.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "core/math/vector2.h" #include "core/math/vector3.h" @@ -264,7 +264,7 @@ TokenPtr GetRequiredToken(const ElementPtr el, unsigned int index); // ------------------------------------------------------------------------------------------------ // read a 4x4 matrix from an array of 16 floats -Transform ReadMatrix(const ElementPtr element); +Transform3D ReadMatrix(const ElementPtr element); } // namespace FBXDocParser #endif // FBX_PARSER_H diff --git a/modules/fbx/register_types.cpp b/modules/fbx/register_types.cpp index c0591dbc77..b615c91cd2 100644 --- a/modules/fbx/register_types.cpp +++ b/modules/fbx/register_types.cpp @@ -36,7 +36,7 @@ #ifdef TOOLS_ENABLED static void _editor_init() { Ref<EditorSceneImporterFBX> import_fbx; - import_fbx.instance(); + import_fbx.instantiate(); ResourceImporterScene::get_singleton()->add_importer(import_fbx); } #endif diff --git a/modules/fbx/tools/import_utils.cpp b/modules/fbx/tools/import_utils.cpp index 368aa09a75..66b0153308 100644 --- a/modules/fbx/tools/import_utils.cpp +++ b/modules/fbx/tools/import_utils.cpp @@ -80,7 +80,7 @@ Basis ImportUtils::EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector return ret; } -Quat ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) { +Quaternion ImportUtils::EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation) { return ImportUtils::EulerToBasis(mode, p_rotation); } @@ -117,13 +117,13 @@ Vector3 ImportUtils::BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basi } } -Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation) { +Vector3 ImportUtils::QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation) { return BasisToEuler(mode, p_rotation); } -Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale) { - Transform unscaled = Transform(p_initial.basis, p_initial.origin * p_scale); - ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform(), "det is zero unscaled?"); +Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale) { + Transform3D unscaled = Transform3D(p_initial.basis, p_initial.origin * p_scale); + ERR_FAIL_COND_V_MSG(unscaled.basis.determinant() == 0, Transform3D(), "det is zero unscaled?"); return unscaled; } diff --git a/modules/fbx/tools/import_utils.h b/modules/fbx/tools/import_utils.h index cf0f811e35..fbe7dbd82f 100644 --- a/modules/fbx/tools/import_utils.h +++ b/modules/fbx/tools/import_utils.h @@ -56,15 +56,15 @@ public: static Basis EulerToBasis(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); /// Converts rotation order vector (in rad) to quaternion. - static Quat EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); + static Quaternion EulerToQuaternion(FBXDocParser::Model::RotOrder mode, const Vector3 &p_rotation); /// Converts basis into rotation order vector (in rad). static Vector3 BasisToEuler(FBXDocParser::Model::RotOrder mode, const Basis &p_rotation); /// Converts quaternion into rotation order vector (in rad). - static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quat &p_rotation); + static Vector3 QuaternionToEuler(FBXDocParser::Model::RotOrder mode, const Quaternion &p_rotation); - static void debug_xform(String name, const Transform &t) { + static void debug_xform(String name, const Transform3D &t) { print_verbose(name + " " + t.origin + " rotation: " + (t.basis.get_euler() * (180 / Math_PI))); } @@ -137,15 +137,15 @@ public: static Vector3 safe_import_vector3(const Vector3 &p_vec) { Vector3 vector = p_vec; - if (Math::is_equal_approx(0, vector.x)) { + if (Math::is_zero_approx(vector.x)) { vector.x = 0; } - if (Math::is_equal_approx(0, vector.y)) { + if (Math::is_zero_approx(vector.y)) { vector.y = 0; } - if (Math::is_equal_approx(0, vector.z)) { + if (Math::is_zero_approx(vector.z)) { vector.z = 0; } return vector; @@ -317,7 +317,7 @@ public: // } // } else { // Ref<Image> img; - // img.instance(); + // img.instantiate(); // PoolByteArray arr; // uint32_t size = tex->mWidth * tex->mHeight; // arr.resize(size); @@ -362,7 +362,7 @@ public: // if (found) { // image_state.raw_image = AssimpUtils::load_image(state, state.assimp_scene, path); // if (image_state.raw_image.is_valid()) { - // image_state.texture.instance(); + // image_state.texture.instantiate(); // image_state.texture->create_from_image(image_state.raw_image); // image_state.texture->set_storage(ImageTexture::STORAGE_COMPRESS_LOSSY); // return true; @@ -391,7 +391,7 @@ public: }; // Apply the transforms so the basis will have scale 1. -Transform get_unscaled_transform(const Transform &p_initial, real_t p_scale); +Transform3D get_unscaled_transform(const Transform3D &p_initial, real_t p_scale); /// Uses the Newell's method to compute any polygon normal. /// The polygon must be at least size of 3 or bigger. diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h index fe0c92b22f..906a721045 100644 --- a/modules/fbx/tools/validation_tools.h +++ b/modules/fbx/tools/validation_tools.h @@ -33,9 +33,8 @@ #ifdef TOOLS_ENABLED -#include "core/io/json.h" -#include "core/os/file_access.h" -#include "core/string/ustring.h" +#include "core/io/file_access.h" +#include "core/string/print_string.h" #include "core/templates/local_vector.h" #include "core/templates/map.h" diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml index 44d9e32ed8..4f1530598c 100644 --- a/modules/gdnative/doc_classes/GDNative.xml +++ b/modules/gdnative/doc_classes/GDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="GDNative" inherits="Reference" version="4.0"> +<class name="GDNative" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml index 9f33d32e81..b88f5e7e1e 100644 --- a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml +++ b/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="MultiplayerPeerGDNative" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="MultiplayerPeerGDNative" inherits="MultiplayerPeer" version="4.0"> <brief_description> </brief_description> <description> diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp index 7c3b76e4d7..1ff591a87f 100644 --- a/modules/gdnative/gdnative.cpp +++ b/modules/gdnative/gdnative.cpp @@ -32,9 +32,9 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "scene/main/scene_tree.h" @@ -52,7 +52,7 @@ extern const godot_gdnative_core_api_struct api_struct; Map<String, Vector<Ref<GDNative>>> GDNativeLibrary::loaded_libraries; GDNativeLibrary::GDNativeLibrary() { - config_file.instance(); + config_file.instantiate(); symbol_prefix = default_symbol_prefix; load_once = default_load_once; @@ -112,7 +112,7 @@ bool GDNativeLibrary::_get(const StringName &p_name, Variant &r_property) const } void GDNativeLibrary::reset_state() { - config_file.instance(); + config_file.instantiate(); current_library_path = ""; current_dependencies.clear(); symbol_prefix = default_symbol_prefix; @@ -252,7 +252,7 @@ void GDNativeLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("set_symbol_prefix", "symbol_prefix"), &GDNativeLibrary::set_symbol_prefix); ClassDB::bind_method(D_METHOD("set_reloadable", "reloadable"), &GDNativeLibrary::set_reloadable); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile", 0), "set_config_file", "get_config_file"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "config_file", PROPERTY_HINT_RESOURCE_TYPE, "ConfigFile", PROPERTY_USAGE_NONE), "set_config_file", "get_config_file"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "load_once"), "set_load_once", "should_load_once"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "singleton"), "set_singleton", "is_singleton"); @@ -532,7 +532,7 @@ Error GDNative::get_symbol(StringName p_procedure_name, void *&r_handle, bool p_ RES GDNativeLibraryResourceLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<GDNativeLibrary> lib; - lib.instance(); + lib.instantiate(); Ref<ConfigFile> config = lib->get_config_file(); diff --git a/modules/gdnative/gdnative.h b/modules/gdnative/gdnative.h index a28c58ec0d..0cc6487ea4 100644 --- a/modules/gdnative/gdnative.h +++ b/modules/gdnative/gdnative.h @@ -138,8 +138,8 @@ struct GDNativeCallRegistry { Vector<StringName> get_native_call_types(); }; -class GDNative : public Reference { - GDCLASS(GDNative, Reference); +class GDNative : public RefCounted { + GDCLASS(GDNative, RefCounted); Ref<GDNativeLibrary> library; diff --git a/modules/gdnative/gdnative/quat.cpp b/modules/gdnative/gdnative/quaternion.cpp index 8ebcf7c91f..62bcbbd382 100644 --- a/modules/gdnative/gdnative/quat.cpp +++ b/modules/gdnative/gdnative/quaternion.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.cpp */ +/* quaternion.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,31 +28,31 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gdnative/quat.h" +#include "gdnative/quaternion.h" -#include "core/math/quat.h" +#include "core/math/quaternion.h" -static_assert(sizeof(godot_quat) == sizeof(Quat), "Quat size mismatch"); +static_assert(sizeof(godot_quaternion) == sizeof(Quaternion), "Quaternion size mismatch"); #ifdef __cplusplus extern "C" { #endif -void GDAPI godot_quat_new(godot_quat *p_self) { - memnew_placement(p_self, Quat); +void GDAPI godot_quaternion_new(godot_quaternion *p_self) { + memnew_placement(p_self, Quaternion); } -void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src) { - memnew_placement(r_dest, Quat(*(Quat *)p_src)); +void GDAPI godot_quaternion_new_copy(godot_quaternion *r_dest, const godot_quaternion *p_src) { + memnew_placement(r_dest, Quaternion(*(Quaternion *)p_src)); } -godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index) { - Quat *self = (Quat *)p_self; +godot_real_t GDAPI *godot_quaternion_operator_index(godot_quaternion *p_self, godot_int p_index) { + Quaternion *self = (Quaternion *)p_self; return (godot_real_t *)&self->operator[](p_index); } -const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index) { - const Quat *self = (const Quat *)p_self; +const godot_real_t GDAPI *godot_quaternion_operator_index_const(const godot_quaternion *p_self, godot_int p_index) { + const Quaternion *self = (const Quaternion *)p_self; return (const godot_real_t *)&self->operator[](p_index); } diff --git a/modules/gdnative/gdnative/transform.cpp b/modules/gdnative/gdnative/transform_3d.cpp index bfaaa13db2..8bd2a68d63 100644 --- a/modules/gdnative/gdnative/transform.cpp +++ b/modules/gdnative/gdnative/transform_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.cpp */ +/* transform_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,22 +28,22 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gdnative/transform.h" +#include "gdnative/transform_3d.h" -#include "core/math/transform.h" +#include "core/math/transform_3d.h" -static_assert(sizeof(godot_transform) == sizeof(Transform), "Transform size mismatch"); +static_assert(sizeof(godot_transform3d) == sizeof(Transform3D), "Transform3D size mismatch"); #ifdef __cplusplus extern "C" { #endif -void GDAPI godot_transform_new(godot_transform *p_self) { - memnew_placement(p_self, Transform); +void GDAPI godot_transform3d_new(godot_transform3d *p_self) { + memnew_placement(p_self, Transform3D); } -void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src) { - memnew_placement(r_dest, Transform(*(Transform *)p_src)); +void GDAPI godot_transform3d_new_copy(godot_transform3d *r_dest, const godot_transform3d *p_src) { + memnew_placement(r_dest, Transform3D(*(Transform3D *)p_src)); } #ifdef __cplusplus diff --git a/modules/gdnative/gdnative/variant.cpp b/modules/gdnative/gdnative/variant.cpp index 7801e21ab2..cfb57137bb 100644 --- a/modules/gdnative/gdnative/variant.cpp +++ b/modules/gdnative/gdnative/variant.cpp @@ -30,7 +30,7 @@ #include "gdnative/variant.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/variant/variant.h" #ifdef __cplusplus @@ -143,10 +143,10 @@ void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_p memnew_placement_custom(dest, Variant, Variant(*plane)); } -void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat) { +void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion) { Variant *dest = (Variant *)r_dest; - const Quat *quat = (const Quat *)p_quat; - memnew_placement_custom(dest, Variant, Variant(*quat)); + const Quaternion *quaternion = (const Quaternion *)p_quaternion; + memnew_placement_custom(dest, Variant, Variant(*quaternion)); } void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb) { @@ -161,9 +161,9 @@ void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_b memnew_placement_custom(dest, Variant, Variant(*basis)); } -void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans) { +void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans) { Variant *dest = (Variant *)r_dest; - const Transform *trans = (const Transform *)p_trans; + const Transform3D *trans = (const Transform3D *)p_trans; memnew_placement_custom(dest, Variant, Variant(*trans)); } @@ -200,17 +200,17 @@ void GDAPI godot_variant_new_signal(godot_variant *r_dest, const godot_signal *p void GDAPI godot_variant_new_object(godot_variant *r_dest, const godot_object *p_obj) { Variant *dest = (Variant *)r_dest; const Object *obj = (const Object *)p_obj; - const Reference *reference = Object::cast_to<Reference>(obj); + const RefCounted *ref_counted = Object::cast_to<RefCounted>(obj); REF ref; - if (reference) { - ref = REF(reference); + if (ref_counted) { + ref = REF(ref_counted); } if (!ref.is_null()) { memnew_placement_custom(dest, Variant, Variant(ref)); } else { #if defined(DEBUG_METHODS_ENABLED) - if (reference) { - ERR_PRINT("Reference object has 0 refcount in godot_variant_new_object - you lost it somewhere."); + if (ref_counted) { + ERR_PRINT("RefCounted object has 0 refcount in godot_variant_new_object - you lost it somewhere."); } #endif memnew_placement_custom(dest, Variant, Variant(obj)); @@ -378,10 +378,10 @@ godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self) { return raw_dest; } -godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self) { - godot_quat raw_dest; +godot_quaternion GDAPI godot_variant_as_quaternion(const godot_variant *p_self) { + godot_quaternion raw_dest; const Variant *self = (const Variant *)p_self; - Quat *dest = (Quat *)&raw_dest; + Quaternion *dest = (Quaternion *)&raw_dest; *dest = *self; return raw_dest; } @@ -402,10 +402,10 @@ godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self) { return raw_dest; } -godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self) { - godot_transform raw_dest; +godot_transform3d GDAPI godot_variant_as_transform3d(const godot_variant *p_self) { + godot_transform3d raw_dest; const Variant *self = (const Variant *)p_self; - Transform *dest = (Transform *)&raw_dest; + Transform3D *dest = (Transform3D *)&raw_dest; *dest = *self; return raw_dest; } diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json index 489083e795..8c65447e5d 100644 --- a/modules/gdnative/gdnative_api.json +++ b/modules/gdnative/gdnative_api.json @@ -469,7 +469,7 @@ ] }, { - "name": "godot_variant_new_quat", + "name": "godot_variant_new_quaternion", "return_type": "void", "arguments": [ [ @@ -477,8 +477,8 @@ "r_dest" ], [ - "const godot_quat *", - "p_quat" + "const godot_quaternion *", + "p_quaternion" ] ] }, @@ -511,7 +511,7 @@ ] }, { - "name": "godot_variant_new_transform", + "name": "godot_variant_new_transform3d", "return_type": "void", "arguments": [ [ @@ -519,7 +519,7 @@ "r_dest" ], [ - "const godot_transform *", + "const godot_transform3d *", "p_trans" ] ] @@ -893,8 +893,8 @@ ] }, { - "name": "godot_variant_as_quat", - "return_type": "godot_quat", + "name": "godot_variant_as_quaternion", + "return_type": "godot_quaternion", "arguments": [ [ "const godot_variant *", @@ -923,8 +923,8 @@ ] }, { - "name": "godot_variant_as_transform", - "return_type": "godot_transform", + "name": "godot_variant_as_transform3d", + "return_type": "godot_transform3d", "arguments": [ [ "const godot_variant *", @@ -3866,35 +3866,35 @@ ] }, { - "name": "godot_quat_new", + "name": "godot_quaternion_new", "return_type": "void", "arguments": [ [ - "godot_quat *", + "godot_quaternion *", "p_self" ] ] }, { - "name": "godot_quat_new_copy", + "name": "godot_quaternion_new_copy", "return_type": "void", "arguments": [ [ - "godot_quat *", + "godot_quaternion *", "r_dest" ], [ - "const godot_quat *", + "const godot_quaternion *", "p_src" ] ] }, { - "name": "godot_quat_operator_index", + "name": "godot_quaternion_operator_index", "return_type": "godot_real_t *", "arguments": [ [ - "godot_quat *", + "godot_quaternion *", "p_self" ], [ @@ -3904,11 +3904,11 @@ ] }, { - "name": "godot_quat_operator_index_const", + "name": "godot_quaternion_operator_index_const", "return_type": "const godot_real_t *", "arguments": [ [ - "const godot_quat *", + "const godot_quaternion *", "p_self" ], [ @@ -4344,25 +4344,25 @@ ] }, { - "name": "godot_transform_new", + "name": "godot_transform3d_new", "return_type": "void", "arguments": [ [ - "godot_transform *", + "godot_transform3d *", "r_dest" ] ] }, { - "name": "godot_transform_new_copy", + "name": "godot_transform3d_new_copy", "return_type": "void", "arguments": [ [ - "godot_transform *", + "godot_transform3d *", "r_dest" ], [ - "const godot_transform *", + "const godot_transform3d *", "p_src" ] ] @@ -5068,12 +5068,12 @@ }, { "name": "godot_xr_get_worldscale", - "return_type": "godot_float", + "return_type": "godot_real_t", "arguments": [] }, { "name": "godot_xr_get_reference_frame", - "return_type": "godot_transform", + "return_type": "godot_transform3d", "arguments": [] }, { @@ -5145,7 +5145,7 @@ "p_controller_id" ], [ - "godot_transform *", + "godot_transform3d *", "p_transform" ], [ @@ -5189,7 +5189,7 @@ "p_exis" ], [ - "godot_float", + "godot_real_t", "p_value" ], [ @@ -5200,7 +5200,7 @@ }, { "name": "godot_xr_get_controller_rumble", - "return_type": "godot_float", + "return_type": "godot_real_t", "arguments": [ [ "godot_int", diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp index b4ac0d886e..bdbf151393 100644 --- a/modules/gdnative/gdnative_library_editor_plugin.cpp +++ b/modules/gdnative/gdnative_library_editor_plugin.cpp @@ -356,12 +356,12 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() { tree->set_column_titles_visible(true); tree->set_columns(4); tree->set_column_expand(0, false); - tree->set_column_min_width(0, int(200 * EDSCALE)); + tree->set_column_custom_minimum_width(0, int(200 * EDSCALE)); tree->set_column_title(0, TTR("Platform")); tree->set_column_title(1, TTR("Dynamic Library")); tree->set_column_title(2, TTR("Dependencies")); tree->set_column_expand(3, false); - tree->set_column_min_width(3, int(110 * EDSCALE)); + tree->set_column_custom_minimum_width(3, int(110 * EDSCALE)); tree->connect("button_pressed", callable_mp(this, &GDNativeLibraryEditor::_on_item_button)); tree->connect("item_collapsed", callable_mp(this, &GDNativeLibraryEditor::_on_item_collapsed)); tree->connect("item_activated", callable_mp(this, &GDNativeLibraryEditor::_on_item_activated)); diff --git a/modules/gdnative/include/gdnative/gdnative.h b/modules/gdnative/include/gdnative/gdnative.h index 9af9226a79..d8c290f6bd 100644 --- a/modules/gdnative/include/gdnative/gdnative.h +++ b/modules/gdnative/include/gdnative/gdnative.h @@ -149,9 +149,9 @@ typedef void godot_object; #include <gdnative/plane.h> -/////// Quat +/////// Quaternion -#include <gdnative/quat.h> +#include <gdnative/quaternion.h> /////// AABB @@ -161,9 +161,9 @@ typedef void godot_object; #include <gdnative/basis.h> -/////// Transform +/////// Transform3D -#include <gdnative/transform.h> +#include <gdnative/transform_3d.h> /////// Color diff --git a/modules/gdnative/include/gdnative/quat.h b/modules/gdnative/include/gdnative/quaternion.h index 00abdb4404..75754e6ab5 100644 --- a/modules/gdnative/include/gdnative/quat.h +++ b/modules/gdnative/include/gdnative/quaternion.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* quat.h */ +/* quaternion.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_QUAT_H -#define GODOT_QUAT_H +#ifndef GODOT_QUATERNION_H +#define GODOT_QUATERNION_H #ifdef __cplusplus extern "C" { @@ -37,24 +37,24 @@ extern "C" { #include <gdnative/math_defs.h> -#define GODOT_QUAT_SIZE (sizeof(godot_real_t) * 4) +#define GODOT_QUATERNION_SIZE (sizeof(godot_real_t) * 4) -#ifndef GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_QUAT_TYPE_DEFINED +#ifndef GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED +#define GODOT_CORE_API_GODOT_QUATERNION_TYPE_DEFINED typedef struct { - uint8_t _dont_touch_that[GODOT_QUAT_SIZE]; -} godot_quat; + uint8_t _dont_touch_that[GODOT_QUATERNION_SIZE]; +} godot_quaternion; #endif #include <gdnative/gdnative.h> -void GDAPI godot_quat_new(godot_quat *p_self); -void GDAPI godot_quat_new_copy(godot_quat *r_dest, const godot_quat *p_src); -godot_real_t GDAPI *godot_quat_operator_index(godot_quat *p_self, godot_int p_index); -const godot_real_t GDAPI *godot_quat_operator_index_const(const godot_quat *p_self, godot_int p_index); +void GDAPI godot_quaternion_new(godot_quaternion *p_self); +void GDAPI godot_quaternion_new_copy(godot_quaternion *r_dest, const godot_quaternion *p_src); +godot_real_t GDAPI *godot_quaternion_operator_index(godot_quaternion *p_self, godot_int p_index); +const godot_real_t GDAPI *godot_quaternion_operator_index_const(const godot_quaternion *p_self, godot_int p_index); #ifdef __cplusplus } #endif -#endif // GODOT_QUAT_H +#endif // GODOT_QUATERNION_H diff --git a/modules/gdnative/include/gdnative/transform.h b/modules/gdnative/include/gdnative/transform_3d.h index 3861b5683a..97ad451e9b 100644 --- a/modules/gdnative/include/gdnative/transform.h +++ b/modules/gdnative/include/gdnative/transform_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* transform.h */ +/* transform_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GODOT_TRANSFORM_H -#define GODOT_TRANSFORM_H +#ifndef GODOT_TRANSFORM3D_H +#define GODOT_TRANSFORM3D_H #ifdef __cplusplus extern "C" { @@ -37,22 +37,24 @@ extern "C" { #include <gdnative/math_defs.h> -#define GODOT_TRANSFORM_SIZE (sizeof(godot_real_t) * 12) +#define GODOT_TRANSFORM3D_SIZE (sizeof(godot_real_t) * 12) -#ifndef GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED -#define GODOT_CORE_API_GODOT_TRANSFORM_TYPE_DEFINED +#ifndef GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED +#define GODOT_CORE_API_GODOT_TRANSFORM3D_TYPE_DEFINED typedef struct { - uint8_t _dont_touch_that[GODOT_TRANSFORM_SIZE]; -} godot_transform; + uint8_t _dont_touch_that[GODOT_TRANSFORM3D_SIZE]; +} godot_transform3d; #endif #include <gdnative/gdnative.h> -void GDAPI godot_transform_new(godot_transform *p_self); -void GDAPI godot_transform_new_copy(godot_transform *r_dest, const godot_transform *p_src); +void GDAPI godot_transform3d_new(godot_transform3d *p_self); +void GDAPI godot_transform3d_new_copy(godot_transform3d *r_dest, const godot_transform3d *p_src); +godot_vector3 GDAPI *godot_transform3d_operator_index(godot_transform3d *p_self, godot_int p_index); +const godot_vector3 GDAPI *godot_transform3d_operator_index_const(const godot_transform3d *p_self, godot_int p_index); #ifdef __cplusplus } #endif -#endif // GODOT_TRANSFORM_H +#endif // GODOT_TRANSFORM3D_H diff --git a/modules/gdnative/include/gdnative/variant.h b/modules/gdnative/include/gdnative/variant.h index 3e06ed9aa4..a88bd2878a 100644 --- a/modules/gdnative/include/gdnative/variant.h +++ b/modules/gdnative/include/gdnative/variant.h @@ -56,10 +56,10 @@ typedef enum godot_variant_type { GODOT_VARIANT_TYPE_VECTOR3I, GODOT_VARIANT_TYPE_TRANSFORM2D, GODOT_VARIANT_TYPE_PLANE, - GODOT_VARIANT_TYPE_QUAT, + GODOT_VARIANT_TYPE_QUATERNION, GODOT_VARIANT_TYPE_AABB, GODOT_VARIANT_TYPE_BASIS, - GODOT_VARIANT_TYPE_TRANSFORM, + GODOT_VARIANT_TYPE_TRANSFORM3D, // misc types GODOT_VARIANT_TYPE_COLOR, @@ -164,7 +164,7 @@ typedef void (*godot_validated_keyed_getter)(const godot_variant *p_base, const typedef bool (*godot_validated_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key, bool *r_valid); typedef void (*godot_ptr_keyed_setter)(void *p_base, const void *p_key, const void *p_value); typedef void (*godot_ptr_keyed_getter)(const void *p_base, const void *p_key, void *r_value); -typedef bool (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key); +typedef uint32_t (*godot_ptr_keyed_checker)(const godot_variant *p_base, const godot_variant *p_key); typedef void (*godot_validated_utility_function)(godot_variant *r_return, const godot_variant **p_arguments, int p_argument_count); typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_arguments, int p_argument_count); @@ -177,14 +177,14 @@ typedef void (*godot_ptr_utility_function)(void *r_return, const void **p_argume #include <gdnative/node_path.h> #include <gdnative/packed_arrays.h> #include <gdnative/plane.h> -#include <gdnative/quat.h> +#include <gdnative/quaternion.h> #include <gdnative/rect2.h> #include <gdnative/rid.h> #include <gdnative/signal.h> #include <gdnative/string.h> #include <gdnative/string_name.h> -#include <gdnative/transform.h> #include <gdnative/transform2d.h> +#include <gdnative/transform_3d.h> #include <gdnative/variant.h> #include <gdnative/vector2.h> #include <gdnative/vector3.h> @@ -208,10 +208,10 @@ void GDAPI godot_variant_new_vector3(godot_variant *r_dest, const godot_vector3 void GDAPI godot_variant_new_vector3i(godot_variant *r_dest, const godot_vector3i *p_v3); void GDAPI godot_variant_new_transform2d(godot_variant *r_dest, const godot_transform2d *p_t2d); void GDAPI godot_variant_new_plane(godot_variant *r_dest, const godot_plane *p_plane); -void GDAPI godot_variant_new_quat(godot_variant *r_dest, const godot_quat *p_quat); +void GDAPI godot_variant_new_quaternion(godot_variant *r_dest, const godot_quaternion *p_quaternion); void GDAPI godot_variant_new_aabb(godot_variant *r_dest, const godot_aabb *p_aabb); void GDAPI godot_variant_new_basis(godot_variant *r_dest, const godot_basis *p_basis); -void GDAPI godot_variant_new_transform(godot_variant *r_dest, const godot_transform *p_trans); +void GDAPI godot_variant_new_transform3d(godot_variant *r_dest, const godot_transform3d *p_trans); void GDAPI godot_variant_new_color(godot_variant *r_dest, const godot_color *p_color); void GDAPI godot_variant_new_string_name(godot_variant *r_dest, const godot_string_name *p_s); void GDAPI godot_variant_new_node_path(godot_variant *r_dest, const godot_node_path *p_np); @@ -243,10 +243,10 @@ godot_vector3 GDAPI godot_variant_as_vector3(const godot_variant *p_self); godot_vector3i GDAPI godot_variant_as_vector3i(const godot_variant *p_self); godot_transform2d GDAPI godot_variant_as_transform2d(const godot_variant *p_self); godot_plane GDAPI godot_variant_as_plane(const godot_variant *p_self); -godot_quat GDAPI godot_variant_as_quat(const godot_variant *p_self); +godot_quaternion GDAPI godot_variant_as_quaternion(const godot_variant *p_self); godot_aabb GDAPI godot_variant_as_aabb(const godot_variant *p_self); godot_basis GDAPI godot_variant_as_basis(const godot_variant *p_self); -godot_transform GDAPI godot_variant_as_transform(const godot_variant *p_self); +godot_transform3d GDAPI godot_variant_as_transform3d(const godot_variant *p_self); godot_color GDAPI godot_variant_as_color(const godot_variant *p_self); godot_string_name GDAPI godot_variant_as_string_name(const godot_variant *p_self); godot_node_path GDAPI godot_variant_as_node_path(const godot_variant *p_self); diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h index 2fa576a5bf..94e7739ef9 100644 --- a/modules/gdnative/include/net/godot_net.h +++ b/modules/gdnative/include/net/godot_net.h @@ -90,7 +90,7 @@ typedef struct { godot_int (*get_available_packet_count)(const void *); godot_int (*get_max_packet_size)(const void *); - /* This is NetworkedMultiplayerPeer */ + /* This is MultiplayerPeer */ void (*set_transfer_mode)(void *, godot_int); godot_int (*get_transfer_mode)(const void *); // 0 = broadcast, 1 = server, <0 = all but abs(value) diff --git a/modules/gdnative/include/pluginscript/godot_pluginscript.h b/modules/gdnative/include/pluginscript/godot_pluginscript.h index b76f89cc99..02ee4066d0 100644 --- a/modules/gdnative/include/pluginscript/godot_pluginscript.h +++ b/modules/gdnative/include/pluginscript/godot_pluginscript.h @@ -61,7 +61,7 @@ typedef struct { //this is used by script languages that keep a reference counter of their own //you can make make Ref<> not die when it reaches zero, so deleting the reference //depends entirely from the script. - // Note: You can set those function pointer to nullptr if not needed. + // Note: You can set those function pointer to nullptr if not needed. void (*refcount_incremented)(godot_pluginscript_instance_data *p_data); bool (*refcount_decremented)(godot_pluginscript_instance_data *p_data); // return true if it can die } godot_pluginscript_instance_desc; @@ -121,18 +121,18 @@ typedef struct { const char *name; const char *type; const char *extension; - const char **recognized_extensions; // nullptr terminated array + const char **recognized_extensions; // nullptr terminated array godot_pluginscript_language_data *(*init)(); void (*finish)(godot_pluginscript_language_data *p_data); - const char **reserved_words; // nullptr terminated array - const char **comment_delimiters; // nullptr terminated array - const char **string_delimiters; // nullptr terminated array + const char **reserved_words; // nullptr terminated array + const char **comment_delimiters; // nullptr terminated array + const char **string_delimiters; // nullptr terminated array godot_bool has_named_classes; godot_bool supports_builtin_mode; godot_bool can_inherit_from_file; godot_string (*get_template_source_code)(godot_pluginscript_language_data *p_data, const godot_string *p_class_name, const godot_string *p_base_class_name); - godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, int *r_line_error, int *r_col_error, godot_string *r_test_error, const godot_string *p_path, godot_packed_string_array *r_functions); + godot_bool (*validate)(godot_pluginscript_language_data *p_data, const godot_string *p_script, const godot_string *p_path, godot_packed_string_array *r_functions, godot_array *r_errors); // errors = Array of Dictionary with "line", "column", "message" keys int (*find_function)(godot_pluginscript_language_data *p_data, const godot_string *p_function, const godot_string *p_code); // Can be nullptr godot_string (*make_function)(godot_pluginscript_language_data *p_data, const godot_string *p_class, const godot_string *p_name, const godot_packed_string_array *p_args); godot_error (*complete_code)(godot_pluginscript_language_data *p_data, const godot_string *p_code, const godot_string *p_path, godot_object *p_owner, godot_array *r_options, godot_bool *r_force, godot_string *r_call_hint); diff --git a/modules/gdnative/include/xr/godot_xr.h b/modules/gdnative/include/xr/godot_xr.h index 7eaf1c7ec3..53cb830cbb 100644 --- a/modules/gdnative/include/xr/godot_xr.h +++ b/modules/gdnative/include/xr/godot_xr.h @@ -41,8 +41,8 @@ extern "C" { // version info to detect whether a call is available // Use these to populate version in your plugin -#define GODOTVR_API_MAJOR 1 -#define GODOTVR_API_MINOR 1 +#define GODOTVR_API_MAJOR 4 +#define GODOTVR_API_MINOR 0 typedef struct { godot_gdnative_api_version version; /* version of our API */ @@ -52,25 +52,32 @@ typedef struct { godot_int (*get_capabilities)(const void *); godot_bool (*get_anchor_detection_is_enabled)(const void *); void (*set_anchor_detection_is_enabled)(void *, godot_bool); - godot_bool (*is_stereo)(const void *); + godot_int (*get_view_count)(const void *); godot_bool (*is_initialized)(const void *); godot_bool (*initialize)(void *); void (*uninitialize)(void *); godot_vector2 (*get_render_targetsize)(const void *); - godot_transform (*get_transform_for_eye)(void *, godot_int, godot_transform *); - void (*fill_projection_for_eye)(void *, godot_float *, godot_int, godot_float, godot_float, godot_float); - void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *); + + godot_transform3d (*get_camera_transform)(void *); + godot_transform3d (*get_transform_for_view)(void *, godot_int, godot_transform3d *); + void (*fill_projection_for_view)(void *, godot_real_t *, godot_int, godot_real_t, godot_real_t, godot_real_t); + void (*commit_views)(void *, godot_rid *, godot_rect2 *); + void (*process)(void *); - godot_int (*get_external_texture_for_eye)(void *, godot_int); void (*notification)(void *, godot_int); godot_int (*get_camera_feed_id)(void *); + + // possibly deprecate but adding/keeping as a reminder these are in Godot 3 + void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *); + godot_int (*get_external_texture_for_eye)(void *, godot_int); + godot_int (*get_external_depth_for_eye)(void *, godot_int); } godot_xr_interface_gdnative; void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface); // helper functions to access XRServer data -godot_float GDAPI godot_xr_get_worldscale(); -godot_transform GDAPI godot_xr_get_reference_frame(); +godot_real_t GDAPI godot_xr_get_worldscale(); +godot_transform3d GDAPI godot_xr_get_reference_frame(); // helper functions for rendering void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect); @@ -79,10 +86,10 @@ godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target); // helper functions for updating XR controllers godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position); void GDAPI godot_xr_remove_controller(godot_int p_controller_id); -void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position); +void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position); void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed); -void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative); -godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id); +void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative); +godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id); #ifdef __cplusplus } diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp index f184c84615..477bc9f74d 100644 --- a/modules/gdnative/nativescript/api_generator.cpp +++ b/modules/gdnative/nativescript/api_generator.cpp @@ -34,10 +34,11 @@ #include "core/config/engine.h" #include "core/core_constants.h" +#include "core/io/file_access.h" #include "core/object/class_db.h" -#include "core/os/file_access.h" #include "core/string/string_builder.h" #include "core/templates/pair.h" +#include "core/variant/variant_parser.h" // helper stuff @@ -121,7 +122,7 @@ struct ClassAPI { String singleton_name; bool is_instantiable = false; // @Unclear - bool is_reference = false; + bool is_ref_counted = false; bool has_indexing = false; // For builtin types. String indexed_type; // For builtin types. bool is_keyed = false; // For builtin types. @@ -250,14 +251,14 @@ List<ClassAPI> generate_c_api_classes() { class_api.singleton_name = name; } } - class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instance(class_name); + class_api.is_instantiable = !class_api.is_singleton && ClassDB::can_instantiate(class_name); { List<StringName> inheriters; - ClassDB::get_inheriters_from_class("Reference", &inheriters); - bool is_reference = !!inheriters.find(class_name) || class_name == "Reference"; + ClassDB::get_inheriters_from_class("RefCounted", &inheriters); + bool is_ref_counted = !!inheriters.find(class_name) || class_name == "RefCounted"; // @Unclear - class_api.is_reference = !class_api.is_singleton && is_reference; + class_api.is_ref_counted = !class_api.is_singleton && is_ref_counted; } // constants @@ -404,7 +405,7 @@ List<ClassAPI> generate_c_api_classes() { arg_type = Variant::get_type_name(arg_info.type); } } else { - arg_type = Variant::get_type_name(arg_info.type); + arg_type = get_type_name(arg_info); } method_api.argument_names.push_back(arg_name); @@ -509,10 +510,10 @@ List<ClassAPI> generate_c_builtin_api_types() { case Variant::PACKED_VECTOR2_ARRAY: case Variant::PACKED_VECTOR3_ARRAY: case Variant::PACKED_COLOR_ARRAY: - class_api.is_reference = true; + class_api.is_ref_counted = true; break; default: - class_api.is_reference = false; + class_api.is_ref_counted = false; break; } @@ -638,6 +639,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { // I'm sorry for the \t mess List<String> source; + VariantWriter writer; source.push_back("[\n"); @@ -652,7 +654,7 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back(String("\t\t\"singleton\": ") + (api.is_singleton ? "true" : "false") + ",\n"); source.push_back("\t\t\"singleton_name\": \"" + api.singleton_name + "\",\n"); source.push_back(String("\t\t\"instantiable\": ") + (api.is_instantiable ? "true" : "false") + ",\n"); - source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n"); + source.push_back(String("\t\t\"is_ref_counted\": ") + (api.is_ref_counted ? "true" : "false") + ",\n"); source.push_back("\t\t\"constants\": {\n"); for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) { @@ -682,7 +684,12 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n"); source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n"); source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n"); - source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n"); + String default_value; + if (e->get().default_arguments.has(i)) { + writer.write_to_string(e->get().default_arguments[i], default_value); + default_value = default_value.replace("\n", "").json_escape(); + } + source.push_back("\t\t\t\t\t\t\"default_value\": \"" + default_value + "\"\n"); source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n"); } source.push_back("\t\t\t\t]\n"); @@ -708,7 +715,12 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) { source.push_back("\t\t\t\t\t\t\"name\": \"" + e->get().argument_names[i] + "\",\n"); source.push_back("\t\t\t\t\t\t\"type\": \"" + e->get().argument_types[i] + "\",\n"); source.push_back(String("\t\t\t\t\t\t\"has_default_value\": ") + (e->get().default_arguments.has(i) ? "true" : "false") + ",\n"); - source.push_back("\t\t\t\t\t\t\"default_value\": \"" + (e->get().default_arguments.has(i) ? (String)e->get().default_arguments[i] : "") + "\"\n"); + String default_value; + if (e->get().default_arguments.has(i)) { + writer.write_to_string(e->get().default_arguments[i], default_value); + default_value = default_value.replace("\n", "").json_escape(); + } + source.push_back("\t\t\t\t\t\t\"default_value\": \"" + default_value + "\"\n"); source.push_back(String("\t\t\t\t\t}") + ((i < e->get().argument_names.size() - 1) ? "," : "") + "\n"); } source.push_back("\t\t\t\t]\n"); @@ -756,6 +768,8 @@ static void append_indented(StringBuilder &p_source, const char *p_text) { } static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_method) { + VariantWriter writer; + append_indented(p_source, vformat(R"("name": "%s",)", p_method.method_name)); append_indented(p_source, vformat(R"("return_type": "%s",)", p_method.return_type)); append_indented(p_source, vformat(R"("is_const": %s,)", p_method.is_const ? "true" : "false")); @@ -771,7 +785,12 @@ static void write_builtin_method(StringBuilder &p_source, const MethodAPI &p_met append_indented(p_source, vformat(R"("name": "%s",)", p_method.argument_names[i])); append_indented(p_source, vformat(R"("type": "%s",)", p_method.argument_types[i])); append_indented(p_source, vformat(R"("has_default_value": %s,)", p_method.default_arguments.has(i) ? "true" : "false")); - append_indented(p_source, vformat(R"("default_value": "%s")", p_method.default_arguments.has(i) ? p_method.default_arguments[i].operator String() : "")); + String default_value; + if (p_method.default_arguments.has(i)) { + writer.write_to_string(p_method.default_arguments[i], default_value); + default_value = default_value.replace("\n", "").json_escape(); + } + append_indented(p_source, vformat(R"("default_value": "%s")", default_value)); indent_level--; append_indented(p_source, i < p_method.argument_count - 1 ? "}," : "}"); @@ -794,7 +813,7 @@ static List<String> generate_c_builtin_api_json(const List<ClassAPI> &p_api) { append_indented(source, vformat(R"("name": "%s",)", class_api.class_name)); append_indented(source, vformat(R"("is_instantiable": %s,)", class_api.is_instantiable ? "true" : "false")); - append_indented(source, vformat(R"("is_reference": %s,)", class_api.is_reference ? "true" : "false")); + append_indented(source, vformat(R"("is_ref_counted": %s,)", class_api.is_ref_counted ? "true" : "false")); append_indented(source, vformat(R"("has_indexing": %s,)", class_api.has_indexing ? "true" : "false")); append_indented(source, vformat(R"("indexed_type": "%s",)", class_api.has_indexing && class_api.indexed_type == "Nil" ? "Variant" : class_api.indexed_type)); append_indented(source, vformat(R"("is_keyed": %s,)", class_api.is_keyed ? "true" : "false")); diff --git a/modules/gdnative/nativescript/godot_nativescript.cpp b/modules/gdnative/nativescript/godot_nativescript.cpp index b2abf8b8ae..70b14836bf 100644 --- a/modules/gdnative/nativescript/godot_nativescript.cpp +++ b/modules/gdnative/nativescript/godot_nativescript.cpp @@ -70,8 +70,7 @@ void GDAPI godot_nativescript_register_class(void *p_gdnative_handle, const char const NativeScriptDesc *b = desc.base_data; while (b) { - desc.rpc_count += b->rpc_count; - desc.rset_count += b->rset_count; + desc.rpc_methods.append_array(b->rpc_methods); b = b->base_data; } @@ -94,8 +93,6 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const desc.destroy_func = p_destroy_func; desc.is_tool = true; desc.base = p_base; - desc.rpc_count = 0; - desc.rset_count = 0; if (classes->has(p_base)) { desc.base_data = &(*classes)[p_base]; @@ -103,8 +100,7 @@ void GDAPI godot_nativescript_register_tool_class(void *p_gdnative_handle, const const NativeScriptDesc *b = desc.base_data; while (b) { - desc.rpc_count += b->rpc_count; - desc.rset_count += b->rset_count; + desc.rpc_methods.append_array(b->rpc_methods); b = b->base_data; } @@ -126,13 +122,16 @@ void GDAPI godot_nativescript_register_method(void *p_gdnative_handle, const cha method.method = p_method; method.rpc_mode = p_attr.rpc_type; method.rpc_method_id = UINT16_MAX; - if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) { - method.rpc_method_id = E->get().rpc_count; - E->get().rpc_count += 1; - } method.info = MethodInfo(p_function_name); E->get().methods.insert(p_function_name, method); + + if (p_attr.rpc_type != GODOT_METHOD_RPC_MODE_DISABLED) { + MultiplayerAPI::RPCConfig nd; + nd.name = String(p_name); + nd.rpc_mode = MultiplayerAPI::RPCMode(p_attr.rpc_type); + E->get().rpc_methods.push_back(nd); + } } void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const char *p_name, const char *p_path, godot_nativescript_property_attributes *p_attr, godot_nativescript_property_set_func p_set_func, godot_nativescript_property_get_func p_get_func) { @@ -144,11 +143,6 @@ void GDAPI godot_nativescript_register_property(void *p_gdnative_handle, const c NativeScriptDesc::Property property; property.default_value = *(Variant *)&p_attr->default_value; property.getter = p_get_func; - property.rset_mode = p_attr->rset_type; - if (p_attr->rset_type != GODOT_METHOD_RPC_MODE_DISABLED) { - property.rset_property_id = E->get().rset_count; - E->get().rset_count += 1; - } property.setter = p_set_func; property.info = PropertyInfo((Variant::Type)p_attr->type, p_path, @@ -338,7 +332,7 @@ void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_i } void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) { - return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object); + return nullptr; } void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time) { diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp index 46af70f73c..d7943827c2 100644 --- a/modules/gdnative/nativescript/nativescript.cpp +++ b/modules/gdnative/nativescript/nativescript.cpp @@ -37,8 +37,8 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "main/main.h" @@ -170,7 +170,7 @@ String NativeScript::get_script_class_icon_path() const { return script_class_icon_path; } -bool NativeScript::can_instance() const { +bool NativeScript::can_instantiate() const { NativeScriptDesc *script_data = get_script_desc(); #ifdef TOOLS_ENABLED @@ -415,245 +415,11 @@ void NativeScript::get_script_property_list(List<PropertyInfo> *p_list) const { } } -Vector<ScriptNetData> NativeScript::get_rpc_methods() const { - Vector<ScriptNetData> v; - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { - if (E->get().rpc_mode != GODOT_METHOD_RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E->key(); - nd.mode = MultiplayerAPI::RPCMode(E->get().rpc_mode); - v.push_back(nd); - } - } - - script_data = script_data->base_data; - } - - return v; -} - -uint16_t NativeScript::get_rpc_method_id(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - return E->get().rpc_method_id; - } - - script_data = script_data->base_data; - } - - return UINT16_MAX; -} - -StringName NativeScript::get_rpc_method(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName()); - +const Vector<MultiplayerAPI::RPCConfig> NativeScript::get_rpc_methods() const { NativeScriptDesc *script_data = get_script_desc(); + ERR_FAIL_COND_V(!script_data, Vector<MultiplayerAPI::RPCConfig>()); - while (script_data) { - for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { - if (E->get().rpc_method_id == p_id) { - return E->key(); - } - } - - script_data = script_data->base_data; - } - - return StringName(); -} - -MultiplayerAPI::RPCMode NativeScript::get_rpc_mode_by_id(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED); - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) { - if (E->get().rpc_method_id == p_id) { - switch (E->get().rpc_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -MultiplayerAPI::RPCMode NativeScript::get_rpc_mode(const StringName &p_method) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.find(p_method); - if (E) { - switch (E->get().rpc_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -Vector<ScriptNetData> NativeScript::get_rset_properties() const { - Vector<ScriptNetData> v; - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (E.get().rset_mode != GODOT_METHOD_RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E.key(); - nd.mode = MultiplayerAPI::RPCMode(E.get().rset_mode); - v.push_back(nd); - } - } - script_data = script_data->base_data; - } - - return v; -} - -uint16_t NativeScript::get_rset_property_id(const StringName &p_variable) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable); - if (E) { - return E.get().rset_property_id; - } - - script_data = script_data->base_data; - } - - return UINT16_MAX; -} - -StringName NativeScript::get_rset_property(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, StringName()); - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (E.get().rset_property_id == p_id) { - return E.key(); - } - } - - script_data = script_data->base_data; - } - - return StringName(); -} - -MultiplayerAPI::RPCMode NativeScript::get_rset_mode_by_id(uint16_t p_id) const { - ERR_FAIL_COND_V(p_id == UINT16_MAX, MultiplayerAPI::RPC_MODE_DISABLED); - - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.front(); E; E = E.next()) { - if (E.get().rset_property_id == p_id) { - switch (E.get().rset_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -MultiplayerAPI::RPCMode NativeScript::get_rset_mode(const StringName &p_variable) const { - NativeScriptDesc *script_data = get_script_desc(); - - while (script_data) { - OrderedHashMap<StringName, NativeScriptDesc::Property>::Element E = script_data->properties.find(p_variable); - if (E) { - switch (E.get().rset_mode) { - case GODOT_METHOD_RPC_MODE_DISABLED: - return MultiplayerAPI::RPC_MODE_DISABLED; - case GODOT_METHOD_RPC_MODE_REMOTE: - return MultiplayerAPI::RPC_MODE_REMOTE; - case GODOT_METHOD_RPC_MODE_MASTER: - return MultiplayerAPI::RPC_MODE_MASTER; - case GODOT_METHOD_RPC_MODE_PUPPET: - return MultiplayerAPI::RPC_MODE_PUPPET; - case GODOT_METHOD_RPC_MODE_REMOTESYNC: - return MultiplayerAPI::RPC_MODE_REMOTESYNC; - case GODOT_METHOD_RPC_MODE_MASTERSYNC: - return MultiplayerAPI::RPC_MODE_MASTERSYNC; - case GODOT_METHOD_RPC_MODE_PUPPETSYNC: - return MultiplayerAPI::RPC_MODE_PUPPETSYNC; - default: - return MultiplayerAPI::RPC_MODE_DISABLED; - } - } - - script_data = script_data->base_data; - } - - return MultiplayerAPI::RPC_MODE_DISABLED; + return script_data->rpc_methods; } String NativeScript::get_class_documentation() const { @@ -737,9 +503,9 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal Object *owner = nullptr; if (!(script_data->base_native_type == "")) { - owner = ClassDB::instance(script_data->base_native_type); + owner = ClassDB::instantiate(script_data->base_native_type); } else { - owner = memnew(Reference); + owner = memnew(RefCounted); } if (!owner) { @@ -747,7 +513,7 @@ Variant NativeScript::_new(const Variant **p_args, int p_argcount, Callable::Cal return Variant(); } - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -1046,46 +812,10 @@ Ref<Script> NativeScriptInstance::get_script() const { return script; } -Vector<ScriptNetData> NativeScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> NativeScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t NativeScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName NativeScriptInstance::get_rpc_method(uint16_t p_id) const { - return script->get_rpc_method(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const { - return script->get_rpc_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> NativeScriptInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t NativeScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName NativeScriptInstance::get_rset_property(uint16_t p_id) const { - return script->get_rset_property(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode_by_id(uint16_t p_id) const { - return script->get_rset_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode NativeScriptInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - ScriptLanguage *NativeScriptInstance::get_language() { return NativeScriptLanguage::get_singleton(); } @@ -1305,7 +1035,7 @@ Ref<Script> NativeScriptLanguage::get_template(const String &p_class_name, const return Ref<NativeScript>(s); } -bool NativeScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool NativeScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { return true; } @@ -1528,6 +1258,8 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) { } void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) { + return nullptr; +#if 0 ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), nullptr); ERR_FAIL_COND_V_MSG(!binding_functions[p_idx].first, nullptr, "Tried to get binding data for a nativescript binding that does not exist."); @@ -1557,9 +1289,12 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec } return (*binding_data)[p_idx]; +#endif } void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { + return nullptr; +#if 0 Vector<void *> *binding_data = new Vector<void *>; binding_data->resize(binding_functions.size()); @@ -1571,9 +1306,11 @@ void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) { binding_instances.insert(binding_data); return (void *)binding_data; +#endif } void NativeScriptLanguage::free_instance_binding_data(void *p_data) { +#if 0 if (!p_data) { return; } @@ -1593,9 +1330,11 @@ void NativeScriptLanguage::free_instance_binding_data(void *p_data) { binding_instances.erase(&binding_data); delete &binding_data; +#endif } void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_object) { +#if 0 void *data = p_object->get_script_instance_binding(lang_idx); if (!data) { @@ -1617,9 +1356,11 @@ void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_objec binding_functions[i].second.refcount_incremented_instance_binding(binding_data[i], p_object); } } +#endif } bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_object) { +#if 0 void *data = p_object->get_script_instance_binding(lang_idx); if (!data) { @@ -1645,6 +1386,8 @@ bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_objec } return can_die; +#endif + return false; } void NativeScriptLanguage::set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag) { @@ -1692,7 +1435,7 @@ void NativeScriptLanguage::init_library(const Ref<GDNativeLibrary> &lib) { if (!E) { Ref<GDNative> gdn; - gdn.instance(); + gdn.instantiate(); gdn->set_library(lib); // TODO check the return value? diff --git a/modules/gdnative/nativescript/nativescript.h b/modules/gdnative/nativescript/nativescript.h index ca5e76e43e..777a878660 100644 --- a/modules/gdnative/nativescript/nativescript.h +++ b/modules/gdnative/nativescript/nativescript.h @@ -62,8 +62,6 @@ struct NativeScriptDesc { godot_nativescript_property_get_func getter; PropertyInfo info; Variant default_value; - int rset_mode = 0; - uint16_t rset_property_id; String documentation; }; @@ -72,9 +70,8 @@ struct NativeScriptDesc { String documentation; }; - uint16_t rpc_count = 0; Map<StringName, Method> methods; - uint16_t rset_count = 0; + Vector<MultiplayerAPI::RPCConfig> rpc_methods; OrderedHashMap<StringName, Property> properties; Map<StringName, Signal> signals_; // QtCreator doesn't like the name signals StringName base; @@ -140,7 +137,7 @@ public: void set_script_class_icon_path(String p_icon_path); String get_script_class_icon_path() const; - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; //for script inheritance @@ -178,17 +175,7 @@ public: virtual void get_script_method_list(List<MethodInfo> *p_list) const override; virtual void get_script_property_list(List<PropertyInfo> *p_list) const override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const override; - virtual StringName get_rset_property(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; String get_class_documentation() const; String get_method_documentation(const StringName &p_method) const; @@ -226,17 +213,7 @@ public: String to_string(bool *r_valid); virtual Ref<Script> get_script() const; - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; virtual ScriptLanguage *get_language(); @@ -340,7 +317,7 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/nativescript/register_types.cpp b/modules/gdnative/nativescript/register_types.cpp index 0353ab2092..0191cfd809 100644 --- a/modules/gdnative/nativescript/register_types.cpp +++ b/modules/gdnative/nativescript/register_types.cpp @@ -50,10 +50,10 @@ void register_nativescript_types() { native_script_language->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(native_script_language); - resource_saver_gdns.instance(); + resource_saver_gdns.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gdns); - resource_loader_gdns.instance(); + resource_loader_gdns.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gdns); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp index 8b5fc8db5c..8ceba0f339 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp +++ b/modules/gdnative/net/multiplayer_peer_gdnative.cpp @@ -61,13 +61,13 @@ int MultiplayerPeerGDNative::get_available_packet_count() const { return interface->get_available_packet_count(interface->data); } -/* NetworkedMultiplayerPeer */ +/* MultiplayerPeer */ void MultiplayerPeerGDNative::set_transfer_mode(TransferMode p_mode) { ERR_FAIL_COND(interface == nullptr); interface->set_transfer_mode(interface->data, (godot_int)p_mode); } -NetworkedMultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { +MultiplayerPeer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const { ERR_FAIL_COND_V(interface == nullptr, TRANSFER_MODE_UNRELIABLE); return (TransferMode)interface->get_transfer_mode(interface->data); } @@ -107,7 +107,7 @@ bool MultiplayerPeerGDNative::is_refusing_new_connections() const { return interface->is_refusing_new_connections(interface->data); } -NetworkedMultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const { +MultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const { ERR_FAIL_COND_V(interface == nullptr, CONNECTION_DISCONNECTED); return (ConnectionStatus)interface->get_connection_status(interface->data); } diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h index 593b2534dd..7c10ab77f7 100644 --- a/modules/gdnative/net/multiplayer_peer_gdnative.h +++ b/modules/gdnative/net/multiplayer_peer_gdnative.h @@ -31,12 +31,12 @@ #ifndef MULTIPLAYER_PEER_GDNATIVE_H #define MULTIPLAYER_PEER_GDNATIVE_H -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "modules/gdnative/gdnative.h" #include "modules/gdnative/include/net/godot_net.h" -class MultiplayerPeerGDNative : public NetworkedMultiplayerPeer { - GDCLASS(MultiplayerPeerGDNative, NetworkedMultiplayerPeer); +class MultiplayerPeerGDNative : public MultiplayerPeer { + GDCLASS(MultiplayerPeerGDNative, MultiplayerPeer); protected: static void _bind_methods(); @@ -55,7 +55,7 @@ public: virtual int get_max_packet_size() const override; virtual int get_available_packet_count() const override; - /* Specific to NetworkedMultiplayerPeer */ + /* Specific to MultiplayerPeer */ virtual void set_transfer_mode(TransferMode p_mode) override; virtual TransferMode get_transfer_mode() const override; virtual void set_target_peer(int p_peer_id) override; diff --git a/modules/gdnative/pluginscript/pluginscript_instance.cpp b/modules/gdnative/pluginscript/pluginscript_instance.cpp index 7f8dba0906..ed1c0af3ed 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.cpp +++ b/modules/gdnative/pluginscript/pluginscript_instance.cpp @@ -100,46 +100,10 @@ String PluginScriptInstance::to_string(bool *r_valid) { return str_ret; } -Vector<ScriptNetData> PluginScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> PluginScriptInstance::get_rpc_methods() const { return _script->get_rpc_methods(); } -uint16_t PluginScriptInstance::get_rpc_method_id(const StringName &p_variable) const { - return _script->get_rpc_method_id(p_variable); -} - -StringName PluginScriptInstance::get_rpc_method(uint16_t p_id) const { - return _script->get_rpc_method(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode_by_id(uint16_t p_id) const { - return _script->get_rpc_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rpc_mode(const StringName &p_method) const { - return _script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> PluginScriptInstance::get_rset_properties() const { - return _script->get_rset_properties(); -} - -uint16_t PluginScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return _script->get_rset_property_id(p_variable); -} - -StringName PluginScriptInstance::get_rset_property(uint16_t p_id) const { - return _script->get_rset_property(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode_by_id(uint16_t p_id) const { - return _script->get_rset_mode_by_id(p_id); -} - -MultiplayerAPI::RPCMode PluginScriptInstance::get_rset_mode(const StringName &p_variable) const { - return _script->get_rset_mode(p_variable); -} - void PluginScriptInstance::refcount_incremented() { if (_desc->refcount_decremented) { _desc->refcount_incremented(_data); diff --git a/modules/gdnative/pluginscript/pluginscript_instance.h b/modules/gdnative/pluginscript/pluginscript_instance.h index b263c0e62c..25b62ae8ab 100644 --- a/modules/gdnative/pluginscript/pluginscript_instance.h +++ b/modules/gdnative/pluginscript/pluginscript_instance.h @@ -71,17 +71,7 @@ public: void set_path(const String &p_path); - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; virtual void refcount_incremented(); virtual bool refcount_decremented(); diff --git a/modules/gdnative/pluginscript/pluginscript_language.cpp b/modules/gdnative/pluginscript/pluginscript_language.cpp index 1360cf0299..79aba342c9 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.cpp +++ b/modules/gdnative/pluginscript/pluginscript_language.cpp @@ -30,7 +30,7 @@ // Godot imports #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" // PluginScript imports #include "pluginscript_language.h" @@ -112,20 +112,29 @@ Ref<Script> PluginScriptLanguage::get_template(const String &p_class_name, const return script; } -bool PluginScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool PluginScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { PackedStringArray functions; + Array errors; if (_desc.validate) { bool ret = _desc.validate( _data, (godot_string *)&p_script, - &r_line_error, - &r_col_error, - (godot_string *)&r_test_error, (godot_string *)&p_path, - (godot_packed_string_array *)&functions); + (godot_packed_string_array *)&functions, + (godot_array *)&errors); for (int i = 0; i < functions.size(); i++) { r_functions->push_back(functions[i]); } + if (r_errors) { + for (int i = 0; i < errors.size(); i++) { + Dictionary error = errors[i]; + ScriptLanguage::ScriptError e; + e.line = error["line"]; + e.column = error["column"]; + e.message = error["message"]; + r_errors->push_back(e); + } + } return ret; } return true; diff --git a/modules/gdnative/pluginscript/pluginscript_language.h b/modules/gdnative/pluginscript/pluginscript_language.h index 957bf355ca..26ab4a95e3 100644 --- a/modules/gdnative/pluginscript/pluginscript_language.h +++ b/modules/gdnative/pluginscript/pluginscript_language.h @@ -75,7 +75,7 @@ public: virtual void get_comment_delimiters(List<String> *p_delimiters) const; virtual void get_string_delimiters(List<String> *p_delimiters) const; virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdnative/pluginscript/pluginscript_loader.cpp b/modules/gdnative/pluginscript/pluginscript_loader.cpp index f2165cd225..462452a897 100644 --- a/modules/gdnative/pluginscript/pluginscript_loader.cpp +++ b/modules/gdnative/pluginscript/pluginscript_loader.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ // Godot imports -#include "core/os/file_access.h" +#include "core/io/file_access.h" // Pythonscript imports #include "pluginscript_language.h" #include "pluginscript_loader.h" diff --git a/modules/gdnative/pluginscript/pluginscript_script.cpp b/modules/gdnative/pluginscript/pluginscript_script.cpp index a48245814f..7fc8178e34 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.cpp +++ b/modules/gdnative/pluginscript/pluginscript_script.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ // Godot imports -#include "core/os/file_access.h" +#include "core/io/file_access.h" // PluginScript imports #include "pluginscript_instance.h" #include "pluginscript_script.h" @@ -38,13 +38,13 @@ #ifdef DEBUG_ENABLED #define __ASSERT_SCRIPT_REASON "Cannot retrieve PluginScript class for this script, is your code correct?" -#define ASSERT_SCRIPT_VALID() \ - { \ - ERR_FAIL_COND_MSG(!can_instance(), __ASSERT_SCRIPT_REASON); \ +#define ASSERT_SCRIPT_VALID() \ + { \ + ERR_FAIL_COND_MSG(!can_instantiate(), __ASSERT_SCRIPT_REASON); \ } -#define ASSERT_SCRIPT_VALID_V(ret) \ - { \ - ERR_FAIL_COND_V_MSG(!can_instance(), ret, __ASSERT_SCRIPT_REASON); \ +#define ASSERT_SCRIPT_VALID_V(ret) \ + { \ + ERR_FAIL_COND_V_MSG(!can_instantiate(), ret, __ASSERT_SCRIPT_REASON); \ } #else #define ASSERT_SCRIPT_VALID() @@ -94,9 +94,9 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal Object *owner = nullptr; if (get_instance_base_type() == "") { - owner = memnew(Reference); + owner = memnew(RefCounted); } else { - owner = ClassDB::instance(get_instance_base_type()); + owner = ClassDB::instantiate(get_instance_base_type()); } if (!owner) { @@ -104,7 +104,7 @@ Variant PluginScript::_new(const Variant **p_args, int p_argcount, Callable::Cal return Variant(); } - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -133,7 +133,7 @@ void PluginScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) #endif -bool PluginScript::can_instance() const { +bool PluginScript::can_instantiate() const { bool can = _valid || (!_tool && !ScriptServer::is_scripting_enabled()); return can; } @@ -198,7 +198,7 @@ ScriptInstance *PluginScript::instance_create(Object *p_this) { StringName base_type = get_instance_base_type(); if (base_type) { if (!ClassDB::is_parent_class(p_this->get_class_name(), base_type)) { - String msg = "Script inherits from native type '" + String(base_type) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"; + String msg = "Script inherits from native type '" + String(base_type) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"; // TODO: implement PluginscriptLanguage::debug_break_parse // if (EngineDebugger::is_active()) { // _language->debug_break_parse(get_path(), 0, msg); @@ -312,10 +312,9 @@ Error PluginScript::reload(bool p_keep_state) { } Array *methods = (Array *)&manifest.methods; _rpc_methods.clear(); - _rpc_variables.clear(); if (_ref_base_parent.is_valid()) { + /// XXX TODO Should this be _rpc_methods.append_array(...) _rpc_methods = _ref_base_parent->get_rpc_methods(); - _rpc_variables = _ref_base_parent->get_rset_properties(); } for (int i = 0; i < methods->size(); ++i) { Dictionary v = (*methods)[i]; @@ -324,9 +323,10 @@ Error PluginScript::reload(bool p_keep_state) { // rpc_mode is passed as an optional field and is not part of MethodInfo Variant var = v["rpc_mode"]; if (var != Variant()) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = mi.name; - nd.mode = MultiplayerAPI::RPCMode(int(var)); + nd.rpc_mode = MultiplayerAPI::RPCMode(int(var)); + // TODO Transfer Channel if (_rpc_methods.find(nd) == -1) { _rpc_methods.push_back(nd); } @@ -334,7 +334,7 @@ Error PluginScript::reload(bool p_keep_state) { } // Sort so we are 100% that they are always the same. - _rpc_methods.sort_custom<SortNetData>(); + _rpc_methods.sort_custom<MultiplayerAPI::SortRPCConfig>(); Array *signals = (Array *)&manifest.signals; for (int i = 0; i < signals->size(); ++i) { @@ -348,21 +348,8 @@ Error PluginScript::reload(bool p_keep_state) { PropertyInfo pi = PropertyInfo::from_dict(v); _properties_info[pi.name] = pi; _properties_default_values[pi.name] = v["default_value"]; - // rset_mode is passed as an optional field and is not part of PropertyInfo - Variant var = v["rset_mode"]; - if (var != Variant()) { - ScriptNetData nd; - nd.name = pi.name; - nd.mode = MultiplayerAPI::RPCMode(int(var)); - if (_rpc_variables.find(nd) == -1) { - _rpc_variables.push_back(nd); - } - } } - // Sort so we are 100% that they are always the same. - _rpc_variables.sort_custom<SortNetData>(); - #ifdef TOOLS_ENABLED /*for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { @@ -486,76 +473,10 @@ int PluginScript::get_member_line(const StringName &p_member) const { return -1; } -Vector<ScriptNetData> PluginScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> PluginScript::get_rpc_methods() const { return _rpc_methods; } -uint16_t PluginScript::get_rpc_method_id(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(UINT16_MAX); - for (int i = 0; i < _rpc_methods.size(); i++) { - if (_rpc_methods[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName PluginScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ASSERT_SCRIPT_VALID_V(StringName()); - if (p_rpc_method_id >= _rpc_methods.size()) { - return StringName(); - } - return _rpc_methods[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode PluginScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - if (p_rpc_method_id >= _rpc_methods.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return _rpc_methods[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode PluginScript::get_rpc_mode(const StringName &p_method) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> PluginScript::get_rset_properties() const { - return _rpc_variables; -} - -uint16_t PluginScript::get_rset_property_id(const StringName &p_property) const { - ASSERT_SCRIPT_VALID_V(UINT16_MAX); - for (int i = 0; i < _rpc_variables.size(); i++) { - if (_rpc_variables[i].name == p_property) { - return i; - } - } - return UINT16_MAX; -} - -StringName PluginScript::get_rset_property(const uint16_t p_rset_property_id) const { - ASSERT_SCRIPT_VALID_V(StringName()); - if (p_rset_property_id >= _rpc_variables.size()) { - return StringName(); - } - return _rpc_variables[p_rset_property_id].name; -} - -MultiplayerAPI::RPCMode PluginScript::get_rset_mode_by_id(const uint16_t p_rset_property_id) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - if (p_rset_property_id >= _rpc_variables.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return _rpc_variables[p_rset_property_id].mode; -} - -MultiplayerAPI::RPCMode PluginScript::get_rset_mode(const StringName &p_variable) const { - ASSERT_SCRIPT_VALID_V(MultiplayerAPI::RPC_MODE_DISABLED); - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - PluginScript::PluginScript() : _script_list(this) { } diff --git a/modules/gdnative/pluginscript/pluginscript_script.h b/modules/gdnative/pluginscript/pluginscript_script.h index 1c86f2056d..838195147f 100644 --- a/modules/gdnative/pluginscript/pluginscript_script.h +++ b/modules/gdnative/pluginscript/pluginscript_script.h @@ -61,8 +61,7 @@ private: Map<StringName, PropertyInfo> _properties_info; Map<StringName, MethodInfo> _signals_info; Map<StringName, MethodInfo> _methods_info; - Vector<ScriptNetData> _rpc_methods; - Vector<ScriptNetData> _rpc_variables; + Vector<MultiplayerAPI::RPCConfig> _rpc_methods; Set<Object *> _instances; //exported members @@ -93,7 +92,7 @@ public: return _icon_path; } - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; //for script inheritance @@ -137,17 +136,7 @@ public: virtual int get_member_line(const StringName &p_member) const override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_property) const override; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; PluginScript(); void init(PluginScriptLanguage *language); diff --git a/modules/gdnative/pluginscript/register_types.cpp b/modules/gdnative/pluginscript/register_types.cpp index b94538b2f7..433544178f 100644 --- a/modules/gdnative/pluginscript/register_types.cpp +++ b/modules/gdnative/pluginscript/register_types.cpp @@ -31,9 +31,9 @@ #include "register_types.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/dir_access.h" #include "core/os/os.h" #include "scene/main/scene_tree.h" diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp index d08bde9e23..8e20a2b90d 100644 --- a/modules/gdnative/register_types.cpp +++ b/modules/gdnative/register_types.cpp @@ -230,7 +230,7 @@ static void editor_init_callback() { ProjectSettingsEditor::get_singleton()->get_tabs()->add_child(library_editor); Ref<GDNativeExportPlugin> export_plugin; - export_plugin.instance(); + export_plugin.instantiate(); EditorExport::get_singleton()->add_export_plugin(export_plugin); @@ -262,10 +262,10 @@ void register_gdnative_types() { ClassDB::register_class<GDNativeLibrary>(); ClassDB::register_class<GDNative>(); - resource_loader_gdnlib.instance(); + resource_loader_gdnlib.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gdnlib); - resource_saver_gdnlib.instance(); + resource_saver_gdnlib.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gdnlib); GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry); @@ -298,7 +298,7 @@ void register_gdnative_types() { Ref<GDNativeLibrary> lib = ResourceLoader::load(path); Ref<GDNative> singleton; - singleton.instance(); + singleton.instantiate(); singleton->set_library(lib); if (!singleton->initialize()) { @@ -363,7 +363,7 @@ void unregister_gdnative_types() { print_line(String("aabb:\t") + itos(sizeof(AABB))); print_line(String("rid:\t") + itos(sizeof(RID))); print_line(String("string:\t") + itos(sizeof(String))); - print_line(String("transform:\t") + itos(sizeof(Transform))); + print_line(String("transform:\t") + itos(sizeof(Transform3D))); print_line(String("transfo2D:\t") + itos(sizeof(Transform2D))); print_line(String("variant:\t") + itos(sizeof(Variant))); print_line(String("vector2:\t") + itos(sizeof(Vector2))); diff --git a/modules/gdnative/videodecoder/register_types.cpp b/modules/gdnative/videodecoder/register_types.cpp index 394831daeb..e822d42312 100644 --- a/modules/gdnative/videodecoder/register_types.cpp +++ b/modules/gdnative/videodecoder/register_types.cpp @@ -36,7 +36,7 @@ static Ref<ResourceFormatLoaderVideoStreamGDNative> resource_loader_vsgdnative; void register_videodecoder_types() { - resource_loader_vsgdnative.instance(); + resource_loader_vsgdnative.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_vsgdnative, true); ClassDB::register_class<VideoStreamGDNative>(); diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.cpp b/modules/gdnative/videodecoder/video_stream_gdnative.cpp index 8b0434c7dd..4c9bfb395d 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.cpp +++ b/modules/gdnative/videodecoder/video_stream_gdnative.cpp @@ -122,7 +122,7 @@ bool VideoStreamPlaybackGDNative::open_file(const String &p_file) { samples_decoded = 0; Ref<Image> img; - img.instance(); + img.instantiate(); img->create((int)texture_size.width, false, (int)texture_size.height, Image::FORMAT_RGBA8); texture->create_from_image(img); @@ -185,7 +185,7 @@ void VideoStreamPlaybackGDNative::update_texture() { Ref<Image> img = memnew(Image(texture_size.width, texture_size.height, 0, Image::FORMAT_RGBA8, *pba)); - texture->update(img, true); + texture->update(img); } // ctor and dtor diff --git a/modules/gdnative/videodecoder/video_stream_gdnative.h b/modules/gdnative/videodecoder/video_stream_gdnative.h index 140888cd4b..c605dbb433 100644 --- a/modules/gdnative/videodecoder/video_stream_gdnative.h +++ b/modules/gdnative/videodecoder/video_stream_gdnative.h @@ -32,7 +32,7 @@ #define VIDEO_STREAM_GDNATIVE_H #include "../gdnative.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "scene/resources/texture.h" #include "scene/resources/video_stream.h" diff --git a/modules/gdnative/xr/xr_interface_gdnative.cpp b/modules/gdnative/xr/xr_interface_gdnative.cpp index 122cb5849b..e51542e23d 100644 --- a/modules/gdnative/xr/xr_interface_gdnative.cpp +++ b/modules/gdnative/xr/xr_interface_gdnative.cpp @@ -70,8 +70,13 @@ void XRInterfaceGDNative::set_interface(const godot_xr_interface_gdnative *p_int // this should only be called once, just being paranoid.. if (interface) { cleanup(); + interface = NULL; } + // validate + ERR_FAIL_NULL(p_interface); + ERR_FAIL_COND_MSG(p_interface->version.major < 4, "This is an incompatible GDNative XR plugin."); + // bind to our interface interface = p_interface; @@ -119,14 +124,14 @@ int XRInterfaceGDNative::get_camera_feed_id() { return (unsigned int)interface->get_camera_feed_id(data); } -bool XRInterfaceGDNative::is_stereo() { - bool stereo; +uint32_t XRInterfaceGDNative::get_view_count() { + uint32_t view_count; - ERR_FAIL_COND_V(interface == nullptr, false); + ERR_FAIL_COND_V(interface == nullptr, 1); - stereo = interface->is_stereo(data); + view_count = interface->get_view_count(data); - return stereo; + return view_count; } bool XRInterfaceGDNative::is_initialized() const { @@ -173,28 +178,52 @@ Size2 XRInterfaceGDNative::get_render_targetsize() { return *vec; } -Transform XRInterfaceGDNative::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { - Transform *ret; +Transform3D XRInterfaceGDNative::get_camera_transform() { + Transform3D *ret; + + ERR_FAIL_COND_V(interface == nullptr, Transform3D()); + + godot_transform3d t = interface->get_camera_transform(data); + + ret = (Transform3D *)&t; + + return *ret; +} + +Transform3D XRInterfaceGDNative::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + Transform3D *ret; - ERR_FAIL_COND_V(interface == nullptr, Transform()); + ERR_FAIL_COND_V(interface == nullptr, Transform3D()); - godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform); + godot_transform3d t = interface->get_transform_for_view(data, (int)p_view, (godot_transform3d *)&p_cam_transform); - ret = (Transform *)&t; + ret = (Transform3D *)&t; return *ret; } -CameraMatrix XRInterfaceGDNative::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix XRInterfaceGDNative::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { CameraMatrix cm; ERR_FAIL_COND_V(interface == nullptr, CameraMatrix()); - interface->fill_projection_for_eye(data, (godot_float *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far); + interface->fill_projection_for_view(data, (godot_real_t *)cm.matrix, (godot_int)p_view, p_aspect, p_z_near, p_z_far); return cm; } +Vector<BlitToScreen> XRInterfaceGDNative::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { + // possibly move this as a member variable and add a callback to populate? + Vector<BlitToScreen> blit_to_screen; + + ERR_FAIL_COND_V(interface == nullptr, blit_to_screen); + + // must implement + interface->commit_views(data, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect); + + return blit_to_screen; +} + unsigned int XRInterfaceGDNative::get_external_texture_for_eye(XRInterface::Eyes p_eye) { ERR_FAIL_COND_V(interface == nullptr, 0); @@ -229,27 +258,27 @@ void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_inte ERR_FAIL_COND_MSG(p_interface->version.major < 4, "GDNative XR interfaces build for Godot 3.x are not supported."); Ref<XRInterfaceGDNative> new_interface; - new_interface.instance(); + new_interface.instantiate(); new_interface->set_interface((const godot_xr_interface_gdnative *)p_interface); XRServer::get_singleton()->add_interface(new_interface); } -godot_float GDAPI godot_xr_get_worldscale() { +godot_real_t GDAPI godot_xr_get_worldscale() { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 1.0); return xr_server->get_world_scale(); } -godot_transform GDAPI godot_xr_get_reference_frame() { - godot_transform reference_frame; - Transform *reference_frame_ptr = (Transform *)&reference_frame; +godot_transform3d GDAPI godot_xr_get_reference_frame() { + godot_transform3d reference_frame; + Transform3D *reference_frame_ptr = (Transform3D *)&reference_frame; XRServer *xr_server = XRServer::get_singleton(); if (xr_server != nullptr) { *reference_frame_ptr = xr_server->get_reference_frame(); } else { - memnew_placement(&reference_frame, Transform); + memnew_placement(&reference_frame, Transform3D); } return reference_frame; @@ -302,7 +331,7 @@ godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, g ERR_FAIL_NULL_V(input, 0); Ref<XRPositionalTracker> new_tracker; - new_tracker.instance(); + new_tracker.instantiate(); new_tracker->set_tracker_name(p_device_name); new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); if (p_hand == 1) { @@ -356,13 +385,13 @@ void GDAPI godot_xr_remove_controller(godot_int p_controller_id) { } } -void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) { +void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); if (tracker.is_valid()) { - Transform *transform = (Transform *)p_transform; + Transform3D *transform = (Transform3D *)p_transform; if (p_tracks_orientation) { tracker->set_orientation(transform->basis); } @@ -383,12 +412,12 @@ void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p if (tracker.is_valid()) { int joyid = tracker->get_joy_id(); if (joyid != -1) { - input->joy_button(joyid, p_button, p_is_pressed); + input->joy_button(joyid, (JoyButton)p_button, p_is_pressed); } } } -void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_float p_value, godot_bool p_can_be_negative) { +void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); @@ -402,12 +431,12 @@ void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_a Input::JoyAxisValue jx; jx.min = p_can_be_negative ? -1 : 0; jx.value = p_value; - input->joy_axis(joyid, p_axis, jx); + input->joy_axis(joyid, (JoyAxis)p_axis, jx); } } } -godot_float GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) { +godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, 0.0); diff --git a/modules/gdnative/xr/xr_interface_gdnative.h b/modules/gdnative/xr/xr_interface_gdnative.h index 84bd8fc731..42e9206c1f 100644 --- a/modules/gdnative/xr/xr_interface_gdnative.h +++ b/modules/gdnative/xr/xr_interface_gdnative.h @@ -72,20 +72,24 @@ public: /** rendering and internal **/ virtual Size2 get_render_targetsize() override; - virtual bool is_stereo() override; - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; // we expose a Vector<float> version of this function to GDNative Vector<float> _get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far); // and a CameraMatrix version to XRServer - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; - virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override; - virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; + virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void process() override; virtual void notification(int p_what) override; + + // deprecated + virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; + virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override; }; #endif // XR_INTERFACE_GDNATIVE_H diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 9e974b6fdc..839aa6b3c6 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -177,7 +177,7 @@ [b]Note:[/b] Resource paths can be obtained by right clicking on a resource in the Assets Panel and choosing "Copy Path" or by dragging the file from the FileSystem dock into the script. [codeblock] # Instance a scene. - var diamond = preload("res://diamond.tscn").instance() + var diamond = preload("res://diamond.tscn").instantiate() [/codeblock] </description> </method> @@ -240,10 +240,10 @@ </method> </methods> <constants> - <constant name="PI" value="3.141593"> + <constant name="PI" value="3.14159265358979"> Constant that represents how many times the diameter of a circle fits around its perimeter. This is equivalent to [code]TAU / 2[/code]. </constant> - <constant name="TAU" value="6.283185"> + <constant name="TAU" value="6.28318530717959"> The circle constant, the circumference of the unit circle in radians. </constant> <constant name="INF" value="inf"> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index d34cccb3af..79ec9eb65f 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -64,6 +64,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) bool in_function_args = false; bool in_member_variable = false; bool in_node_path = false; + bool in_annotation = false; bool is_hex_notation = false; bool is_bin_notation = false; bool expect_type = false; @@ -357,9 +358,18 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) in_node_path = false; } + if (!in_annotation && in_region == -1 && str[j] == '@') { + in_annotation = true; + } else if (in_region != -1 || is_a_symbol) { + in_annotation = false; + } + if (in_node_path) { next_type = NODE_PATH; color = node_path_color; + } else if (in_annotation) { + next_type = ANNOTATION; + color = annotation_color; } else if (in_keyword) { next_type = KEYWORD; color = keyword_color; @@ -546,19 +556,22 @@ void GDScriptSyntaxHighlighter::_update_cache() { } const String text_edit_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme"); - const bool default_theme = text_edit_color_theme == "Godot 2"; + const bool godot_2_theme = text_edit_color_theme == "Godot 2"; - if (default_theme || EditorSettings::get_singleton()->is_dark_theme()) { + if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) { function_definition_color = Color(0.4, 0.9, 1.0); node_path_color = Color(0.39, 0.76, 0.35); + annotation_color = Color(1.0, 0.7, 0.45); } else { function_definition_color = Color(0.0, 0.65, 0.73); node_path_color = Color(0.32, 0.55, 0.29); + annotation_color = Color(0.8, 0.5, 0.25); } EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color); EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color); - if (text_edit_color_theme == "Default" || default_theme) { + EDITOR_DEF("text_editor/highlighting/gdscript/annotation_color", annotation_color); + if (text_edit_color_theme == "Default" || godot_2_theme) { EditorSettings::get_singleton()->set_initial_value( "text_editor/highlighting/gdscript/function_definition_color", function_definition_color, @@ -567,10 +580,15 @@ void GDScriptSyntaxHighlighter::_update_cache() { "text_editor/highlighting/gdscript/node_path_color", node_path_color, true); + EditorSettings::get_singleton()->set_initial_value( + "text_editor/highlighting/gdscript/annotation_color", + annotation_color, + true); } function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color"); node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color"); + annotation_color = EDITOR_GET("text_editor/highlighting/gdscript/annotation_color"); type_color = EDITOR_GET("text_editor/highlighting/base_type_color"); } @@ -604,6 +622,6 @@ void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, cons Ref<EditorSyntaxHighlighter> GDScriptSyntaxHighlighter::_create() const { Ref<GDScriptSyntaxHighlighter> syntax_highlighter; - syntax_highlighter.instance(); + syntax_highlighter.instantiate(); return syntax_highlighter; } diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 1b57cb1923..d07c182aa6 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -54,6 +54,7 @@ private: NONE, REGION, NODE_PATH, + ANNOTATION, SYMBOL, NUMBER, FUNCTION, @@ -72,6 +73,7 @@ private: Color number_color; Color member_color; Color node_path_color; + Color annotation_color; Color type_color; void add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index d7814e85b0..8b12b1eae4 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -36,8 +36,8 @@ #include "core/config/project_settings.h" #include "core/core_constants.h" #include "core/core_string_names.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "gdscript_analyzer.h" #include "gdscript_cache.h" @@ -72,19 +72,19 @@ void GDScriptNativeClass::_bind_methods() { } Variant GDScriptNativeClass::_new() { - Object *o = instance(); + Object *o = instantiate(); ERR_FAIL_COND_V_MSG(!o, Variant(), "Class type: '" + String(name) + "' is not instantiable."); - Reference *ref = Object::cast_to<Reference>(o); - if (ref) { - return REF(ref); + RefCounted *rc = Object::cast_to<RefCounted>(o); + if (rc) { + return REF(rc); } else { return o; } } -Object *GDScriptNativeClass::instance() { - return ClassDB::instance(name); +Object *GDScriptNativeClass::instantiate() { + return ClassDB::instantiate(name); } void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) { @@ -98,11 +98,11 @@ void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance p_script->implicit_initializer->call(p_instance, nullptr, 0, r_error); } -GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) { +GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) { /* STEP 1, CREATE */ GDScriptInstance *instance = memnew(GDScriptInstance); - instance->base_ref = p_isref; + instance->base_ref_counted = p_is_ref_counted; instance->members.resize(member_indices.size()); instance->script = Ref<GDScript>(this); instance->owner = p_owner; @@ -170,13 +170,13 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant()); if (_baseptr->native.ptr()) { - owner = _baseptr->native->instance(); + owner = _baseptr->native->instantiate(); } else { - owner = memnew(Reference); //by default, no base means use reference + owner = memnew(RefCounted); //by default, no base means use reference } ERR_FAIL_COND_V_MSG(!owner, Variant(), "Can't inherit from a virtual class."); - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -196,7 +196,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr } } -bool GDScript::can_instance() const { +bool GDScript::can_instantiate() const { #ifdef TOOLS_ENABLED return valid && (tool || ScriptServer::is_scripting_enabled()); #else @@ -346,21 +346,21 @@ ScriptInstance *GDScript::instance_create(Object *p_this) { if (top->native.is_valid()) { if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) { if (EngineDebugger::is_active()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); + GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } - ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instanced in object of type '" + p_this->get_class() + "'" + "."); + ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type '" + p_this->get_class() + "'" + "."); } } Callable::CallError unchecked_error; - return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error); + return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error); } PlaceHolderScriptInstance *GDScript::placeholder_instance_create(Object *p_this) { #ifdef TOOLS_ENABLED PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(), Ref<Script>(this), p_this)); placeholders.insert(si); - _update_exports(); + _update_exports(nullptr, false, si); return si; #else return nullptr; @@ -584,7 +584,7 @@ void GDScript::_update_doc() { } #endif -bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) { +bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderScriptInstance *p_instance_to_update) { #ifdef TOOLS_ENABLED static Vector<GDScript *> base_caches; @@ -721,15 +721,19 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call) { } } - if (placeholders.size()) { //hm :( + if ((changed || p_instance_to_update) && placeholders.size()) { //hm :( // update placeholders if any Map<StringName, Variant> values; List<PropertyInfo> propnames; _update_exports_values(values, propnames); - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); + if (changed) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->update(propnames, values); + } + } else { + p_instance_to_update->update(propnames, values); } } @@ -897,68 +901,10 @@ void GDScript::get_members(Set<StringName> *p_members) { } } -Vector<ScriptNetData> GDScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> GDScript::get_rpc_methods() const { return rpc_functions; } -uint16_t GDScript::get_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < rpc_functions.size(); i++) { - if (rpc_functions[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName GDScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - if (p_rpc_method_id >= rpc_functions.size()) { - return StringName(); - } - return rpc_functions[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode GDScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - if (p_rpc_method_id >= rpc_functions.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return rpc_functions[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode GDScript::get_rpc_mode(const StringName &p_method) const { - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> GDScript::get_rset_properties() const { - return rpc_variables; -} - -uint16_t GDScript::get_rset_property_id(const StringName &p_variable) const { - for (int i = 0; i < rpc_variables.size(); i++) { - if (rpc_variables[i].name == p_variable) { - return i; - } - } - return UINT16_MAX; -} - -StringName GDScript::get_rset_property(const uint16_t p_rset_member_id) const { - if (p_rset_member_id >= rpc_variables.size()) { - return StringName(); - } - return rpc_variables[p_rset_member_id].name; -} - -MultiplayerAPI::RPCMode GDScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - if (p_rset_member_id >= rpc_variables.size()) { - return MultiplayerAPI::RPC_MODE_DISABLED; - } - return rpc_variables[p_rset_member_id].mode; -} - -MultiplayerAPI::RPCMode GDScript::get_rset_mode(const StringName &p_variable) const { - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *top = this; while (top) { @@ -1210,10 +1156,8 @@ void GDScript::_save_orphaned_subclasses() { void GDScript::_init_rpc_methods_properties() { // Copy the base rpc methods so we don't mask their IDs. rpc_functions.clear(); - rpc_variables.clear(); if (base.is_valid()) { rpc_functions = base->rpc_functions; - rpc_variables = base->rpc_variables; } GDScript *cscript = this; @@ -1222,25 +1166,17 @@ void GDScript::_init_rpc_methods_properties() { // RPC Methods for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) { if (E->get()->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = E->key(); - nd.mode = E->get()->get_rpc_mode(); + nd.rpc_mode = E->get()->get_rpc_mode(); + // TODO + nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + nd.channel = 0; if (-1 == rpc_functions.find(nd)) { rpc_functions.push_back(nd); } } } - // RSet - for (Map<StringName, MemberInfo>::Element *E = cscript->member_indices.front(); E; E = E->next()) { - if (E->get().rpc_mode != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; - nd.name = E->key(); - nd.mode = E->get().rpc_mode; - if (-1 == rpc_variables.find(nd)) { - rpc_variables.push_back(nd); - } - } - } if (cscript != this) { sub_E = sub_E->next(); @@ -1254,8 +1190,7 @@ void GDScript::_init_rpc_methods_properties() { } // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<SortNetData>(); - rpc_variables.sort_custom<SortNetData>(); + rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); } GDScript::~GDScript() { @@ -1611,46 +1546,10 @@ ScriptLanguage *GDScriptInstance::get_language() { return GDScriptLanguage::get_singleton(); } -Vector<ScriptNetData> GDScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> GDScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t GDScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName GDScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { - return script->get_rpc_method(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - return script->get_rpc_mode_by_id(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> GDScriptInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t GDScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName GDScriptInstance::get_rset_property(const uint16_t p_rset_member_id) const { - return script->get_rset_property(p_rset_member_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - return script->get_rset_mode_by_id(p_rset_member_id); -} - -MultiplayerAPI::RPCMode GDScriptInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - void GDScriptInstance::reload_members() { #ifdef DEBUG_ENABLED @@ -1681,7 +1580,7 @@ void GDScriptInstance::reload_members() { GDScriptInstance::GDScriptInstance() { owner = nullptr; - base_ref = false; + base_ref_counted = false; } GDScriptInstance::~GDScriptInstance() { @@ -2169,7 +2068,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b if (err == OK) { const GDScriptParser::ClassNode *c = parser.get_tree(); if (r_icon_path) { - if (c->icon_path.is_empty() || c->icon_path.is_abs_path()) { + if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) { *r_icon_path = c->icon_path; } else if (c->icon_path.is_rel_path()) { *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path(); @@ -2237,7 +2136,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b break; } } else { - *r_base_type = "Reference"; + *r_base_type = "RefCounted"; subclass = nullptr; } } @@ -2357,7 +2256,7 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_ori if (script.is_null()) { // Don't fail loading because of parsing error. - script.instance(); + script.instantiate(); } if (r_error) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 6df66e876d..078b7a2fd0 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -39,8 +39,8 @@ #include "core/object/script_language.h" #include "gdscript_function.h" -class GDScriptNativeClass : public Reference { - GDCLASS(GDScriptNativeClass, Reference); +class GDScriptNativeClass : public RefCounted { + GDCLASS(GDScriptNativeClass, RefCounted); StringName name; @@ -51,7 +51,7 @@ protected: public: _FORCE_INLINE_ const StringName &get_name() const { return name; } Variant _new(); - Object *instance(); + Object *instantiate(); GDScriptNativeClass(const StringName &p_name); }; @@ -80,14 +80,13 @@ class GDScript : public Script { GDScript *_base = nullptr; //fast pointer access GDScript *_owner = nullptr; //for subclasses - Set<StringName> members; //members are just indices to the instanced script. + Set<StringName> members; //members are just indices to the instantiated script. Map<StringName, Variant> constants; Map<StringName, GDScriptFunction *> member_functions; - Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script. + Map<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. Map<StringName, Ref<GDScript>> subclasses; Map<StringName, Vector<StringName>> _signals; - Vector<ScriptNetData> rpc_functions; - Vector<ScriptNetData> rpc_variables; + Vector<MultiplayerAPI::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED @@ -133,7 +132,7 @@ class GDScript : public Script { SelfList<GDScriptFunctionState>::List pending_func_states; void _super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error); - GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error); + GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error); void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path); @@ -149,7 +148,7 @@ class GDScript : public Script { #endif - bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false); + bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false, PlaceHolderScriptInstance *p_instance_to_update = nullptr); void _save_orphaned_subclasses(); void _init_rpc_methods_properties(); @@ -158,7 +157,7 @@ class GDScript : public Script { void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const; void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const; - // This method will map the class name from "Reference" to "MyClass.InnerClass". + // This method will map the class name from "RefCounted" to "MyClass.InnerClass". static String _get_gdscript_reference_class_name(const GDScript *p_gdscript); protected: @@ -197,7 +196,7 @@ public: StringName debug_get_member_by_index(int p_idx) const; Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; @@ -247,17 +246,7 @@ public: virtual void get_constants(Map<StringName, Variant> *p_constants) override; virtual void get_members(Set<StringName> *p_members) override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const override; - virtual StringName get_rset_property(const uint16_t p_variable_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED virtual bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; } @@ -281,7 +270,7 @@ class GDScriptInstance : public ScriptInstance { Map<StringName, int> member_indices_cache; //used only for hot script reloading #endif Vector<Variant> members; - bool base_ref; + bool base_ref_counted; SelfList<GDScriptFunctionState>::List pending_func_states; @@ -310,17 +299,7 @@ public: void reload_members(); - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_variable) const; - virtual StringName get_rset_property(const uint16_t p_variable_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; GDScriptInstance(); ~GDScriptInstance(); @@ -468,7 +447,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index d8d60b35c6..e7fb33a6a7 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -31,10 +31,10 @@ #include "gdscript_analyzer.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/object/class_db.h" #include "core/object/script_language.h" -#include "core/os/file_access.h" #include "core/templates/hash_map.h" #include "gdscript.h" #include "gdscript_utility_functions.h" @@ -163,7 +163,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, if (!p_class->extends_used) { result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; result.kind = GDScriptParser::DataType::NATIVE; - result.native_type = "Reference"; + result.native_type = "RefCounted"; } else { result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; @@ -229,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, push_error(vformat(R"(Could not resolve super class inheritance from "%s".)", name), p_class); return err; } - } else if (class_exists(name) && ClassDB::can_instance(GDScriptParser::get_real_class_name(name))) { + } else if (class_exists(name) && ClassDB::can_instantiate(GDScriptParser::get_real_class_name(name))) { base.kind = GDScriptParser::DataType::NATIVE; base.native_type = name; } else { @@ -1779,10 +1779,10 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o } else { if (p_binary_op->variant_op < Variant::OP_MAX) { bool valid = false; - result = get_operation_type(p_binary_op->variant_op, p_binary_op->left_operand->get_datatype(), right_type, valid, p_binary_op); + result = get_operation_type(p_binary_op->variant_op, left_type, right_type, valid, p_binary_op); if (!valid) { - push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", p_binary_op->left_operand->get_datatype().to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", left_type.to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); } } else { if (p_binary_op->operation == GDScriptParser::BinaryOpNode::OP_TYPE_TEST) { @@ -2349,6 +2349,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod GDScriptParser::DataType result; result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; result.kind = GDScriptParser::DataType::ENUM_VALUE; + result.builtin_type = base.builtin_type; result.native_type = base.native_type; result.enum_type = name; p_identifier->set_datatype(result); @@ -2825,7 +2826,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::RECT2: case Variant::RECT2I: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::OBJECT: error = index_type.builtin_type != Variant::STRING; @@ -2836,8 +2837,8 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::VECTOR2I: case Variant::VECTOR3: case Variant::VECTOR3I: - case Variant::TRANSFORM: case Variant::TRANSFORM2D: + case Variant::TRANSFORM3D: error = index_type.builtin_type != Variant::INT && index_type.builtin_type != Variant::FLOAT && index_type.builtin_type != Variant::STRING; break; @@ -2904,7 +2905,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri case Variant::PACKED_FLOAT64_ARRAY: case Variant::VECTOR2: case Variant::VECTOR3: - case Variant::QUAT: + case Variant::QUATERNION: result_type.builtin_type = Variant::FLOAT; break; // Return Color. @@ -2933,7 +2934,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri result_type.builtin_type = Variant::VECTOR3; break; // Depends on the index. - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::PLANE: case Variant::COLOR: case Variant::DICTIONARY: @@ -3446,6 +3447,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator } r_valid = true; + result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED; result.kind = GDScriptParser::DataType::BUILTIN; result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type); diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index aabf407c76..8cd3fcf837 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -32,7 +32,7 @@ #define GDSCRIPT_ANALYZER_H #include "core/object/object.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/set.h" #include "gdscript_cache.h" #include "gdscript_parser.h" diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 77a972ef12..5a297cc50a 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -85,10 +85,10 @@ uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type case Variant::VECTOR3I: case Variant::TRANSFORM2D: case Variant::PLANE: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::AABB: case Variant::BASIS: - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::COLOR: case Variant::STRING_NAME: case Variant::NODE_PATH: @@ -458,8 +458,8 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia case Variant::PLANE: append(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE, 1); break; - case Variant::QUAT: - append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUAT, 1); + case Variant::QUATERNION: + append(GDScriptFunction::OPCODE_TYPE_ADJUST_QUATERNION, 1); break; case Variant::AABB: append(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB, 1); @@ -467,7 +467,7 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia case Variant::BASIS: append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1); break; case Variant::COLOR: @@ -554,6 +554,14 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) { + if (p_target.mode == Address::TEMPORARY) { + Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); + Variant::Type temp_type = temporaries[p_target.address].type; + if (result_type != temp_type) { + write_type_adjust(p_target, result_type); + } + } + // Gather specific operator. Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); @@ -1100,12 +1108,12 @@ void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, cons CASE_TYPE(PLANE); CASE_TYPE(AABB); CASE_TYPE(BASIS); - CASE_TYPE(TRANSFORM); + CASE_TYPE(TRANSFORM3D); CASE_TYPE(COLOR); CASE_TYPE(STRING_NAME); CASE_TYPE(NODE_PATH); CASE_TYPE(RID); - CASE_TYPE(QUAT); + CASE_TYPE(QUATERNION); CASE_TYPE(OBJECT); CASE_TYPE(CALLABLE); CASE_TYPE(SIGNAL); diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 601cdb4080..1a844bf241 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -30,7 +30,7 @@ #include "gdscript_cache.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/templates/vector.h" #include "gdscript.h" #include "gdscript_analyzer.h" @@ -134,7 +134,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP return ref; } GDScriptParser *parser = memnew(GDScriptParser); - ref.instance(); + ref.instantiate(); ref->parser = parser; ref->path = p_path; singleton->parser_map[p_path] = ref.ptr(); @@ -180,7 +180,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri } Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(p_path, true); script->set_script_path(p_path); script->load_source_code(p_path); diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h index d1d2a2abbf..943638d29f 100644 --- a/modules/gdscript/gdscript_cache.h +++ b/modules/gdscript/gdscript_cache.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_CACHE_H #define GDSCRIPT_CACHE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/templates/hash_map.h" #include "core/templates/set.h" @@ -40,7 +40,7 @@ class GDScriptAnalyzer; class GDScriptParser; -class GDScriptParserRef : public Reference { +class GDScriptParserRef : public RefCounted { public: enum Status { EMPTY, diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index c7ca9449c2..7fa8e9c067 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2282,9 +2282,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar } prop_info.hint = export_info.hint; prop_info.hint_string = export_info.hint_string; - prop_info.usage = export_info.usage; + prop_info.usage = export_info.usage | PROPERTY_USAGE_SCRIPT_VARIABLE; + } else { + prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE; } - prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; #ifdef TOOLS_ENABLED p_script->doc_variables[name] = variable->doc_description; #endif @@ -2511,7 +2512,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa p_script->placeholders.erase(psi); //remove placeholder GDScriptInstance *instance = memnew(GDScriptInstance); - instance->base_ref = Object::cast_to<Reference>(E->get()); + instance->base_ref_counted = Object::cast_to<RefCounted>(E->get()); instance->members.resize(p_script->member_indices.size()); instance->script = Ref<GDScript>(p_script); instance->owner = E->get(); @@ -2586,7 +2587,7 @@ void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::C if (orphan_subclass.is_valid()) { subclass = orphan_subclass; } else { - subclass.instance(); + subclass.instantiate(); } } diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index eee713aa45..1acb9ceddc 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -620,12 +620,12 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { DISASSEMBLE_PTRCALL(PLANE); DISASSEMBLE_PTRCALL(AABB); DISASSEMBLE_PTRCALL(BASIS); - DISASSEMBLE_PTRCALL(TRANSFORM); + DISASSEMBLE_PTRCALL(TRANSFORM3D); DISASSEMBLE_PTRCALL(COLOR); DISASSEMBLE_PTRCALL(STRING_NAME); DISASSEMBLE_PTRCALL(NODE_PATH); DISASSEMBLE_PTRCALL(RID); - DISASSEMBLE_PTRCALL(QUAT); + DISASSEMBLE_PTRCALL(QUATERNION); DISASSEMBLE_PTRCALL(OBJECT); DISASSEMBLE_PTRCALL(CALLABLE); DISASSEMBLE_PTRCALL(SIGNAL); @@ -957,7 +957,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { DISASSEMBLE_TYPE_ADJUST(VECTOR3I); DISASSEMBLE_TYPE_ADJUST(TRANSFORM2D); DISASSEMBLE_TYPE_ADJUST(PLANE); - DISASSEMBLE_TYPE_ADJUST(QUAT); + DISASSEMBLE_TYPE_ADJUST(QUATERNION); DISASSEMBLE_TYPE_ADJUST(AABB); DISASSEMBLE_TYPE_ADJUST(BASIS); DISASSEMBLE_TYPE_ADJUST(TRANSFORM); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 504c7414f6..c1a7bedbc8 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -32,7 +32,7 @@ #include "core/config/engine.h" #include "core/core_constants.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "gdscript_analyzer.h" #include "gdscript_compiler.h" #include "gdscript_parser.h" @@ -104,7 +104,7 @@ Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const Str _template = _get_processed_template(_template, p_base_class_name); Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_source_code(_template); return script; @@ -131,7 +131,7 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl } } -bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { GDScriptParser parser; GDScriptAnalyzer analyzer(&parser); @@ -156,10 +156,16 @@ bool GDScriptLanguage::validate(const String &p_script, int &r_line_error, int & } #endif if (err) { - GDScriptParser::ParserError parse_error = parser.get_errors().front()->get(); - r_line_error = parse_error.line; - r_col_error = parse_error.column; - r_test_error = parse_error.message; + if (r_errors) { + for (const List<GDScriptParser::ParserError>::Element *E = parser.get_errors().front(); E; E = E->next()) { + const GDScriptParser::ParserError &pe = E->get(); + ScriptLanguage::ScriptError e; + e.line = pe.line; + e.column = pe.column; + e.message = pe.message; + r_errors->push_back(e); + } + } return false; } else { const GDScriptParser::ClassNode *cl = parser.get_tree(); @@ -1029,7 +1035,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool } static const char *_type_names[Variant::VARIANT_MAX] = { - "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", + "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D", "Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray", "PackedVector2Array", "PackedVector3Array", "PackedColorArray" }; @@ -2378,7 +2384,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c r_forced = r_result.size() > 0; } -Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { +::Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { const String quote_style = EDITOR_DEF("text_editor/completion/use_single_quotes", false) ? "'" : "\""; GDScriptParser parser; @@ -2894,7 +2900,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co Variant v; REF v_ref; if (base_type.builtin_type == Variant::OBJECT) { - v_ref.instance(); + v_ref.instantiate(); v = v_ref; } else { Callable::CallError err; @@ -2929,7 +2935,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return ERR_CANT_RESOLVE; } -Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { +::Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) { //before parsing, try the usual stuff if (ClassDB::class_exists(p_symbol)) { r_result.type = ScriptLanguage::LookupResult::RESULT_CLASS; @@ -3032,9 +3038,9 @@ Error GDScriptLanguage::lookup_code(const String &p_code, const String &p_symbol if (!is_function) { // Guess in autoloads as singletons. if (ProjectSettings::get_singleton()->has_autoload(p_symbol)) { - const ProjectSettings::AutoloadInfo &singleton = ProjectSettings::get_singleton()->get_autoload(p_symbol); - if (singleton.is_singleton) { - String script = singleton.path; + const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(p_symbol); + if (autoload.is_singleton) { + String script = autoload.path; if (!script.ends_with(".gd")) { // Not a script, try find the script anyway, // may have some success. diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 26b8809337..553c2ecc01 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_FUNCTION_H #define GDSCRIPT_FUNCTION_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" #include "core/os/thread.h" #include "core/string/string_name.h" @@ -278,10 +278,10 @@ public: OPCODE_CALL_PTRCALL_VECTOR3I, OPCODE_CALL_PTRCALL_TRANSFORM2D, OPCODE_CALL_PTRCALL_PLANE, - OPCODE_CALL_PTRCALL_QUAT, + OPCODE_CALL_PTRCALL_QUATERNION, OPCODE_CALL_PTRCALL_AABB, OPCODE_CALL_PTRCALL_BASIS, - OPCODE_CALL_PTRCALL_TRANSFORM, + OPCODE_CALL_PTRCALL_TRANSFORM3D, OPCODE_CALL_PTRCALL_COLOR, OPCODE_CALL_PTRCALL_STRING_NAME, OPCODE_CALL_PTRCALL_NODE_PATH, @@ -365,7 +365,7 @@ public: OPCODE_TYPE_ADJUST_VECTOR3I, OPCODE_TYPE_ADJUST_TRANSFORM2D, OPCODE_TYPE_ADJUST_PLANE, - OPCODE_TYPE_ADJUST_QUAT, + OPCODE_TYPE_ADJUST_QUATERNION, OPCODE_TYPE_ADJUST_AABB, OPCODE_TYPE_ADJUST_BASIS, OPCODE_TYPE_ADJUST_TRANSFORM, @@ -597,8 +597,8 @@ public: ~GDScriptFunction(); }; -class GDScriptFunctionState : public Reference { - GDCLASS(GDScriptFunctionState, Reference); +class GDScriptFunctionState : public RefCounted { + GDCLASS(GDScriptFunctionState, RefCounted); friend class GDScriptFunction; GDScriptFunction *function = nullptr; GDScriptFunction::CallState state; diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h index 357c845250..336778d549 100644 --- a/modules/gdscript/gdscript_lambda_callable.h +++ b/modules/gdscript/gdscript_lambda_callable.h @@ -31,7 +31,7 @@ #ifndef GDSCRIPT_LAMBDA_CALLABLE #define GDSCRIPT_LAMBDA_CALLABLE -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/vector.h" #include "core/variant/callable.h" #include "core/variant/variant.h" diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index b61b469fbc..1a22820c63 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -31,9 +31,9 @@ #include "gdscript_parser.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/math/math_defs.h" -#include "core/os/file_access.h" #include "gdscript.h" #ifdef DEBUG_ENABLED @@ -61,9 +61,9 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) { builtin_types["Vector3i"] = Variant::VECTOR3I; builtin_types["AABB"] = Variant::AABB; builtin_types["Plane"] = Variant::PLANE; - builtin_types["Quat"] = Variant::QUAT; + builtin_types["Quaternion"] = Variant::QUATERNION; builtin_types["Basis"] = Variant::BASIS; - builtin_types["Transform"] = Variant::TRANSFORM; + builtin_types["Transform3D"] = Variant::TRANSFORM3D; builtin_types["Color"] = Variant::COLOR; builtin_types["RID"] = Variant::RID; builtin_types["Object"] = Variant::OBJECT; @@ -157,7 +157,6 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, 3); - register_annotation(MethodInfo("@export_exp_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_RANGE, Variant::FLOAT>, 3); register_annotation(MethodInfo("@export_exp_easing", { Variant::STRING, "hint1" }, { Variant::STRING, "hint2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, 2); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); register_annotation(MethodInfo("@export_node_path", { Variant::STRING, "type" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, 1, true); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index ee5e411cad..9e0b60a407 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -33,7 +33,7 @@ #include "core/io/multiplayer_api.h" #include "core/io/resource.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/object/script_language.h" #include "core/string/string_name.h" #include "core/string/ustring.h" diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 56b0f6db83..8a261a88e3 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -166,10 +166,10 @@ void (*type_init_function_table[])(Variant *) = { &VariantInitializer<Vector3i>::init, // VECTOR3I. &VariantInitializer<Transform2D>::init, // TRANSFORM2D. &VariantInitializer<Plane>::init, // PLANE. - &VariantInitializer<Quat>::init, // QUAT. + &VariantInitializer<Quaternion>::init, // QUATERNION. &VariantInitializer<AABB>::init, // AABB. &VariantInitializer<Basis>::init, // BASIS. - &VariantInitializer<Transform>::init, // TRANSFORM. + &VariantInitializer<Transform3D>::init, // TRANSFORM3D. &VariantInitializer<Color>::init, // COLOR. &VariantInitializer<StringName>::init, // STRING_NAME. &VariantInitializer<NodePath>::init, // NODE_PATH. @@ -248,10 +248,10 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_CALL_PTRCALL_VECTOR3I, \ &&OPCODE_CALL_PTRCALL_TRANSFORM2D, \ &&OPCODE_CALL_PTRCALL_PLANE, \ - &&OPCODE_CALL_PTRCALL_QUAT, \ + &&OPCODE_CALL_PTRCALL_QUATERNION, \ &&OPCODE_CALL_PTRCALL_AABB, \ &&OPCODE_CALL_PTRCALL_BASIS, \ - &&OPCODE_CALL_PTRCALL_TRANSFORM, \ + &&OPCODE_CALL_PTRCALL_TRANSFORM3D, \ &&OPCODE_CALL_PTRCALL_COLOR, \ &&OPCODE_CALL_PTRCALL_STRING_NAME, \ &&OPCODE_CALL_PTRCALL_NODE_PATH, \ @@ -335,7 +335,7 @@ void (*type_init_function_table[])(Variant *) = { &&OPCODE_TYPE_ADJUST_VECTOR3I, \ &&OPCODE_TYPE_ADJUST_TRANSFORM2D, \ &&OPCODE_TYPE_ADJUST_PLANE, \ - &&OPCODE_TYPE_ADJUST_QUAT, \ + &&OPCODE_TYPE_ADJUST_QUATERNION, \ &&OPCODE_TYPE_ADJUST_AABB, \ &&OPCODE_TYPE_ADJUST_BASIS, \ &&OPCODE_TYPE_ADJUST_TRANSFORM, \ @@ -398,7 +398,7 @@ void (*type_init_function_table[])(Variant *) = { #define OP_GET_VECTOR3I get_vector3i #define OP_GET_RECT2 get_rect2 #define OP_GET_RECT2I get_rect2i -#define OP_GET_QUAT get_quat +#define OP_GET_QUATERNION get_quaternion #define OP_GET_COLOR get_color #define OP_GET_STRING get_string #define OP_GET_STRING_NAME get_string_name @@ -416,7 +416,7 @@ void (*type_init_function_table[])(Variant *) = { #define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array #define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array #define OP_GET_PACKED_COLOR_ARRAY get_color_array -#define OP_GET_TRANSFORM get_transform +#define OP_GET_TRANSFORM3D get_transform #define OP_GET_TRANSFORM2D get_transform2d #define OP_GET_PLANE get_plane #define OP_GET_AABB get_aabb @@ -1733,10 +1733,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_CALL_PTR(VECTOR3I); OPCODE_CALL_PTR(TRANSFORM2D); OPCODE_CALL_PTR(PLANE); - OPCODE_CALL_PTR(QUAT); + OPCODE_CALL_PTR(QUATERNION); OPCODE_CALL_PTR(AABB); OPCODE_CALL_PTR(BASIS); - OPCODE_CALL_PTR(TRANSFORM); + OPCODE_CALL_PTR(TRANSFORM3D); OPCODE_CALL_PTR(COLOR); OPCODE_CALL_PTR(STRING_NAME); OPCODE_CALL_PTR(NODE_PATH); @@ -1989,7 +1989,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a ip += instr_arg_count; - int self_fun = _code_ptr[ip + 1]; + int argc = _code_ptr[ip + 1]; + GD_ERR_BREAK(argc < 0); + + int self_fun = _code_ptr[ip + 2]; #ifdef DEBUG_ENABLED if (self_fun < 0 || self_fun >= _global_names_count) { err_text = "compiler bug, function name not found"; @@ -1998,9 +2001,6 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #endif const StringName *methodname = &_global_names_ptr[self_fun]; - int argc = _code_ptr[ip + 2]; - GD_ERR_BREAK(argc < 0); - Variant **argptrs = instruction_args; GET_INSTRUCTION_ARG(dst, argc); @@ -3150,10 +3150,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_TYPE_ADJUST(VECTOR3I, Vector3i); OPCODE_TYPE_ADJUST(TRANSFORM2D, Transform2D); OPCODE_TYPE_ADJUST(PLANE, Plane); - OPCODE_TYPE_ADJUST(QUAT, Quat); + OPCODE_TYPE_ADJUST(QUATERNION, Quaternion); OPCODE_TYPE_ADJUST(AABB, AABB); OPCODE_TYPE_ADJUST(BASIS, Basis); - OPCODE_TYPE_ADJUST(TRANSFORM, Transform); + OPCODE_TYPE_ADJUST(TRANSFORM, Transform3D); OPCODE_TYPE_ADJUST(COLOR, Color); OPCODE_TYPE_ADJUST(STRING_NAME, StringName); OPCODE_TYPE_ADJUST(NODE_PATH, NodePath); diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 15236d900d..f817964a3c 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -32,7 +32,6 @@ #include "../gdscript.h" #include "../gdscript_analyzer.h" -#include "core/io/json.h" #include "gdscript_language_protocol.h" #include "gdscript_workspace.h" @@ -183,7 +182,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p symbol.detail += ": " + m.get_datatype().to_string(); } if (m.variable->initializer != nullptr && m.variable->initializer->is_constant) { - symbol.detail += " = " + JSON::print(m.variable->initializer->reduced_value); + symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string(); } symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line)); @@ -224,10 +223,10 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p } } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } } else { - value_text = JSON::print(default_value); + value_text = default_value.to_json_string(); } if (!value_text.is_empty()) { symbol.detail += " = " + value_text; @@ -353,8 +352,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN parameters += ": " + parameter->get_datatype().to_string(); } if (parameter->default_value != nullptr) { - String value = JSON::print(parameter->default_value->reduced_value); - parameters += " = " + value; + parameters += " = " + parameter->default_value->reduced_value.to_json_string(); } } r_symbol.detail += parameters + ")"; diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp index c16a7fa889..0d1f98778e 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.cpp +++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp @@ -31,7 +31,6 @@ #include "gdscript_language_protocol.h" #include "core/config/project_settings.h" -#include "core/io/json.h" #include "editor/doc_tools.h" #include "editor/editor_log.h" #include "editor/editor_node.h" @@ -194,7 +193,7 @@ Dictionary GDScriptLanguageProtocol::initialize(const Dictionary &p_params) { vformat("GDScriptLanguageProtocol: Can't initialize invalid peer '%d'.", latest_client_id)); Ref<LSPeer> peer = clients.get(latest_client_id); if (peer != nullptr) { - String msg = JSON::print(request); + String msg = Variant(request).to_json_string(); msg = format_output(msg); (*peer)->res_queue.push_back(msg.utf8()); } @@ -280,7 +279,7 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia ERR_FAIL_COND(peer == nullptr); Dictionary message = make_notification(p_method, p_params); - String msg = JSON::print(message); + String msg = Variant(message).to_json_string(); msg = format_output(msg); peer->res_queue.push_back(msg.utf8()); } @@ -294,10 +293,10 @@ bool GDScriptLanguageProtocol::is_goto_native_symbols_enabled() const { } GDScriptLanguageProtocol::GDScriptLanguageProtocol() { - server.instance(); + server.instantiate(); singleton = this; - workspace.instance(); - text_document.instance(); + workspace.instantiate(); + text_document.instantiate(); set_scope("textDocument", text_document.ptr()); set_scope("completionItem", text_document.ptr()); set_scope("workspace", workspace.ptr()); diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h index a5c5a233b1..969c38eab6 100644 --- a/modules/gdscript/language_server/gdscript_language_protocol.h +++ b/modules/gdscript/language_server/gdscript_language_protocol.h @@ -46,7 +46,7 @@ class GDScriptLanguageProtocol : public JSONRPC { GDCLASS(GDScriptLanguageProtocol, JSONRPC) private: - struct LSPeer : Reference { + struct LSPeer : RefCounted { Ref<StreamPeerTCP> connection; uint8_t req_buf[LSP_MAX_BUFFER_SIZE]; diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp index 340a7b9343..33597c286f 100644 --- a/modules/gdscript/language_server/gdscript_language_server.cpp +++ b/modules/gdscript/language_server/gdscript_language_server.cpp @@ -30,7 +30,7 @@ #include "gdscript_language_server.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "editor/editor_log.h" #include "editor/editor_node.h" diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp index 030633274c..59d2e6c8fa 100644 --- a/modules/gdscript/language_server/gdscript_text_document.cpp +++ b/modules/gdscript/language_server/gdscript_text_document.cpp @@ -40,6 +40,7 @@ void GDScriptTextDocument::_bind_methods() { ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen); + ClassDB::bind_method(D_METHOD("didClose"), &GDScriptTextDocument::didClose); ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange); ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol); ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol); @@ -61,6 +62,11 @@ void GDScriptTextDocument::didOpen(const Variant &p_param) { sync_script_content(doc.uri, doc.text); } +void GDScriptTextDocument::didClose(const Variant &p_param) { + // Left empty on purpose. Godot does nothing special on closing a document, + // but it satisfies LSP clients that require didClose be implemented. +} + void GDScriptTextDocument::didChange(const Variant &p_param) { lsp::TextDocumentItem doc = load_document_item(p_param); Dictionary dict = p_param; diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h index 792e601bc1..e2987f779c 100644 --- a/modules/gdscript/language_server/gdscript_text_document.h +++ b/modules/gdscript/language_server/gdscript_text_document.h @@ -31,18 +31,19 @@ #ifndef GDSCRIPT_TEXT_DOCUMENT_H #define GDSCRIPT_TEXT_DOCUMENT_H -#include "core/object/reference.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" +#include "core/object/ref_counted.h" #include "lsp.hpp" -class GDScriptTextDocument : public Reference { - GDCLASS(GDScriptTextDocument, Reference) +class GDScriptTextDocument : public RefCounted { + GDCLASS(GDScriptTextDocument, RefCounted) protected: static void _bind_methods(); FileAccess *file_checker; void didOpen(const Variant &p_param); + void didClose(const Variant &p_param); void didChange(const Variant &p_param); void sync_script_content(const String &p_path, const String &p_content); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 9b7b2b36b4..1915c92cbf 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -188,7 +188,9 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) { E->get()->get_symbols().symbol_tree_as_list(E->key(), script_symbols); for (int i = 0; i < script_symbols.size(); ++i) { if (query.is_subsequence_ofi(script_symbols[i].name)) { - arr.push_back(script_symbols[i].to_json()); + lsp::DocumentedSymbolInformation symbol = script_symbols[i]; + symbol.location.uri = get_file_uri(symbol.location.uri); + arr.push_back(symbol.to_json()); } } } @@ -424,7 +426,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) { RES owner_res = ResourceLoader::load(owner_path); if (Object::cast_to<PackedScene>(owner_res.ptr())) { Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res)); - owner_scene_node = owner_packed_scene->instance(); + owner_scene_node = owner_packed_scene->instantiate(); break; } } diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h index 27616a2989..8b166a873c 100644 --- a/modules/gdscript/language_server/gdscript_workspace.h +++ b/modules/gdscript/language_server/gdscript_workspace.h @@ -37,8 +37,8 @@ #include "gdscript_extend_parser.h" #include "lsp.hpp" -class GDScriptWorkspace : public Reference { - GDCLASS(GDScriptWorkspace, Reference); +class GDScriptWorkspace : public RefCounted { + GDCLASS(GDScriptWorkspace, RefCounted); private: void _get_owners(EditorFileSystemDirectory *efsd, String p_path, List<String> &owners); diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp index 47bcfeaefc..a7dcfdb22d 100644 --- a/modules/gdscript/language_server/lsp.hpp +++ b/modules/gdscript/language_server/lsp.hpp @@ -766,7 +766,7 @@ struct MarkupContent { // Use namespace instead of enumeration to follow the LSP specifications // lsp::EnumName::EnumValue is OK but lsp::EnumValue is not -// And here C++ compilers are unhappy with our enumeration name like Color, File, Reference etc. +// And here C++ compilers are unhappy with our enumeration name like Color, File, RefCounted etc. /** * The kind of a completion entry. */ @@ -788,7 +788,7 @@ static const int Keyword = 14; static const int Snippet = 15; static const int Color = 16; static const int File = 17; -static const int Reference = 18; +static const int RefCounted = 18; static const int Folder = 19; static const int EnumMember = 20; static const int Constant = 21; diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp index 2d2f94f5e0..ad4ed8bf71 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -30,10 +30,10 @@ #include "register_types.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_encrypted.h" #include "core/io/resource_loader.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "gdscript.h" #include "gdscript_analyzer.h" #include "gdscript_cache.h" @@ -92,12 +92,12 @@ public: static void _editor_init() { Ref<EditorExportGDScript> gd_export; - gd_export.instance(); + gd_export.instantiate(); EditorExport::get_singleton()->add_export_plugin(gd_export); #ifdef TOOLS_ENABLED Ref<GDScriptSyntaxHighlighter> gdscript_syntax_highlighter; - gdscript_syntax_highlighter.instance(); + gdscript_syntax_highlighter.instantiate(); ScriptEditor::get_singleton()->register_syntax_highlighter(gdscript_syntax_highlighter); #endif @@ -117,10 +117,10 @@ void register_gdscript_types() { script_language_gd = memnew(GDScriptLanguage); ScriptServer::register_language(script_language_gd); - resource_loader_gd.instance(); + resource_loader_gd.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_gd); - resource_saver_gd.instance(); + resource_saver_gd.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_gd); gdscript_cache = memnew(GDScriptCache); @@ -128,7 +128,7 @@ void register_gdscript_types() { #ifdef TOOLS_ENABLED EditorNode::add_init_callback(_editor_init); - gdscript_translation_parser_plugin.instance(); + gdscript_translation_parser_plugin.instantiate(); EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD); #endif // TOOLS_ENABLED diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index e20e427597..b7faebb4ef 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -37,8 +37,8 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" +#include "core/io/dir_access.h" #include "core/io/file_access_pack.h" -#include "core/os/dir_access.h" #include "core/os/os.h" #include "core/string/string_builder.h" #include "scene/resources/packed_scene.h" @@ -75,14 +75,14 @@ void init_autoloads() { Node *n = nullptr; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; - n = ps->instance(); + n = ps->instantiate(); } else if (res->is_class("Script")) { Ref<Script> script_res = res; StringName ibt = script_res->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path); - Object *obj = ClassDB::instance(ibt); + Object *obj = ClassDB::instantiate(ibt); ERR_CONTINUE_MSG(obj == nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + @@ -420,7 +420,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { // Create script. Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(source_file); script->set_script_path(source_file); err = script->load_source_code(source_file); @@ -510,10 +510,10 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) { script->reload(); // Create object instance for test. - Object *obj = ClassDB::instance(script->get_native()->get_name()); - Ref<Reference> obj_ref; - if (obj->is_reference()) { - obj_ref = Ref<Reference>(Object::cast_to<Reference>(obj)); + Object *obj = ClassDB::instantiate(script->get_native()->get_name()); + Ref<RefCounted> obj_ref; + if (obj->is_ref_counted()) { + obj_ref = Ref<RefCounted>(Object::cast_to<RefCounted>(obj)); } obj->set_script(script); GDScriptInstance *instance = static_cast<GDScriptInstance *>(obj->get_script_instance()); diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h index 8fd77239cd..cf4e61f07d 100644 --- a/modules/gdscript/tests/gdscript_test_runner_suite.h +++ b/modules/gdscript/tests/gdscript_test_runner_suite.h @@ -51,7 +51,7 @@ TEST_SUITE("[Modules][GDScript]") { TEST_CASE("[Modules][GDScript] Load source code dynamically and run it") { Ref<GDScript> gdscript = memnew(GDScript); gdscript->set_source_code(R"( -extends Reference +extends RefCounted func _init(): set_meta("result", 42) @@ -64,9 +64,9 @@ func _init(): CHECK_MESSAGE(error == OK, "The script should parse successfully."); // Run the script by assigning it to a reference-counted object. - Ref<Reference> reference = memnew(Reference); - reference->set_script(gdscript); - CHECK_MESSAGE(int(reference->get_meta("result")) == 42, "The script should assign object metadata successfully."); + Ref<RefCounted> ref_counted = memnew(RefCounted); + ref_counted->set_script(gdscript); + CHECK_MESSAGE(int(ref_counted->get_meta("result")) == 42, "The script should assign object metadata successfully."); } } // namespace GDScriptTests diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index fc73b5bb72..7aa5895981 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -31,8 +31,8 @@ #include "test_gdscript.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "core/os/file_access.h" #include "core/os/main_loop.h" #include "core/os/os.h" #include "core/string/string_builder.h" @@ -165,7 +165,7 @@ static void test_compiler(const String &p_code, const String &p_script_path, con GDScriptCompiler compiler; Ref<GDScript> script; - script.instance(); + script.instantiate(); script->set_path(p_script_path); err = compiler.compile(&parser, script.ptr(), false); diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp index 8979eabfc3..730c6b89f7 100644 --- a/modules/glslang/register_types.cpp +++ b/modules/glslang/register_types.cpp @@ -116,6 +116,10 @@ static Vector<uint8_t> _compile_shader_glsl(RenderingDevice::ShaderStage p_stage } } + if (p_capabilities->supports_multiview) { + preamble += "#define has_VK_KHR_multiview 1\n"; + } + if (preamble != "") { shader.setPreamble(preamble.c_str()); } diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml index a1f596f7dd..41a318ce19 100644 --- a/modules/gltf/doc_classes/GLTFAccessor.xml +++ b/modules/gltf/doc_classes/GLTFAccessor.xml @@ -17,9 +17,9 @@ </member> <member name="count" type="int" setter="set_count" getter="get_count" default="0"> </member> - <member name="max" type="PackedFloat64Array" setter="set_max" getter="get_max" default="PackedFloat64Array( )"> + <member name="max" type="PackedFloat64Array" setter="set_max" getter="get_max" default="PackedFloat64Array()"> </member> - <member name="min" type="PackedFloat64Array" setter="set_min" getter="get_min" default="PackedFloat64Array( )"> + <member name="min" type="PackedFloat64Array" setter="set_min" getter="get_min" default="PackedFloat64Array()"> </member> <member name="normalized" type="bool" setter="set_normalized" getter="get_normalized" default="false"> </member> diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml index bfeaf9a86e..f51d287685 100644 --- a/modules/gltf/doc_classes/GLTFLight.xml +++ b/modules/gltf/doc_classes/GLTFLight.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="color" type="Color" setter="set_color" getter="get_color" default="Color( 0, 0, 0, 1 )"> + <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)"> </member> <member name="inner_cone_angle" type="float" setter="set_inner_cone_angle" getter="get_inner_cone_angle" default="0.0"> </member> diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml index 55f79d2c55..fd7e4a169e 100644 --- a/modules/gltf/doc_classes/GLTFMesh.xml +++ b/modules/gltf/doc_classes/GLTFMesh.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array( )"> + <member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()"> </member> <member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh"> </member> diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml index af7be55e4b..bfbb12df4d 100644 --- a/modules/gltf/doc_classes/GLTFNode.xml +++ b/modules/gltf/doc_classes/GLTFNode.xml @@ -11,7 +11,7 @@ <members> <member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1"> </member> - <member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array( )"> + <member name="children" type="PackedInt32Array" setter="set_children" getter="get_children" default="PackedInt32Array()"> </member> <member name="height" type="int" setter="set_height" getter="get_height" default="-1"> </member> @@ -23,17 +23,17 @@ </member> <member name="parent" type="int" setter="set_parent" getter="get_parent" default="-1"> </member> - <member name="rotation" type="Quat" setter="set_rotation" getter="get_rotation" default="Quat( 0, 0, 0, 1 )"> + <member name="rotation" type="Quaternion" setter="set_rotation" getter="get_rotation" default="Quaternion(0, 0, 0, 1)"> </member> - <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3( 1, 1, 1 )"> + <member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)"> </member> <member name="skeleton" type="int" setter="set_skeleton" getter="get_skeleton" default="-1"> </member> <member name="skin" type="int" setter="set_skin" getter="get_skin" default="-1"> </member> - <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3( 0, 0, 0 )"> + <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3(0, 0, 0)"> </member> - <member name="xform" type="Transform" setter="set_xform" getter="get_xform" default="Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )"> + <member name="xform" type="Transform3D" setter="set_xform" getter="get_xform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)"> </member> </members> <constants> diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml index 9680c27705..40563c9ac6 100644 --- a/modules/gltf/doc_classes/GLTFSkeleton.xml +++ b/modules/gltf/doc_classes/GLTFSkeleton.xml @@ -57,9 +57,9 @@ </method> </methods> <members> - <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array( )"> + <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array()"> </member> - <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array( )"> + <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array()"> </member> </members> <constants> diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml index 5a80c7097a..e20e127e52 100644 --- a/modules/gltf/doc_classes/GLTFSkin.xml +++ b/modules/gltf/doc_classes/GLTFSkin.xml @@ -53,13 +53,13 @@ <members> <member name="godot_skin" type="Skin" setter="set_godot_skin" getter="get_godot_skin"> </member> - <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array( )"> + <member name="joints" type="PackedInt32Array" setter="set_joints" getter="get_joints" default="PackedInt32Array()"> </member> - <member name="joints_original" type="PackedInt32Array" setter="set_joints_original" getter="get_joints_original" default="PackedInt32Array( )"> + <member name="joints_original" type="PackedInt32Array" setter="set_joints_original" getter="get_joints_original" default="PackedInt32Array()"> </member> - <member name="non_joints" type="PackedInt32Array" setter="set_non_joints" getter="get_non_joints" default="PackedInt32Array( )"> + <member name="non_joints" type="PackedInt32Array" setter="set_non_joints" getter="get_non_joints" default="PackedInt32Array()"> </member> - <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array( )"> + <member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array()"> </member> <member name="skeleton" type="int" setter="set_skeleton" getter="get_skeleton" default="-1"> </member> diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml index 68cc7c845d..6e9c419649 100644 --- a/modules/gltf/doc_classes/GLTFSpecGloss.xml +++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color( 1, 1, 1, 1 )"> + <member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color(1, 1, 1, 1)"> </member> <member name="diffuse_img" type="Image" setter="set_diffuse_img" getter="get_diffuse_img"> </member> @@ -17,7 +17,7 @@ </member> <member name="spec_gloss_img" type="Image" setter="set_spec_gloss_img" getter="get_spec_gloss_img"> </member> - <member name="specular_factor" type="Color" setter="set_specular_factor" getter="get_specular_factor" default="Color( 1, 1, 1, 1 )"> + <member name="specular_factor" type="Color" setter="set_specular_factor" getter="get_specular_factor" default="Color(1, 1, 1, 1)"> </member> </members> <constants> diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml index 8255cd73d0..a7b5b7b43e 100644 --- a/modules/gltf/doc_classes/GLTFState.xml +++ b/modules/gltf/doc_classes/GLTFState.xml @@ -243,9 +243,9 @@ </method> </methods> <members> - <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[ ]"> + <member name="buffers" type="Array" setter="set_buffers" getter="get_buffers" default="[]"> </member> - <member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray( )"> + <member name="glb_data" type="PackedByteArray" setter="set_glb_data" getter="get_glb_data" default="PackedByteArray()"> </member> <member name="json" type="Dictionary" setter="set_json" getter="get_json" default="{}"> </member> @@ -253,7 +253,7 @@ </member> <member name="minor_version" type="int" setter="set_minor_version" getter="get_minor_version" default="0"> </member> - <member name="root_nodes" type="Array" setter="set_root_nodes" getter="get_root_nodes" default="[ ]"> + <member name="root_nodes" type="Array" setter="set_root_nodes" getter="get_root_nodes" default="[]"> </member> <member name="scene_name" type="String" setter="set_scene_name" getter="get_scene_name" default=""""> </member> diff --git a/modules/gltf/doc_classes/PackedSceneGLTF.xml b/modules/gltf/doc_classes/PackedSceneGLTF.xml index a04c6ef0b6..a22111e9b7 100644 --- a/modules/gltf/doc_classes/PackedSceneGLTF.xml +++ b/modules/gltf/doc_classes/PackedSceneGLTF.xml @@ -51,7 +51,7 @@ </method> </methods> <members> - <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" override="true" default="{"conn_count": 0,"conns": PackedInt32Array( ),"editable_instances": [ ],"names": PackedStringArray( ),"node_count": 0,"node_paths": [ ],"nodes": PackedInt32Array( ),"variants": [ ],"version": 2}" /> + <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" override="true" default="{"conn_count": 0,"conns": PackedInt32Array(),"editable_instances": [],"names": PackedStringArray(),"node_count": 0,"node_paths": [],"nodes": PackedInt32Array(),"variants": [],"version": 2}" /> </members> <constants> </constants> diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp index 4cdaccde6f..ae080bcc9a 100644 --- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp +++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp @@ -49,7 +49,7 @@ bool SceneExporterGLTFPlugin::has_main_screen() const { SceneExporterGLTFPlugin::SceneExporterGLTFPlugin(EditorNode *p_node) { editor = p_node; - convert_gltf2.instance(); + convert_gltf2.instantiate(); file_export_lib = memnew(EditorFileDialog); editor->get_gui_base()->add_child(file_export_lib); file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action)); diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp index 35f44ca122..cef5278f03 100644 --- a/modules/gltf/editor_scene_importer_gltf.cpp +++ b/modules/gltf/editor_scene_importer_gltf.cpp @@ -29,10 +29,9 @@ /*************************************************************************/ #include "core/crypto/crypto_core.h" -#include "core/io/json.h" +#include "core/io/file_access.h" #include "core/math/disjoint_set.h" #include "core/math/math_defs.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "editor/import/resource_importer_scene.h" #include "modules/gltf/gltf_state.h" @@ -60,7 +59,7 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path, List<String> *r_missing_deps, Error *r_err) { Ref<PackedSceneGLTF> importer; - importer.instance(); + importer.instantiate(); return importer->import_scene(p_path, p_flags, p_bake_fps, r_missing_deps, r_err, Ref<GLTFState>()); } @@ -91,13 +90,13 @@ Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags, Error *r_err, Ref<GLTFState> r_state) { if (r_state == Ref<GLTFState>()) { - r_state.instance(); + r_state.instantiate(); } r_state->use_named_skin_binds = p_flags & EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS; Ref<GLTFDocument> gltf_document; - gltf_document.instance(); + gltf_document.instantiate(); Error err = gltf_document->parse(r_state, p_path); if (r_err) { *r_err = err; @@ -139,9 +138,9 @@ void PackedSceneGLTF::save_scene(Node *p_node, const String &p_path, *r_err = err; } Ref<GLTFDocument> gltf_document; - gltf_document.instance(); + gltf_document.instantiate(); Ref<GLTFState> state; - state.instance(); + state.instantiate(); err = gltf_document->serialize(state, p_node, p_path); if (r_err) { *r_err = err; @@ -172,7 +171,7 @@ Error PackedSceneGLTF::export_gltf(Node *p_root, String p_path, int32_t flags = p_flags; real_t baked_fps = p_bake_fps; Ref<PackedSceneGLTF> exporter; - exporter.instance(); + exporter.instantiate(); exporter->save_scene(p_root, path, "", flags, baked_fps, &deps, &err); int32_t error_code = err; if (error_code != 0) { diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h index af1a885f2b..566d5cfd34 100644 --- a/modules/gltf/editor_scene_importer_gltf.h +++ b/modules/gltf/editor_scene_importer_gltf.h @@ -32,7 +32,6 @@ #define EDITOR_SCENE_IMPORTER_GLTF_H #include "core/config/project_settings.h" -#include "core/io/json.h" #include "core/object/object.h" #include "core/templates/vector.h" #include "editor/import/resource_importer_scene.h" diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h index a494e6bd67..216d2161c4 100644 --- a/modules/gltf/gltf_animation.h +++ b/modules/gltf/gltf_animation.h @@ -56,7 +56,7 @@ public: struct Track { Channel<Vector3> translation_track; - Channel<Quat> rotation_track; + Channel<Quaternion> rotation_track; Channel<Vector3> scale_track; Vector<Channel<float>> weight_tracks; }; diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp index abac0a2e17..660c2ab305 100644 --- a/modules/gltf/gltf_document.cpp +++ b/modules/gltf/gltf_document.cpp @@ -49,9 +49,9 @@ #include "core/core_bind.h" #include "core/crypto/crypto_core.h" +#include "core/io/file_access.h" #include "core/io/json.h" #include "core/math/disjoint_set.h" -#include "core/os/file_access.h" #include "core/variant/typed_array.h" #include "core/version.h" #include "core/version_hash.gen.h" @@ -238,15 +238,13 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) { String text; text.parse_utf8((const char *)array.ptr(), array.size()); - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); + _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT); return err; } - state->json = v; + state->json = json.get_data(); return OK; } @@ -299,16 +297,14 @@ Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) { String text; text.parse_utf8((const char *)json_data.ptr(), json_data.size()); - String err_txt; - int err_line; - Variant v; - err = JSON::parse(text, v, err_txt, err_line); + JSON json; + err = json.parse(text); if (err != OK) { - _err_print_error("", p_path.utf8().get_data(), err_line, err_txt.utf8().get_data(), ERR_HANDLER_SCRIPT); + _err_print_error("", p_path.utf8().get_data(), json.get_error_line(), json.get_error_message().utf8().get_data(), ERR_HANDLER_SCRIPT); return err; } - state->json = v; + state->json = json.get_data(); //data? @@ -342,25 +338,25 @@ static Vector3 _arr_to_vec3(const Array &p_array) { return Vector3(p_array[0], p_array[1], p_array[2]); } -static Array _quat_to_array(const Quat &p_quat) { +static Array _quaternion_to_array(const Quaternion &p_quaternion) { Array array; array.resize(4); - array[0] = p_quat.x; - array[1] = p_quat.y; - array[2] = p_quat.z; - array[3] = p_quat.w; + array[0] = p_quaternion.x; + array[1] = p_quaternion.y; + array[2] = p_quaternion.z; + array[3] = p_quaternion.w; return array; } -static Quat _arr_to_quat(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 4, Quat()); - return Quat(p_array[0], p_array[1], p_array[2], p_array[3]); +static Quaternion _arr_to_quaternion(const Array &p_array) { + ERR_FAIL_COND_V(p_array.size() != 4, Quaternion()); + return Quaternion(p_array[0], p_array[1], p_array[2], p_array[3]); } -static Transform _arr_to_xform(const Array &p_array) { - ERR_FAIL_COND_V(p_array.size() != 16, Transform()); +static Transform3D _arr_to_xform(const Array &p_array) { + ERR_FAIL_COND_V(p_array.size() != 16, Transform3D()); - Transform xform; + Transform3D xform; xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2])); xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6])); xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10])); @@ -369,7 +365,7 @@ static Transform _arr_to_xform(const Array &p_array) { return xform; } -static Vector<real_t> _xform_to_array(const Transform p_transform) { +static Vector<real_t> _xform_to_array(const Transform3D p_transform) { Vector<real_t> array; array.resize(16); Vector3 axis_x = p_transform.get_basis().get_axis(Vector3::AXIS_X); @@ -421,12 +417,12 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) { } if (n->skeleton != -1 && n->skin < 0) { } - if (n->xform != Transform()) { + if (n->xform != Transform3D()) { node["matrix"] = _xform_to_array(n->xform); } - if (!n->rotation.is_equal_approx(Quat())) { - node["rotation"] = _quat_to_array(n->rotation); + if (!n->rotation.is_equal_approx(Quaternion())) { + node["rotation"] = _quaternion_to_array(n->rotation); } if (!n->scale.is_equal_approx(Vector3(1.0f, 1.0f, 1.0f))) { @@ -569,7 +565,7 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { const Array &nodes = state->json["nodes"]; for (int i = 0; i < nodes.size(); i++) { Ref<GLTFNode> node; - node.instance(); + node.instantiate(); const Dictionary &n = nodes[i]; if (n.has("name")) { @@ -591,13 +587,13 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) { node->translation = _arr_to_vec3(n["translation"]); } if (n.has("rotation")) { - node->rotation = _arr_to_quat(n["rotation"]); + node->rotation = _arr_to_quaternion(n["rotation"]); } if (n.has("scale")) { node->scale = _arr_to_vec3(n["scale"]); } - node->xform.basis.set_quat_scale(node->rotation, node->scale); + node->xform.basis.set_quaternion_scale(node->rotation, node->scale); node->xform.origin = node->translation; } @@ -830,7 +826,7 @@ Error GLTFDocument::_parse_buffer_views(Ref<GLTFState> state) { const Dictionary &d = buffers[i]; Ref<GLTFBufferView> buffer_view; - buffer_view.instance(); + buffer_view.instantiate(); ERR_FAIL_COND_V(!d.has("buffer"), ERR_PARSE_ERROR); buffer_view->buffer = d["buffer"]; @@ -976,7 +972,7 @@ Error GLTFDocument::_parse_accessors(Ref<GLTFState> state) { const Dictionary &d = accessors[i]; Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); ERR_FAIL_COND_V(!d.has("componentType"), ERR_PARSE_ERROR); accessor->component_type = d["componentType"]; @@ -1118,7 +1114,7 @@ Error GLTFDocument::_encode_buffer_view(Ref<GLTFState> state, const double *src, } Ref<GLTFBufferView> bv; - bv.instance(); + bv.instantiate(); const uint32_t offset = bv->byte_offset = byte_offset; Vector<uint8_t> &gltf_buffer = state->buffers.write[0]; @@ -1512,7 +1508,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_ints(Ref<GLTFState> state, c ERR_FAIL_COND_V(attribs.size() == 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; @@ -1596,7 +1592,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec2(Ref<GLTFState> state, c ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC2; @@ -1645,7 +1641,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_color(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1710,7 +1706,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_weights(Ref<GLTFState> state ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1757,7 +1753,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1779,7 +1775,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_joints(Ref<GLTFState> state, return state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, const Vector<Quat> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quaternions(Ref<GLTFState> state, const Vector<Quaternion> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1794,11 +1790,11 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, Vector<double> type_min; type_min.resize(element_count); for (int i = 0; i < p_attribs.size(); i++) { - Quat quat = p_attribs[i]; - attribs.write[(i * element_count) + 0] = Math::snapped(quat.x, CMP_NORMALIZE_TOLERANCE); - attribs.write[(i * element_count) + 1] = Math::snapped(quat.y, CMP_NORMALIZE_TOLERANCE); - attribs.write[(i * element_count) + 2] = Math::snapped(quat.z, CMP_NORMALIZE_TOLERANCE); - attribs.write[(i * element_count) + 3] = Math::snapped(quat.w, CMP_NORMALIZE_TOLERANCE); + Quaternion quaternion = p_attribs[i]; + attribs.write[(i * element_count) + 0] = Math::snapped(quaternion.x, CMP_NORMALIZE_TOLERANCE); + attribs.write[(i * element_count) + 1] = Math::snapped(quaternion.y, CMP_NORMALIZE_TOLERANCE); + attribs.write[(i * element_count) + 2] = Math::snapped(quaternion.z, CMP_NORMALIZE_TOLERANCE); + attribs.write[(i * element_count) + 3] = Math::snapped(quaternion.w, CMP_NORMALIZE_TOLERANCE); _calc_accessor_min_max(i, element_count, type_max, attribs, type_min); } @@ -1806,7 +1802,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_quats(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC4; @@ -1871,7 +1867,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_floats(Ref<GLTFState> state, ERR_FAIL_COND_V(!attribs.size(), -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR; @@ -1917,7 +1913,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_VEC3; @@ -1939,7 +1935,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_vec3(Ref<GLTFState> state, c return state->accessors.size() - 1; } -GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform> p_attribs, const bool p_for_vertex) { +GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, const Vector<Transform3D> p_attribs, const bool p_for_vertex) { if (p_attribs.size() == 0) { return -1; } @@ -1953,7 +1949,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, Vector<double> type_min; type_min.resize(element_count); for (int i = 0; i < p_attribs.size(); i++) { - Transform attrib = p_attribs[i]; + Transform3D attrib = p_attribs[i]; Basis basis = attrib.get_basis(); Vector3 axis_0 = basis.get_axis(Vector3::AXIS_X); @@ -1985,7 +1981,7 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state, ERR_FAIL_COND_V(attribs.size() % element_count != 0, -1); Ref<GLTFAccessor> accessor; - accessor.instance(); + accessor.instantiate(); GLTFBufferIndex buffer_view_i; int64_t size = state->buffers[0].size(); const GLTFDocument::GLTFType type = GLTFDocument::TYPE_MAT4; @@ -2053,9 +2049,9 @@ Vector<Color> GLTFDocument::_decode_accessor_as_color(Ref<GLTFState> state, cons } return ret; } -Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { +Vector<Quaternion> GLTFDocument::_decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Quat> ret; + Vector<Quaternion> ret; if (attribs.size() == 0) { return ret; @@ -2067,7 +2063,7 @@ Vector<Quat> GLTFDocument::_decode_accessor_as_quat(Ref<GLTFState> state, const ret.resize(ret_size); { for (int i = 0; i < ret_size; i++) { - ret.write[i] = Quat(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); + ret.write[i] = Quaternion(attribs_ptr[i * 4 + 0], attribs_ptr[i * 4 + 1], attribs_ptr[i * 4 + 2], attribs_ptr[i * 4 + 3]).normalized(); } } return ret; @@ -2107,9 +2103,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons return ret; } -Vector<Transform> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { +Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex) { const Vector<double> attribs = _decode_accessor(state, p_accessor, p_for_vertex); - Vector<Transform> ret; + Vector<Transform3D> ret; if (attribs.size() == 0) { return ret; @@ -2335,7 +2331,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) { //generate indices because they need to be swapped for CW/CCW const Vector<Vector3> &vertices = array[Mesh::ARRAY_VERTEX]; Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->create_from_triangle_arrays(array); st->index(); Vector<int32_t> generated_indices = st->commit_to_arrays()[Mesh::ARRAY_INDEX]; @@ -2459,7 +2455,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Dictionary d = meshes[i]; Ref<GLTFMesh> mesh; - mesh.instance(); + mesh.instantiate(); bool has_vertex_color = false; ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR); @@ -2467,7 +2463,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { Array primitives = d["primitives"]; const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary(); Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instance(); + import_mesh.instantiate(); String mesh_name = "mesh"; if (d.has("name") && !String(d["name"]).is_empty()) { mesh_name = d["name"]; @@ -2652,11 +2648,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (generate_tangents) { //must generate mikktspace tangents.. ergh.. Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); + st->create_from_triangle_arrays(array); if (a.has("JOINTS_0") && a.has("JOINTS_1")) { st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); } - st->create_from_triangle_arrays(array); st->generate_tangents(); array = st->commit_to_arrays(); } @@ -2771,11 +2767,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { if (generate_tangents) { Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); + st->create_from_triangle_arrays(array_copy); if (a.has("JOINTS_0") && a.has("JOINTS_1")) { st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS); } - st->create_from_triangle_arrays(array_copy); st->deindex(); st->generate_tangents(); array_copy = st->commit_to_arrays(); @@ -2799,7 +2795,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) { } else if (has_vertex_color) { Ref<StandardMaterial3D> mat3d; - mat3d.instance(); + mat3d.instantiate(); mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); mat = mat3d; } @@ -2847,7 +2843,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path GLTFBufferViewIndex bvi; Ref<GLTFBufferView> bv; - bv.instance(); + bv.instantiate(); const GLTFBufferIndex bi = 0; bv->buffer = bi; @@ -2879,7 +2875,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path name = _gen_unique_name(state, name); name = name.pad_zeros(3); Ref<_Directory> dir; - dir.instance(); + dir.instantiate(); String texture_dir = "textures"; String new_texture_dir = p_path.get_base_dir() + "/" + texture_dir; dir->open(p_path.get_base_dir()); @@ -3038,7 +3034,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat } Ref<ImageTexture> t; - t.instance(); + t.instantiate(); t->create_from_image(img); state->images.push_back(t); @@ -3079,7 +3075,7 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { ERR_FAIL_COND_V(!d.has("source"), ERR_PARSE_ERROR); Ref<GLTFTexture> t; - t.instance(); + t.instantiate(); t->set_src_image(d["source"]); state->textures.push_back(t); } @@ -3090,7 +3086,7 @@ Error GLTFDocument::_parse_textures(Ref<GLTFState> state) { GLTFTextureIndex GLTFDocument::_set_texture(Ref<GLTFState> state, Ref<Texture2D> p_texture) { ERR_FAIL_COND_V(p_texture.is_null(), -1); Ref<GLTFTexture> gltf_texture; - gltf_texture.instance(); + gltf_texture.instantiate(); ERR_FAIL_COND_V(p_texture->get_image().is_null(), -1); GLTFImageIndex gltf_src_image_i = state->images.size(); state->images.push_back(p_texture); @@ -3163,9 +3159,9 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { Ref<Texture2D> ao_texture = material->get_texture(BaseMaterial3D::TEXTURE_AMBIENT_OCCLUSION); BaseMaterial3D::TextureChannel ao_channel = material->get_ao_texture_channel(); Ref<ImageTexture> orm_texture; - orm_texture.instance(); + orm_texture.instantiate(); Ref<Image> orm_image; - orm_image.instance(); + orm_image.instantiate(); int32_t height = 0; int32_t width = 0; Ref<Image> ao_image; @@ -3285,7 +3281,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) { if (material->get_feature(BaseMaterial3D::FEATURE_NORMAL_MAPPING)) { Dictionary nt; Ref<ImageTexture> tex; - tex.instance(); + tex.instantiate(); { Ref<Texture2D> normal_texture = material->get_texture(BaseMaterial3D::TEXTURE_NORMAL); // Code for uncompressing RG normal maps @@ -3373,7 +3369,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { const Dictionary &d = materials[i]; Ref<StandardMaterial3D> material; - material.instance(); + material.instantiate(); if (d.has("name") && !String(d["name"]).is_empty()) { material->set_name(d["name"]); } else { @@ -3389,7 +3385,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) { Dictionary sgm = pbr_spec_gloss_extensions["KHR_materials_pbrSpecularGlossiness"]; Ref<GLTFSpecGloss> spec_gloss; - spec_gloss.instance(); + spec_gloss.instantiate(); if (sgm.has("diffuseTexture")) { const Dictionary &diffuse_texture_dict = sgm["diffuseTexture"]; if (diffuse_texture_dict.has("index")) { @@ -3572,7 +3568,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re return; } Ref<Image> rm_img; - rm_img.instance(); + rm_img.instantiate(); bool has_roughness = false; bool has_metal = false; p_material->set_roughness(1.0f); @@ -3600,7 +3596,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re if (!Math::is_equal_approx(mr.g, 1.0f)) { has_roughness = true; } - if (!Math::is_equal_approx(mr.b, 0.0f)) { + if (!Math::is_zero_approx(mr.b)) { has_metal = true; } mr.g *= r_spec_gloss->gloss_factor; @@ -3614,11 +3610,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re rm_img->generate_mipmaps(); r_spec_gloss->diffuse_img->generate_mipmaps(); Ref<ImageTexture> diffuse_image_texture; - diffuse_image_texture.instance(); + diffuse_image_texture.instantiate(); diffuse_image_texture->create_from_image(r_spec_gloss->diffuse_img); p_material->set_texture(BaseMaterial3D::TEXTURE_ALBEDO, diffuse_image_texture); Ref<ImageTexture> rm_image_texture; - rm_image_texture.instance(); + rm_image_texture.instantiate(); rm_image_texture->create_from_image(rm_img); if (has_roughness) { p_material->set_texture(BaseMaterial3D::TEXTURE_ROUGHNESS, rm_image_texture); @@ -3894,7 +3890,7 @@ Error GLTFDocument::_parse_skins(Ref<GLTFState> state) { const Dictionary &d = skins[i]; Ref<GLTFSkin> skin; - skin.instance(); + skin.instantiate(); ERR_FAIL_COND_V(!d.has("joints"), ERR_PARSE_ERROR); @@ -4022,7 +4018,7 @@ Error GLTFDocument::_determine_skeletons(Ref<GLTFState> state) { for (GLTFSkeletonIndex skel_i = 0; skel_i < skeleton_owners.size(); ++skel_i) { const GLTFNodeIndex skeleton_owner = skeleton_owners[skel_i]; Ref<GLTFSkeleton> skeleton; - skeleton.instance(); + skeleton.instantiate(); Vector<GLTFNodeIndex> skeleton_nodes; skeleton_sets.get_members(skeleton_nodes, skeleton_owner); @@ -4270,7 +4266,7 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) { Ref<GLTFSkin> gltf_skin = state->skins.write[skin_i]; Ref<Skin> skin; - skin.instance(); + skin.instantiate(); // Some skins don't have IBM's! What absolute monsters! const bool has_ibms = !gltf_skin->inverse_binds.is_empty(); @@ -4279,7 +4275,7 @@ Error GLTFDocument::_create_skins(Ref<GLTFState> state) { GLTFNodeIndex node = gltf_skin->joints_original[joint_i]; String bone_name = state->nodes[node]->get_name(); - Transform xform; + Transform3D xform; if (has_ibms) { xform = gltf_skin->inverse_binds[joint_i]; } @@ -4323,8 +4319,8 @@ bool GLTFDocument::_skins_are_same(const Ref<Skin> skin_a, const Ref<Skin> skin_ return false; } - Transform a_xform = skin_a->get_bind_pose(i); - Transform b_xform = skin_b->get_bind_pose(i); + Transform3D a_xform = skin_a->get_bind_pose(i); + Transform3D b_xform = skin_b->get_bind_pose(i); if (a_xform != b_xform) { return false; @@ -4452,7 +4448,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) { const Dictionary &d = lights[light_i]; Ref<GLTFLight> light; - light.instance(); + light.instantiate(); ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); const String &type = d["type"]; light->type = type; @@ -4497,7 +4493,7 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) { const Dictionary &d = cameras[i]; Ref<GLTFCamera> camera; - camera.instance(); + camera.instantiate(); ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR); const String &type = d["type"]; if (type == "orthographic") { @@ -4607,8 +4603,8 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) { s["interpolation"] = interpolation_to_string(track.rotation_track.interpolation); Vector<real_t> times = Variant(track.rotation_track.times); s["input"] = _encode_accessor_as_floats(state, times, false); - Vector<Quat> values = track.rotation_track.values; - s["output"] = _encode_accessor_as_quats(state, values, false); + Vector<Quaternion> values = track.rotation_track.values; + s["output"] = _encode_accessor_as_quaternions(state, values, false); samplers.push_back(s); @@ -4700,7 +4696,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { const Dictionary &d = animations[i]; Ref<GLTFAnimation> animation; - animation.instance(); + animation.instantiate(); if (!d.has("channels") || !d.has("samplers")) { continue; @@ -4777,7 +4773,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) { track->translation_track.times = Variant(times); //convert via variant track->translation_track.values = Variant(translations); //convert via variant } else if (path == "rotation") { - const Vector<Quat> rotations = _decode_accessor_as_quat(state, output, false); + const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(state, output, false); track->rotation_track.interpolation = interp; track->rotation_track.times = Variant(times); //convert via variant track->rotation_track.values = rotations; @@ -4868,7 +4864,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns return -1; } Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instance(); + import_mesh.instantiate(); Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh(); if (godot_mesh.is_null()) { return -1; @@ -4905,7 +4901,7 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshIns blend_weights.write[blend_i] = 0.0f; } Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); gltf_mesh->set_mesh(import_mesh); gltf_mesh->set_blend_weights(blend_weights); GLTFMeshIndex mesh_i = state->meshes.size(); @@ -5010,7 +5006,7 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_ print_verbose("glTF: Converting camera: " + p_camera->get_name()); Ref<GLTFCamera> c; - c.instance(); + c.instantiate(); if (p_camera->get_projection() == Camera3D::Projection::PROJECTION_PERSPECTIVE) { c->set_perspective(true); @@ -5031,7 +5027,7 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig print_verbose("glTF: Converting light: " + p_light->get_name()); Ref<GLTFLight> l; - l.instance(); + l.instantiate(); l->color = p_light->get_color(); if (cast_to<DirectionalLight3D>(p_light)) { l->type = "directional"; @@ -5066,7 +5062,7 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton) { print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name()); Ref<GLTFSkeleton> gltf_skeleton; - gltf_skeleton.instance(); + gltf_skeleton.instantiate(); gltf_skeleton->set_name(_gen_unique_name(state, p_skeleton->get_name())); gltf_skeleton->godot_skeleton = p_skeleton; GLTFSkeletonIndex skeleton_i = state->skeletons.size(); @@ -5075,9 +5071,9 @@ GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton } void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) { - Transform xform = p_spatial->get_transform(); + Transform3D xform = p_spatial->get_transform(); p_node->scale = xform.basis.get_scale(); - p_node->rotation = xform.basis.get_rotation_quat(); + p_node->rotation = xform.basis.get_rotation_quaternion(); p_node->translation = xform.origin; } @@ -5096,7 +5092,7 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, No return; } Ref<GLTFNode> gltf_node; - gltf_node.instance(); + gltf_node.instantiate(); gltf_node->set_name(_gen_unique_name(state, p_current->get_name())); if (cast_to<Node3D>(p_current)) { Node3D *spatial = cast_to<Node3D>(p_current); @@ -5162,9 +5158,9 @@ void GLTFDocument::_convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_g mat = csg->get_material_override(); } Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); Ref<EditorSceneImporterMesh> import_mesh; - import_mesh.instance(); + import_mesh.instantiate(); Ref<ArrayMesh> array_mesh = csg->get_meshes()[1]; for (int32_t surface_i = 0; surface_i < array_mesh->get_surface_count(); surface_i++) { import_mesh->add_surface(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, array_mesh->surface_get_arrays(surface_i), Array(), Dictionary(), mat, array_mesh->surface_get_name(surface_i)); @@ -5240,7 +5236,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNod Vector3(cell_location.x, cell_location.y, cell_location.z)); EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D); import_mesh_node->set_mesh(grid_map->get_mesh_library()->get_item_mesh(cell)); - Transform cell_xform; + Transform3D cell_xform; cell_xform.basis.set_orthogonal_index( grid_map->get_cell_item_orientation( Vector3(cell_location.x, cell_location.y, cell_location.z))); @@ -5250,7 +5246,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNod cell_xform.set_origin(grid_map->map_to_world( Vector3(cell_location.x, cell_location.y, cell_location.z))); Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); gltf_mesh = import_mesh_node; new_gltf_node->mesh = state->meshes.size(); state->meshes.push_back(gltf_mesh); @@ -5268,15 +5264,15 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count(); instance_i++) { GLTFNode *new_gltf_node = memnew(GLTFNode); - Transform transform; + Transform3D transform; if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) { Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i); transform.origin = Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y); real_t rotation = xform_2d.get_rotation(); - Quat quat(Vector3(0, 1, 0), rotation); + Quaternion quaternion(Vector3(0, 1, 0), rotation); Size2 scale = xform_2d.get_scale(); - transform.basis.set_quat_scale(quat, + transform.basis.set_quaternion_scale(quaternion, Vector3(scale.x, 0, scale.y)); transform = multi_mesh_instance->get_transform() * transform; @@ -5287,14 +5283,14 @@ void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, con Ref<ArrayMesh> mm = multi_mesh->get_mesh(); if (mm.is_valid()) { Ref<EditorSceneImporterMesh> mesh; - mesh.instance(); + mesh.instantiate(); for (int32_t surface_i = 0; surface_i < mm->get_surface_count(); surface_i++) { Array surface = mm->surface_get_arrays(surface_i); mesh->add_surface(mm->surface_get_primitive_type(surface_i), surface, Array(), Dictionary(), mm->surface_get_material(surface_i), mm->get_name()); } Ref<GLTFMesh> gltf_mesh; - gltf_mesh.instance(); + gltf_mesh.instantiate(); gltf_mesh->set_name(multi_mesh->get_name()); gltf_mesh->set_mesh(mesh); new_gltf_node->mesh = state->meshes.size(); @@ -5516,24 +5512,24 @@ struct EditorSceneImporterGLTFInterpolate { // thank you for existing, partial specialization template <> -struct EditorSceneImporterGLTFInterpolate<Quat> { - Quat lerp(const Quat &a, const Quat &b, const float c) const { - ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quat(), "The quaternion \"a\" must be normalized."); - ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quat(), "The quaternion \"b\" must be normalized."); +struct EditorSceneImporterGLTFInterpolate<Quaternion> { + Quaternion lerp(const Quaternion &a, const Quaternion &b, const float c) const { + ERR_FAIL_COND_V_MSG(!a.is_normalized(), Quaternion(), "The quaternion \"a\" must be normalized."); + ERR_FAIL_COND_V_MSG(!b.is_normalized(), Quaternion(), "The quaternion \"b\" must be normalized."); return a.slerp(b, c).normalized(); } - Quat catmull_rom(const Quat &p0, const Quat &p1, const Quat &p2, const Quat &p3, const float c) { - ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quat(), "The quaternion \"p1\" must be normalized."); - ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quat(), "The quaternion \"p2\" must be normalized."); + Quaternion catmull_rom(const Quaternion &p0, const Quaternion &p1, const Quaternion &p2, const Quaternion &p3, const float c) { + ERR_FAIL_COND_V_MSG(!p1.is_normalized(), Quaternion(), "The quaternion \"p1\" must be normalized."); + ERR_FAIL_COND_V_MSG(!p2.is_normalized(), Quaternion(), "The quaternion \"p2\" must be normalized."); return p1.slerp(p2, c).normalized(); } - Quat bezier(const Quat start, const Quat control_1, const Quat control_2, const Quat end, const float t) { - ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quat(), "The start quaternion must be normalized."); - ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quat(), "The end quaternion must be normalized."); + Quaternion bezier(const Quaternion start, const Quaternion control_1, const Quaternion control_2, const Quaternion end, const float t) { + ERR_FAIL_COND_V_MSG(!start.is_normalized(), Quaternion(), "The start quaternion must be normalized."); + ERR_FAIL_COND_V_MSG(!end.is_normalized(), Quaternion(), "The end quaternion must be normalized."); return start.slerp(end, t).normalized(); } @@ -5541,6 +5537,8 @@ struct EditorSceneImporterGLTFInterpolate<Quat> { template <class T> T GLTFDocument::_interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp) { + ERR_FAIL_COND_V(!p_values.size(), T()); + ERR_FAIL_COND_V(p_times.size() != p_values.size(), p_values[0]); //could use binary search, worth it? int idx = -1; for (int i = 0; i < p_times.size(); i++) { @@ -5615,7 +5613,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } Ref<Animation> animation; - animation.instance(); + animation.instantiate(); animation->set_name(name); if (anim->get_loop()) { @@ -5673,7 +5671,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, if ((track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) { //make transform track int track_idx = animation->get_track_count(); - animation->add_track(Animation::TYPE_TRANSFORM); + animation->add_track(Animation::TYPE_TRANSFORM3D); animation->track_set_path(track_idx, transform_node_path); //first determine animation length @@ -5681,7 +5679,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, double time = 0.0; Vector3 base_pos; - Quat base_rot; + Quaternion base_rot; Vector3 base_scale = Vector3(1, 1, 1); if (!track.rotation_track.values.size()) { @@ -5699,7 +5697,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, bool last = false; while (true) { Vector3 pos = base_pos; - Quat rot = base_rot; + Quaternion rot = base_rot; Vector3 scale = base_scale; if (track.translation_track.times.size()) { @@ -5707,7 +5705,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } if (track.rotation_track.times.size()) { - rot = _interpolate_track<Quat>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); + rot = _interpolate_track<Quaternion>(track.rotation_track.times, track.rotation_track.values, time, track.rotation_track.interpolation); } if (track.scale_track.times.size()) { @@ -5715,15 +5713,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap, } if (gltf_node->skeleton >= 0) { - Transform xform; - xform.basis.set_quat_scale(rot, scale); + Transform3D xform; + xform.basis.set_quaternion_scale(rot, scale); xform.origin = pos; const Skeleton3D *skeleton = state->skeletons[gltf_node->skeleton]->godot_skeleton; const int bone_idx = skeleton->find_bone(gltf_node->get_name()); xform = skeleton->get_bone_rest(bone_idx).affine_inverse() * xform; - rot = xform.basis.get_rotation_quat(); + rot = xform.basis.get_rotation_quaternion(); rot.normalize(); scale = xform.basis.get_scale(); pos = xform.origin; @@ -5808,9 +5806,9 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { } MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); ERR_CONTINUE(!mi); - Transform mi_xform = mi->get_transform(); + Transform3D mi_xform = mi->get_transform(); node->scale = mi_xform.basis.get_scale(); - node->rotation = mi_xform.basis.get_rotation_quat(); + node->rotation = mi_xform.basis.get_rotation_quaternion(); node->translation = mi_xform.origin; Dictionary json_skin; @@ -5826,7 +5824,7 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { skin = skeleton->register_skin(nullptr)->get_skin(); } Ref<GLTFSkin> gltf_skin; - gltf_skin.instance(); + gltf_skin.instantiate(); Array json_joints; GLTFSkeletonIndex skeleton_gltf_i = -1; @@ -5868,13 +5866,13 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) { BoneId bone_index = skeleton->find_bone(godot_bone_name); ERR_CONTINUE(bone_index == -1); Ref<GLTFNode> joint_node; - joint_node.instance(); + joint_node.instantiate(); String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name); joint_node->set_name(gltf_bone_name); - Transform bone_rest_xform = skeleton->get_bone_rest(bone_index); + Transform3D bone_rest_xform = skeleton->get_bone_rest(bone_index); joint_node->scale = bone_rest_xform.basis.get_scale(); - joint_node->rotation = bone_rest_xform.basis.get_rotation_quat(); + joint_node->rotation = bone_rest_xform.basis.get_rotation_quaternion(); joint_node->translation = bone_rest_xform.origin; joint_node->joint = true; @@ -5995,12 +5993,12 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo mi->set_skin(state->skins.write[skin_i]->godot_skin); mi->set_skeleton_path(mi->get_path_to(skeleton)); - mi->set_transform(Transform()); + mi->set_transform(Transform3D()); } } } -GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) { +GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, Ref<Animation> p_animation, Transform3D p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i) { Animation::InterpolationType interpolation = p_animation->track_get_interpolation_type(p_track_i); GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR; @@ -6020,7 +6018,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i); } const float BAKE_FPS = 30.0f; - if (track_type == Animation::TYPE_TRANSFORM) { + if (track_type == Animation::TYPE_TRANSFORM3D) { p_track.translation_track.times = times; p_track.translation_track.interpolation = gltf_interpolation; p_track.rotation_track.times = times; @@ -6036,16 +6034,16 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { Vector3 translation; - Quat rotation; + Quaternion rotation; Vector3 scale; Error err = p_animation->transform_track_get_key(p_track_i, key_i, &translation, &rotation, &scale); ERR_CONTINUE(err != OK); - Transform xform; - xform.basis.set_quat_scale(rotation, scale); + Transform3D xform; + xform.basis.set_quaternion_scale(rotation, scale); xform.origin = translation; xform = p_bone_rest * xform; p_track.translation_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat(); + p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion(); p_track.scale_track.values.write[key_i] = xform.basis.get_scale(); } } else if (path.find(":transform") != -1) { @@ -6063,9 +6061,9 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.values.resize(key_count); p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { - Transform xform = p_animation->track_get_key_value(p_track_i, key_i); + Transform3D xform = p_animation->track_get_key_value(p_track_i, key_i); p_track.translation_track.values.write[key_i] = xform.get_origin(); - p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quat(); + p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion(); p_track.scale_track.values.write[key_i] = xform.basis.get_scale(); } } else if (track_type == Animation::TYPE_VALUE) { @@ -6077,7 +6075,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { - Quat rotation_track = p_animation->track_get_key_value(p_track_i, key_i); + Quaternion rotation_track = p_animation->track_get_key_value(p_track_i, key_i); p_track.rotation_track.values.write[key_i] = rotation_track; } } else if (path.find(":translation") != -1) { @@ -6091,7 +6089,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state Vector3 translation = p_animation->track_get_key_value(p_track_i, key_i); p_track.translation_track.values.write[key_i] = translation; } - } else if (path.find(":rotation_degrees") != -1) { + } else if (path.find(":rotation") != -1) { p_track.rotation_track.times = times; p_track.rotation_track.interpolation = gltf_interpolation; @@ -6099,12 +6097,8 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state p_track.rotation_track.interpolation = gltf_interpolation; for (int32_t key_i = 0; key_i < key_count; key_i++) { - Vector3 rotation_degrees = p_animation->track_get_key_value(p_track_i, key_i); - Vector3 rotation_radian; - rotation_radian.x = Math::deg2rad(rotation_degrees.x); - rotation_radian.y = Math::deg2rad(rotation_degrees.y); - rotation_radian.z = Math::deg2rad(rotation_degrees.z); - p_track.rotation_track.values.write[key_i] = Quat(rotation_radian); + Vector3 rotation_radian = p_animation->track_get_key_value(p_track_i, key_i); + p_track.rotation_track.values.write[key_i] = Quaternion(rotation_radian); } } else if (path.find(":scale") != -1) { p_track.scale_track.times = times; @@ -6190,7 +6184,7 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, String p_animation_track_name) { Ref<Animation> animation = ap->get_animation(p_animation_track_name); Ref<GLTFAnimation> gltf_animation; - gltf_animation.instance(); + gltf_animation.instantiate(); gltf_animation->set_name(_gen_unique_name(state, p_animation_track_name)); for (int32_t track_i = 0; track_i < animation->get_track_count(); track_i++) { @@ -6210,7 +6204,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (translation_track_i) { track = translation_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6226,7 +6220,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (rotation_degree_track_i) { track = rotation_degree_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6242,7 +6236,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (scale_track_i) { track = scale_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); } } @@ -6253,7 +6247,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) { if (transform_track_i->get() == node) { GLTFAnimation::Track track; - track = _convert_animation_track(state, track, animation, Transform(), track_i, transform_track_i->key()); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i->key()); gltf_animation->get_tracks().insert(transform_track_i->key(), track); } } @@ -6341,7 +6335,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, Ref<GLTFSkeleton> skeleton_gltf = state->skeletons[skeleton_gltf_i]; int32_t bone = skeleton->find_bone(suffix); ERR_CONTINUE(bone == -1); - Transform xform = skeleton->get_bone_rest(bone); + Transform3D xform = skeleton->get_bone_rest(bone); if (!skeleton_gltf->godot_bone_node.has(bone)) { continue; } @@ -6368,7 +6362,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap, if (node_track_i) { track = node_track_i->get(); } - track = _convert_animation_track(state, track, animation, Transform(), track_i, node_index); + track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index); gltf_animation->get_tracks().insert(node_index, track); break; } @@ -6584,7 +6578,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err); ERR_FAIL_COND_V(!f, FAILED); - String json = JSON::print(state->json); + String json = Variant(state->json).to_json_string(); const uint32_t magic = 0x46546C67; // GLTF const int32_t header_size = 12; @@ -6625,7 +6619,7 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) { ERR_FAIL_COND_V(!f, FAILED); f->create(FileAccess::ACCESS_RESOURCES); - String json = JSON::print(state->json); + String json = Variant(state->json).to_json_string(); f->store_string(json); f->close(); } diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 900c367010..514373c4f0 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -205,7 +205,7 @@ private: Vector<Color> _decode_accessor_as_color(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Quat> _decode_accessor_as_quat(Ref<GLTFState> state, + Vector<Quaternion> _decode_accessor_as_quaternion(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); Vector<Transform2D> _decode_accessor_as_xform2d(Ref<GLTFState> state, @@ -214,7 +214,7 @@ private: Vector<Basis> _decode_accessor_as_basis(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); - Vector<Transform> _decode_accessor_as_xform(Ref<GLTFState> state, + Vector<Transform3D> _decode_accessor_as_xform(Ref<GLTFState> state, const GLTFAccessorIndex p_accessor, const bool p_for_vertex); Error _parse_meshes(Ref<GLTFState> state); @@ -273,8 +273,8 @@ private: T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values, const float p_time, const GLTFAnimation::Interpolation p_interp); - GLTFAccessorIndex _encode_accessor_as_quats(Ref<GLTFState> state, - const Vector<Quat> p_attribs, + GLTFAccessorIndex _encode_accessor_as_quaternions(Ref<GLTFState> state, + const Vector<Quaternion> p_attribs, const bool p_for_vertex); GLTFAccessorIndex _encode_accessor_as_weights(Ref<GLTFState> state, const Vector<Color> p_attribs, @@ -317,7 +317,7 @@ private: const Vector<int32_t> p_attribs, const bool p_for_vertex); GLTFAccessorIndex _encode_accessor_as_xform(Ref<GLTFState> state, - const Vector<Transform> p_attribs, + const Vector<Transform3D> p_attribs, const bool p_for_vertex); Error _encode_buffer_view(Ref<GLTFState> state, const double *src, const int count, const GLTFType type, @@ -333,7 +333,7 @@ private: String interpolation_to_string(const GLTFAnimation::Interpolation p_interp); GLTFAnimation::Track _convert_animation_track(Ref<GLTFState> state, GLTFAnimation::Track p_track, - Ref<Animation> p_animation, Transform p_bone_rest, + Ref<Animation> p_animation, Transform3D p_bone_rest, int32_t p_track_i, GLTFNodeIndex p_node_i); Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path); diff --git a/modules/gltf/gltf_node.cpp b/modules/gltf/gltf_node.cpp index f6f33ef009..5db7ad66c3 100644 --- a/modules/gltf/gltf_node.cpp +++ b/modules/gltf/gltf_node.cpp @@ -60,14 +60,14 @@ void GLTFNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "parent"), "set_parent", "get_parent"); // GLTFNodeIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "height"), "set_height", "get_height"); // int - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "xform"), "set_xform", "get_xform"); // Transform + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "xform"), "set_xform", "get_xform"); // Transform3D ADD_PROPERTY(PropertyInfo(Variant::INT, "mesh"), "set_mesh", "get_mesh"); // GLTFMeshIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "camera"), "set_camera", "get_camera"); // GLTFCameraIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "skin"), "set_skin", "get_skin"); // GLTFSkinIndex ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // GLTFSkeletonIndex ADD_PROPERTY(PropertyInfo(Variant::BOOL, "joint"), "set_joint", "get_joint"); // bool ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation"), "set_translation", "get_translation"); // Vector3 - ADD_PROPERTY(PropertyInfo(Variant::QUAT, "rotation"), "set_rotation", "get_rotation"); // Quat + ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "rotation"), "set_rotation", "get_rotation"); // Quaternion ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale"), "set_scale", "get_scale"); // Vector3 ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "children"), "set_children", "get_children"); // Vector<int> ADD_PROPERTY(PropertyInfo(Variant::INT, "light"), "set_light", "get_light"); // GLTFLightIndex @@ -89,11 +89,11 @@ void GLTFNode::set_height(int p_height) { height = p_height; } -Transform GLTFNode::get_xform() { +Transform3D GLTFNode::get_xform() { return xform; } -void GLTFNode::set_xform(Transform p_xform) { +void GLTFNode::set_xform(Transform3D p_xform) { xform = p_xform; } @@ -145,11 +145,11 @@ void GLTFNode::set_translation(Vector3 p_translation) { translation = p_translation; } -Quat GLTFNode::get_rotation() { +Quaternion GLTFNode::get_rotation() { return rotation; } -void GLTFNode::set_rotation(Quat p_rotation) { +void GLTFNode::set_rotation(Quaternion p_rotation) { rotation = p_rotation; } diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h index 3a5689d004..378b6da8bf 100644 --- a/modules/gltf/gltf_node.h +++ b/modules/gltf/gltf_node.h @@ -43,14 +43,14 @@ private: // matrices need to be transformed to this GLTFNodeIndex parent = -1; int height = -1; - Transform xform; + Transform3D xform; GLTFMeshIndex mesh = -1; GLTFCameraIndex camera = -1; GLTFSkinIndex skin = -1; GLTFSkeletonIndex skeleton = -1; bool joint = false; Vector3 translation; - Quat rotation; + Quaternion rotation; Vector3 scale = Vector3(1, 1, 1); Vector<int> children; GLTFLightIndex light = -1; @@ -65,8 +65,8 @@ public: int get_height(); void set_height(int p_height); - Transform get_xform(); - void set_xform(Transform p_xform); + Transform3D get_xform(); + void set_xform(Transform3D p_xform); GLTFMeshIndex get_mesh(); void set_mesh(GLTFMeshIndex p_mesh); @@ -86,8 +86,8 @@ public: Vector3 get_translation(); void set_translation(Vector3 p_translation); - Quat get_rotation(); - void set_rotation(Quat p_rotation); + Quaternion get_rotation(); + void set_rotation(Quaternion p_rotation); Vector3 get_scale(); void set_scale(Vector3 p_scale); diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp index 5a61e5778c..5cf17135ac 100644 --- a/modules/gltf/gltf_skin.cpp +++ b/modules/gltf/gltf_skin.cpp @@ -54,7 +54,7 @@ void GLTFSkin::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "skin_root"), "set_skin_root", "get_skin_root"); // GLTFNodeIndex ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints_original"), "set_joints_original", "get_joints_original"); // Vector<GLTFNodeIndex> - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform> + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "inverse_binds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_inverse_binds", "get_inverse_binds"); // Vector<Transform3D> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "non_joints"), "set_non_joints", "get_non_joints"); // Vector<GLTFNodeIndex> ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex> diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h index 7cc09d85bc..e32e2d397c 100644 --- a/modules/gltf/gltf_skin.h +++ b/modules/gltf/gltf_skin.h @@ -43,7 +43,7 @@ private: GLTFNodeIndex skin_root = -1; Vector<GLTFNodeIndex> joints_original; - Vector<Transform> inverse_binds; + Vector<Transform3D> inverse_binds; // Note: joints + non_joints should form a complete subtree, or subtrees // with a common parent diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp index dc995c9249..d11c7cb9cd 100644 --- a/modules/gltf/register_types.cpp +++ b/modules/gltf/register_types.cpp @@ -51,7 +51,7 @@ #ifdef TOOLS_ENABLED static void _editor_init() { Ref<EditorSceneImporterGLTF> import_gltf; - import_gltf.instance(); + import_gltf.instantiate(); ResourceImporterScene::get_singleton()->add_importer(import_gltf); } #endif diff --git a/modules/gridmap/config.py b/modules/gridmap/config.py index a6319fe1ea..720401b92d 100644 --- a/modules/gridmap/config.py +++ b/modules/gridmap/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/gridmap/doc_classes/GridMap.xml b/modules/gridmap/doc_classes/GridMap.xml index 9b6fa138e5..a2c8e8eabf 100644 --- a/modules/gridmap/doc_classes/GridMap.xml +++ b/modules/gridmap/doc_classes/GridMap.xml @@ -41,7 +41,7 @@ <return type="Array"> </return> <description> - Returns an array of [ArrayMesh]es and [Transform] references of all bake meshes that exist within the current GridMap. + Returns an array of [ArrayMesh]es and [Transform3D] references of all bake meshes that exist within the current GridMap. </description> </method> <method name="get_cell_item" qualifiers="const"> @@ -84,7 +84,7 @@ <return type="Array"> </return> <description> - Returns an array of [Transform] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space. + Returns an array of [Transform3D] and [Mesh] references corresponding to the non-empty cells in the grid. The transforms are specified in world space. </description> </method> <method name="get_used_cells" qualifiers="const"> @@ -203,7 +203,7 @@ The scale of the cell items. This does not affect the size of the grid cells themselves, only the items in them. This can be used to make cell items overlap their neighbors. </member> - <member name="cell_size" type="Vector3" setter="set_cell_size" getter="get_cell_size" default="Vector3( 2, 2, 2 )"> + <member name="cell_size" type="Vector3" setter="set_cell_size" getter="get_cell_size" default="Vector3(2, 2, 2)"> The dimensions of the grid's cells. This does not affect the size of the meshes. See [member cell_scale]. </member> diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp index eaceaac33c..e9134b32d9 100644 --- a/modules/gridmap/grid_map.cpp +++ b/modules/gridmap/grid_map.cpp @@ -446,7 +446,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { * and set said multimesh bounding box to one containing all cells which have this item */ - Map<int, List<Pair<Transform, IndexKey>>> multimesh_items; + Map<int, List<Pair<Transform3D, IndexKey>>> multimesh_items; for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) { ERR_CONTINUE(!cell_map.has(E->get())); @@ -459,7 +459,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z); Vector3 ofs = _get_offset(); - Transform xform; + Transform3D xform; xform.basis.set_orthogonal_index(c.rot); xform.set_origin(cellpos * cell_size + ofs); @@ -467,10 +467,10 @@ bool GridMap::_octant_update(const OctantKey &p_key) { if (baked_meshes.size() == 0) { if (mesh_library->get_item_mesh(c.item).is_valid()) { if (!multimesh_items.has(c.item)) { - multimesh_items[c.item] = List<Pair<Transform, IndexKey>>(); + multimesh_items[c.item] = List<Pair<Transform3D, IndexKey>>(); } - Pair<Transform, IndexKey> p; + Pair<Transform3D, IndexKey> p; p.first = xform; p.second = E->get(); multimesh_items[c.item].push_back(p); @@ -511,7 +511,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { //update multimeshes, only if not baked if (baked_meshes.size() == 0) { - for (Map<int, List<Pair<Transform, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) { + for (Map<int, List<Pair<Transform3D, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) { Octant::MultimeshInstance mmi; RID mm = RS::get_singleton()->multimesh_create(); @@ -519,7 +519,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) { RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid()); int idx = 0; - for (List<Pair<Transform, IndexKey>>::Element *F = E->get().front(); F; F = F->next()) { + for (List<Pair<Transform3D, IndexKey>>::Element *F = E->get().front(); F; F = F->next()) { RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first); #ifdef TOOLS_ENABLED @@ -672,7 +672,7 @@ void GridMap::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - Transform new_xform = get_global_transform(); + Transform3D new_xform = get_global_transform(); if (new_xform == last_transform) { break; } @@ -686,7 +686,6 @@ void GridMap::_notification(int p_what) { for (int i = 0; i < baked_meshes.size(); i++) { RS::get_singleton()->instance_set_transform(baked_meshes[i].instance, get_global_transform()); } - } break; case NOTIFICATION_EXIT_WORLD: { for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) { @@ -781,7 +780,7 @@ void GridMap::_update_octants_callback() { while (to_delete.front()) { octant_map.erase(to_delete.front()->get()); - to_delete.pop_back(); + to_delete.pop_front(); } _update_visibility(); @@ -934,7 +933,7 @@ Array GridMap::get_meshes() { Vector3 cellpos = Vector3(ik.x, ik.y, ik.z); - Transform xform; + Transform3D xform; xform.basis.set_orthogonal_index(E->get().rot); @@ -988,7 +987,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe Vector3 cellpos = Vector3(key.x, key.y, key.z); Vector3 ofs = _get_offset(); - Transform xform; + Transform3D xform; xform.basis.set_orthogonal_index(E->get().rot); xform.set_origin(cellpos * cell_size + ofs); @@ -1013,7 +1012,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe Ref<Material> surf_mat = mesh->surface_get_material(i); if (!mat_map.has(surf_mat)) { Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->begin(Mesh::PRIMITIVE_TRIANGLES); st->set_material(surf_mat); mat_map[surf_mat] = st; @@ -1025,7 +1024,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>>::Element *E = surface_map.front(); E; E = E->next()) { Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); for (Map<Ref<Material>, Ref<SurfaceTool>>::Element *F = E->get().front(); F; F = F->next()) { F->get()->commit(mesh); } @@ -1057,7 +1056,7 @@ Array GridMap::get_bake_meshes() { Array arr; for (int i = 0; i < baked_meshes.size(); i++) { arr.push_back(baked_meshes[i].mesh); - arr.push_back(Transform()); + arr.push_back(Transform3D()); } return arr; diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h index 4c04d492f7..8cd82e1f4c 100644 --- a/modules/gridmap/grid_map.h +++ b/modules/gridmap/grid_map.h @@ -89,7 +89,7 @@ class GridMap : public Node3D { struct Octant { struct NavMesh { RID region; - Transform xform; + Transform3D xform; }; struct MultimeshInstance { @@ -97,7 +97,7 @@ class GridMap : public Node3D { RID multimesh; struct Item { int index = 0; - Transform transform; + Transform3D transform; IndexKey key; }; @@ -137,7 +137,7 @@ class GridMap : public Node3D { bool bake_navigation = false; uint32_t navigation_layers = 1; - Transform last_transform; + Transform3D last_transform; bool _in_tree = false; Vector3 cell_size = Vector3(2, 2, 2); diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp index 813b4b9689..a2f570e6a5 100644 --- a/modules/gridmap/grid_map_editor_plugin.cpp +++ b/modules/gridmap/grid_map_editor_plugin.cpp @@ -62,12 +62,6 @@ void GridMapEditor::_menu_option(int p_option) { floor->set_value(floor->get_value() + 1); } break; - case MENU_OPTION_LOCK_VIEW: { - int index = options->get_popup()->get_item_index(MENU_OPTION_LOCK_VIEW); - lock_view = !options->get_popup()->is_item_checked(index); - - options->get_popup()->set_item_checked(index, lock_view); - } break; case MENU_OPTION_CLIP_DISABLED: case MENU_OPTION_CLIP_ABOVE: case MENU_OPTION_CLIP_BELOW: { @@ -255,7 +249,7 @@ void GridMapEditor::_menu_option(int p_option) { } void GridMapEditor::_update_cursor_transform() { - cursor_transform = Transform(); + cursor_transform = Transform3D(); cursor_transform.origin = cursor_origin; cursor_transform.basis.set_orthogonal_index(cursor_rot); cursor_transform.basis *= node->get_cell_scale(); @@ -268,7 +262,7 @@ void GridMapEditor::_update_cursor_transform() { } void GridMapEditor::_update_selection_transform() { - Transform xf_zero; + Transform3D xf_zero; xf_zero.basis.set_zero(); if (!selection.active) { @@ -279,7 +273,7 @@ void GridMapEditor::_update_selection_transform() { return; } - Transform xf; + Transform3D xf; xf.scale((Vector3(1, 1, 1) + (selection.end - selection.begin)) * node->get_cell_size()); xf.origin = selection.begin * node->get_cell_size(); @@ -297,7 +291,7 @@ void GridMapEditor::_update_selection_transform() { scale *= node->get_cell_size(); position *= node->get_cell_size(); - Transform xf2; + Transform3D xf2; xf2.basis.scale(scale); xf2.origin = position; @@ -362,7 +356,7 @@ bool GridMapEditor::do_input_action(Camera3D *p_camera, const Point2 &p_point, b Camera3D *camera = p_camera; Vector3 from = camera->project_ray_origin(p_point); Vector3 normal = camera->project_ray_normal(p_point); - Transform local_xform = node->get_global_transform().affine_inverse(); + Transform3D local_xform = node->get_global_transform().affine_inverse(); Vector<Plane> planes = camera->get_frustum(); from = local_xform.xform(from); normal = local_xform.basis.xform(normal).normalized(); @@ -540,7 +534,7 @@ void GridMapEditor::_set_clipboard_data() { void GridMapEditor::_update_paste_indicator() { if (input_action != INPUT_PASTE) { - Transform xf; + Transform3D xf; xf.basis.set_zero(); RenderingServer::get_singleton()->instance_set_transform(paste_instance, xf); return; @@ -548,7 +542,7 @@ void GridMapEditor::_update_paste_indicator() { Vector3 center = 0.5 * Vector3(real_t(node->get_center_x()), real_t(node->get_center_y()), real_t(node->get_center_z())); Vector3 scale = (Vector3(1, 1, 1) + (paste_indicator.end - paste_indicator.begin)) * node->get_cell_size(); - Transform xf; + Transform3D xf; xf.scale(scale); xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size(); Basis rot; @@ -561,7 +555,7 @@ void GridMapEditor::_update_paste_indicator() { for (List<ClipboardItem>::Element *E = clipboard_items.front(); E; E = E->next()) { ClipboardItem &item = E->get(); - xf = Transform(); + xf = Transform3D(); xf.origin = (paste_indicator.begin + (paste_indicator.current - paste_indicator.click) + center) * node->get_cell_size(); xf.basis = rot * xf.basis; xf.translate(item.grid_offset * node->get_cell_size()); @@ -1068,7 +1062,7 @@ void GridMapEditor::_notification(int p_what) { return; } - Transform xf = node->get_global_transform(); + Transform3D xf = node->get_global_transform(); if (xf != grid_xform) { for (int i = 0; i < 3; i++) { @@ -1080,26 +1074,22 @@ void GridMapEditor::_notification(int p_what) { if (cgmt.operator->() != last_mesh_library) { update_palette(); } - - if (lock_view) { - EditorNode *editor = Object::cast_to<EditorNode>(get_tree()->get_root()->get_child(0)); - - Plane p; - p.normal[edit_axis] = 1.0; - p.d = edit_floor[edit_axis] * node->get_cell_size()[edit_axis]; - p = node->get_transform().xform(p); // plane to snap - - Node3DEditorPlugin *sep = Object::cast_to<Node3DEditorPlugin>(editor->get_editor_plugin_screen()); - if (sep) { - sep->snap_cursor_to_plane(p); - } - } } break; case NOTIFICATION_THEME_CHANGED: { options->set_icon(get_theme_icon("GridMap", "EditorIcons")); search_box->set_right_icon(get_theme_icon("Search", "EditorIcons")); } break; + + case NOTIFICATION_APPLICATION_FOCUS_OUT: { + if (input_action == INPUT_PAINT) { + // Simulate mouse released event to stop drawing when editor focus exists. + Ref<InputEventMouseButton> release; + release.instantiate(); + release->set_button_index(MOUSE_BUTTON_LEFT); + forward_spatial_input_event(nullptr, release); + } + } break; } } @@ -1187,8 +1177,6 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { spatial_editor_hb->hide(); options->set_text(TTR("Grid Map")); - options->get_popup()->add_check_item(TTR("Snap View"), MENU_OPTION_LOCK_VIEW); - options->get_popup()->add_separator(); options->get_popup()->add_item(TTR("Previous Floor"), MENU_OPTION_PREV_LEVEL, KEY_Q); options->get_popup()->add_item(TTR("Next Floor"), MENU_OPTION_NEXT_LEVEL, KEY_E); options->get_popup()->add_separator(); @@ -1368,7 +1356,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { Array d; d.resize(RS::ARRAY_MAX); - inner_mat.instance(); + inner_mat.instantiate(); inner_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.2)); inner_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); inner_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); @@ -1377,14 +1365,14 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { RenderingServer::get_singleton()->mesh_add_surface_from_arrays(selection_mesh, RS::PRIMITIVE_TRIANGLES, d); RenderingServer::get_singleton()->mesh_surface_set_material(selection_mesh, 0, inner_mat->get_rid()); - outer_mat.instance(); + outer_mat.instantiate(); outer_mat->set_albedo(Color(0.7, 0.7, 1.0, 0.8)); outer_mat->set_on_top_of_alpha(); outer_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); outer_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); - selection_floor_mat.instance(); + selection_floor_mat.instantiate(); selection_floor_mat->set_albedo(Color(0.80, 0.80, 1.0, 1)); selection_floor_mat->set_on_top_of_alpha(); selection_floor_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); @@ -1411,7 +1399,7 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) { _set_selection(false); - indicator_mat.instance(); + indicator_mat.instantiate(); indicator_mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); indicator_mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA); indicator_mat->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h index 6c7f0bedf6..4bc849e071 100644 --- a/modules/gridmap/grid_map_editor_plugin.h +++ b/modules/gridmap/grid_map_editor_plugin.h @@ -94,9 +94,8 @@ class GridMapEditor : public VBoxContainer { MeshLibrary *last_mesh_library; ClipMode clip_mode = CLIP_DISABLED; - bool lock_view = false; - Transform grid_xform; - Transform edit_grid_xform; + Transform3D grid_xform; + Transform3D edit_grid_xform; Vector3::Axis edit_axis; int edit_floor[3]; Vector3 grid_ofs; @@ -146,7 +145,7 @@ class GridMapEditor : public VBoxContainer { PasteIndicator paste_indicator; bool cursor_visible = false; - Transform cursor_transform; + Transform3D cursor_transform; Vector3 cursor_origin; diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp index d237544d66..b5e4753e8d 100644 --- a/modules/jpg/image_loader_jpegd.cpp +++ b/modules/jpg/image_loader_jpegd.cpp @@ -127,7 +127,7 @@ void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const static Ref<Image> _jpegd_mem_loader_func(const uint8_t *p_png, int p_size) { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = jpeg_load_image_from_buffer(img.ptr(), p_png, p_size); ERR_FAIL_COND_V(err, Ref<Image>()); return img; diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp index 306c0ff087..3d0759d83e 100644 --- a/modules/jsonrpc/jsonrpc.cpp +++ b/modules/jsonrpc/jsonrpc.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "jsonrpc.h" + #include "core/io/json.h" JSONRPC::JSONRPC() { @@ -156,19 +157,17 @@ String JSONRPC::process_string(const String &p_input) { } Variant ret; - Variant input; - String err_message; - int err_line; - if (OK != JSON::parse(p_input, input, err_message, err_line)) { - ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error"); + JSON json; + if (json.parse(p_input) == OK) { + ret = process_action(json.get_data(), true); } else { - ret = process_action(input, true); + ret = make_response_error(JSONRPC::PARSE_ERROR, "Parse error"); } if (ret.get_type() == Variant::NIL) { return ""; } - return JSON::print(ret); + return ret.to_json_string(); } void JSONRPC::set_scope(const String &p_scope, Object *p_obj) { diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 3b0fbb1c47..b75cf6502e 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -248,13 +248,13 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ for (int i = 0; i < atlas_slices; i++) { Ref<Image> albedo; - albedo.instance(); + albedo.instantiate(); albedo->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBA8); albedo->set_as_black(); albedo_images.write[i] = albedo; Ref<Image> emission; - emission.instance(); + emission.instantiate(); emission->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH); emission->set_as_black(); emission_images.write[i] = emission; @@ -479,7 +479,7 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i } Ref<Image> img; - img.instance(); + img.instantiate(); img->create(grid_size, grid_size, false, Image::FORMAT_L8, grid_usage); img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png"); } @@ -725,7 +725,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d panorama_tex = p_environment_panorama; panorama_tex->convert(Image::FORMAT_RGBAF); } else { - panorama_tex.instance(); + panorama_tex.instantiate(); panorama_tex->create(8, 8, false, Image::FORMAT_RGBAF); for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { @@ -782,7 +782,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d //shaders Ref<RDShaderFile> raster_shader; - raster_shader.instance(); + raster_shader.instantiate(); Error err = raster_shader->parse_versions_from_text(lm_raster_shader_glsl); if (err != OK) { raster_shader->print_errors("raster_shader"); @@ -915,7 +915,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices; i++) { Vector<uint8_t> s = rd->texture_get_data(position_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s); img->save_exr("res://1_position_" + itos(i) + ".exr", false); @@ -933,7 +933,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d /* Plot direct light */ Ref<RDShaderFile> compute_shader; - compute_shader.instance(); + compute_shader.instantiate(); err = compute_shader->parse_versions_from_text(lm_compute_shader_glsl, p_bake_sh ? "\n#define USE_SH_LIGHTMAPS\n" : ""); if (err != OK) { FREE_TEXTURES @@ -1129,7 +1129,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices; i++) { Vector<uint8_t> s = rd->texture_get_data(light_source_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false); } @@ -1379,12 +1379,12 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d #if 0 for (int i = 0; i < probe_positions.size(); i++) { Ref<Image> img; - img.instance(); + img.instantiate(); img->create(6, 4, false, Image::FORMAT_RGB8); for (int j = 0; j < 6; j++) { Vector<uint8_t> s = rd->texture_get_data(lightprobe_tex, i * 6 + j); Ref<Image> img2; - img2.instance(); + img2.instantiate(); img2->create(2, 2, false, Image::FORMAT_RGBAF, s); img2->convert(Image::FORMAT_RGB8); img->blit_rect(img2, Rect2(0, 0, 2, 2), Point2((j % 3) * 2, (j / 3) * 2)); @@ -1405,7 +1405,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); Ref<Image> denoised = denoiser->denoise_image(img); @@ -1432,7 +1432,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false); } @@ -1484,7 +1484,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->convert(Image::FORMAT_RGBA8); img->save_png("res://5_dilated_" + itos(i) + ".png"); @@ -1494,7 +1494,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d /* BLEND SEAMS */ //shaders Ref<RDShaderFile> blendseams_shader; - blendseams_shader.instance(); + blendseams_shader.instantiate(); err = blendseams_shader->parse_versions_from_text(lm_blendseams_shader_glsl); if (err != OK) { FREE_TEXTURES @@ -1641,7 +1641,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->save_exr("res://5_blendseams" + itos(i) + ".exr", false); } @@ -1653,7 +1653,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d for (int i = 0; i < atlas_slices * (p_bake_sh ? 4 : 1); i++) { Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s); img->convert(Image::FORMAT_RGBH); //remove alpha bake_textures.push_back(img); @@ -1668,7 +1668,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d #ifdef DEBUG_TEXTURES { Ref<Image> img2; - img2.instance(); + img2.instantiate(); img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data); img2->save_exr("res://6_lightprobes.exr", false); } diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp index c389609984..2522f1bb11 100644 --- a/modules/mbedtls/crypto_mbedtls.cpp +++ b/modules/mbedtls/crypto_mbedtls.cpp @@ -30,7 +30,7 @@ #include "crypto_mbedtls.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/config/engine.h" #include "core/config/project_settings.h" @@ -249,6 +249,13 @@ PackedByteArray HMACContextMbedTLS::finish() { return out; } +HMACContextMbedTLS::~HMACContextMbedTLS() { + if (ctx != nullptr) { + mbedtls_md_free((mbedtls_md_context_t *)ctx); + memfree((mbedtls_md_context_t *)ctx); + } +} + Crypto *CryptoMbedTLS::create() { return memnew(CryptoMbedTLS); } @@ -324,7 +331,7 @@ void CryptoMbedTLS::load_default_certificates(String p_path) { Ref<CryptoKey> CryptoMbedTLS::generate_rsa(int p_bytes) { Ref<CryptoKeyMbedTLS> out; - out.instance(); + out.instantiate(); int ret = mbedtls_pk_setup(&(out->pkey), mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); ERR_FAIL_COND_V(ret != 0, nullptr); ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(out->pkey), mbedtls_ctr_drbg_random, &ctr_drbg, p_bytes, 65537); @@ -366,7 +373,7 @@ Ref<X509Certificate> CryptoMbedTLS::generate_self_signed_certificate(Ref<CryptoK buf[4095] = '\0'; // Make sure strlen can't fail. Ref<X509CertificateMbedTLS> out; - out.instance(); + out.instantiate(); out->load_from_memory(buf, strlen((char *)buf) + 1); // Use strlen to find correct output size. return out; } diff --git a/modules/mbedtls/crypto_mbedtls.h b/modules/mbedtls/crypto_mbedtls.h index 5ced4d136c..afa1ea7a64 100644 --- a/modules/mbedtls/crypto_mbedtls.h +++ b/modules/mbedtls/crypto_mbedtls.h @@ -119,6 +119,7 @@ public: virtual PackedByteArray finish(); HMACContextMbedTLS() {} + ~HMACContextMbedTLS(); }; class CryptoMbedTLS : public Crypto { diff --git a/modules/mbedtls/dtls_server_mbedtls.cpp b/modules/mbedtls/dtls_server_mbedtls.cpp index 5d895d8579..b1b6b3844b 100644 --- a/modules/mbedtls/dtls_server_mbedtls.cpp +++ b/modules/mbedtls/dtls_server_mbedtls.cpp @@ -45,7 +45,7 @@ void DTLSServerMbedTLS::stop() { Ref<PacketPeerDTLS> DTLSServerMbedTLS::take_connection(Ref<PacketPeerUDP> p_udp_peer) { Ref<PacketPeerMbedDTLS> out; - out.instance(); + out.instantiate(); ERR_FAIL_COND_V(!out.is_valid(), out); ERR_FAIL_COND_V(!p_udp_peer.is_valid(), out); @@ -68,7 +68,7 @@ void DTLSServerMbedTLS::finalize() { } DTLSServerMbedTLS::DTLSServerMbedTLS() { - _cookies.instance(); + _cookies.instantiate(); } DTLSServerMbedTLS::~DTLSServerMbedTLS() { diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp index d77d946a77..114bf49e9e 100644 --- a/modules/mbedtls/packet_peer_mbed_dtls.cpp +++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp @@ -31,8 +31,8 @@ #include "packet_peer_mbed_dtls.h" #include "mbedtls/platform_util.h" +#include "core/io/file_access.h" #include "core/io/stream_peer_ssl.h" -#include "core/os/file_access.h" int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { if (buf == nullptr || len <= 0) { @@ -245,7 +245,7 @@ int PacketPeerMbedDTLS::get_max_packet_size() const { } PacketPeerMbedDTLS::PacketPeerMbedDTLS() { - ssl_ctx.instance(); + ssl_ctx.instantiate(); } PacketPeerMbedDTLS::~PacketPeerMbedDTLS() { diff --git a/modules/mbedtls/ssl_context_mbedtls.h b/modules/mbedtls/ssl_context_mbedtls.h index 30632018a8..1b55a54a10 100644 --- a/modules/mbedtls/ssl_context_mbedtls.h +++ b/modules/mbedtls/ssl_context_mbedtls.h @@ -33,9 +33,9 @@ #include "crypto_mbedtls.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include <mbedtls/config.h> #include <mbedtls/ctr_drbg.h> @@ -46,7 +46,7 @@ class SSLContextMbedTLS; -class CookieContextMbedTLS : public Reference { +class CookieContextMbedTLS : public RefCounted { friend class SSLContextMbedTLS; protected: @@ -63,7 +63,7 @@ public: ~CookieContextMbedTLS(); }; -class SSLContextMbedTLS : public Reference { +class SSLContextMbedTLS : public RefCounted { protected: bool inited = false; diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp index 8e40451806..5727f5f82f 100644 --- a/modules/mbedtls/stream_peer_mbedtls.cpp +++ b/modules/mbedtls/stream_peer_mbedtls.cpp @@ -30,8 +30,8 @@ #include "stream_peer_mbedtls.h" +#include "core/io/file_access.h" #include "core/io/stream_peer_tcp.h" -#include "core/os/file_access.h" int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) { if (buf == nullptr || len <= 0) { @@ -273,7 +273,7 @@ int StreamPeerMbedTLS::get_available_bytes() const { } StreamPeerMbedTLS::StreamPeerMbedTLS() { - ssl_ctx.instance(); + ssl_ctx.instantiate(); } StreamPeerMbedTLS::~StreamPeerMbedTLS() { diff --git a/modules/meshoptimizer/config.py b/modules/meshoptimizer/config.py index 82e4e43397..b7e69569b9 100644 --- a/modules/meshoptimizer/config.py +++ b/modules/meshoptimizer/config.py @@ -1,6 +1,6 @@ def can_build(env, platform): # Having this on release by default, it's small and a lot of users like to do procedural stuff - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 24ec206191..2cc974322d 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -35,7 +35,7 @@ #include "audio_stream_mp3.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" void AudioStreamPlaybackMP3::_mix_internal(AudioFrame *p_buffer, int p_frames) { ERR_FAIL_COND(!active); @@ -126,7 +126,7 @@ Ref<AudioStreamPlayback> AudioStreamMP3::instance_playback() { "to it. AudioStreamMP3 should not be created from the " "inspector or with `.new()`. Instead, load an audio file."); - mp3s.instance(); + mp3s.instantiate(); mp3s->mp3_stream = Ref<AudioStreamMP3>(this); mp3s->mp3d = (mp3dec_ex_t *)memalloc(sizeof(mp3dec_ex_t)); diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml index 92e777ca0f..5507329a18 100644 --- a/modules/minimp3/doc_classes/AudioStreamMP3.xml +++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()"> Contains the audio data in bytes. </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp index 4ab4c743d6..27ea512b69 100644 --- a/modules/minimp3/register_types.cpp +++ b/modules/minimp3/register_types.cpp @@ -41,7 +41,7 @@ void register_minimp3_types() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { Ref<ResourceImporterMP3> mp3_import; - mp3_import.instance(); + mp3_import.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(mp3_import); } #endif diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp index f5137965da..dc360c12ba 100644 --- a/modules/minimp3/resource_importer_mp3.cpp +++ b/modules/minimp3/resource_importer_mp3.cpp @@ -30,8 +30,8 @@ #include "resource_importer_mp3.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "scene/resources/texture.h" String ResourceImporterMP3::get_importer_name() const { @@ -90,7 +90,7 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s memdelete(f); Ref<AudioStreamMP3> mp3_stream; - mp3_stream.instance(); + mp3_stream.instantiate(); mp3_stream->set_data(data); ERR_FAIL_COND_V(!mp3_stream->get_data().size(), ERR_FILE_CORRUPT); diff --git a/modules/mobile_vr/config.py b/modules/mobile_vr/config.py index ee401c1a2a..f6b64fb690 100644 --- a/modules/mobile_vr/config.py +++ b/modules/mobile_vr/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp index 5140cfbbaf..590b95ab79 100644 --- a/modules/mobile_vr/mobile_vr_interface.cpp +++ b/modules/mobile_vr/mobile_vr_interface.cpp @@ -185,8 +185,8 @@ void MobileVRInterface::set_position_from_sensors() { // if you have a gyro + accelerometer that combo tends to be better than combining all three but without a gyro you need the magnetometer.. if (has_magneto && has_grav && !has_gyro) { // convert to quaternions, easier to smooth those out - Quat transform_quat(orientation); - Quat acc_mag_quat(combine_acc_mag(grav, magneto)); + Quaternion transform_quat(orientation); + Quaternion acc_mag_quat(combine_acc_mag(grav, magneto)); transform_quat = transform_quat.slerp(acc_mag_quat, 0.1); orientation = Basis(transform_quat); @@ -300,9 +300,9 @@ real_t MobileVRInterface::get_k2() const { return k2; }; -bool MobileVRInterface::is_stereo() { +uint32_t MobileVRInterface::get_view_count() { // needs stereo... - return true; + return 2; }; bool MobileVRInterface::is_initialized() const { @@ -361,10 +361,32 @@ Size2 MobileVRInterface::get_render_targetsize() { return target_size; }; -Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { +Transform3D MobileVRInterface::get_camera_transform() { _THREAD_SAFE_METHOD_ - Transform transform_for_eye; + Transform3D transform_for_eye; + + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, transform_for_eye); + + if (initialized) { + float world_scale = xr_server->get_world_scale(); + + // just scale our origin point of our transform + Transform3D hmd_transform; + hmd_transform.basis = orientation; + hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0); + + transform_for_eye = (xr_server->get_reference_frame()) * hmd_transform; + } + + return transform_for_eye; +}; + +Transform3D MobileVRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + _THREAD_SAFE_METHOD_ + + Transform3D transform_for_eye; XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, transform_for_eye); @@ -374,16 +396,16 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons // we don't need to check for the existence of our HMD, doesn't affect our values... // note * 0.01 to convert cm to m and * 0.5 as we're moving half in each direction... - if (p_eye == XRInterface::EYE_LEFT) { + if (p_view == 0) { transform_for_eye.origin.x = -(intraocular_dist * 0.01 * 0.5 * world_scale); - } else if (p_eye == XRInterface::EYE_RIGHT) { + } else if (p_view == 1) { transform_for_eye.origin.x = intraocular_dist * 0.01 * 0.5 * world_scale; } else { - // for mono we don't reposition, we want our center position. + // should not have any other values.. }; // just scale our origin point of our transform - Transform hmd_transform; + Transform3D hmd_transform; hmd_transform.basis = orientation; hmd_transform.origin = Vector3(0.0, eye_height * world_scale, 0.0); @@ -396,21 +418,13 @@ Transform MobileVRInterface::get_transform_for_eye(XRInterface::Eyes p_eye, cons return transform_for_eye; }; -CameraMatrix MobileVRInterface::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { _THREAD_SAFE_METHOD_ CameraMatrix eye; - if (p_eye == XRInterface::EYE_MONO) { - ///@TODO for now hardcode some of this, what is really needed here is that this needs to be in sync with the real camera's properties - // which probably means implementing a specific class for iOS and Android. For now this is purely here as an example. - // Note also that if you use a normal viewport with AR/VR turned off you can still use the tracker output of this interface - // to position a stock standard Godot camera and have control over this. - // This will make more sense when we implement ARkit on iOS (probably a separate interface). - eye.set_perspective(60.0, p_aspect, p_z_near, p_z_far, false); - } else { - eye.set_for_hmd(p_eye == XRInterface::EYE_LEFT ? 1 : 2, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far); - }; + aspect = p_aspect; + eye.set_for_hmd(p_view + 1, p_aspect, intraocular_dist, display_width, display_to_lens, oversample, p_z_near, p_z_far); return eye; }; @@ -440,6 +454,45 @@ void MobileVRInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_tar eye_center.y = 0.0; } +Vector<BlitToScreen> MobileVRInterface::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { + _THREAD_SAFE_METHOD_ + + Vector<BlitToScreen> blit_to_screen; + + // We must have a valid render target + ERR_FAIL_COND_V(!p_render_target.is_valid(), blit_to_screen); + + // Because we are rendering to our device we must use our main viewport! + ERR_FAIL_COND_V(p_screen_rect == Rect2(), blit_to_screen); + + // and add our blits + BlitToScreen blit; + blit.render_target = p_render_target; + blit.multi_view.use_layer = true; + blit.lens_distortion.apply = true; + blit.lens_distortion.k1 = k1; + blit.lens_distortion.k2 = k2; + blit.lens_distortion.upscale = oversample; + blit.lens_distortion.aspect_ratio = aspect; + + // left eye + blit.rect = p_screen_rect; + blit.rect.size.width *= 0.5; + blit.multi_view.layer = 0; + blit.lens_distortion.eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0); + blit_to_screen.push_back(blit); + + // right eye + blit.rect = p_screen_rect; + blit.rect.size.width *= 0.5; + blit.rect.position.x = blit.rect.size.width; + blit.multi_view.layer = 1; + blit.lens_distortion.eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0); + blit_to_screen.push_back(blit); + + return blit_to_screen; +} + void MobileVRInterface::process() { _THREAD_SAFE_METHOD_ diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h index d28c2196af..29ce0f92c8 100644 --- a/modules/mobile_vr/mobile_vr_interface.h +++ b/modules/mobile_vr/mobile_vr_interface.h @@ -63,9 +63,9 @@ private: real_t display_to_lens = 4.0; real_t oversample = 1.5; - //@TODO not yet used, these are needed in our distortion shader... real_t k1 = 0.215; real_t k2 = 0.215; + real_t aspect = 1.0; /* logic for processing our sensor data, this was originally in our positional tracker logic but I think @@ -138,16 +138,20 @@ public: virtual void uninitialize() override; virtual Size2 get_render_targetsize() override; - virtual bool is_stereo() override; - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; - virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; + virtual uint32_t get_view_count() override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; virtual void process() override; virtual void notification(int p_what) override {} MobileVRInterface(); ~MobileVRInterface(); + + // deprecated + virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; }; #endif // !MOBILE_VR_INTERFACE_H diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp index e7d33ba8a7..7d138aa4c9 100644 --- a/modules/mobile_vr/register_types.cpp +++ b/modules/mobile_vr/register_types.cpp @@ -37,7 +37,7 @@ void register_mobile_vr_types() { if (XRServer::get_singleton()) { Ref<MobileVRInterface> mobile_vr; - mobile_vr.instance(); + mobile_vr.instantiate(); XRServer::get_singleton()->add_interface(mobile_vr); } } diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py index 309abfbff7..8e441e7e07 100644 --- a/modules/mono/build_scripts/mono_configure.py +++ b/modules/mono/build_scripts/mono_configure.py @@ -101,12 +101,6 @@ def configure(env, env_mono): mono_lib_names = ["mono-2.0-sgen", "monosgen-2.0"] - is_travis = os.environ.get("TRAVIS") == "true" - - if is_travis: - # Travis CI may have a Mono version lower than 5.12 - env_mono.Append(CPPDEFINES=["NO_PENDING_EXCEPTIONS"]) - if is_android and not env["android_arch"] in android_arch_dirs: raise RuntimeError("This module does not support the specified 'android_arch': " + env["android_arch"]) diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp index 553c6eca53..25193a1352 100644 --- a/modules/mono/class_db_api_json.cpp +++ b/modules/mono/class_db_api_json.cpp @@ -33,8 +33,8 @@ #ifdef DEBUG_METHODS_ENABLED #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/json.h" -#include "core/os/file_access.h" #include "core/version.h" void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { @@ -240,7 +240,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) { FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE); ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'."); - f->store_string(JSON::print(classes_dict, /*indent: */ "\t")); + JSON json; + f->store_string(json.stringify(classes_dict, "\t")); f->close(); print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file)); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index b6a7a7579c..ff6a47f59b 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -37,8 +37,7 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/io/json.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/mutex.h" #include "core/os/os.h" #include "core/os/thread.h" @@ -376,7 +375,7 @@ Ref<Script> CSharpLanguage::get_template(const String &p_class_name, const Strin .replace("%CLASS%", class_name_no_spaces); Ref<CSharpScript> script; - script.instance(); + script.instantiate(); script->set_source_code(script_template); script->set_name(class_name_no_spaces); @@ -496,10 +495,10 @@ static String variant_type_to_managed_name(const String &p_var_type_name) { Variant::VECTOR3I, Variant::TRANSFORM2D, Variant::PLANE, - Variant::QUAT, + Variant::QUATERNION, Variant::AABB, Variant::BASIS, - Variant::TRANSFORM, + Variant::TRANSFORM3D, Variant::COLOR, Variant::STRING_NAME, Variant::NODE_PATH, @@ -863,13 +862,13 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { List<Ref<CSharpScript>> to_reload; // We need to keep reference instances alive during reloading - List<Ref<Reference>> ref_instances; + List<Ref<RefCounted>> rc_instances; for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) { CSharpScriptBinding &script_binding = E->value(); - Reference *ref = Object::cast_to<Reference>(script_binding.owner); - if (ref) { - ref_instances.push_back(Ref<Reference>(ref)); + RefCounted *rc = Object::cast_to<RefCounted>(script_binding.owner); + if (rc) { + rc_instances.push_back(Ref<RefCounted>(rc)); } } @@ -892,9 +891,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { Object *obj = F->get(); script->pending_reload_instances.insert(obj->get_instance_id()); - Reference *ref = Object::cast_to<Reference>(obj); - if (ref) { - ref_instances.push_back(Ref<Reference>(ref)); + RefCounted *rc = Object::cast_to<RefCounted>(obj); + if (rc) { + rc_instances.push_back(Ref<RefCounted>(rc)); } } @@ -903,9 +902,9 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) { Object *obj = F->get()->get_owner(); script->pending_reload_instances.insert(obj->get_instance_id()); - Reference *ref = Object::cast_to<Reference>(obj); - if (ref) { - ref_instances.push_back(Ref<Reference>(ref)); + RefCounted *rc = Object::cast_to<RefCounted>(obj); + if (rc) { + rc_instances.push_back(Ref<RefCounted>(rc)); } } #endif @@ -1438,16 +1437,16 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b r_script_binding.owner = p_object; // Tie managed to unmanaged - Reference *ref = Object::cast_to<Reference>(p_object); + RefCounted *rc = Object::cast_to<RefCounted>(p_object); - if (ref) { + if (rc) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) + // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) - ref->reference(); - CSharpLanguage::get_singleton()->post_unsafe_reference(ref); + rc->reference(); + CSharpLanguage::get_singleton()->post_unsafe_reference(rc); } return true; @@ -1511,10 +1510,11 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) { } void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { - Reference *ref_owner = Object::cast_to<Reference>(p_object); +#if 0 + RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object); #ifdef DEBUG_ENABLED - CRASH_COND(!ref_owner); + CRASH_COND(!rc_owner); CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif @@ -1528,7 +1528,7 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { return; } - if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 GD_MONO_SCOPE_THREAD_ATTACH; // The reference count was increased after the managed side was the only one referencing our owner. @@ -1545,13 +1545,15 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) { gchandle.release(); gchandle = strong_gchandle; } +#endif } bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { - Reference *ref_owner = Object::cast_to<Reference>(p_object); +#if 0 + RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object); #ifdef DEBUG_ENABLED - CRASH_COND(!ref_owner); + CRASH_COND(!rc_owner); CRASH_COND(!p_object->has_script_instance_binding(get_language_index())); #endif @@ -1561,7 +1563,7 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); MonoGCHandleData &gchandle = script_binding.gchandle; - int refcount = ref_owner->reference_get_count(); + int refcount = rc_owner->reference_get_count(); if (!script_binding.inited) { return refcount == 0; @@ -1587,18 +1589,20 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) { } return refcount == 0; +#endif + return false; } CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) { CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(p_script))); - Reference *ref = Object::cast_to<Reference>(p_owner); + RefCounted *rc = Object::cast_to<RefCounted>(p_owner); - instance->base_ref = ref != nullptr; + instance->base_ref_counted = rc != nullptr; instance->owner = p_owner; instance->gchandle = p_gchandle; - if (instance->base_ref) { + if (instance->base_ref_counted) { instance->_reference_owner_unsafe(); } @@ -1900,7 +1904,7 @@ Variant CSharpInstance::call(const StringName &p_method, const Variant **p_args, bool CSharpInstance::_reference_owner_unsafe() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); CRASH_COND(unsafe_referenced); // already referenced #endif @@ -1911,7 +1915,7 @@ bool CSharpInstance::_reference_owner_unsafe() { // See: _unreference_owner_unsafe() // May not me referenced yet, so we must use init_ref() instead of reference() - if (static_cast<Reference *>(owner)->init_ref()) { + if (static_cast<RefCounted *>(owner)->init_ref()) { CSharpLanguage::get_singleton()->post_unsafe_reference(owner); unsafe_referenced = true; } @@ -1921,7 +1925,7 @@ bool CSharpInstance::_reference_owner_unsafe() { bool CSharpInstance::_unreference_owner_unsafe() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); #endif @@ -1938,7 +1942,7 @@ bool CSharpInstance::_unreference_owner_unsafe() { // Destroying the owner here means self destructing, so we defer the owner destruction to the caller. CSharpLanguage::get_singleton()->pre_unsafe_unreference(owner); - return static_cast<Reference *>(owner)->unreference(); + return static_cast<RefCounted *>(owner)->unreference(); } MonoObject *CSharpInstance::_internal_new_managed() { @@ -1970,7 +1974,7 @@ MonoObject *CSharpInstance::_internal_new_managed() { // Tie managed to unmanaged gchandle = MonoGCHandleData::new_strong_handle(mono_object); - if (base_ref) { + if (base_ref_counted) { _reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback) } @@ -1987,7 +1991,7 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) { disconnect_event_signals(); #ifdef DEBUG_ENABLED - CRASH_COND(base_ref); + CRASH_COND(base_ref_counted); CRASH_COND(gchandle.is_released()); #endif CSharpLanguage::get_singleton()->release_script_gchandle(p_obj, gchandle); @@ -1995,7 +1999,7 @@ void CSharpInstance::mono_object_disposed(MonoObject *p_obj) { void CSharpInstance::mono_object_disposed_baseref(MonoObject *p_obj, bool p_is_finalizer, bool &r_delete_owner, bool &r_remove_script_instance) { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(gchandle.is_released()); #endif @@ -2056,13 +2060,13 @@ void CSharpInstance::disconnect_event_signals() { void CSharpInstance::refcount_incremented() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); #endif - Reference *ref_owner = Object::cast_to<Reference>(owner); + RefCounted *rc_owner = Object::cast_to<RefCounted>(owner); - if (ref_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 + if (rc_owner->reference_get_count() > 1 && gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 GD_MONO_SCOPE_THREAD_ATTACH; // The reference count was increased after the managed side was the only one referencing our owner. @@ -2078,13 +2082,13 @@ void CSharpInstance::refcount_incremented() { bool CSharpInstance::refcount_decremented() { #ifdef DEBUG_ENABLED - CRASH_COND(!base_ref); + CRASH_COND(!base_ref_counted); CRASH_COND(owner == nullptr); #endif - Reference *ref_owner = Object::cast_to<Reference>(owner); + RefCounted *rc_owner = Object::cast_to<RefCounted>(owner); - int refcount = ref_owner->reference_get_count(); + int refcount = rc_owner->reference_get_count(); if (refcount == 1 && !gchandle.is_weak()) { // The managed side also holds a reference, hence 1 instead of 0 GD_MONO_SCOPE_THREAD_ATTACH; @@ -2105,46 +2109,10 @@ bool CSharpInstance::refcount_decremented() { return ref_dying; } -Vector<ScriptNetData> CSharpInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> CSharpInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t CSharpInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName CSharpInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { - return script->get_rpc_method(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - return script->get_rpc_mode_by_id(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> CSharpInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t CSharpInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName CSharpInstance::get_rset_property(const uint16_t p_rset_member_id) const { - return script->get_rset_property(p_rset_member_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - return script->get_rset_mode_by_id(p_rset_member_id); -} - -MultiplayerAPI::RPCMode CSharpInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - void CSharpInstance::notification(int p_notification) { GD_MONO_SCOPE_THREAD_ATTACH; @@ -2155,12 +2123,12 @@ void CSharpInstance::notification(int p_notification) { predelete_notified = true; - if (base_ref) { - // It's not safe to proceed if the owner derives Reference and the refcount reached 0. + if (base_ref_counted) { + // It's not safe to proceed if the owner derives RefCounted and the refcount reached 0. // At this point, Dispose() was already called (manually or from the finalizer) so // that's not a problem. The refcount wouldn't have reached 0 otherwise, since the // managed side references it and Dispose() needs to be called to release it. - // However, this means C# Reference scripts can't receive NOTIFICATION_PREDELETE, but + // However, this means C# RefCounted scripts can't receive NOTIFICATION_PREDELETE, but // this is likely the case with GDScript as well: https://github.com/godotengine/godot/issues/6784 return; } @@ -2286,23 +2254,25 @@ CSharpInstance::~CSharpInstance() { } // If not being called from the owner's destructor, and we still hold a reference to the owner - if (base_ref && !ref_dying && owner && unsafe_referenced) { + if (base_ref_counted && !ref_dying && owner && unsafe_referenced) { // The owner's script or script instance is being replaced (or removed) // Transfer ownership to an "instance binding" - Reference *ref_owner = static_cast<Reference *>(owner); + RefCounted *rc_owner = static_cast<RefCounted *>(owner); // We will unreference the owner before referencing it again, so we need to keep it alive - Ref<Reference> scope_keep_owner_alive(ref_owner); + Ref<RefCounted> scope_keep_owner_alive(rc_owner); (void)scope_keep_owner_alive; // Unreference the owner here, before the new "instance binding" references it. // Otherwise, the unsafe reference debug checks will incorrectly detect a bug. bool die = _unreference_owner_unsafe(); CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die - +#if 0 void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + + CRASH_COND(data == nullptr); CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -2319,7 +2289,8 @@ CSharpInstance::~CSharpInstance() { #ifdef DEBUG_ENABLED // The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope - CRASH_COND(ref_owner->reference_get_count() <= 1); + CRASH_COND(rc_owner->reference_get_count() <= 1); +#endif #endif } @@ -2406,7 +2377,7 @@ void CSharpScript::_update_member_info_no_exports() { } #endif -bool CSharpScript::_update_exports() { +bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_update) { #ifdef TOOLS_ENABLED bool is_editor = Engine::get_singleton()->is_editor_hint(); if (is_editor) { @@ -2547,7 +2518,7 @@ bool CSharpScript::_update_exports() { #ifdef TOOLS_ENABLED if (is_editor) { // Need to check this here, before disposal - bool base_ref = Object::cast_to<Reference>(tmp_native) != nullptr; + bool base_ref_counted = Object::cast_to<RefCounted>(tmp_native) != nullptr; // Dispose the temporary managed instance @@ -2562,7 +2533,7 @@ bool CSharpScript::_update_exports() { GDMonoUtils::free_gchandle(tmp_pinned_gchandle); tmp_object = nullptr; - if (tmp_native && !base_ref) { + if (tmp_native && !base_ref_counted) { Node *node = Object::cast_to<Node>(tmp_native); if (node && node->is_inside_tree()) { ERR_PRINT("Temporary instance was added to the scene tree."); @@ -2578,14 +2549,18 @@ bool CSharpScript::_update_exports() { if (is_editor) { placeholder_fallback_enabled = false; - if (placeholders.size()) { + if ((changed || p_instance_to_update) && placeholders.size()) { // Update placeholders if any Map<StringName, Variant> values; List<PropertyInfo> propnames; _update_exports_values(values, propnames); - for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { - E->get()->update(propnames, values); + if (changed) { + for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) { + E->get()->update(propnames, values); + } + } else { + p_instance_to_update->update(propnames, values); } } } @@ -3046,7 +3021,6 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { p_script->script_class->fetch_methods_with_godot_api_checks(p_script->native); p_script->rpc_functions.clear(); - p_script->rpc_variables.clear(); GDMonoClass *top = p_script->script_class; while (top && top != p_script->native) { @@ -3060,9 +3034,12 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { if (!methods[i]->is_static()) { MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(methods[i]); if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = methods[i]->get_name(); - nd.mode = mode; + nd.rpc_mode = mode; + // TODO Transfer mode, channel + nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; + nd.channel = 0; if (-1 == p_script->rpc_functions.find(nd)) { p_script->rpc_functions.push_back(nd); } @@ -3071,51 +3048,16 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) { } } - { - Vector<GDMonoField *> fields = top->get_all_fields(); - for (int i = 0; i < fields.size(); i++) { - if (!fields[i]->is_static()) { - MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(fields[i]); - if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - ScriptNetData nd; - nd.name = fields[i]->get_name(); - nd.mode = mode; - if (-1 == p_script->rpc_variables.find(nd)) { - p_script->rpc_variables.push_back(nd); - } - } - } - } - } - - { - Vector<GDMonoProperty *> properties = top->get_all_properties(); - for (int i = 0; i < properties.size(); i++) { - if (!properties[i]->is_static()) { - MultiplayerAPI::RPCMode mode = p_script->_member_get_rpc_mode(properties[i]); - if (MultiplayerAPI::RPC_MODE_DISABLED != mode) { - ScriptNetData nd; - nd.name = properties[i]->get_name(); - nd.mode = mode; - if (-1 == p_script->rpc_variables.find(nd)) { - p_script->rpc_variables.push_back(nd); - } - } - } - } - } - top = top->get_parent_class(); } // Sort so we are 100% that they are always the same. - p_script->rpc_functions.sort_custom<SortNetData>(); - p_script->rpc_variables.sort_custom<SortNetData>(); + p_script->rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); p_script->load_script_signals(p_script->script_class, p_script->native); } -bool CSharpScript::can_instance() const { +bool CSharpScript::can_instantiate() const { #ifdef TOOLS_ENABLED bool extra_cond = tool || ScriptServer::is_scripting_enabled(); #else @@ -3146,7 +3088,7 @@ StringName CSharpScript::get_instance_base_type() const { } } -CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error) { +CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error) { GD_MONO_ASSERT_THREAD_ATTACHED; /* STEP 1, CREATE */ @@ -3162,12 +3104,12 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg ERR_FAIL_V_MSG(nullptr, "Constructor not found."); } - Ref<Reference> ref; - if (p_isref) { + Ref<RefCounted> ref; + if (p_is_ref_counted) { // Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance. - ref = Ref<Reference>(static_cast<Reference *>(p_owner)); + ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner)); } - +#if 0 // If the object had a script instance binding, dispose it before adding the CSharpInstance if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) { void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); @@ -3189,9 +3131,9 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg script_binding.inited = false; } } - +#endif CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this))); - instance->base_ref = p_isref; + instance->base_ref_counted = p_is_ref_counted; instance->owner = p_owner; instance->owner->set_script_instance(instance); @@ -3216,7 +3158,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg // Tie managed to unmanaged instance->gchandle = MonoGCHandleData::new_strong_handle(mono_object); - if (instance->base_ref) { + if (instance->base_ref_counted) { instance->_reference_owner_unsafe(); // Here, after assigning the gchandle (for the refcount_incremented callback) } @@ -3248,10 +3190,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal GD_MONO_SCOPE_THREAD_ATTACH; - Object *owner = ClassDB::instance(NATIVE_GDMONOCLASS_NAME(native)); + Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native)); REF ref; - Reference *r = Object::cast_to<Reference>(owner); + RefCounted *r = Object::cast_to<RefCounted>(owner); if (r) { ref = REF(r); } @@ -3282,24 +3224,24 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) { if (EngineDebugger::is_active()) { CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + String(native_name) + - "', so it can't be instanced in object of type: '" + p_this->get_class() + "'"); + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'"); } ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(native_name) + - "', so it can't be instanced in object of type: '" + p_this->get_class() + "'."); + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'."); } } GD_MONO_SCOPE_THREAD_ATTACH; Callable::CallError unchecked_error; - return _create_instance(nullptr, 0, p_this, Object::cast_to<Reference>(p_this) != nullptr, unchecked_error); + return _create_instance(nullptr, 0, p_this, Object::cast_to<RefCounted>(p_this) != nullptr, unchecked_error); } PlaceHolderScriptInstance *CSharpScript::placeholder_instance_create(Object *p_this) { #ifdef TOOLS_ENABLED PlaceHolderScriptInstance *si = memnew(PlaceHolderScriptInstance(CSharpLanguage::get_singleton(), Ref<Script>(this), p_this)); placeholders.insert(si); - _update_exports(); + _update_exports(si); return si; #else return nullptr; @@ -3543,60 +3485,10 @@ MultiplayerAPI::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_m return MultiplayerAPI::RPC_MODE_DISABLED; } -Vector<ScriptNetData> CSharpScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> CSharpScript::get_rpc_methods() const { return rpc_functions; } -uint16_t CSharpScript::get_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < rpc_functions.size(); i++) { - if (rpc_functions[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName CSharpScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName()); - return rpc_functions[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rpc_mode(const StringName &p_method) const { - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> CSharpScript::get_rset_properties() const { - return rpc_variables; -} - -uint16_t CSharpScript::get_rset_property_id(const StringName &p_variable) const { - for (int i = 0; i < rpc_variables.size(); i++) { - if (rpc_variables[i].name == p_variable) { - return i; - } - } - return UINT16_MAX; -} - -StringName CSharpScript::get_rset_property(const uint16_t p_rset_member_id) const { - ERR_FAIL_COND_V(p_rset_member_id >= rpc_variables.size(), StringName()); - return rpc_variables[p_rset_member_id].name; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rset_mode_by_id(const uint16_t p_rset_member_id) const { - ERR_FAIL_COND_V(p_rset_member_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rset_member_id].mode; -} - -MultiplayerAPI::RPCMode CSharpScript::get_rset_mode(const StringName &p_variable) const { - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - Error CSharpScript::load_source_code(const String &p_path) { Error ferr = read_all_file_utf8(p_path, source); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 992c7e93c8..da6b60aee2 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -136,8 +136,7 @@ private: Map<StringName, EventSignal> event_signals; bool signals_invalidated = true; - Vector<ScriptNetData> rpc_functions; - Vector<ScriptNetData> rpc_variables; + Vector<MultiplayerAPI::RPCConfig> rpc_functions; #ifdef TOOLS_ENABLED List<PropertyInfo> exported_members_cache; // members_cache @@ -164,14 +163,14 @@ private: void load_script_signals(GDMonoClass *p_class, GDMonoClass *p_native_class); bool _get_signal(GDMonoClass *p_class, GDMonoMethod *p_delegate_invoke, Vector<SignalParameter> ¶ms); - bool _update_exports(); + bool _update_exports(PlaceHolderScriptInstance *p_instance_to_update = nullptr); bool _get_member_export(IMonoClassMember *p_member, bool p_inspect_export, PropertyInfo &r_prop_info, bool &r_exported); #ifdef TOOLS_ENABLED static int _try_get_member_export_hint(IMonoClassMember *p_member, ManagedType p_type, Variant::Type p_variant_type, bool p_allow_generics, PropertyHint &r_hint, String &r_hint_string); #endif - CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Callable::CallError &r_error); + CSharpInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error); Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error); // Do not use unless you know what you are doing @@ -192,7 +191,7 @@ protected: void _get_property_list(List<PropertyInfo> *p_properties) const; public: - bool can_instance() const override; + bool can_instantiate() const override; StringName get_instance_base_type() const override; ScriptInstance *instance_create(Object *p_this) override; PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this) override; @@ -235,17 +234,7 @@ public: int get_member_line(const StringName &p_member) const override; - Vector<ScriptNetData> get_rpc_methods() const override; - uint16_t get_rpc_method_id(const StringName &p_method) const override; - StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - Vector<ScriptNetData> get_rset_properties() const override; - uint16_t get_rset_property_id(const StringName &p_variable) const override; - StringName get_rset_property(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED bool is_placeholder_fallback_enabled() const override { return placeholder_fallback_enabled; } @@ -262,7 +251,7 @@ class CSharpInstance : public ScriptInstance { friend class CSharpLanguage; Object *owner = nullptr; - bool base_ref = false; + bool base_ref_counted = false; bool ref_dying = false; bool unsafe_referenced = false; bool predelete_notified = false; @@ -322,17 +311,7 @@ public: void refcount_incremented() override; bool refcount_decremented() override; - Vector<ScriptNetData> get_rpc_methods() const override; - uint16_t get_rpc_method_id(const StringName &p_method) const override; - StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - Vector<ScriptNetData> get_rset_properties() const override; - uint16_t get_rset_property_id(const StringName &p_variable) const override; - StringName get_rset_property(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_variable_id) const override; - MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; void notification(int p_notification) override; void _call_notification(int p_notification); @@ -470,15 +449,14 @@ public: /* EDITOR FUNCTIONS */ void get_reserved_words(List<String> *p_words) const override; - bool is_control_flow_keyword(String p_keyword) const; + bool is_control_flow_keyword(String p_keyword) const override; void get_comment_delimiters(List<String> *p_delimiters) const override; void get_string_delimiters(List<String> *p_delimiters) const override; Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const override; bool is_using_templates() override; void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) override; - /* TODO */ bool validate(const String &p_script, int &r_line_error, int &r_col_error, - String &r_test_error, const String &p_path, List<String> *r_functions, - List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override { + /* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions, + List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override { return true; } String validate_path(const String &p_path) const override; diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs index 51055dc9b9..27737c3da0 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildInfo.cs @@ -7,7 +7,7 @@ using Path = System.IO.Path; namespace GodotTools.Build { [Serializable] - public sealed class BuildInfo : Reference // TODO Remove Reference once we have proper serialization + public sealed class BuildInfo : RefCounted // TODO Remove RefCounted once we have proper serialization { public string Solution { get; } public string[] Targets { get; } diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs index 1a1639aac7..c380707587 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs @@ -11,7 +11,7 @@ namespace GodotTools.Build public class BuildOutputView : VBoxContainer, ISerializationListener { [Serializable] - private class BuildIssue : Reference // TODO Remove Reference once we have proper serialization + private class BuildIssue : RefCounted // TODO Remove RefCounted once we have proper serialization { public bool Warning { get; set; } public string File { get; set; } diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 58561c5097..c71c44d79d 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -371,7 +371,7 @@ namespace GodotTools return (ExternalEditorId)editorSettings.GetSetting("mono/editor/external_editor") != ExternalEditorId.None; } - public override bool Build() + public override bool _Build() { return BuildManager.EditorBuildCallback(); } @@ -413,9 +413,9 @@ namespace GodotTools bottomPanelBtn.Icon = MSBuildPanel.BuildOutputView.BuildStateIcon; } - public override void EnablePlugin() + public override void _EnablePlugin() { - base.EnablePlugin(); + base._EnablePlugin(); if (Instance != null) throw new InvalidOperationException(); diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index b48e5df9eb..620b031ddb 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -35,8 +35,8 @@ #include "core/config/engine.h" #include "core/core_constants.h" #include "core/io/compression.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "core/string/ucaps.h" #include "main/main.h" @@ -1260,7 +1260,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str CRASH_COND(itype.cname != name_cache.type_Object); CRASH_COND(!itype.is_instantiable); CRASH_COND(itype.api_type != ClassDB::API_CORE); - CRASH_COND(itype.is_reference); + CRASH_COND(itype.is_ref_counted); CRASH_COND(itype.is_singleton); } @@ -2284,8 +2284,8 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte } if (return_type->is_object_type) { - ptrcall_return_type = return_type->is_reference ? "Ref<Reference>" : return_type->c_type; - initialization = return_type->is_reference ? "" : " = nullptr"; + ptrcall_return_type = return_type->is_ref_counted ? "Ref<RefCounted>" : return_type->c_type; + initialization = return_type->is_ref_counted ? "" : " = nullptr"; } else { ptrcall_return_type = return_type->c_type; } @@ -2520,10 +2520,10 @@ bool BindingsGenerator::_arg_default_value_is_assignable_to_type(const Variant & p_arg_type.name == name_cache.type_NodePath; case Variant::NODE_PATH: return p_arg_type.name == name_cache.type_NodePath; - case Variant::TRANSFORM: case Variant::TRANSFORM2D: + case Variant::TRANSFORM3D: case Variant::BASIS: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::PLANE: case Variant::AABB: case Variant::COLOR: @@ -2600,12 +2600,12 @@ bool BindingsGenerator::_populate_object_type_interfaces() { itype.base_name = ClassDB::get_parent_class(type_cname); itype.is_singleton = Engine::get_singleton()->has_singleton(itype.proxy_name); itype.is_instantiable = class_info->creation_func && !itype.is_singleton; - itype.is_reference = ClassDB::is_parent_class(type_cname, name_cache.type_Reference); - itype.memory_own = itype.is_reference; + itype.is_ref_counted = ClassDB::is_parent_class(type_cname, name_cache.type_RefCounted); + itype.memory_own = itype.is_ref_counted; itype.c_out = "\treturn "; itype.c_out += C_METHOD_UNMANAGED_GET_MANAGED; - itype.c_out += itype.is_reference ? "(%1.ptr());\n" : "(%1);\n"; + itype.c_out += itype.is_ref_counted ? "(%1.ptr());\n" : "(%1);\n"; itype.cs_in = itype.is_singleton ? BINDINGS_PTR_FIELD : "Object." CS_SMETHOD_GETINSTANCE "(%0)"; @@ -2741,7 +2741,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() { imethod.return_type.cname = return_info.class_name; bool bad_reference_hint = !imethod.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE && - ClassDB::is_parent_class(return_info.class_name, name_cache.type_Reference); + ClassDB::is_parent_class(return_info.class_name, name_cache.type_RefCounted); ERR_FAIL_COND_V_MSG(bad_reference_hint, false, String() + "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'." + " Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'."); @@ -3053,28 +3053,25 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar break; case Variant::PLANE: { Plane plane = p_val.operator Plane(); - r_iarg.default_argument = "new Plane(new Vector3(" + plane.normal.operator String() + "), " + rtos(plane.d) + ")"; + r_iarg.default_argument = "new Plane(new Vector3" + plane.normal.operator String() + ", " + rtos(plane.d) + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::AABB: { AABB aabb = p_val.operator ::AABB(); - r_iarg.default_argument = "new AABB(new Vector3(" + aabb.position.operator String() + "), new Vector3(" + aabb.position.operator String() + "))"; + r_iarg.default_argument = "new AABB(new Vector3" + aabb.position.operator String() + ", new Vector3" + aabb.size.operator String() + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::RECT2: { Rect2 rect = p_val.operator Rect2(); - r_iarg.default_argument = "new Rect2(new Vector2(" + rect.position.operator String() + "), new Vector2(" + rect.position.operator String() + "))"; + r_iarg.default_argument = "new Rect2(new Vector2" + rect.position.operator String() + ", new Vector2" + rect.size.operator String() + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::RECT2I: { Rect2i rect = p_val.operator Rect2i(); - r_iarg.default_argument = "new Rect2i(new Vector2i(" + rect.position.operator String() + "), new Vector2i(" + rect.position.operator String() + "))"; + r_iarg.default_argument = "new Rect2i(new Vector2i" + rect.position.operator String() + ", new Vector2i" + rect.size.operator String() + ")"; r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; case Variant::COLOR: - r_iarg.default_argument = "new %s(" + r_iarg.default_argument + ")"; - r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; - break; case Variant::VECTOR2: case Variant::VECTOR2I: case Variant::VECTOR3: @@ -3123,13 +3120,13 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; - case Variant::TRANSFORM: { - Transform transform = p_val.operator Transform(); - if (transform == Transform()) { - r_iarg.default_argument = "Transform.Identity"; + case Variant::TRANSFORM3D: { + Transform3D transform = p_val.operator Transform3D(); + if (transform == Transform3D()) { + r_iarg.default_argument = "Transform3D.Identity"; } else { Basis basis = transform.basis; - r_iarg.default_argument = "new Transform(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")"; + r_iarg.default_argument = "new Transform3D(new Vector3" + basis.get_column(0).operator String() + ", new Vector3" + basis.get_column(1).operator String() + ", new Vector3" + basis.get_column(2).operator String() + ", new Vector3" + transform.origin.operator String() + ")"; } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; @@ -3142,12 +3139,12 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; - case Variant::QUAT: { - Quat quat = p_val.operator Quat(); - if (quat == Quat()) { - r_iarg.default_argument = "Quat.Identity"; + case Variant::QUATERNION: { + Quaternion quaternion = p_val.operator Quaternion(); + if (quaternion == Quaternion()) { + r_iarg.default_argument = "Quaternion.Identity"; } else { - r_iarg.default_argument = "new Quat" + quat.operator String(); + r_iarg.default_argument = "new Quaternion" + quaternion.operator String(); } r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL; } break; @@ -3196,8 +3193,8 @@ void BindingsGenerator::_populate_builtin_type_interfaces() { INSERT_STRUCT_TYPE(Vector3) INSERT_STRUCT_TYPE(Vector3i) INSERT_STRUCT_TYPE(Basis) - INSERT_STRUCT_TYPE(Quat) - INSERT_STRUCT_TYPE(Transform) + INSERT_STRUCT_TYPE(Quaternion) + INSERT_STRUCT_TYPE(Transform3D) INSERT_STRUCT_TYPE(AABB) INSERT_STRUCT_TYPE(Color) INSERT_STRUCT_TYPE(Plane) diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 876046176b..48c0e02723 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -216,7 +216,7 @@ class BindingsGenerator { bool is_enum = false; bool is_object_type = false; bool is_singleton = false; - bool is_reference = false; + bool is_ref_counted = false; /** * Used only by Object-derived types. @@ -228,7 +228,7 @@ class BindingsGenerator { /** * Used only by Object-derived types. * Determines if the C# class owns the native handle and must free it somehow when disposed. - * e.g.: Reference types must notify when the C# instance is disposed, for proper refcounting. + * e.g.: RefCounted types must notify when the C# instance is disposed, for proper refcounting. */ bool memory_own = false; @@ -295,7 +295,7 @@ class BindingsGenerator { * VarArg (fictitious type to represent variable arguments): Array * float: double (because ptrcall only supports double) * int: int64_t (because ptrcall only supports int64_t and uint64_t) - * Reference types override this for the type of the return variable: Ref<Reference> + * RefCounted types override this for the type of the return variable: Ref<RefCounted> */ String c_type; @@ -534,7 +534,7 @@ class BindingsGenerator { StringName type_Variant = StaticCString::create("Variant"); StringName type_VarArg = StaticCString::create("VarArg"); StringName type_Object = StaticCString::create("Object"); - StringName type_Reference = StaticCString::create("Reference"); + StringName type_RefCounted = StaticCString::create("RefCounted"); StringName type_RID = StaticCString::create("RID"); StringName type_String = StaticCString::create("String"); StringName type_StringName = StaticCString::create("StringName"); @@ -623,7 +623,7 @@ class BindingsGenerator { } inline String get_unique_sig(const TypeInterface &p_type) { - if (p_type.is_reference) { + if (p_type.is_ref_counted) { return "Ref"; } else if (p_type.is_object_type) { return "Obj"; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs index 3aecce50f5..2b641a8937 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs @@ -676,7 +676,7 @@ namespace Godot public override string ToString() { - return String.Format("{0} - {1}", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(), _size.ToString() @@ -685,7 +685,7 @@ namespace Godot public string ToString(string format) { - return String.Format("{0} - {1}", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(format), _size.ToString(format) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 3f1120575f..5dbf5d5657 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -207,7 +207,7 @@ namespace Godot } } - public Quat RotationQuat() + public Quaternion RotationQuaternion() { Basis orthonormalizedBasis = Orthonormalized(); real_t det = orthonormalizedBasis.Determinant(); @@ -218,18 +218,18 @@ namespace Godot orthonormalizedBasis = orthonormalizedBasis.Scaled(-Vector3.One); } - return orthonormalizedBasis.Quat(); + return orthonormalizedBasis.Quaternion(); } - internal void SetQuatScale(Quat quat, Vector3 scale) + internal void SetQuaternionScale(Quaternion quaternion, Vector3 scale) { SetDiagonal(scale); - Rotate(quat); + Rotate(quaternion); } - private void Rotate(Quat quat) + private void Rotate(Quaternion quaternion) { - this *= new Basis(quat); + this *= new Basis(quaternion); } private void SetDiagonal(Vector3 diagonal) @@ -263,8 +263,8 @@ namespace Godot /// The returned vector contains the rotation angles in /// the format (X angle, Y angle, Z angle). /// - /// Consider using the <see cref="Basis.Quat()"/> method instead, which - /// returns a <see cref="Godot.Quat"/> quaternion instead of Euler angles. + /// Consider using the <see cref="Basis.Quaternion()"/> method instead, which + /// returns a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles. /// </summary> /// <returns>A Vector3 representing the basis rotation in Euler angles.</returns> public Vector3 GetEuler() @@ -486,8 +486,8 @@ namespace Godot /// <returns>The resulting basis matrix of the interpolation.</returns> public Basis Slerp(Basis target, real_t weight) { - Quat from = new Quat(this); - Quat to = new Quat(target); + Quaternion from = new Quaternion(this); + Quaternion to = new Quaternion(target); Basis b = new Basis(from.Slerp(to, weight)); b.Row0 *= Mathf.Lerp(Row0.Length(), target.Row0.Length(), weight); @@ -588,8 +588,8 @@ namespace Godot /// See <see cref="GetEuler()"/> if you need Euler angles, but keep in /// mind that quaternions should generally be preferred to Euler angles. /// </summary> - /// <returns>A <see cref="Godot.Quat"/> representing the basis's rotation.</returns> - public Quat Quat() + /// <returns>A <see cref="Godot.Quaternion"/> representing the basis's rotation.</returns> + public Quaternion Quaternion() { real_t trace = Row0[0] + Row1[1] + Row2[2]; @@ -597,7 +597,7 @@ namespace Godot { real_t s = Mathf.Sqrt(trace + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row2[1] - Row1[2]) * inv_s, (Row0[2] - Row2[0]) * inv_s, (Row1[0] - Row0[1]) * inv_s, @@ -609,7 +609,7 @@ namespace Godot { real_t s = Mathf.Sqrt(Row0[0] - Row1[1] - Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( s * 0.25f, (Row0[1] + Row1[0]) * inv_s, (Row0[2] + Row2[0]) * inv_s, @@ -621,7 +621,7 @@ namespace Godot { real_t s = Mathf.Sqrt(-Row0[0] + Row1[1] - Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row0[1] + Row1[0]) * inv_s, s * 0.25f, (Row1[2] + Row2[1]) * inv_s, @@ -632,7 +632,7 @@ namespace Godot { real_t s = Mathf.Sqrt(-Row0[0] - Row1[1] + Row2[2] + 1.0f) * 2f; real_t inv_s = 1f / s; - return new Quat( + return new Quaternion( (Row0[2] + Row2[0]) * inv_s, (Row1[2] + Row2[1]) * inv_s, s * 0.25f, @@ -699,23 +699,23 @@ namespace Godot /// <summary> /// Constructs a pure rotation basis matrix from the given quaternion. /// </summary> - /// <param name="quat">The quaternion to create the basis from.</param> - public Basis(Quat quat) + /// <param name="quaternion">The quaternion to create the basis from.</param> + public Basis(Quaternion quaternion) { - real_t s = 2.0f / quat.LengthSquared; + real_t s = 2.0f / quaternion.LengthSquared; - real_t xs = quat.x * s; - real_t ys = quat.y * s; - real_t zs = quat.z * s; - real_t wx = quat.w * xs; - real_t wy = quat.w * ys; - real_t wz = quat.w * zs; - real_t xx = quat.x * xs; - real_t xy = quat.x * ys; - real_t xz = quat.x * zs; - real_t yy = quat.y * ys; - real_t yz = quat.y * zs; - real_t zz = quat.z * zs; + real_t xs = quaternion.x * s; + real_t ys = quaternion.y * s; + real_t zs = quaternion.z * s; + real_t wx = quaternion.w * xs; + real_t wy = quaternion.w * ys; + real_t wz = quaternion.w * zs; + real_t xx = quaternion.x * xs; + real_t xy = quaternion.x * ys; + real_t xz = quaternion.x * zs; + real_t yy = quaternion.y * ys; + real_t yz = quaternion.y * zs; + real_t zz = quaternion.z * zs; Row0 = new Vector3(1.0f - (yy + zz), xy - wz, xz + wy); Row1 = new Vector3(xy + wz, 1.0f - (xx + zz), yz - wx); @@ -727,8 +727,8 @@ namespace Godot /// (in the YXZ convention: when *composing*, first Y, then X, and Z last), /// given in the vector format as (X angle, Y angle, Z angle). /// - /// Consider using the <see cref="Basis(Quat)"/> constructor instead, which - /// uses a <see cref="Godot.Quat"/> quaternion instead of Euler angles. + /// Consider using the <see cref="Basis(Quaternion)"/> constructor instead, which + /// uses a <see cref="Godot.Quaternion"/> quaternion instead of Euler angles. /// </summary> /// <param name="eulerYXZ">The Euler angles to create the basis from.</param> public Basis(Vector3 eulerYXZ) @@ -863,22 +863,16 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - Row0.ToString(), - Row1.ToString(), - Row2.ToString() - }); + return "[X: " + x.ToString() + + ", Y: " + y.ToString() + + ", Z: " + z.ToString() + "]"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - Row0.ToString(format), - Row1.ToString(format), - Row2.ToString(format) - }); + return "[X: " + x.ToString(format) + + ", Y: " + y.ToString(format) + + ", Z: " + z.ToString(format) + "]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index 24b9218197..155ffcff32 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -1010,12 +1010,12 @@ namespace Godot public override string ToString() { - return String.Format("{0},{1},{2},{3}", r.ToString(), g.ToString(), b.ToString(), a.ToString()); + return String.Format("({0}, {1}, {2}, {3})", r.ToString(), g.ToString(), b.ToString(), a.ToString()); } public string ToString(string format) { - return String.Format("{0},{1},{2},{3}", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format)); + return String.Format("({0}, {1}, {2}, {3})", r.ToString(format), g.ToString(format), b.ToString(format), a.ToString(format)); } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs index 763f470504..214bbf5179 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/PackedSceneExtensions.cs @@ -8,9 +8,9 @@ namespace Godot /// `Node.NotificationInstanced` notification on the root node. /// </summary> /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam> - public T Instance<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class + public T Instantiate<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class { - return (T)(object)Instance(editState); + return (T)(object)Instantiate(editState); } /// <summary> @@ -19,9 +19,9 @@ namespace Godot /// `Node.NotificationInstanced` notification on the root node. /// </summary> /// <typeparam name="T">The type to cast to. Should be a descendant of Node.</typeparam> - public T InstanceOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class + public T InstantiateOrNull<T>(PackedScene.GenEditState editState = (PackedScene.GenEditState)0) where T : class { - return Instance(editState) as T; + return Instantiate(editState) as T; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs index 48582d5ad8..d486d79557 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs @@ -66,7 +66,7 @@ namespace Godot if (memoryOwn) { memoryOwn = false; - godot_icall_Reference_Disposed(this, ptr, !disposing); + godot_icall_RefCounted_Disposed(this, ptr, !disposing); } else { @@ -129,7 +129,7 @@ namespace Godot internal static extern void godot_icall_Object_Disposed(Object obj, IntPtr ptr); [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern void godot_icall_Reference_Disposed(Object obj, IntPtr ptr, bool isFinalizer); + internal static extern void godot_icall_RefCounted_Disposed(Object obj, IntPtr ptr, bool isFinalizer); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void godot_icall_Object_ConnectEventSignals(IntPtr obj); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index 2f8b5f297c..ad6ca51e8b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -355,7 +355,7 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _normal.ToString(), D.ToString() @@ -364,7 +364,7 @@ namespace Godot public string ToString(string format) { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _normal.ToString(format), D.ToString(format) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index bd3bcb0c58..817103994a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quat.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -15,7 +15,7 @@ namespace Godot /// It is similar to Basis, which implements matrix representation of /// rotations, and can be parametrized using both an axis-angle pair /// or Euler angles. Basis stores rotation, scale, and shearing, - /// while Quat only stores rotation. + /// while Quaternion only stores rotation. /// /// Due to its compactness and the way it is stored in memory, certain /// operations (obtaining axis-angle and performing SLERP, in particular) @@ -23,7 +23,7 @@ namespace Godot /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] - public struct Quat : IEquatable<Quat> + public struct Quaternion : IEquatable<Quaternion> { /// <summary> /// X component of the quaternion (imaginary `i` axis part). @@ -114,6 +114,23 @@ namespace Godot } /// <summary> + /// Returns the angle between this quaternion and `to`. + /// This is the magnitude of the angle you would need to rotate + /// by to get from one to the other. + /// + /// Note: This method has an abnormally high amount + /// of floating-point error, so methods such as + /// <see cref="Mathf.IsZeroApprox"/> will not work reliably. + /// </summary> + /// <param name="to">The other quaternion.</param> + /// <returns>The angle between the quaternions.</returns> + public real_t AngleTo(Quaternion to) + { + real_t dot = Dot(to); + return Mathf.Acos(Mathf.Clamp(dot * dot * 2 - 1, -1, 1)); + } + + /// <summary> /// Performs a cubic spherical interpolation between quaternions `preA`, /// this vector, `b`, and `postB`, by the given amount `t`. /// </summary> @@ -122,11 +139,11 @@ namespace Godot /// <param name="postB">A quaternion after `b`.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated quaternion.</returns> - public Quat CubicSlerp(Quat b, Quat preA, Quat postB, real_t weight) + public Quaternion CubicSlerp(Quaternion b, Quaternion preA, Quaternion postB, real_t weight) { real_t t2 = (1.0f - weight) * weight * 2f; - Quat sp = Slerp(b, weight); - Quat sq = preA.Slerpni(postB, weight); + Quaternion sp = Slerp(b, weight); + Quaternion sq = preA.Slerpni(postB, weight); return sp.Slerpni(sq, t2); } @@ -135,7 +152,7 @@ namespace Godot /// </summary> /// <param name="b">The other quaternion.</param> /// <returns>The dot product.</returns> - public real_t Dot(Quat b) + public real_t Dot(Quaternion b) { return x * b.x + y * b.y + z * b.z + w * b.w; } @@ -152,7 +169,7 @@ namespace Godot #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif var basis = new Basis(this); @@ -163,15 +180,15 @@ namespace Godot /// Returns the inverse of the quaternion. /// </summary> /// <returns>The inverse quaternion.</returns> - public Quat Inverse() + public Quaternion Inverse() { #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif - return new Quat(-x, -y, -z, w); + return new Quaternion(-x, -y, -z, w); } /// <summary> @@ -187,7 +204,7 @@ namespace Godot /// Returns a copy of the quaternion, normalized to unit length. /// </summary> /// <returns>The normalized quaternion.</returns> - public Quat Normalized() + public Quaternion Normalized() { return this / Length; } @@ -201,12 +218,12 @@ namespace Godot /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quat Slerp(Quat to, real_t weight) + public Quaternion Slerp(Quaternion to, real_t weight) { #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } if (!to.IsNormalized()) { @@ -217,7 +234,7 @@ namespace Godot // Calculate cosine. real_t cosom = x * to.x + y * to.y + z * to.z + w * to.w; - var to1 = new Quat(); + var to1 = new Quaternion(); // Adjust signs if necessary. if (cosom < 0.0) @@ -255,7 +272,7 @@ namespace Godot } // Calculate final values. - return new Quat + return new Quaternion ( scale0 * x + scale1 * to1.x, scale0 * y + scale1 * to1.y, @@ -272,7 +289,7 @@ namespace Godot /// <param name="to">The destination quaternion for interpolation. Must be normalized.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The resulting quaternion of the interpolation.</returns> - public Quat Slerpni(Quat to, real_t weight) + public Quaternion Slerpni(Quaternion to, real_t weight) { real_t dot = Dot(to); @@ -286,7 +303,7 @@ namespace Godot real_t newFactor = Mathf.Sin(weight * theta) * sinT; real_t invFactor = Mathf.Sin((1.0f - weight) * theta) * sinT; - return new Quat + return new Quaternion ( invFactor * x + newFactor * to.x, invFactor * y + newFactor * to.y, @@ -305,7 +322,7 @@ namespace Godot #if DEBUG if (!IsNormalized()) { - throw new InvalidOperationException("Quat is not normalized"); + throw new InvalidOperationException("Quaternion is not normalized"); } #endif var u = new Vector3(x, y, z); @@ -314,15 +331,15 @@ namespace Godot } // Constants - private static readonly Quat _identity = new Quat(0, 0, 0, 1); + private static readonly Quaternion _identity = new Quaternion(0, 0, 0, 1); /// <summary> /// The identity quaternion, representing no rotation. /// Equivalent to an identity <see cref="Basis"/> matrix. If a vector is transformed by /// an identity quaternion, it will not change. /// </summary> - /// <value>Equivalent to `new Quat(0, 0, 0, 1)`.</value> - public static Quat Identity { get { return _identity; } } + /// <value>Equivalent to `new Quaternion(0, 0, 0, 1)`.</value> + public static Quaternion Identity { get { return _identity; } } /// <summary> /// Constructs a quaternion defined by the given values. @@ -331,7 +348,7 @@ namespace Godot /// <param name="y">Y component of the quaternion (imaginary `j` axis part).</param> /// <param name="z">Z component of the quaternion (imaginary `k` axis part).</param> /// <param name="w">W component of the quaternion (real part).</param> - public Quat(real_t x, real_t y, real_t z, real_t w) + public Quaternion(real_t x, real_t y, real_t z, real_t w) { this.x = x; this.y = y; @@ -343,7 +360,7 @@ namespace Godot /// Constructs a quaternion from the given quaternion. /// </summary> /// <param name="q">The existing quaternion.</param> - public Quat(Quat q) + public Quaternion(Quaternion q) { this = q; } @@ -352,9 +369,9 @@ namespace Godot /// Constructs a quaternion from the given <see cref="Basis"/>. /// </summary> /// <param name="basis">The basis to construct from.</param> - public Quat(Basis basis) + public Quaternion(Basis basis) { - this = basis.Quat(); + this = basis.Quaternion(); } /// <summary> @@ -364,7 +381,7 @@ namespace Godot /// given in the vector format as (X angle, Y angle, Z angle). /// </summary> /// <param name="eulerYXZ"></param> - public Quat(Vector3 eulerYXZ) + public Quaternion(Vector3 eulerYXZ) { real_t half_a1 = eulerYXZ.y * 0.5f; real_t half_a2 = eulerYXZ.x * 0.5f; @@ -393,7 +410,7 @@ namespace Godot /// </summary> /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="angle">The angle to rotate, in radians.</param> - public Quat(Vector3 axis, real_t angle) + public Quaternion(Vector3 axis, real_t angle) { #if DEBUG if (!axis.IsNormalized()) @@ -424,9 +441,9 @@ namespace Godot } } - public static Quat operator *(Quat left, Quat right) + public static Quaternion operator *(Quaternion left, Quaternion right) { - return new Quat + return new Quaternion ( left.w * right.x + left.x * right.w + left.y * right.z - left.z * right.y, left.w * right.y + left.y * right.w + left.z * right.x - left.x * right.z, @@ -435,24 +452,24 @@ namespace Godot ); } - public static Quat operator +(Quat left, Quat right) + public static Quaternion operator +(Quaternion left, Quaternion right) { - return new Quat(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); + return new Quaternion(left.x + right.x, left.y + right.y, left.z + right.z, left.w + right.w); } - public static Quat operator -(Quat left, Quat right) + public static Quaternion operator -(Quaternion left, Quaternion right) { - return new Quat(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); + return new Quaternion(left.x - right.x, left.y - right.y, left.z - right.z, left.w - right.w); } - public static Quat operator -(Quat left) + public static Quaternion operator -(Quaternion left) { - return new Quat(-left.x, -left.y, -left.z, -left.w); + return new Quaternion(-left.x, -left.y, -left.z, -left.w); } - public static Quat operator *(Quat left, Vector3 right) + public static Quaternion operator *(Quaternion left, Vector3 right) { - return new Quat + return new Quaternion ( left.w * right.x + left.y * right.z - left.z * right.y, left.w * right.y + left.z * right.x - left.x * right.z, @@ -461,9 +478,9 @@ namespace Godot ); } - public static Quat operator *(Vector3 left, Quat right) + public static Quaternion operator *(Vector3 left, Quaternion right) { - return new Quat + return new Quaternion ( right.w * left.x + right.y * left.z - right.z * left.y, right.w * left.y + right.z * left.x - right.x * left.z, @@ -472,42 +489,42 @@ namespace Godot ); } - public static Quat operator *(Quat left, real_t right) + public static Quaternion operator *(Quaternion left, real_t right) { - return new Quat(left.x * right, left.y * right, left.z * right, left.w * right); + return new Quaternion(left.x * right, left.y * right, left.z * right, left.w * right); } - public static Quat operator *(real_t left, Quat right) + public static Quaternion operator *(real_t left, Quaternion right) { - return new Quat(right.x * left, right.y * left, right.z * left, right.w * left); + return new Quaternion(right.x * left, right.y * left, right.z * left, right.w * left); } - public static Quat operator /(Quat left, real_t right) + public static Quaternion operator /(Quaternion left, real_t right) { return left * (1.0f / right); } - public static bool operator ==(Quat left, Quat right) + public static bool operator ==(Quaternion left, Quaternion right) { return left.Equals(right); } - public static bool operator !=(Quat left, Quat right) + public static bool operator !=(Quaternion left, Quaternion right) { return !left.Equals(right); } public override bool Equals(object obj) { - if (obj is Quat) + if (obj is Quaternion) { - return Equals((Quat)obj); + return Equals((Quaternion)obj); } return false; } - public bool Equals(Quat other) + public bool Equals(Quaternion other) { return x == other.x && y == other.y && z == other.z && w == other.w; } @@ -518,7 +535,7 @@ namespace Godot /// </summary> /// <param name="other">The other quaternion to compare.</param> /// <returns>Whether or not the quaternions are approximately equal.</returns> - public bool IsEqualApprox(Quat other) + public bool IsEqualApprox(Quaternion other) { return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w); } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index 868c3536fe..612fb64a3d 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -405,7 +405,7 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(), _size.ToString() @@ -414,7 +414,7 @@ namespace Godot public string ToString(string format) { - return String.Format("({0}, {1})", new object[] + return String.Format("{0}, {1}", new object[] { _position.ToString(format), _size.ToString(format) diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index bc0f81b2a7..fe93592667 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -492,22 +492,16 @@ namespace Godot public override string ToString() { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(), - y.ToString(), - origin.ToString() - }); + return "[X: " + x.ToString() + + ", Y: " + y.ToString() + + ", O: " + origin.ToString() + "]"; } public string ToString(string format) { - return String.Format("({0}, {1}, {2})", new object[] - { - x.ToString(format), - y.ToString(format), - origin.ToString(format) - }); + return "[X: " + x.ToString(format) + + ", Y: " + y.ToString(format) + + ", O: " + origin.ToString(format) + "]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index ac47f6029f..26b1a9e8b2 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -19,7 +19,7 @@ namespace Godot /// </summary> [Serializable] [StructLayout(LayoutKind.Sequential)] - public struct Transform : IEquatable<Transform> + public struct Transform3D : IEquatable<Transform3D> { /// <summary> /// The <see cref="Basis"/> of this transform. Contains the X, Y, and Z basis @@ -107,10 +107,10 @@ namespace Godot /// the transformation is composed of rotation, scaling, and translation. /// </summary> /// <returns>The inverse transformation matrix.</returns> - public Transform AffineInverse() + public Transform3D AffineInverse() { Basis basisInv = basis.Inverse(); - return new Transform(basisInv, basisInv.Xform(-origin)); + return new Transform3D(basisInv, basisInv.Xform(-origin)); } /// <summary> @@ -119,20 +119,20 @@ namespace Godot /// <param name="transform">The other transform.</param> /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param> /// <returns>The interpolated transform.</returns> - public Transform InterpolateWith(Transform transform, real_t weight) + public Transform3D InterpolateWith(Transform3D transform, real_t weight) { /* not sure if very "efficient" but good enough? */ Vector3 sourceScale = basis.Scale; - Quat sourceRotation = basis.RotationQuat(); + Quaternion sourceRotation = basis.RotationQuaternion(); Vector3 sourceLocation = origin; Vector3 destinationScale = transform.basis.Scale; - Quat destinationRotation = transform.basis.RotationQuat(); + Quaternion destinationRotation = transform.basis.RotationQuaternion(); Vector3 destinationLocation = transform.origin; - var interpolated = new Transform(); - interpolated.basis.SetQuatScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight)); + var interpolated = new Transform3D(); + interpolated.basis.SetQuaternionScale(sourceRotation.Slerp(destinationRotation, weight).Normalized(), sourceScale.Lerp(destinationScale, weight)); interpolated.origin = sourceLocation.Lerp(destinationLocation, weight); return interpolated; @@ -144,10 +144,10 @@ namespace Godot /// (no scaling, use <see cref="AffineInverse"/> for transforms with scaling). /// </summary> /// <returns>The inverse matrix.</returns> - public Transform Inverse() + public Transform3D Inverse() { Basis basisTr = basis.Transposed(); - return new Transform(basisTr, basisTr.Xform(-origin)); + return new Transform3D(basisTr, basisTr.Xform(-origin)); } /// <summary> @@ -163,7 +163,7 @@ namespace Godot /// <param name="target">The object to look at.</param> /// <param name="up">The relative up direction</param> /// <returns>The resulting transform.</returns> - public Transform LookingAt(Vector3 target, Vector3 up) + public Transform3D LookingAt(Vector3 target, Vector3 up) { var t = this; t.SetLookAt(origin, target, up); @@ -175,9 +175,9 @@ namespace Godot /// and normalized axis vectors (scale of 1 or -1). /// </summary> /// <returns>The orthonormalized transform.</returns> - public Transform Orthonormalized() + public Transform3D Orthonormalized() { - return new Transform(basis.Orthonormalized(), origin); + return new Transform3D(basis.Orthonormalized(), origin); } /// <summary> @@ -187,9 +187,9 @@ namespace Godot /// <param name="axis">The axis to rotate around. Must be normalized.</param> /// <param name="phi">The angle to rotate, in radians.</param> /// <returns>The rotated transformation matrix.</returns> - public Transform Rotated(Vector3 axis, real_t phi) + public Transform3D Rotated(Vector3 axis, real_t phi) { - return new Transform(new Basis(axis, phi), new Vector3()) * this; + return new Transform3D(new Basis(axis, phi), new Vector3()) * this; } /// <summary> @@ -197,9 +197,9 @@ namespace Godot /// </summary> /// <param name="scale">The scale to introduce.</param> /// <returns>The scaled transformation matrix.</returns> - public Transform Scaled(Vector3 scale) + public Transform3D Scaled(Vector3 scale) { - return new Transform(basis.Scaled(scale), origin * scale); + return new Transform3D(basis.Scaled(scale), origin * scale); } private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up) @@ -234,9 +234,9 @@ namespace Godot /// </summary> /// <param name="offset">The offset to translate by.</param> /// <returns>The translated matrix.</returns> - public Transform Translated(Vector3 offset) + public Transform3D Translated(Vector3 offset) { - return new Transform(basis, new Vector3 + return new Transform3D(basis, new Vector3 ( origin[0] += basis.Row0.Dot(offset), origin[1] += basis.Row1.Dot(offset), @@ -280,10 +280,10 @@ namespace Godot } // Constants - private static readonly Transform _identity = new Transform(Basis.Identity, Vector3.Zero); - private static readonly Transform _flipX = new Transform(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); - private static readonly Transform _flipY = new Transform(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); - private static readonly Transform _flipZ = new Transform(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); + private static readonly Transform3D _identity = new Transform3D(Basis.Identity, Vector3.Zero); + private static readonly Transform3D _flipX = new Transform3D(new Basis(-1, 0, 0, 0, 1, 0, 0, 0, 1), Vector3.Zero); + private static readonly Transform3D _flipY = new Transform3D(new Basis(1, 0, 0, 0, -1, 0, 0, 0, 1), Vector3.Zero); + private static readonly Transform3D _flipZ = new Transform3D(new Basis(1, 0, 0, 0, 1, 0, 0, 0, -1), Vector3.Zero); /// <summary> /// The identity transform, with no translation, rotation, or scaling applied. @@ -291,22 +291,22 @@ namespace Godot /// Do not use `new Transform()` with no arguments in C#, because it sets all values to zero. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value> - public static Transform Identity { get { return _identity; } } + public static Transform3D Identity { get { return _identity; } } /// <summary> /// The transform that will flip something along the X axis. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Left, Vector3.Up, Vector3.Back, Vector3.Zero)`.</value> - public static Transform FlipX { get { return _flipX; } } + public static Transform3D FlipX { get { return _flipX; } } /// <summary> /// The transform that will flip something along the Y axis. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Down, Vector3.Back, Vector3.Zero)`.</value> - public static Transform FlipY { get { return _flipY; } } + public static Transform3D FlipY { get { return _flipY; } } /// <summary> /// The transform that will flip something along the Z axis. /// </summary> /// <value>Equivalent to `new Transform(Vector3.Right, Vector3.Up, Vector3.Forward, Vector3.Zero)`.</value> - public static Transform FlipZ { get { return _flipZ; } } + public static Transform3D FlipZ { get { return _flipZ; } } /// <summary> /// Constructs a transformation matrix from 4 vectors (matrix columns). @@ -315,7 +315,7 @@ namespace Godot /// <param name="column1">The Y vector, or column index 1.</param> /// <param name="column2">The Z vector, or column index 2.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) + public Transform3D(Vector3 column0, Vector3 column1, Vector3 column2, Vector3 origin) { basis = new Basis(column0, column1, column2); this.origin = origin; @@ -324,11 +324,11 @@ namespace Godot /// <summary> /// Constructs a transformation matrix from the given quaternion and origin vector. /// </summary> - /// <param name="quat">The <see cref="Godot.Quat"/> to create the basis from.</param> + /// <param name="quaternion">The <see cref="Godot.Quaternion"/> to create the basis from.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Quat quat, Vector3 origin) + public Transform3D(Quaternion quaternion, Vector3 origin) { - basis = new Basis(quat); + basis = new Basis(quaternion); this.origin = origin; } @@ -337,40 +337,40 @@ namespace Godot /// </summary> /// <param name="basis">The <see cref="Godot.Basis"/> to create the basis from.</param> /// <param name="origin">The origin vector, or column index 3.</param> - public Transform(Basis basis, Vector3 origin) + public Transform3D(Basis basis, Vector3 origin) { this.basis = basis; this.origin = origin; } - public static Transform operator *(Transform left, Transform right) + public static Transform3D operator *(Transform3D left, Transform3D right) { left.origin = left.Xform(right.origin); left.basis *= right.basis; return left; } - public static bool operator ==(Transform left, Transform right) + public static bool operator ==(Transform3D left, Transform3D right) { return left.Equals(right); } - public static bool operator !=(Transform left, Transform right) + public static bool operator !=(Transform3D left, Transform3D right) { return !left.Equals(right); } public override bool Equals(object obj) { - if (obj is Transform) + if (obj is Transform3D) { - return Equals((Transform)obj); + return Equals((Transform3D)obj); } return false; } - public bool Equals(Transform other) + public bool Equals(Transform3D other) { return basis.Equals(other.basis) && origin.Equals(other.origin); } @@ -381,7 +381,7 @@ namespace Godot /// </summary> /// <param name="other">The other transform to compare.</param> /// <returns>Whether or not the matrices are approximately equal.</returns> - public bool IsEqualApprox(Transform other) + public bool IsEqualApprox(Transform3D other) { return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin); } @@ -393,20 +393,18 @@ namespace Godot public override string ToString() { - return String.Format("{0} - {1}", new object[] - { - basis.ToString(), - origin.ToString() - }); + return "[X: " + basis.x.ToString() + + ", Y: " + basis.y.ToString() + + ", Z: " + basis.z.ToString() + + ", O: " + origin.ToString() + "]"; } public string ToString(string format) { - return String.Format("{0} - {1}", new object[] - { - basis.ToString(format), - origin.ToString(format) - }); + return "[X: " + basis.x.ToString(format) + + ", Y: " + basis.y.ToString(format) + + ", Z: " + basis.z.ToString(format) + + ", O: " + origin.ToString(format) + "]"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 334c7cd510..af053bd263 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -442,7 +442,7 @@ namespace Godot #if DEBUG if (!normal.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(normal)); + throw new ArgumentException("Argument is not normalized", nameof(normal)); } #endif return 2 * Dot(normal) * normal - this; diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index fe1b3ad3c0..31a9af2d9e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -456,7 +456,7 @@ namespace Godot #if DEBUG if (!normal.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(normal)); + throw new ArgumentException("Argument is not normalized", nameof(normal)); } #endif return 2.0f * Dot(normal) * normal - this; @@ -474,7 +474,7 @@ namespace Godot #if DEBUG if (!axis.IsNormalized()) { - throw new ArgumentException("Argument is not normalized", nameof(axis)); + throw new ArgumentException("Argument is not normalized", nameof(axis)); } #endif return new Basis(axis, phi).Xform(this); diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj index 54aaaf1f92..1fcfe74c86 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj +++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj @@ -50,7 +50,7 @@ <Compile Include="Core\NodePath.cs" /> <Compile Include="Core\Object.base.cs" /> <Compile Include="Core\Plane.cs" /> - <Compile Include="Core\Quat.cs" /> + <Compile Include="Core\Quaternion.cs" /> <Compile Include="Core\Rect2.cs" /> <Compile Include="Core\Rect2i.cs" /> <Compile Include="Core\RID.cs" /> @@ -58,8 +58,8 @@ <Compile Include="Core\SignalAwaiter.cs" /> <Compile Include="Core\StringExtensions.cs" /> <Compile Include="Core\StringName.cs" /> - <Compile Include="Core\Transform.cs" /> <Compile Include="Core\Transform2D.cs" /> + <Compile Include="Core\Transform3D.cs" /> <Compile Include="Core\UnhandledExceptionArgs.cs" /> <Compile Include="Core\Vector2.cs" /> <Compile Include="Core\Vector2i.cs" /> diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp index 34a96eba17..2d04cedb9b 100644 --- a/modules/mono/glue/base_object_glue.cpp +++ b/modules/mono/glue/base_object_glue.cpp @@ -31,7 +31,7 @@ #ifdef MONO_GLUE_ENABLED #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/string_name.h" #include "../csharp_script.h" @@ -64,7 +64,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { return; } } - +#if 0 void *data = p_ptr->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { @@ -76,19 +76,20 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) { } } } +#endif } -void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { +void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolean p_is_finalizer) { #ifdef DEBUG_ENABLED CRASH_COND(p_ptr == nullptr); - // This is only called with Reference derived classes - CRASH_COND(!Object::cast_to<Reference>(p_ptr)); + // This is only called with RefCounted derived classes + CRASH_COND(!Object::cast_to<RefCounted>(p_ptr)); #endif +#if 0 + RefCounted *rc = static_cast<RefCounted *>(p_ptr); - Reference *ref = static_cast<Reference *>(p_ptr); - - if (ref->get_script_instance()) { - CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(ref->get_script_instance()); + if (rc->get_script_instance()) { + CSharpInstance *cs_instance = CAST_CSHARP_INSTANCE(rc->get_script_instance()); if (cs_instance) { if (!cs_instance->is_destructing_script_instance()) { bool delete_owner; @@ -97,9 +98,9 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea cs_instance->mono_object_disposed_baseref(p_obj, p_is_finalizer, delete_owner, remove_script_instance); if (delete_owner) { - memdelete(ref); + memdelete(rc); } else if (remove_script_instance) { - ref->set_script_instance(nullptr); + rc->set_script_instance(nullptr); } } return; @@ -108,11 +109,11 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea // Unsafe refcount decrement. The managed instance also counts as a reference. // See: CSharpLanguage::alloc_instance_binding_data(Object *p_object) - CSharpLanguage::get_singleton()->pre_unsafe_unreference(ref); - if (ref->unreference()) { - memdelete(ref); + CSharpLanguage::get_singleton()->pre_unsafe_unreference(rc); + if (rc->unreference()) { + memdelete(rc); } else { - void *data = ref->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); + void *data = rc->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index()); if (data) { CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get(); @@ -124,6 +125,7 @@ void godot_icall_Reference_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoolea } } } +#endif } void godot_icall_Object_ConnectEventSignals(Object *p_ptr) { @@ -145,18 +147,18 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) { } Ref<WeakRef> wref; - Reference *ref = Object::cast_to<Reference>(p_ptr); + RefCounted *rc = Object::cast_to<RefCounted>(p_ptr); - if (ref) { - REF r = ref; + if (rc) { + REF r = rc; if (!r.is_valid()) { return nullptr; } - wref.instance(); + wref.instantiate(); wref->set_ref(r); } else { - wref.instance(); + wref.instantiate(); wref->set_obj(p_ptr); } @@ -242,7 +244,7 @@ MonoString *godot_icall_Object_ToString(Object *p_ptr) { void godot_register_object_icalls() { GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Ctor", godot_icall_Object_Ctor); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_Disposed", godot_icall_Object_Disposed); - GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Reference_Disposed", godot_icall_Reference_Disposed); + GDMonoUtils::add_internal_call("Godot.Object::godot_icall_RefCounted_Disposed", godot_icall_RefCounted_Disposed); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ConnectEventSignals", godot_icall_Object_ConnectEventSignals); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ClassDB_get_method", godot_icall_Object_ClassDB_get_method); GDMonoUtils::add_internal_call("Godot.Object::godot_icall_Object_ToString", godot_icall_Object_ToString); diff --git a/modules/mono/glue/glue_header.h b/modules/mono/glue/glue_header.h index 3db52d7c30..eed3bd2167 100644 --- a/modules/mono/glue/glue_header.h +++ b/modules/mono/glue/glue_header.h @@ -61,7 +61,7 @@ void godot_register_glue_header_icalls() { #include "core/config/engine.h" #include "core/object/class_db.h" #include "core/object/method_bind.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/node_path.h" #include "core/string/ustring.h" #include "core/typedefs.h" diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp index 68134b9b20..375ad413c4 100644 --- a/modules/mono/godotsharp_dirs.cpp +++ b/modules/mono/godotsharp_dirs.cpp @@ -31,7 +31,7 @@ #include "godotsharp_dirs.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" #ifdef TOOLS_ENABLED diff --git a/modules/mono/mono_gc_handle.h b/modules/mono/mono_gc_handle.h index f435aab3dd..d0e51d159f 100644 --- a/modules/mono/mono_gc_handle.h +++ b/modules/mono/mono_gc_handle.h @@ -33,7 +33,7 @@ #include <mono/jit/jit.h> -#include "core/object/reference.h" +#include "core/object/ref_counted.h" namespace gdmono { @@ -79,8 +79,8 @@ struct MonoGCHandleData { static MonoGCHandleData new_weak_handle(MonoObject *p_object); }; -class MonoGCHandleRef : public Reference { - GDCLASS(MonoGCHandleRef, Reference); +class MonoGCHandleRef : public RefCounted { + GDCLASS(MonoGCHandleRef, RefCounted); MonoGCHandleData data; diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp index c523d381f6..02d875f669 100644 --- a/modules/mono/mono_gd/gd_mono.cpp +++ b/modules/mono/mono_gd/gd_mono.cpp @@ -39,8 +39,8 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "core/os/thread.h" @@ -691,7 +691,7 @@ static bool try_get_cached_api_hash_for(const String &p_api_assemblies_dir, bool } Ref<ConfigFile> cfg; - cfg.instance(); + cfg.instantiate(); Error cfg_err = cfg->load(cached_api_hash_path); ERR_FAIL_COND_V(cfg_err != OK, false); @@ -717,7 +717,7 @@ static void create_cached_api_hash_for(const String &p_api_assemblies_dir) { String cached_api_hash_path = p_api_assemblies_dir.plus_file("api_hash_cache.cfg"); Ref<ConfigFile> cfg; - cfg.instance(); + cfg.instantiate(); cfg->set_value("core", "modified_time", FileAccess::get_modified_time(core_api_assembly_path)); cfg->set_value("editor", "modified_time", FileAccess::get_modified_time(editor_api_assembly_path)); diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp index a1556bace5..67d6f3ef29 100644 --- a/modules/mono/mono_gd/gd_mono_assembly.cpp +++ b/modules/mono/mono_gd/gd_mono_assembly.cpp @@ -34,8 +34,8 @@ #include <mono/metadata/tokentype.h> #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/templates/list.h" diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp index d66cc29b9a..341ca88728 100644 --- a/modules/mono/mono_gd/gd_mono_cache.cpp +++ b/modules/mono/mono_gd/gd_mono_cache.cpp @@ -109,8 +109,8 @@ void CachedData::clear_godot_api_cache() { class_Vector3 = nullptr; class_Vector3i = nullptr; class_Basis = nullptr; - class_Quat = nullptr; - class_Transform = nullptr; + class_Quaternion = nullptr; + class_Transform3D = nullptr; class_AABB = nullptr; class_Color = nullptr; class_Plane = nullptr; @@ -238,8 +238,8 @@ void update_godot_api_cache() { CACHE_CLASS_AND_CHECK(Vector3, GODOT_API_CLASS(Vector3)); CACHE_CLASS_AND_CHECK(Vector3i, GODOT_API_CLASS(Vector3i)); CACHE_CLASS_AND_CHECK(Basis, GODOT_API_CLASS(Basis)); - CACHE_CLASS_AND_CHECK(Quat, GODOT_API_CLASS(Quat)); - CACHE_CLASS_AND_CHECK(Transform, GODOT_API_CLASS(Transform)); + CACHE_CLASS_AND_CHECK(Quaternion, GODOT_API_CLASS(Quaternion)); + CACHE_CLASS_AND_CHECK(Transform3D, GODOT_API_CLASS(Transform3D)); CACHE_CLASS_AND_CHECK(AABB, GODOT_API_CLASS(AABB)); CACHE_CLASS_AND_CHECK(Color, GODOT_API_CLASS(Color)); CACHE_CLASS_AND_CHECK(Plane, GODOT_API_CLASS(Plane)); diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h index 51370da452..3d867060f5 100644 --- a/modules/mono/mono_gd/gd_mono_cache.h +++ b/modules/mono/mono_gd/gd_mono_cache.h @@ -80,8 +80,8 @@ struct CachedData { GDMonoClass *class_Vector3; GDMonoClass *class_Vector3i; GDMonoClass *class_Basis; - GDMonoClass *class_Quat; - GDMonoClass *class_Transform; + GDMonoClass *class_Quaternion; + GDMonoClass *class_Transform3D; GDMonoClass *class_AABB; GDMonoClass *class_Color; GDMonoClass *class_Plane; diff --git a/modules/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp index 1d4d52dfce..111eaa0bbf 100644 --- a/modules/mono/mono_gd/gd_mono_field.cpp +++ b/modules/mono/mono_gd/gd_mono_field.cpp @@ -146,14 +146,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ break; } - if (tclass == CACHED_CLASS(Quat)) { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + if (tclass == CACHED_CLASS(Quaternion)) { + GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion()); mono_field_set_value(p_object, mono_field, &from); break; } - if (tclass == CACHED_CLASS(Transform)) { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + if (tclass == CACHED_CLASS(Transform3D)) { + GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D()); mono_field_set_value(p_object, mono_field, &from); break; } @@ -336,8 +336,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_value.operator ::Plane()); mono_field_set_value(p_object, mono_field, &from); } break; - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_value.operator ::Quat()); + case Variant::QUATERNION: { + GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_value.operator ::Quaternion()); mono_field_set_value(p_object, mono_field, &from); } break; case Variant::AABB: { @@ -348,8 +348,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_value.operator ::Basis()); mono_field_set_value(p_object, mono_field, &from); } break; - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_value.operator ::Transform()); + case Variant::TRANSFORM3D: { + GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_value.operator ::Transform3D()); mono_field_set_value(p_object, mono_field, &from); } break; case Variant::COLOR: { diff --git a/modules/mono/mono_gd/gd_mono_internals.cpp b/modules/mono/mono_gd/gd_mono_internals.cpp index fa93c6533a..d6545d50ec 100644 --- a/modules/mono/mono_gd/gd_mono_internals.cpp +++ b/modules/mono/mono_gd/gd_mono_internals.cpp @@ -45,13 +45,13 @@ namespace GDMonoInternals { void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { // This method should not fail - +#if 0 CRASH_COND(!unmanaged); // All mono objects created from the managed world (e.g.: 'new Player()') // need to have a CSharpScript in order for their methods to be callable from the unmanaged side - Reference *ref = Object::cast_to<Reference>(unmanaged); + RefCounted *rc = Object::cast_to<RefCounted>(unmanaged); GDMonoClass *klass = GDMonoUtils::get_object_class(managed); @@ -73,18 +73,18 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { script_binding.inited = true; script_binding.type_name = NATIVE_GDMONOCLASS_NAME(klass); script_binding.wrapper_class = klass; - script_binding.gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); + script_binding.gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); script_binding.owner = unmanaged; - if (ref) { + if (rc) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) + // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) // May not me referenced yet, so we must use init_ref() instead of reference() - if (ref->init_ref()) { - CSharpLanguage::get_singleton()->post_unsafe_reference(ref); + if (rc->init_ref()) { + CSharpLanguage::get_singleton()->post_unsafe_reference(rc); } } @@ -99,7 +99,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { return; } - MonoGCHandleData gchandle = ref ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); + MonoGCHandleData gchandle = rc ? MonoGCHandleData::new_weak_handle(managed) : MonoGCHandleData::new_strong_handle(managed); Ref<CSharpScript> script = CSharpScript::create_for_managed_type(klass, native); @@ -108,6 +108,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) { CSharpInstance *csharp_instance = CSharpInstance::create_for_managed_type(unmanaged, script.ptr(), gchandle); unmanaged->set_script_and_instance(script, csharp_instance); +#endif } void unhandled_exception(MonoException *p_exc) { diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp index dafd36c36b..179bbfb40c 100644 --- a/modules/mono/mono_gd/gd_mono_log.cpp +++ b/modules/mono/mono_gd/gd_mono_log.cpp @@ -32,7 +32,7 @@ #include <stdlib.h> // abort -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/os/os.h" #include "../godotsharp_dirs.h" @@ -161,8 +161,8 @@ void GDMonoLog::initialize() { OS::Time time_now = OS::get_singleton()->get_time(); String log_file_name = str_format("%04d-%02d-%02d_%02d.%02d.%02d", - date_now.year, date_now.month, date_now.day, - time_now.hour, time_now.min, time_now.sec); + (int)date_now.year, (int)date_now.month, (int)date_now.day, + (int)time_now.hour, (int)time_now.minute, (int)time_now.second); log_file_name += str_format("_%d", OS::get_singleton()->get_process_id()); diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h index f7a53156ab..9ddbd251ac 100644 --- a/modules/mono/mono_gd/gd_mono_log.h +++ b/modules/mono/mono_gd/gd_mono_log.h @@ -41,7 +41,7 @@ #endif #ifdef GD_MONO_LOG_ENABLED -#include "core/os/file_access.h" +#include "core/io/file_access.h" #endif class GDMonoLog { diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp index 359f6bba4d..9f2977bfa2 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.cpp +++ b/modules/mono/mono_gd/gd_mono_marshal.cpp @@ -104,12 +104,12 @@ Variant::Type managed_to_variant_type(const ManagedType &p_type, bool *r_nil_is_ return Variant::BASIS; } - if (vtclass == CACHED_CLASS(Quat)) { - return Variant::QUAT; + if (vtclass == CACHED_CLASS(Quaternion)) { + return Variant::QUATERNION; } - if (vtclass == CACHED_CLASS(Transform)) { - return Variant::TRANSFORM; + if (vtclass == CACHED_CLASS(Transform3D)) { + return Variant::TRANSFORM3D; } if (vtclass == CACHED_CLASS(AABB)) { @@ -508,9 +508,9 @@ MonoObject *variant_to_mono_object(const Variant &p_var) { GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var.operator ::Plane()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from); } - case Variant::QUAT: { - GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var.operator ::Quat()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from); + case Variant::QUATERNION: { + GDMonoMarshal::M_Quaternion from = MARSHALLED_OUT(Quaternion, p_var.operator ::Quaternion()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quaternion), &from); } case Variant::AABB: { GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var.operator ::AABB()); @@ -520,9 +520,9 @@ MonoObject *variant_to_mono_object(const Variant &p_var) { GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var.operator ::Basis()); return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from); } - case Variant::TRANSFORM: { - GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var.operator ::Transform()); - return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from); + case Variant::TRANSFORM3D: { + GDMonoMarshal::M_Transform3D from = MARSHALLED_OUT(Transform3D, p_var.operator ::Transform3D()); + return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform3D), &from); } case Variant::COLOR: { GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var.operator ::Color()); @@ -619,8 +619,8 @@ size_t variant_get_managed_unboxed_size(const ManagedType &p_type) { RETURN_CHECK_FOR_STRUCT(Vector3); RETURN_CHECK_FOR_STRUCT(Vector3i); RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quat); - RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(Quaternion); + RETURN_CHECK_FOR_STRUCT(Transform3D); RETURN_CHECK_FOR_STRUCT(AABB); RETURN_CHECK_FOR_STRUCT(Color); RETURN_CHECK_FOR_STRUCT(Plane); @@ -724,8 +724,8 @@ void *variant_to_managed_unboxed(const Variant &p_var, const ManagedType &p_type RETURN_CHECK_FOR_STRUCT(Vector3); RETURN_CHECK_FOR_STRUCT(Vector3i); RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quat); - RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(Quaternion); + RETURN_CHECK_FOR_STRUCT(Transform3D); RETURN_CHECK_FOR_STRUCT(AABB); RETURN_CHECK_FOR_STRUCT(Color); RETURN_CHECK_FOR_STRUCT(Plane); @@ -880,8 +880,8 @@ MonoObject *variant_to_mono_object(const Variant &p_var, const ManagedType &p_ty RETURN_CHECK_FOR_STRUCT(Vector3); RETURN_CHECK_FOR_STRUCT(Vector3i); RETURN_CHECK_FOR_STRUCT(Basis); - RETURN_CHECK_FOR_STRUCT(Quat); - RETURN_CHECK_FOR_STRUCT(Transform); + RETURN_CHECK_FOR_STRUCT(Quaternion); + RETURN_CHECK_FOR_STRUCT(Transform3D); RETURN_CHECK_FOR_STRUCT(AABB); RETURN_CHECK_FOR_STRUCT(Color); RETURN_CHECK_FOR_STRUCT(Plane); @@ -1036,12 +1036,12 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type return MARSHALLED_IN(Basis, unbox_addr<GDMonoMarshal::M_Basis>(p_obj)); } - if (vtclass == CACHED_CLASS(Quat)) { - return MARSHALLED_IN(Quat, unbox_addr<GDMonoMarshal::M_Quat>(p_obj)); + if (vtclass == CACHED_CLASS(Quaternion)) { + return MARSHALLED_IN(Quaternion, unbox_addr<GDMonoMarshal::M_Quaternion>(p_obj)); } - if (vtclass == CACHED_CLASS(Transform)) { - return MARSHALLED_IN(Transform, unbox_addr<GDMonoMarshal::M_Transform>(p_obj)); + if (vtclass == CACHED_CLASS(Transform3D)) { + return MARSHALLED_IN(Transform3D, unbox_addr<GDMonoMarshal::M_Transform3D>(p_obj)); } if (vtclass == CACHED_CLASS(AABB)) { @@ -1136,8 +1136,8 @@ Variant mono_object_to_variant_impl(MonoObject *p_obj, const ManagedType &p_type if (CACHED_CLASS(GodotObject)->is_assignable_from(type_class)) { Object *ptr = unbox<Object *>(CACHED_FIELD(GodotObject, ptr)->get_value(p_obj)); if (ptr != nullptr) { - Reference *ref = Object::cast_to<Reference>(ptr); - return ref ? Variant(Ref<Reference>(ref)) : Variant(ptr); + RefCounted *rc = Object::cast_to<RefCounted>(ptr); + return rc ? Variant(Ref<RefCounted>(rc)) : Variant(ptr); } return Variant(); } diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h index 668809ae5d..88afc7ebc5 100644 --- a/modules/mono/mono_gd/gd_mono_marshal.h +++ b/modules/mono/mono_gd/gd_mono_marshal.h @@ -263,15 +263,15 @@ enum { MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array - MATCHES_Quat = (MATCHES_real_t && (sizeof(Quat) == (sizeof(real_t) * 4)) && - offsetof(Quat, x) == (sizeof(real_t) * 0) && - offsetof(Quat, y) == (sizeof(real_t) * 1) && - offsetof(Quat, z) == (sizeof(real_t) * 2) && - offsetof(Quat, w) == (sizeof(real_t) * 3)), + MATCHES_Quaternion = (MATCHES_real_t && (sizeof(Quaternion) == (sizeof(real_t) * 4)) && + offsetof(Quaternion, x) == (sizeof(real_t) * 0) && + offsetof(Quaternion, y) == (sizeof(real_t) * 1) && + offsetof(Quaternion, z) == (sizeof(real_t) * 2) && + offsetof(Quaternion, w) == (sizeof(real_t) * 3)), - MATCHES_Transform = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform) == (sizeof(Basis) + sizeof(Vector3))) && - offsetof(Transform, basis) == 0 && - offsetof(Transform, origin) == sizeof(Basis)), + MATCHES_Transform3D = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform3D) == (sizeof(Basis) + sizeof(Vector3))) && + offsetof(Transform3D, basis) == 0 && + offsetof(Transform3D, origin) == sizeof(Basis)), MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) && offsetof(AABB, position) == (sizeof(Vector3) * 0) && @@ -292,7 +292,7 @@ enum { #ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY /* clang-format off */ static_assert(MATCHES_Vector2 && MATCHES_Rect2 && MATCHES_Transform2D && MATCHES_Vector3 && - MATCHES_Basis && MATCHES_Quat && MATCHES_Transform && MATCHES_AABB && MATCHES_Color && + MATCHES_Basis && MATCHES_Quaternion && MATCHES_Transform3D && MATCHES_AABB && MATCHES_Color && MATCHES_Plane && MATCHES_Vector2i && MATCHES_Rect2i && MATCHES_Vector3i); /* clang-format on */ #endif @@ -420,29 +420,29 @@ struct M_Basis { } }; -struct M_Quat { +struct M_Quaternion { real_t x, y, z, w; - static _FORCE_INLINE_ Quat convert_to(const M_Quat &p_from) { - return Quat(p_from.x, p_from.y, p_from.z, p_from.w); + static _FORCE_INLINE_ Quaternion convert_to(const M_Quaternion &p_from) { + return Quaternion(p_from.x, p_from.y, p_from.z, p_from.w); } - static _FORCE_INLINE_ M_Quat convert_from(const Quat &p_from) { - M_Quat ret = { p_from.x, p_from.y, p_from.z, p_from.w }; + static _FORCE_INLINE_ M_Quaternion convert_from(const Quaternion &p_from) { + M_Quaternion ret = { p_from.x, p_from.y, p_from.z, p_from.w }; return ret; } }; -struct M_Transform { +struct M_Transform3D { M_Basis basis; M_Vector3 origin; - static _FORCE_INLINE_ Transform convert_to(const M_Transform &p_from) { - return Transform(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin)); + static _FORCE_INLINE_ Transform3D convert_to(const M_Transform3D &p_from) { + return Transform3D(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin)); } - static _FORCE_INLINE_ M_Transform convert_from(const Transform &p_from) { - M_Transform ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) }; + static _FORCE_INLINE_ M_Transform3D convert_from(const Transform3D &p_from) { + M_Transform3D ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) }; return ret; } }; @@ -533,8 +533,8 @@ DECL_TYPE_MARSHAL_TEMPLATES(Transform2D) DECL_TYPE_MARSHAL_TEMPLATES(Vector3) DECL_TYPE_MARSHAL_TEMPLATES(Vector3i) DECL_TYPE_MARSHAL_TEMPLATES(Basis) -DECL_TYPE_MARSHAL_TEMPLATES(Quat) -DECL_TYPE_MARSHAL_TEMPLATES(Transform) +DECL_TYPE_MARSHAL_TEMPLATES(Quaternion) +DECL_TYPE_MARSHAL_TEMPLATES(Transform3D) DECL_TYPE_MARSHAL_TEMPLATES(AABB) DECL_TYPE_MARSHAL_TEMPLATES(Color) DECL_TYPE_MARSHAL_TEMPLATES(Plane) diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp index 6e0a263c7f..080398c997 100644 --- a/modules/mono/mono_gd/gd_mono_utils.cpp +++ b/modules/mono/mono_gd/gd_mono_utils.cpp @@ -35,8 +35,8 @@ #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" -#include "core/object/reference.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" +#include "core/object/ref_counted.h" #include "core/os/mutex.h" #include "core/os/os.h" @@ -54,6 +54,7 @@ namespace GDMonoUtils { MonoObject *unmanaged_get_managed(Object *unmanaged) { +#if 0 if (!unmanaged) { return nullptr; } @@ -108,18 +109,20 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) { gchandle = MonoGCHandleData::new_strong_handle(mono_object); // Tie managed to unmanaged - Reference *ref = Object::cast_to<Reference>(unmanaged); + RefCounted *rc = Object::cast_to<RefCounted>(unmanaged); - if (ref) { + if (rc) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner // but the managed instance is alive, the refcount will be 1 instead of 0. - // See: godot_icall_Reference_Dtor(MonoObject *p_obj, Object *p_ptr) - ref->reference(); - CSharpLanguage::get_singleton()->post_unsafe_reference(ref); + // See: godot_icall_RefCounted_Dtor(MonoObject *p_obj, Object *p_ptr) + rc->reference(); + CSharpLanguage::get_singleton()->post_unsafe_reference(rc); } return mono_object; +#endif + return nullptr; } void set_main_thread(MonoThread *p_thread) { @@ -238,7 +241,7 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) { MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) { bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native); ERR_FAIL_COND_V_MSG(!parent_is_object_class, nullptr, - "Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'."); + "Type inherits from native type '" + p_native + "', so it can't be instantiated in object of type: '" + p_object->get_class() + "'."); MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr()); ERR_FAIL_NULL_V(mono_object, nullptr); diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h index 9e024418e1..773501e93d 100644 --- a/modules/mono/mono_gd/gd_mono_utils.h +++ b/modules/mono/mono_gd/gd_mono_utils.h @@ -41,7 +41,7 @@ #endif #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #define UNHANDLED_EXCEPTION(m_exc) \ if (unlikely(m_exc != nullptr)) { \ diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp index 80eb47bfd4..b4a6bfdcd4 100644 --- a/modules/mono/register_types.cpp +++ b/modules/mono/register_types.cpp @@ -52,10 +52,10 @@ void register_mono_types() { script_language_cs->set_language_index(ScriptServer::get_language_count()); ScriptServer::register_language(script_language_cs); - resource_loader_cs.instance(); + resource_loader_cs.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_cs); - resource_saver_cs.instance(); + resource_saver_cs.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_cs); } diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h index 4c77f8cfed..e12ea45b3f 100644 --- a/modules/mono/signal_awaiter_utils.h +++ b/modules/mono/signal_awaiter_utils.h @@ -31,7 +31,7 @@ #ifndef SIGNAL_AWAITER_UTILS_H #define SIGNAL_AWAITER_UTILS_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "csharp_script.h" #include "mono_gc_handle.h" diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp index bb1265e959..6b616dd52d 100644 --- a/modules/mono/utils/mono_reg_utils.cpp +++ b/modules/mono/utils/mono_reg_utils.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "mono_reg_utils.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #ifdef WINDOWS_ENABLED diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp index 93d44628ac..ec04d50704 100644 --- a/modules/mono/utils/path_utils.cpp +++ b/modules/mono/utils/path_utils.cpp @@ -31,8 +31,8 @@ #include "path_utils.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #ifdef WINDOWS_ENABLED @@ -80,7 +80,7 @@ String cwd() { } String abspath(const String &p_path) { - if (p_path.is_abs_path()) { + if (p_path.is_absolute_path()) { return p_path.simplify_path(); } else { return path::join(path::cwd(), p_path).simplify_path(); diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp index ee68458268..053618ebe4 100644 --- a/modules/mono/utils/string_utils.cpp +++ b/modules/mono/utils/string_utils.cpp @@ -30,7 +30,7 @@ #include "string_utils.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include <stdio.h> #include <stdlib.h> diff --git a/modules/gdnavigation/SCsub b/modules/navigation/SCsub index 22b5509b32..22b5509b32 100644 --- a/modules/gdnavigation/SCsub +++ b/modules/navigation/SCsub diff --git a/modules/gdnavigation/config.py b/modules/navigation/config.py index d22f9454ed..d22f9454ed 100644 --- a/modules/gdnavigation/config.py +++ b/modules/navigation/config.py diff --git a/modules/gdnavigation/gd_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 88ef434e0f..df003cfe6f 100644 --- a/modules/gdnavigation/gd_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gd_navigation_server.cpp */ +/* godot_navigation_server.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gd_navigation_server.h" +#include "godot_navigation_server.h" #include "core/os/mutex.h" @@ -44,96 +44,96 @@ /// an instance of that struct with the submitted parameters. /// Then, that struct is stored in an array; the `sync` function consume that array. -#define COMMAND_1(F_NAME, T_0, D_0) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - MERGE(F_NAME, _command) \ - (T_0 p_d_0) : \ - d_0(p_d_0) {} \ - virtual void exec(GdNavigationServer *server) { \ - server->MERGE(_cmd_, F_NAME)(d_0); \ - } \ - }; \ - void GdNavigationServer::F_NAME(T_0 D_0) const { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0)); \ - add_command(cmd); \ - } \ - void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0) - -#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - T_1 d_1; \ - MERGE(F_NAME, _command) \ - ( \ - T_0 p_d_0, \ - T_1 p_d_1) : \ - d_0(p_d_0), \ - d_1(p_d_1) {} \ - virtual void exec(GdNavigationServer *server) { \ - server->MERGE(_cmd_, F_NAME)(d_0, d_1); \ - } \ - }; \ - void GdNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0, \ - D_1)); \ - add_command(cmd); \ - } \ - void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) - -#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \ - struct MERGE(F_NAME, _command) : public SetCommand { \ - T_0 d_0; \ - T_1 d_1; \ - T_2 d_2; \ - T_3 d_3; \ - MERGE(F_NAME, _command) \ - ( \ - T_0 p_d_0, \ - T_1 p_d_1, \ - T_2 p_d_2, \ - T_3 p_d_3) : \ - d_0(p_d_0), \ - d_1(p_d_1), \ - d_2(p_d_2), \ - d_3(p_d_3) {} \ - virtual void exec(GdNavigationServer *server) { \ - server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \ - } \ - }; \ - void GdNavigationServer::F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) const { \ - auto cmd = memnew(MERGE(F_NAME, _command)( \ - D_0, \ - D_1, \ - D_2, \ - D_3)); \ - add_command(cmd); \ - } \ - void GdNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) - -GdNavigationServer::GdNavigationServer() : +#define COMMAND_1(F_NAME, T_0, D_0) \ + struct MERGE(F_NAME, _command) : public SetCommand { \ + T_0 d_0; \ + MERGE(F_NAME, _command) \ + (T_0 p_d_0) : \ + d_0(p_d_0) {} \ + virtual void exec(GodotNavigationServer *server) { \ + server->MERGE(_cmd_, F_NAME)(d_0); \ + } \ + }; \ + void GodotNavigationServer::F_NAME(T_0 D_0) const { \ + auto cmd = memnew(MERGE(F_NAME, _command)( \ + D_0)); \ + add_command(cmd); \ + } \ + void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0) + +#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \ + struct MERGE(F_NAME, _command) : public SetCommand { \ + T_0 d_0; \ + T_1 d_1; \ + MERGE(F_NAME, _command) \ + ( \ + T_0 p_d_0, \ + T_1 p_d_1) : \ + d_0(p_d_0), \ + d_1(p_d_1) {} \ + virtual void exec(GodotNavigationServer *server) { \ + server->MERGE(_cmd_, F_NAME)(d_0, d_1); \ + } \ + }; \ + void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \ + auto cmd = memnew(MERGE(F_NAME, _command)( \ + D_0, \ + D_1)); \ + add_command(cmd); \ + } \ + void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1) + +#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \ + struct MERGE(F_NAME, _command) : public SetCommand { \ + T_0 d_0; \ + T_1 d_1; \ + T_2 d_2; \ + T_3 d_3; \ + MERGE(F_NAME, _command) \ + ( \ + T_0 p_d_0, \ + T_1 p_d_1, \ + T_2 p_d_2, \ + T_3 p_d_3) : \ + d_0(p_d_0), \ + d_1(p_d_1), \ + d_2(p_d_2), \ + d_3(p_d_3) {} \ + virtual void exec(GodotNavigationServer *server) { \ + server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \ + } \ + }; \ + void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) const { \ + auto cmd = memnew(MERGE(F_NAME, _command)( \ + D_0, \ + D_1, \ + D_2, \ + D_3)); \ + add_command(cmd); \ + } \ + void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) + +GodotNavigationServer::GodotNavigationServer() : NavigationServer3D() { } -GdNavigationServer::~GdNavigationServer() { +GodotNavigationServer::~GodotNavigationServer() { flush_queries(); } -void GdNavigationServer::add_command(SetCommand *command) const { - GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this); +void GodotNavigationServer::add_command(SetCommand *command) const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); { MutexLock lock(commands_mutex); mut_this->commands.push_back(command); } } -RID GdNavigationServer::map_create() const { - GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this); +RID GodotNavigationServer::map_create() const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); - NavMap *space = memnew(NavMap); - RID rid = map_owner.make_rid(space); + RID rid = map_owner.make_rid(); + NavMap *space = map_owner.getornull(rid); space->set_self(rid); return rid; } @@ -155,7 +155,7 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) { } } -bool GdNavigationServer::map_is_active(RID p_map) const { +bool GodotNavigationServer::map_is_active(RID p_map) const { NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, false); @@ -169,7 +169,7 @@ COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) { map->set_up(p_up); } -Vector3 GdNavigationServer::map_get_up(RID p_map) const { +Vector3 GodotNavigationServer::map_get_up(RID p_map) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); @@ -183,7 +183,7 @@ COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) { map->set_cell_size(p_cell_size); } -real_t GdNavigationServer::map_get_cell_size(RID p_map) const { +real_t GodotNavigationServer::map_get_cell_size(RID p_map) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, 0); @@ -197,53 +197,53 @@ COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margi map->set_edge_connection_margin(p_connection_margin); } -real_t GdNavigationServer::map_get_edge_connection_margin(RID p_map) const { +real_t GodotNavigationServer::map_get_edge_connection_margin(RID p_map) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, 0); return map->get_edge_connection_margin(); } -Vector<Vector3> GdNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const { +Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>()); return map->get_path(p_origin, p_destination, p_optimize, p_layers); } -Vector3 GdNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { +Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); return map->get_closest_point_to_segment(p_from, p_to, p_use_collision); } -Vector3 GdNavigationServer::map_get_closest_point(RID p_map, const Vector3 &p_point) const { +Vector3 GodotNavigationServer::map_get_closest_point(RID p_map, const Vector3 &p_point) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); return map->get_closest_point(p_point); } -Vector3 GdNavigationServer::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const { +Vector3 GodotNavigationServer::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, Vector3()); return map->get_closest_point_normal(p_point); } -RID GdNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const { +RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const { const NavMap *map = map_owner.getornull(p_map); ERR_FAIL_COND_V(map == nullptr, RID()); return map->get_closest_point_owner(p_point); } -RID GdNavigationServer::region_create() const { - GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this); +RID GodotNavigationServer::region_create() const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); - NavRegion *reg = memnew(NavRegion); - RID rid = region_owner.make_rid(reg); + RID rid = region_owner.make_rid(); + NavRegion *reg = region_owner.getornull(rid); reg->set_self(rid); return rid; } @@ -270,7 +270,7 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) { } } -COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform) { +COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND(region == nullptr); @@ -284,7 +284,7 @@ COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) { region->set_layers(p_layers); } -uint32_t GdNavigationServer::region_get_layers(RID p_region) const { +uint32_t GodotNavigationServer::region_get_layers(RID p_region) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(region == nullptr, 0); @@ -298,7 +298,7 @@ COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) { region->set_mesh(p_nav_mesh); } -void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const { +void GodotNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const { ERR_FAIL_COND(r_mesh.is_null()); ERR_FAIL_COND(p_node == nullptr); @@ -308,32 +308,32 @@ void GdNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p #endif } -int GdNavigationServer::region_get_connections_count(RID p_region) const { +int GodotNavigationServer::region_get_connections_count(RID p_region) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(!region, 0); return region->get_connections_count(); } -Vector3 GdNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const { +Vector3 GodotNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(!region, Vector3()); return region->get_connection_pathway_start(p_connection_id); } -Vector3 GdNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const { +Vector3 GodotNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const { NavRegion *region = region_owner.getornull(p_region); ERR_FAIL_COND_V(!region, Vector3()); return region->get_connection_pathway_end(p_connection_id); } -RID GdNavigationServer::agent_create() const { - GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this); +RID GodotNavigationServer::agent_create() const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); - RvoAgent *agent = memnew(RvoAgent()); - RID rid = agent_owner.make_rid(agent); + RID rid = agent_owner.make_rid(); + RvoAgent *agent = agent_owner.getornull(rid); agent->set_self(rid); return rid; } @@ -428,7 +428,7 @@ COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore) { agent->get_agent()->ignore_y_ = p_ignore; } -bool GdNavigationServer::agent_is_map_changed(RID p_agent) const { +bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const { RvoAgent *agent = agent_owner.getornull(p_agent); ERR_FAIL_COND_V(agent == nullptr, false); @@ -472,7 +472,6 @@ COMMAND_1(free, RID, p_object) { active_maps.remove(map_index); active_maps_update_id.remove(map_index); map_owner.free(p_object); - memdelete(map); } else if (region_owner.owns(p_object)) { NavRegion *region = region_owner.getornull(p_object); @@ -484,7 +483,6 @@ COMMAND_1(free, RID, p_object) { } region_owner.free(p_object); - memdelete(region); } else if (agent_owner.owns(p_object)) { RvoAgent *agent = agent_owner.getornull(p_object); @@ -496,20 +494,19 @@ COMMAND_1(free, RID, p_object) { } agent_owner.free(p_object); - memdelete(agent); } else { ERR_FAIL_COND("Invalid ID."); } } -void GdNavigationServer::set_active(bool p_active) const { - GdNavigationServer *mut_this = const_cast<GdNavigationServer *>(this); +void GodotNavigationServer::set_active(bool p_active) const { + GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); mut_this->active = p_active; } -void GdNavigationServer::flush_queries() { +void GodotNavigationServer::flush_queries() { // In c++ we can't be sure that this is performed in the main thread // even with mutable functions. MutexLock lock(commands_mutex); @@ -521,7 +518,7 @@ void GdNavigationServer::flush_queries() { commands.clear(); } -void GdNavigationServer::process(real_t p_delta_time) { +void GodotNavigationServer::process(real_t p_delta_time) { flush_queries(); if (!active) { diff --git a/modules/gdnavigation/gd_navigation_server.h b/modules/navigation/godot_navigation_server.h index 2f51f6431e..65224493fd 100644 --- a/modules/gdnavigation/gd_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gd_navigation_server.h */ +/* godot_navigation_server.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GD_NAVIGATION_SERVER_H -#define GD_NAVIGATION_SERVER_H +#ifndef GODOT_NAVIGATION_SERVER_H +#define GODOT_NAVIGATION_SERVER_H #include "core/templates/local_vector.h" #include "core/templates/rid.h" @@ -61,31 +61,31 @@ virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const; \ void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3) -class GdNavigationServer; +class GodotNavigationServer; struct SetCommand { virtual ~SetCommand() {} - virtual void exec(GdNavigationServer *server) = 0; + virtual void exec(GodotNavigationServer *server) = 0; }; -class GdNavigationServer : public NavigationServer3D { +class GodotNavigationServer : public NavigationServer3D { Mutex commands_mutex; /// Mutex used to make any operation threadsafe. Mutex operations_mutex; std::vector<SetCommand *> commands; - mutable RID_PtrOwner<NavMap> map_owner; - mutable RID_PtrOwner<NavRegion> region_owner; - mutable RID_PtrOwner<RvoAgent> agent_owner; + mutable RID_Owner<NavMap> map_owner; + mutable RID_Owner<NavRegion> region_owner; + mutable RID_Owner<RvoAgent> agent_owner; bool active = true; LocalVector<NavMap *> active_maps; LocalVector<uint32_t> active_maps_update_id; public: - GdNavigationServer(); - virtual ~GdNavigationServer(); + GodotNavigationServer(); + virtual ~GodotNavigationServer(); void add_command(SetCommand *command) const; @@ -113,7 +113,7 @@ public: COMMAND_2(region_set_map, RID, p_region, RID, p_map); COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers); virtual uint32_t region_get_layers(RID p_region) const; - COMMAND_2(region_set_transform, RID, p_region, Transform, p_transform); + COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform); COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh); virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const; virtual int region_get_connections_count(RID p_region) const; @@ -146,4 +146,4 @@ public: #undef COMMAND_2 #undef COMMAND_4_DEF -#endif // GD_NAVIGATION_SERVER_H +#endif // GODOT_NAVIGATION_SERVER_H diff --git a/modules/gdnavigation/nav_map.cpp b/modules/navigation/nav_map.cpp index 41306f0687..41306f0687 100644 --- a/modules/gdnavigation/nav_map.cpp +++ b/modules/navigation/nav_map.cpp diff --git a/modules/gdnavigation/nav_map.h b/modules/navigation/nav_map.h index 8e013a72eb..8e013a72eb 100644 --- a/modules/gdnavigation/nav_map.h +++ b/modules/navigation/nav_map.h diff --git a/modules/gdnavigation/nav_region.cpp b/modules/navigation/nav_region.cpp index c1690b2a4b..81b15a49f5 100644 --- a/modules/gdnavigation/nav_region.cpp +++ b/modules/navigation/nav_region.cpp @@ -52,7 +52,7 @@ uint32_t NavRegion::get_layers() const { return layers; } -void NavRegion::set_transform(Transform p_transform) { +void NavRegion::set_transform(Transform3D p_transform) { transform = p_transform; polygons_dirty = true; } diff --git a/modules/gdnavigation/nav_region.h b/modules/navigation/nav_region.h index 527b2500ac..f8b067e638 100644 --- a/modules/gdnavigation/nav_region.h +++ b/modules/navigation/nav_region.h @@ -46,7 +46,7 @@ class NavRegion; class NavRegion : public NavRid { NavMap *map = nullptr; - Transform transform; + Transform3D transform; Ref<NavigationMesh> mesh; uint32_t layers = 1; Vector<gd::Edge::Connection> connections; @@ -71,8 +71,8 @@ public: void set_layers(uint32_t p_layers); uint32_t get_layers() const; - void set_transform(Transform transform); - const Transform &get_transform() const { + void set_transform(Transform3D transform); + const Transform3D &get_transform() const { return transform; } diff --git a/modules/gdnavigation/nav_rid.h b/modules/navigation/nav_rid.h index a0a60a3643..a0a60a3643 100644 --- a/modules/gdnavigation/nav_rid.h +++ b/modules/navigation/nav_rid.h diff --git a/modules/gdnavigation/nav_utils.h b/modules/navigation/nav_utils.h index 35da391eea..35da391eea 100644 --- a/modules/gdnavigation/nav_utils.h +++ b/modules/navigation/nav_utils.h diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp b/modules/navigation/navigation_mesh_editor_plugin.cpp index aa9248d2a1..aa9248d2a1 100644 --- a/modules/gdnavigation/navigation_mesh_editor_plugin.cpp +++ b/modules/navigation/navigation_mesh_editor_plugin.cpp diff --git a/modules/gdnavigation/navigation_mesh_editor_plugin.h b/modules/navigation/navigation_mesh_editor_plugin.h index c39269865b..c39269865b 100644 --- a/modules/gdnavigation/navigation_mesh_editor_plugin.h +++ b/modules/navigation/navigation_mesh_editor_plugin.h diff --git a/modules/gdnavigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index 7d30ce0f44..0d8330c1da 100644 --- a/modules/gdnavigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -68,7 +68,7 @@ void NavigationMeshGenerator::_add_vertex(const Vector3 &p_vec3, Vector<float> & p_verticies.push_back(p_vec3.z); } -void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { +void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { int current_vertex_count; for (int i = 0; i < p_mesh->get_surface_count(); i++) { @@ -123,7 +123,7 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform } } -void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { +void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices) { int face_count = p_faces.size() / 3; int current_vertex_count = p_verticies.size() / 3; @@ -138,7 +138,7 @@ void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, cons } } -void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { +void NavigationMeshGenerator::_parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children) { if (Object::cast_to<MeshInstance3D>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(p_node); Ref<Mesh> mesh = mesh_instance->get_mesh(); @@ -169,7 +169,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, if (Object::cast_to<CollisionShape3D>(child)) { CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child); - Transform transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform(); + Transform3D transform = p_accumulated_transform * static_body->get_transform() * col_shape->get_transform(); Ref<Mesh> mesh; Ref<Shape3D> s = col_shape->get_shape(); @@ -177,7 +177,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, BoxShape3D *box = Object::cast_to<BoxShape3D>(*s); if (box) { Ref<BoxMesh> box_mesh; - box_mesh.instance(); + box_mesh.instantiate(); box_mesh->set_size(box->get_size()); mesh = box_mesh; } @@ -185,7 +185,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s); if (capsule) { Ref<CapsuleMesh> capsule_mesh; - capsule_mesh.instance(); + capsule_mesh.instantiate(); capsule_mesh->set_radius(capsule->get_radius()); capsule_mesh->set_mid_height(capsule->get_height() / 2.0); mesh = capsule_mesh; @@ -194,7 +194,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s); if (cylinder) { Ref<CylinderMesh> cylinder_mesh; - cylinder_mesh.instance(); + cylinder_mesh.instantiate(); cylinder_mesh->set_height(cylinder->get_height()); cylinder_mesh->set_bottom_radius(cylinder->get_radius()); cylinder_mesh->set_top_radius(cylinder->get_radius()); @@ -204,7 +204,7 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s); if (sphere) { Ref<SphereMesh> sphere_mesh; - sphere_mesh.instance(); + sphere_mesh.instantiate(); sphere_mesh->set_radius(sphere->get_radius()); sphere_mesh->set_height(sphere->get_radius() * 2.0); mesh = sphere_mesh; @@ -251,11 +251,11 @@ void NavigationMeshGenerator::_parse_geometry(Transform p_accumulated_transform, if (Object::cast_to<GridMap>(p_node) && p_generate_from != NavigationMesh::PARSED_GEOMETRY_STATIC_COLLIDERS) { GridMap *gridmap_instance = Object::cast_to<GridMap>(p_node); Array meshes = gridmap_instance->get_meshes(); - Transform xform = gridmap_instance->get_transform(); + Transform3D xform = gridmap_instance->get_transform(); for (int i = 0; i < meshes.size(); i += 2) { Ref<Mesh> mesh = meshes[i + 1]; if (mesh.is_valid()) { - _add_mesh(mesh, p_accumulated_transform * xform * meshes[i], p_verticies, p_indices); + _add_mesh(mesh, p_accumulated_transform * xform * (Transform3D)meshes[i], p_verticies, p_indices); } } } @@ -513,7 +513,7 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) p_node->get_tree()->get_nodes_in_group(p_nav_mesh->get_source_group_name(), &parse_nodes); } - Transform navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse(); + Transform3D navmesh_xform = Object::cast_to<Node3D>(p_node)->get_transform().affine_inverse(); for (const List<Node *>::Element *E = parse_nodes.front(); E; E = E->next()) { int geometry_type = p_nav_mesh->get_parsed_geometry_type(); uint32_t collision_mask = p_nav_mesh->get_collision_mask(); diff --git a/modules/gdnavigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h index 88ccdb1c41..847c7d097b 100644 --- a/modules/gdnavigation/navigation_mesh_generator.h +++ b/modules/navigation/navigation_mesh_generator.h @@ -50,9 +50,9 @@ protected: static void _bind_methods(); static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_verticies); - static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); - static void _add_faces(const PackedVector3Array &p_faces, const Transform &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); - static void _parse_geometry(Transform p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); + static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); + static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_verticies, Vector<int> &p_indices); + static void _parse_geometry(Transform3D p_accumulated_transform, Node *p_node, Vector<float> &p_verticies, Vector<int> &p_indices, int p_generate_from, uint32_t p_collision_mask, bool p_recurse_children); static void _convert_detail_mesh_to_native_navigation_mesh(const rcPolyMeshDetail *p_detail_mesh, Ref<NavigationMesh> p_nav_mesh); static void _build_recast_navigation_mesh( diff --git a/modules/gdnavigation/register_types.cpp b/modules/navigation/register_types.cpp index 8443d3d242..0f3c412d4a 100644 --- a/modules/gdnavigation/register_types.cpp +++ b/modules/navigation/register_types.cpp @@ -31,9 +31,10 @@ #include "register_types.h" #include "core/config/engine.h" -#include "gd_navigation_server.h" #include "servers/navigation_server_3d.h" +#include "godot_navigation_server.h" + #ifndef _3D_DISABLED #include "navigation_mesh_generator.h" #endif @@ -42,19 +43,15 @@ #include "navigation_mesh_editor_plugin.h" #endif -/** - @author AndreaCatania -*/ - #ifndef _3D_DISABLED NavigationMeshGenerator *_nav_mesh_generator = nullptr; #endif NavigationServer3D *new_server() { - return memnew(GdNavigationServer); + return memnew(GodotNavigationServer); } -void register_gdnavigation_types() { +void register_navigation_types() { NavigationServer3DManager::set_default_server(new_server); #ifndef _3D_DISABLED @@ -65,15 +62,10 @@ void register_gdnavigation_types() { #ifdef TOOLS_ENABLED EditorPlugins::add_by_type<NavigationMeshEditorPlugin>(); - - ClassDB::APIType prev_api = ClassDB::get_current_api(); - ClassDB::set_current_api(ClassDB::API_EDITOR); - - ClassDB::set_current_api(prev_api); #endif } -void unregister_gdnavigation_types() { +void unregister_navigation_types() { #ifndef _3D_DISABLED if (_nav_mesh_generator) { memdelete(_nav_mesh_generator); diff --git a/modules/gdnavigation/register_types.h b/modules/navigation/register_types.h index c2bb08c649..4737c818eb 100644 --- a/modules/gdnavigation/register_types.h +++ b/modules/navigation/register_types.h @@ -28,14 +28,10 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -/** - @author AndreaCatania -*/ +#ifndef NAVIGATION_REGISTER_TYPES_H +#define NAVIGATION_REGISTER_TYPES_H -#ifndef GDNAVIGATION_REGISTER_TYPES_H -#define GDNAVIGATION_REGISTER_TYPES_H +void register_navigation_types(); +void unregister_navigation_types(); -void register_gdnavigation_types(); -void unregister_gdnavigation_types(); - -#endif // GDNAVIGATION_REGISTER_TYPES_H +#endif // NAVIGATION_REGISTER_TYPES_H diff --git a/modules/gdnavigation/rvo_agent.cpp b/modules/navigation/rvo_agent.cpp index 21e43d08c1..21e43d08c1 100644 --- a/modules/gdnavigation/rvo_agent.cpp +++ b/modules/navigation/rvo_agent.cpp diff --git a/modules/gdnavigation/rvo_agent.h b/modules/navigation/rvo_agent.h index 369cb1f9a3..369cb1f9a3 100644 --- a/modules/gdnavigation/rvo_agent.h +++ b/modules/navigation/rvo_agent.h diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml index a12412a9cd..2ae7f8cad9 100644 --- a/modules/opensimplex/doc_classes/NoiseTexture.xml +++ b/modules/opensimplex/doc_classes/NoiseTexture.xml @@ -31,7 +31,7 @@ <member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise"> The [OpenSimplexNoise] instance used to generate the noise. </member> - <member name="noise_offset" type="Vector2" setter="set_noise_offset" getter="get_noise_offset" default="Vector2( 0, 0 )"> + <member name="noise_offset" type="Vector2" setter="set_noise_offset" getter="get_noise_offset" default="Vector2(0, 0)"> An offset used to specify the noise space coordinate of the top left corner of the generated noise. This value is ignored if [member seamless] is enabled. </member> <member name="seamless" type="bool" setter="set_seamless" getter="get_seamless" default="false"> diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml index 2fdbd61ee7..4d45e41cc3 100644 --- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml +++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml @@ -31,7 +31,7 @@ </argument> <argument index="1" name="height" type="int"> </argument> - <argument index="2" name="noise_offset" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="noise_offset" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Generate a noise image in [constant Image.FORMAT_L8] format with the requested [code]width[/code] and [code]height[/code], based on the current noise parameters. If [code]noise_offset[/code] is specified, then the offset value is used as the coordinates of the top-left corner of the generated noise. diff --git a/modules/opensimplex/noise_texture.cpp b/modules/opensimplex/noise_texture.cpp index 9e0155da94..66c52ffbf9 100644 --- a/modules/opensimplex/noise_texture.cpp +++ b/modules/opensimplex/noise_texture.cpp @@ -187,6 +187,7 @@ Ref<OpenSimplexNoise> NoiseTexture::get_noise() { } void NoiseTexture::set_width(int p_width) { + ERR_FAIL_COND(p_width <= 0); if (p_width == size.x) { return; } @@ -195,6 +196,7 @@ void NoiseTexture::set_width(int p_width) { } void NoiseTexture::set_height(int p_height) { + ERR_FAIL_COND(p_height <= 0); if (p_height == size.y) { return; } diff --git a/modules/opensimplex/noise_texture.h b/modules/opensimplex/noise_texture.h index 20a53bb58b..6237b6460d 100644 --- a/modules/opensimplex/noise_texture.h +++ b/modules/opensimplex/noise_texture.h @@ -34,7 +34,7 @@ #include "open_simplex_noise.h" #include "core/io/image.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "editor/editor_node.h" #include "editor/editor_plugin.h" #include "editor/property_editor.h" diff --git a/modules/opensimplex/open_simplex_noise.h b/modules/opensimplex/open_simplex_noise.h index bb50c523d2..dcf922a8bf 100644 --- a/modules/opensimplex/open_simplex_noise.h +++ b/modules/opensimplex/open_simplex_noise.h @@ -32,7 +32,7 @@ #define OPEN_SIMPLEX_NOISE_H #include "core/io/image.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "scene/resources/texture.h" #include "thirdparty/misc/open-simplex-noise.h" diff --git a/modules/pvr/image_compress_pvrtc.cpp b/modules/pvr/image_compress_pvrtc.cpp index 6cb9837f49..980cac17d3 100644 --- a/modules/pvr/image_compress_pvrtc.cpp +++ b/modules/pvr/image_compress_pvrtc.cpp @@ -31,7 +31,7 @@ #include "image_compress_pvrtc.h" #include "core/io/image.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include <PvrTcEncoder.h> #include <RgbaBitmap.h> @@ -43,6 +43,10 @@ static void _compress_pvrtc1_4bpp(Image *p_img) { if (!img->is_size_po2() || img->get_width() != img->get_height()) { make_mipmaps = img->has_mipmaps(); img->resize_to_po2(true); + // Resizing can fail for some formats + if (!img->is_size_po2() || img->get_width() != img->get_height()) { + ERR_FAIL_MSG("Failed to resize the image for compression."); + } } img->convert(Image::FORMAT_RGBA8); if (!img->has_mipmaps() && make_mipmaps) { @@ -52,7 +56,7 @@ static void _compress_pvrtc1_4bpp(Image *p_img) { bool use_alpha = img->detect_alpha(); Ref<Image> new_img; - new_img.instance(); + new_img.instantiate(); new_img->create(img->get_width(), img->get_height(), img->has_mipmaps(), use_alpha ? Image::FORMAT_PVRTC1_4A : Image::FORMAT_PVRTC1_4); Vector<uint8_t> data = new_img->get_data(); diff --git a/modules/pvr/register_types.cpp b/modules/pvr/register_types.cpp index aeac564c93..ef72087d25 100644 --- a/modules/pvr/register_types.cpp +++ b/modules/pvr/register_types.cpp @@ -36,7 +36,7 @@ static Ref<ResourceFormatPVR> resource_loader_pvr; void register_pvr_types() { - resource_loader_pvr.instance(); + resource_loader_pvr.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_pvr); _register_pvrtc_compress_func(); diff --git a/modules/pvr/texture_loader_pvr.cpp b/modules/pvr/texture_loader_pvr.cpp index 83f032ca2b..cb12976090 100644 --- a/modules/pvr/texture_loader_pvr.cpp +++ b/modules/pvr/texture_loader_pvr.cpp @@ -30,7 +30,7 @@ #include "texture_loader_pvr.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" static void _pvrtc_decompress(Image *p_img); diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index 66558efa8c..88c0145ebc 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -64,7 +64,7 @@ void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) { camera_ray_masks.resize(ray_packets_count * TILE_SIZE * TILE_SIZE); } -void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool) { +void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool) { CameraRayThreadData td; td.camera_matrix = p_cam_projection; td.camera_transform = p_cam_transform; @@ -82,7 +82,7 @@ void RaycastOcclusionCull::RaycastHZBuffer::_camera_rays_threaded(uint32_t p_thr _generate_camera_rays(p_data->camera_transform, p_data->camera_matrix, p_data->camera_orthogonal, from, to); } -void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to) { +void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to) { Size2i buffer_size = sizes[0]; CameraMatrix inv_camera_matrix = p_cam_projection.inverse(); @@ -227,7 +227,7 @@ void RaycastOcclusionCull::remove_scenario(RID p_scenario) { scenario.removed = true; } -void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) { +void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) { ERR_FAIL_COND(!scenarios.has(p_scenario)); Scenario &scenario = scenarios[p_scenario]; @@ -345,7 +345,7 @@ void RaycastOcclusionCull::Scenario::_transform_vertices_thread(uint32_t p_threa _transform_vertices_range(p_data->read, p_data->write, p_data->xform, from, to); } -void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform &p_xform, int p_from, int p_to) { +void RaycastOcclusionCull::Scenario::_transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to) { for (int i = p_from; i < p_to; i++) { p_write[i] = p_xform.xform(p_read[i]); } @@ -491,7 +491,7 @@ void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size) buffers[p_buffer].resize(p_size); } -void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) { +void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) { if (!buffers.has(p_buffer)) { return; } diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h index acaceb9459..85710a790c 100644 --- a/modules/raycast/raycast_occlusion_cull.h +++ b/modules/raycast/raycast_occlusion_cull.h @@ -34,7 +34,7 @@ #include "core/io/image.h" #include "core/math/camera_matrix.h" #include "core/object/object.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "scene/resources/mesh.h" @@ -52,14 +52,14 @@ public: struct CameraRayThreadData { CameraMatrix camera_matrix; - Transform camera_transform; + Transform3D camera_transform; bool camera_orthogonal; int thread_count; Size2i buffer_size; }; void _camera_rays_threaded(uint32_t p_thread, CameraRayThreadData *p_data); - void _generate_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to); + void _generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to); public: LocalVector<RayPacket> camera_rays; @@ -69,7 +69,7 @@ public: virtual void clear() override; virtual void resize(const Size2i &p_size) override; void sort_rays(); - void update_camera_rays(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool); + void update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool); }; private: @@ -99,7 +99,7 @@ private: RID occluder; LocalVector<uint32_t> indices; LocalVector<Vector3> xformed_vertices; - Transform xform; + Transform3D xform; bool enabled = true; bool removed = false; }; @@ -113,7 +113,7 @@ private: struct TransformThreadData { uint32_t thread_count; uint32_t vertex_count; - Transform xform; + Transform3D xform; const Vector3 *read; Vector3 *write; }; @@ -134,7 +134,7 @@ private: void _update_dirty_instance_thread(int p_idx, RID *p_instances); void _update_dirty_instance(int p_idx, RID *p_instances, ThreadWorkPool *p_thread_pool); void _transform_vertices_thread(uint32_t p_thread, TransformThreadData *p_data); - void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform &p_xform, int p_from, int p_to); + void _transform_vertices_range(const Vector3 *p_read, Vector3 *p_write, const Transform3D &p_xform, int p_from, int p_to); static void _commit_scene(void *p_ud); bool update(ThreadWorkPool &p_thread_pool); @@ -164,7 +164,7 @@ public: virtual void add_scenario(RID p_scenario) override; virtual void remove_scenario(RID p_scenario) override; - virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) override; + virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) override; virtual void scenario_remove_instance(RID p_scenario, RID p_instance) override; virtual void add_buffer(RID p_buffer) override; @@ -172,7 +172,7 @@ public: virtual HZBuffer *buffer_get_ptr(RID p_buffer) override; virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) override; virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) override; - virtual void buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) override; + virtual void buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) override; virtual RID buffer_get_debug_texture(RID p_buffer) override; virtual void set_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality) override; diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml index b21f5d1e7a..7f5a0dfecb 100644 --- a/modules/regex/doc_classes/RegEx.xml +++ b/modules/regex/doc_classes/RegEx.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RegEx" inherits="Reference" version="4.0"> +<class name="RegEx" inherits="RefCounted" version="4.0"> <brief_description> Class for searching text for patterns using regular expressions. </brief_description> diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml index a45de60aef..492519d3d9 100644 --- a/modules/regex/doc_classes/RegExMatch.xml +++ b/modules/regex/doc_classes/RegExMatch.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="RegExMatch" inherits="Reference" version="4.0"> +<class name="RegExMatch" inherits="RefCounted" version="4.0"> <brief_description> Contains the results of a [RegEx] search. </brief_description> @@ -51,7 +51,7 @@ <member name="names" type="Dictionary" setter="" getter="get_names" default="{}"> A dictionary of named groups and its corresponding group number. Only groups that were matched are included. If multiple groups have the same name, that name would refer to the first matching one. </member> - <member name="strings" type="Array" setter="" getter="get_strings" default="[ ]"> + <member name="strings" type="Array" setter="" getter="get_strings" default="[]"> An [Array] of the match and its capturing groups. </member> <member name="subject" type="String" setter="" getter="get_subject" default=""""> diff --git a/modules/regex/regex.h b/modules/regex/regex.h index f5773042fb..68fe2bc6e0 100644 --- a/modules/regex/regex.h +++ b/modules/regex/regex.h @@ -31,15 +31,15 @@ #ifndef REGEX_H #define REGEX_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/string/ustring.h" #include "core/templates/map.h" #include "core/templates/vector.h" #include "core/variant/array.h" #include "core/variant/dictionary.h" -class RegExMatch : public Reference { - GDCLASS(RegExMatch, Reference); +class RegExMatch : public RefCounted { + GDCLASS(RegExMatch, RefCounted); struct Range { int start = 0; @@ -68,8 +68,8 @@ public: int get_end(const Variant &p_name) const; }; -class RegEx : public Reference { - GDCLASS(RegEx, Reference); +class RegEx : public RefCounted { + GDCLASS(RegEx, RefCounted); void *general_ctx; void *code = nullptr; diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp index e8e481de2d..768b419348 100644 --- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp +++ b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp @@ -30,7 +30,7 @@ #include "audio_stream_ogg_vorbis.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" void AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) { ERR_FAIL_COND(!active); @@ -129,7 +129,7 @@ Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() { "to it. AudioStreamOGGVorbis should not be created from the " "inspector or with `.new()`. Instead, load an audio file."); - ovs.instance(); + ovs.instantiate(); ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this); ovs->ogg_alloc.alloc_buffer = (char *)memalloc(decode_mem_size); ovs->ogg_alloc.alloc_buffer_length_in_bytes = decode_mem_size; diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml index 8a1bb62e24..94fdff5d43 100644 --- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml +++ b/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml @@ -11,7 +11,7 @@ <methods> </methods> <members> - <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray( )"> + <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()"> Contains the audio data in bytes. </member> <member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false"> diff --git a/modules/stb_vorbis/register_types.cpp b/modules/stb_vorbis/register_types.cpp index 6f7eb53bc8..d9c6c06d65 100644 --- a/modules/stb_vorbis/register_types.cpp +++ b/modules/stb_vorbis/register_types.cpp @@ -41,7 +41,7 @@ void register_stb_vorbis_types() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { Ref<ResourceImporterOGGVorbis> ogg_import; - ogg_import.instance(); + ogg_import.instantiate(); ResourceFormatImporter::get_singleton()->add_importer(ogg_import); } #endif diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp index e3aa630cef..85de698efd 100644 --- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp +++ b/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp @@ -30,8 +30,8 @@ #include "resource_importer_ogg_vorbis.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "scene/resources/texture.h" String ResourceImporterOGGVorbis::get_importer_name() const { @@ -90,7 +90,7 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin memdelete(f); Ref<AudioStreamOGGVorbis> ogg_stream; - ogg_stream.instance(); + ogg_stream.instantiate(); ogg_stream->set_data(data); ERR_FAIL_COND_V(!ogg_stream->get_data().size(), ERR_FILE_CORRUPT); diff --git a/modules/text_server_adv/dynamic_font_adv.cpp b/modules/text_server_adv/dynamic_font_adv.cpp index c29aac05bb..62eedebb59 100644 --- a/modules/text_server_adv/dynamic_font_adv.cpp +++ b/modules/text_server_adv/dynamic_font_adv.cpp @@ -420,7 +420,7 @@ DynamicFontDataAdvanced::Character DynamicFontDataAdvanced::bitmap_to_character( Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata)); if (tex.texture.is_null()) { - tex.texture.instance(); + tex.texture.instantiate(); tex.texture->create_from_image(img); } else { tex.texture->update(img); //update diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index 7eff3f8dee..906ebe4993 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -2352,24 +2352,22 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { sd->glyphs.push_back(gl); } else { Vector<RID> fonts; - // Push fonts with the language and script support first. - for (int l = 0; l < span.fonts.size(); l++) { - if ((font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) { - fonts.push_back(sd->spans[k].fonts[l]); - } - } - // Push fonts with the script support. - for (int l = 0; l < sd->spans[k].fonts.size(); l++) { - if (!(font_is_language_supported(span.fonts[l], span.language)) && (font_is_script_supported(span.fonts[l], script))) { - fonts.push_back(sd->spans[k].fonts[l]); - } - } - // Push the rest valid fonts. - for (int l = 0; l < sd->spans[k].fonts.size(); l++) { - if (!(font_is_language_supported(span.fonts[l], span.language)) && !(font_is_script_supported(span.fonts[l], script))) { - fonts.push_back(sd->spans[k].fonts[l]); + Vector<RID> fonts_scr_only; + Vector<RID> fonts_no_match; + int font_count = span.fonts.size(); + for (int l = 0; l < font_count; l++) { + if (font_is_script_supported(span.fonts[l], script)) { + if (font_is_language_supported(span.fonts[l], span.language)) { + fonts.push_back(sd->spans[k].fonts[l]); + } else { + fonts_scr_only.push_back(sd->spans[k].fonts[l]); + } + } else { + fonts_no_match.push_back(sd->spans[k].fonts[l]); } } + fonts.append_array(fonts_scr_only); + fonts.append_array(fonts_no_match); _shape_run(sd, MAX(sd->spans[k].start, script_run_start), MIN(sd->spans[k].end, script_run_end), sd->script_iter->script_ranges[j].script, bidi_run_direction, fonts, k, 0); } } diff --git a/modules/text_server_fb/dynamic_font_fb.cpp b/modules/text_server_fb/dynamic_font_fb.cpp index a261ba8f37..7e77987074 100644 --- a/modules/text_server_fb/dynamic_font_fb.cpp +++ b/modules/text_server_fb/dynamic_font_fb.cpp @@ -306,7 +306,7 @@ DynamicFontDataFallback::Character DynamicFontDataFallback::bitmap_to_character( Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata)); if (tex.texture.is_null()) { - tex.texture.instance(); + tex.texture.instantiate(); tex.texture->create_from_image(img); } else { tex.texture->update(img); //update diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 98a67ef309..a22559efdd 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -634,17 +634,17 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te span.start = sd->text.length(); span.end = span.start + p_text.length(); // Pre-sort fonts, push fonts with the language support first. - for (int i = 0; i < p_fonts.size(); i++) { + Vector<RID> fonts_no_match; + int font_count = p_fonts.size(); + for (int i = 0; i < font_count; i++) { if (font_is_language_supported(p_fonts[i], p_language)) { span.fonts.push_back(p_fonts[i]); + } else { + fonts_no_match.push_back(p_fonts[i]); } } - // Push the rest valid fonts. - for (int i = 0; i < p_fonts.size(); i++) { - if (!font_is_language_supported(p_fonts[i], p_language)) { - span.fonts.push_back(p_fonts[i]); - } - } + span.fonts.append_array(fonts_no_match); + ERR_FAIL_COND_V(span.fonts.is_empty(), false); span.font_size = p_size; span.language = p_language; diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp index 3cfd4ff36a..f0d7c335bd 100644 --- a/modules/tga/image_loader_tga.cpp +++ b/modules/tga/image_loader_tga.cpp @@ -35,7 +35,7 @@ #include "core/os/os.h" #include "core/string/print_string.h" -Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size) { +Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size, size_t p_input_size) { Error error; Vector<uint8_t> pixels; @@ -56,11 +56,14 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t compressed_pos += 1; count = (c & 0x7f) + 1; - if (output_pos + count * p_pixel_size > output_pos) { + if (output_pos + count * p_pixel_size > p_output_size) { return ERR_PARSE_ERROR; } if (c & 0x80) { + if (compressed_pos + p_pixel_size > p_input_size) { + return ERR_PARSE_ERROR; + } for (size_t i = 0; i < p_pixel_size; i++) { pixels_w[i] = p_compressed_buffer[compressed_pos]; compressed_pos += 1; @@ -72,6 +75,9 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t output_pos += p_pixel_size; } } else { + if (compressed_pos + count * p_pixel_size > p_input_size) { + return ERR_PARSE_ERROR; + } count *= p_pixel_size; for (size_t i = 0; i < count; i++) { p_uncompressed_buffer[output_pos] = p_compressed_buffer[compressed_pos]; @@ -83,7 +89,7 @@ Error ImageLoaderTGA::decode_tga_rle(const uint8_t *p_compressed_buffer, size_t return OK; } -Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_output_size) { +Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size) { #define TGA_PUT_PIXEL(r, g, b, a) \ int image_data_ofs = ((y * width) + x); \ image_data_w[image_data_ofs * 4 + 0] = r; \ @@ -134,7 +140,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff if (p_is_monochrome) { while (y != y_end) { while (x != x_end) { - if (i > p_output_size) { + if (i >= p_input_size) { return ERR_PARSE_ERROR; } uint8_t shade = p_buffer[i]; @@ -150,7 +156,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } else { while (y != y_end) { while (x != x_end) { - if (i > p_output_size) { + if (i >= p_input_size) { return ERR_PARSE_ERROR; } uint8_t index = p_buffer[i]; @@ -181,7 +187,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } else if (p_header.pixel_depth == 24) { while (y != y_end) { while (x != x_end) { - if (i + 2 > p_output_size) { + if (i + 2 >= p_input_size) { return ERR_PARSE_ERROR; } @@ -200,7 +206,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff } else if (p_header.pixel_depth == 32) { while (y != y_end) { while (x != x_end) { - if (i + 3 > p_output_size) { + if (i + 3 >= p_input_size) { return ERR_PARSE_ERROR; } @@ -307,7 +313,7 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force const uint8_t *buffer = nullptr; if (is_encoded) { - err = decode_tga_rle(src_image_r, pixel_size, uncompressed_buffer_w, buffer_size); + err = decode_tga_rle(src_image_r, pixel_size, uncompressed_buffer_w, buffer_size, src_image_len); if (err == OK) { uncompressed_buffer_r = uncompressed_buffer.ptr(); @@ -337,7 +343,7 @@ static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) { Error open_memfile_error = memfile.open_custom(p_tga, p_size); ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer."); Ref<Image> img; - img.instance(); + img.instantiate(); Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f); ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load TGA image."); return img; diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h index cb2ce07edd..e4463a322f 100644 --- a/modules/tga/image_loader_tga.h +++ b/modules/tga/image_loader_tga.h @@ -72,8 +72,8 @@ class ImageLoaderTGA : public ImageFormatLoader { uint8_t pixel_depth = 0; uint8_t image_descriptor = 0; }; - static Error decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size); - static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_output_size); + static Error decode_tga_rle(const uint8_t *p_compressed_buffer, size_t p_pixel_size, uint8_t *p_uncompressed_buffer, size_t p_output_size, size_t p_input_size); + static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size); public: virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp index 0218b8c7a4..fd6c9dcd3c 100644 --- a/modules/theora/register_types.cpp +++ b/modules/theora/register_types.cpp @@ -35,7 +35,7 @@ static Ref<ResourceFormatLoaderTheora> resource_loader_theora; void register_theora_types() { - resource_loader_theora.instance(); + resource_loader_theora.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_theora, true); ClassDB::register_class<VideoStreamTheora>(); diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp index 7b421bdc16..2f6faec8ec 100644 --- a/modules/theora/video_stream_theora.cpp +++ b/modules/theora/video_stream_theora.cpp @@ -108,7 +108,7 @@ void VideoStreamPlaybackTheora::video_write() { Ref<Image> img = memnew(Image(size.x, size.y, 0, Image::FORMAT_RGBA8, frame_data)); //zero copy image creation - texture->update(img, true); //zero copy send to visual server + texture->update(img); //zero copy send to visual server frames_pending = 1; } @@ -302,7 +302,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { } } - /* and now we have it all. initialize decoders */ + /* And now we have it all. Initialize decoders. */ if (theora_p) { td = th_decode_alloc(&ti, ts); px_fmt = ti.pixel_fmt; @@ -335,7 +335,7 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) { size.y = h; Ref<Image> img; - img.instance(); + img.instantiate(); img->create(w, h, false, Image::FORMAT_RGBA8); } else { @@ -484,10 +484,10 @@ void VideoStreamPlaybackTheora::update(float p_delta) { //printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready); - /* is it already too old to be useful? This is only actually - useful cosmetically after a SIGSTOP. Note that we have to + /* is it already too old to be useful? This is only actually + useful cosmetically after a SIGSTOP. Note that we have to decode the frame even if we don't show it (for now) due to - keyframing. Soon enough libtheora will be able to deal + keyframing. Soon enough libtheora will be able to deal with non-keyframe seeks. */ if (videobuf_time >= get_time()) { diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 2685a8a013..760173d0df 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -31,8 +31,8 @@ #ifndef VIDEO_STREAM_THEORA_H #define VIDEO_STREAM_THEORA_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/os/semaphore.h" #include "core/os/thread.h" #include "core/templates/ring_buffer.h" diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml index 785c8dad50..09a2c8a88c 100644 --- a/modules/upnp/doc_classes/UPNP.xml +++ b/modules/upnp/doc_classes/UPNP.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UPNP" inherits="Reference" version="4.0"> +<class name="UPNP" inherits="RefCounted" version="4.0"> <brief_description> UPNP network functions. </brief_description> diff --git a/modules/upnp/doc_classes/UPNPDevice.xml b/modules/upnp/doc_classes/UPNPDevice.xml index f3b96bb89d..f7b5386d86 100644 --- a/modules/upnp/doc_classes/UPNPDevice.xml +++ b/modules/upnp/doc_classes/UPNPDevice.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="UPNPDevice" inherits="Reference" version="4.0"> +<class name="UPNPDevice" inherits="RefCounted" version="4.0"> <brief_description> UPNP device. </brief_description> diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp index 8e4e833d45..efe618012a 100644 --- a/modules/upnp/upnp.cpp +++ b/modules/upnp/upnp.cpp @@ -92,7 +92,7 @@ int UPNP::discover(int timeout, int ttl, const String &device_filter) { void UPNP::add_device_to_list(UPNPDev *dev, UPNPDev *devlist) { Ref<UPNPDevice> new_device; - new_device.instance(); + new_device.instantiate(); new_device->set_description_url(dev->descURL); new_device->set_service_type(dev->st); diff --git a/modules/upnp/upnp.h b/modules/upnp/upnp.h index a0cca96bc8..b961a9667f 100644 --- a/modules/upnp/upnp.h +++ b/modules/upnp/upnp.h @@ -31,14 +31,14 @@ #ifndef GODOT_UPNP_H #define GODOT_UPNP_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "upnp_device.h" #include <miniupnpc/miniupnpc.h> -class UPNP : public Reference { - GDCLASS(UPNP, Reference); +class UPNP : public RefCounted { + GDCLASS(UPNP, RefCounted); private: String discover_multicast_if = ""; diff --git a/modules/upnp/upnp_device.h b/modules/upnp/upnp_device.h index 126e761a56..0a66c36ab9 100644 --- a/modules/upnp/upnp_device.h +++ b/modules/upnp/upnp_device.h @@ -31,10 +31,10 @@ #ifndef GODOT_UPNP_DEVICE_H #define GODOT_UPNP_DEVICE_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class UPNPDevice : public Reference { - GDCLASS(UPNPDevice, Reference); +class UPNPDevice : public RefCounted { + GDCLASS(UPNPDevice, RefCounted); public: enum IGDStatus { diff --git a/modules/vhacd/config.py b/modules/vhacd/config.py index d22f9454ed..a42f27fbe1 100644 --- a/modules/vhacd/config.py +++ b/modules/vhacd/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp index daad39bdfb..3d7aaee921 100644 --- a/modules/vhacd/register_types.cpp +++ b/modules/vhacd/register_types.cpp @@ -32,7 +32,7 @@ #include "scene/resources/mesh.h" #include "thirdparty/vhacd/public/VHACD.h" -static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces) { +static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int p_max_convex_hulls = -1) { Vector<float> vertices; vertices.resize(p_faces.size() * 9); Vector<uint32_t> indices; @@ -47,8 +47,12 @@ static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces) { } } - VHACD::IVHACD *decomposer = VHACD::CreateVHACD(); VHACD::IVHACD::Parameters params; + if (p_max_convex_hulls > 0) { + params.m_maxConvexHulls = p_max_convex_hulls; + } + + VHACD::IVHACD *decomposer = VHACD::CreateVHACD(); decomposer->Compute(vertices.ptr(), vertices.size() / 3, indices.ptr(), indices.size() / 3, params); int hull_count = decomposer->GetNConvexHulls(); diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml index 5112ea43a7..9d51bd86a2 100644 --- a/modules/visual_script/doc_classes/VisualScript.xml +++ b/modules/visual_script/doc_classes/VisualScript.xml @@ -4,7 +4,7 @@ A script implemented in the Visual Script programming environment. </brief_description> <description> - A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it. + A script implemented in the Visual Script programming environment. The script extends the functionality of all objects that instance it. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes. You are most likely to use this class via the Visual Script editor or when writing plugins for it. </description> @@ -39,7 +39,7 @@ </argument> <argument index="1" name="node" type="VisualScriptNode"> </argument> - <argument index="2" name="position" type="Vector2" default="Vector2( 0, 0 )"> + <argument index="2" name="position" type="Vector2" default="Vector2(0, 0)"> </argument> <description> Add a node to the VisualScript. diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml index de5d731cc0..d6b96957f5 100644 --- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml +++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml @@ -15,10 +15,10 @@ <methods> </methods> <members> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> The constant's parent class. </member> - <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="@"""> + <member name="constant" type="StringName" setter="set_class_constant" getter="get_class_constant" default="&"""> The constant to return. See the given class for its available constants. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml index 243338ea52..02cec97b27 100644 --- a/modules/visual_script/doc_classes/VisualScriptComment.xml +++ b/modules/visual_script/doc_classes/VisualScriptComment.xml @@ -15,7 +15,7 @@ <member name="description" type="String" setter="set_description" getter="get_description" default=""""> The text inside the comment node. </member> - <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2( 150, 150 )"> + <member name="size" type="Vector2" setter="set_size" getter="get_size" default="Vector2(150, 150)"> The comment node's size (in pixels). </member> <member name="title" type="String" setter="set_title" getter="get_title" default=""Comment""> diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml index 5c9c8d3eca..df3121d093 100644 --- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml @@ -15,7 +15,7 @@ <methods> </methods> <members> - <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="@"""> + <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&"""> The signal to emit. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml index 2d0fac1fa0..48104afcf7 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml @@ -11,13 +11,13 @@ <members> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> </member> <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> </member> <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptFunctionCall.CallMode" default="0"> </member> - <member name="function" type="StringName" setter="set_function" getter="get_function" default="@"""> + <member name="function" type="StringName" setter="set_function" getter="get_function" default="&"""> </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> </member> diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml index 68083614a6..16c1629fe4 100644 --- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml +++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="VisualScriptFunctionState" inherits="Reference" version="4.0"> +<class name="VisualScriptFunctionState" inherits="RefCounted" version="4.0"> <brief_description> </brief_description> <description> @@ -28,7 +28,7 @@ <method name="resume"> <return type="Variant"> </return> - <argument index="0" name="args" type="Array" default="null"> + <argument index="0" name="args" type="Array" default="[]"> </argument> <description> </description> diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml index 6c296fdb4b..9ca67feacb 100644 --- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml +++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml @@ -9,7 +9,7 @@ <methods> </methods> <members> - <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="@"""> + <member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="&"""> </member> <member name="mode" type="int" setter="set_action_mode" getter="get_action_mode" enum="VisualScriptInputAction.Mode" default="0"> </member> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml index c3741eea89..185f0f1ffb 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml @@ -18,7 +18,7 @@ <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0"> The local variable's type. </member> - <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="@"new_local""> + <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&"new_local""> The local variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml index 619bbb90ca..865f0153c9 100644 --- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml @@ -20,7 +20,7 @@ <member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0"> The local variable's type. </member> - <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="@"new_local""> + <member name="var_name" type="StringName" setter="set_var_name" getter="get_var_name" default="&"new_local""> The local variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml index 1c22070ab1..ff6c723a3e 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml @@ -11,7 +11,7 @@ <members> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> </member> <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> </member> @@ -19,7 +19,7 @@ </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> </member> - <member name="property" type="StringName" setter="set_property" getter="get_property" default="@"""> + <member name="property" type="StringName" setter="set_property" getter="get_property" default="&"""> </member> <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertyGet.CallMode" default="0"> </member> diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml index 629576e261..71bfc4c8a5 100644 --- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml +++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml @@ -13,7 +13,7 @@ </member> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script"> </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> </member> <member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type"> </member> @@ -21,7 +21,7 @@ </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> </member> - <member name="property" type="StringName" setter="set_property" getter="get_property" default="@"""> + <member name="property" type="StringName" setter="set_property" getter="get_property" default="&"""> </member> <member name="set_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptPropertySet.CallMode" default="0"> </member> diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml index 80a8d31041..9e3e020f2d 100644 --- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml +++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml @@ -11,7 +11,7 @@ <members> <member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default=""""> </member> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> </member> </members> <constants> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml index d182e14e4d..df20ac53f2 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml @@ -15,7 +15,7 @@ <methods> </methods> <members> - <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="@"""> + <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&"""> The variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml index 3bd392dd85..eb8ebbe338 100644 --- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml +++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml @@ -16,7 +16,7 @@ <methods> </methods> <members> - <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="@"""> + <member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&"""> The variable's name. </member> </members> diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml index 483cdfeaf8..c59234433f 100644 --- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml +++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml @@ -9,13 +9,13 @@ <methods> </methods> <members> - <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="@"Object""> + <member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&"Object""> </member> <member name="call_mode" type="int" setter="set_call_mode" getter="get_call_mode" enum="VisualScriptYieldSignal.CallMode" default="0"> </member> <member name="node_path" type="NodePath" setter="set_base_path" getter="get_base_path"> </member> - <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="@"""> + <member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&"""> </member> </members> <constants> diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp index b863f622bd..c4b3f9ba44 100644 --- a/modules/visual_script/visual_script.cpp +++ b/modules/visual_script/visual_script.cpp @@ -725,7 +725,7 @@ int VisualScript::get_available_id() const { ///////////////////////////////// -bool VisualScript::can_instance() const { +bool VisualScript::can_instantiate() const { return true; // ScriptServer::is_scripting_enabled(); } @@ -954,60 +954,10 @@ bool VisualScript::are_subnodes_edited() const { } #endif -Vector<ScriptNetData> VisualScript::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> VisualScript::get_rpc_methods() const { return rpc_functions; } -uint16_t VisualScript::get_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < rpc_functions.size(); i++) { - if (rpc_functions[i].name == p_method) { - return i; - } - } - return UINT16_MAX; -} - -StringName VisualScript::get_rpc_method(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), StringName()); - return rpc_functions[p_rpc_method_id].name; -} - -MultiplayerAPI::RPCMode VisualScript::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - ERR_FAIL_COND_V(p_rpc_method_id >= rpc_functions.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_functions[p_rpc_method_id].mode; -} - -MultiplayerAPI::RPCMode VisualScript::get_rpc_mode(const StringName &p_method) const { - return get_rpc_mode_by_id(get_rpc_method_id(p_method)); -} - -Vector<ScriptNetData> VisualScript::get_rset_properties() const { - return rpc_variables; -} - -uint16_t VisualScript::get_rset_property_id(const StringName &p_variable) const { - for (int i = 0; i < rpc_variables.size(); i++) { - if (rpc_variables[i].name == p_variable) { - return i; - } - } - return UINT16_MAX; -} - -StringName VisualScript::get_rset_property(const uint16_t p_rset_property_id) const { - ERR_FAIL_COND_V(p_rset_property_id >= rpc_variables.size(), StringName()); - return rpc_variables[p_rset_property_id].name; -} - -MultiplayerAPI::RPCMode VisualScript::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const { - ERR_FAIL_COND_V(p_rset_variable_id >= rpc_variables.size(), MultiplayerAPI::RPC_MODE_DISABLED); - return rpc_variables[p_rset_variable_id].mode; -} - -MultiplayerAPI::RPCMode VisualScript::get_rset_mode(const StringName &p_variable) const { - return get_rset_mode_by_id(get_rset_property_id(p_variable)); -} - void VisualScript::_set_data(const Dictionary &p_data) { Dictionary d = p_data; if (d.has("base_type")) { @@ -1065,7 +1015,6 @@ void VisualScript::_set_data(const Dictionary &p_data) { // Takes all the rpc methods. rpc_functions.clear(); - rpc_variables.clear(); List<StringName> fns; functions.get_key_list(&fns); for (const List<StringName>::Element *E = fns.front(); E; E = E->next()) { @@ -1073,9 +1022,10 @@ void VisualScript::_set_data(const Dictionary &p_data) { Ref<VisualScriptFunction> vsf = nodes[functions[E->get()].func_id].node; if (vsf.is_valid()) { if (vsf->get_rpc_mode() != MultiplayerAPI::RPC_MODE_DISABLED) { - ScriptNetData nd; + MultiplayerAPI::RPCConfig nd; nd.name = E->get(); - nd.mode = vsf->get_rpc_mode(); + nd.rpc_mode = vsf->get_rpc_mode(); + nd.transfer_mode = MultiplayerPeer::TRANSFER_MODE_RELIABLE; // TODO if (rpc_functions.find(nd) == -1) { rpc_functions.push_back(nd); } @@ -1085,7 +1035,7 @@ void VisualScript::_set_data(const Dictionary &p_data) { } // Sort so we are 100% that they are always the same. - rpc_functions.sort_custom<SortNetData>(); + rpc_functions.sort_custom<MultiplayerAPI::SortRPCConfig>(); } Dictionary VisualScript::_get_data() const { @@ -1882,46 +1832,10 @@ Ref<Script> VisualScriptInstance::get_script() const { return script; } -Vector<ScriptNetData> VisualScriptInstance::get_rpc_methods() const { +const Vector<MultiplayerAPI::RPCConfig> VisualScriptInstance::get_rpc_methods() const { return script->get_rpc_methods(); } -uint16_t VisualScriptInstance::get_rpc_method_id(const StringName &p_method) const { - return script->get_rpc_method_id(p_method); -} - -StringName VisualScriptInstance::get_rpc_method(const uint16_t p_rpc_method_id) const { - return script->get_rpc_method(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - return script->get_rpc_mode_by_id(p_rpc_method_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rpc_mode(const StringName &p_method) const { - return script->get_rpc_mode(p_method); -} - -Vector<ScriptNetData> VisualScriptInstance::get_rset_properties() const { - return script->get_rset_properties(); -} - -uint16_t VisualScriptInstance::get_rset_property_id(const StringName &p_variable) const { - return script->get_rset_property_id(p_variable); -} - -StringName VisualScriptInstance::get_rset_property(const uint16_t p_rset_property_id) const { - return script->get_rset_property(p_rset_property_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode_by_id(const uint16_t p_rset_variable_id) const { - return script->get_rset_mode_by_id(p_rset_variable_id); -} - -MultiplayerAPI::RPCMode VisualScriptInstance::get_rset_mode(const StringName &p_variable) const { - return script->get_rset_mode(p_variable); -} - void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_owner) { script = p_script; owner = p_owner; @@ -2044,7 +1958,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) { Ref<VisualScriptNode> node = script->nodes[F->get()].node; - VisualScriptNodeInstance *instance = node->instance(this); // Create instance. + VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance. ERR_FAIL_COND(!instance); instance->base = node.ptr(); @@ -2290,7 +2204,7 @@ Variant VisualScriptFunctionState::resume(Array p_args) { void VisualScriptFunctionState::_bind_methods() { ClassDB::bind_method(D_METHOD("connect_to_signal", "obj", "signals", "args"), &VisualScriptFunctionState::connect_to_signal); - ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("resume", "args"), &VisualScriptFunctionState::resume, DEFVAL(Array())); ClassDB::bind_method(D_METHOD("is_valid"), &VisualScriptFunctionState::is_valid); ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &VisualScriptFunctionState::_signal_callback, MethodInfo("_signal_callback")); } @@ -2348,7 +2262,7 @@ void VisualScriptLanguage::get_string_delimiters(List<String> *p_delimiters) con Ref<Script> VisualScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const { Ref<VisualScript> script; - script.instance(); + script.instantiate(); script->set_instance_base_type(p_base_class_name); return script; } @@ -2362,7 +2276,7 @@ void VisualScriptLanguage::make_template(const String &p_class_name, const Strin script->set_instance_base_type(p_base_class_name); } -bool VisualScriptLanguage::validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path, List<String> *r_functions, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { +bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const { return false; } diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h index cc78b3242d..932ebeb27f 100644 --- a/modules/visual_script/visual_script.h +++ b/modules/visual_script/visual_script.h @@ -87,7 +87,7 @@ public: void set_breakpoint(bool p_breakpoint); bool is_breakpoint() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) = 0; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) = 0; struct TypeGuess { Variant::Type type = Variant::NIL; @@ -234,8 +234,7 @@ private: HashMap<StringName, Function> functions; HashMap<StringName, Variable> variables; Map<StringName, Vector<Argument>> custom_signals; - Vector<ScriptNetData> rpc_functions; - Vector<ScriptNetData> rpc_variables; + Vector<MultiplayerAPI::RPCConfig> rpc_functions; Map<Object *, VisualScriptInstance *> instances; @@ -326,7 +325,7 @@ public: void set_instance_base_type(const StringName &p_type); - virtual bool can_instance() const override; + virtual bool can_instantiate() const override; virtual Ref<Script> get_base_script() const override; virtual StringName get_instance_base_type() const override; @@ -363,17 +362,7 @@ public: virtual int get_member_line(const StringName &p_member) const override; - virtual Vector<ScriptNetData> get_rpc_methods() const override; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const override; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override; - - virtual Vector<ScriptNetData> get_rset_properties() const override; - virtual uint16_t get_rset_property_id(const StringName &p_property) const override; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const override; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override; #ifdef TOOLS_ENABLED virtual bool are_subnodes_edited() const; @@ -454,24 +443,14 @@ public: virtual ScriptLanguage *get_language(); - virtual Vector<ScriptNetData> get_rpc_methods() const; - virtual uint16_t get_rpc_method_id(const StringName &p_method) const; - virtual StringName get_rpc_method(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode_by_id(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const; - - virtual Vector<ScriptNetData> get_rset_properties() const; - virtual uint16_t get_rset_property_id(const StringName &p_property) const; - virtual StringName get_rset_property(const uint16_t p_rset_property_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode_by_id(const uint16_t p_rpc_method_id) const; - virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const; + virtual const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const; VisualScriptInstance(); ~VisualScriptInstance(); }; -class VisualScriptFunctionState : public Reference { - GDCLASS(VisualScriptFunctionState, Reference); +class VisualScriptFunctionState : public RefCounted { + GDCLASS(VisualScriptFunctionState, RefCounted); friend class VisualScriptInstance; ObjectID instance_id; @@ -592,7 +571,7 @@ public: virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const; virtual bool is_using_templates(); virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script); - virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; + virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const; virtual Script *create_script() const; virtual bool has_named_classes() const; virtual bool supports_builtin_mode() const; @@ -640,7 +619,7 @@ public: template <class T> static Ref<VisualScriptNode> create_node_generic(const String &p_name) { Ref<T> node; - node.instance(); + node.instantiate(); return node; } diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp index df34ec22ce..f17ad62531 100644 --- a/modules/visual_script/visual_script_builtin_funcs.cpp +++ b/modules/visual_script/visual_script_builtin_funcs.cpp @@ -33,7 +33,7 @@ #include "core/io/marshalls.h" #include "core/math/math_funcs.h" #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" @@ -1187,7 +1187,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptBuiltinFunc::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptBuiltinFunc::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceBuiltinFunc *instance = memnew(VisualScriptNodeInstanceBuiltinFunc); instance->node = this; instance->instance = p_instance; diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h index 1fafaf1d98..7196d4b46a 100644 --- a/modules/visual_script/visual_script_builtin_funcs.h +++ b/modules/visual_script/visual_script_builtin_funcs.h @@ -139,7 +139,7 @@ public: void set_func(BuiltinFunc p_which); BuiltinFunc get_func(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptBuiltinFunc(VisualScriptBuiltinFunc::BuiltinFunc func); VisualScriptBuiltinFunc(); diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 7432440603..8712bfa06b 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -381,7 +381,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; - case Variant::QUAT: + case Variant::QUATERNION: color = Color(0.93, 0.41, 0.64); break; case Variant::AABB: @@ -390,7 +390,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::BASIS: color = Color(0.89, 0.93, 0.41); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: color = Color(0.96, 0.66, 0.43); break; @@ -487,7 +487,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::PLANE: color = Color(0.97, 0.44, 0.44); break; - case Variant::QUAT: + case Variant::QUATERNION: color = Color(0.93, 0.41, 0.64); break; case Variant::AABB: @@ -496,7 +496,7 @@ static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) { case Variant::BASIS: color = Color(0.7, 0.73, 0.1); break; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: color = Color(0.96, 0.56, 0.28); break; @@ -624,10 +624,10 @@ void VisualScriptEditor::_update_graph(int p_only_id) { Control::get_theme_icon("Vector3i", "EditorIcons"), Control::get_theme_icon("Transform2D", "EditorIcons"), Control::get_theme_icon("Plane", "EditorIcons"), - Control::get_theme_icon("Quat", "EditorIcons"), + Control::get_theme_icon("Quaternion", "EditorIcons"), Control::get_theme_icon("AABB", "EditorIcons"), Control::get_theme_icon("Basis", "EditorIcons"), - Control::get_theme_icon("Transform", "EditorIcons"), + Control::get_theme_icon("Transform3D", "EditorIcons"), Control::get_theme_icon("Color", "EditorIcons"), Control::get_theme_icon("NodePath", "EditorIcons"), Control::get_theme_icon("RID", "EditorIcons"), @@ -739,6 +739,7 @@ void VisualScriptEditor::_update_graph(int p_only_id) { } Color c = sbf->get_border_color(); + c = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85); Color ic = c; gnode->add_theme_color_override("title_color", c); c.a = 1; @@ -1074,10 +1075,10 @@ void VisualScriptEditor::_update_members() { Control::get_theme_icon("Vector3i", "EditorIcons"), Control::get_theme_icon("Transform2D", "EditorIcons"), Control::get_theme_icon("Plane", "EditorIcons"), - Control::get_theme_icon("Quat", "EditorIcons"), + Control::get_theme_icon("Quaternion", "EditorIcons"), Control::get_theme_icon("AABB", "EditorIcons"), Control::get_theme_icon("Basis", "EditorIcons"), - Control::get_theme_icon("Transform", "EditorIcons"), + Control::get_theme_icon("Transform3D", "EditorIcons"), Control::get_theme_icon("Color", "EditorIcons"), Control::get_theme_icon("NodePath", "EditorIcons"), Control::get_theme_icon("RID", "EditorIcons"), @@ -1299,10 +1300,10 @@ void VisualScriptEditor::_create_function_dialog() { void VisualScriptEditor::_create_function() { String name = _validate_name((func_name_box->get_text() == "") ? "new_func" : func_name_box->get_text()); selected = name; - Vector2 ofs = _get_available_pos(); + Vector2 pos = _get_available_pos(); Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(name); for (int i = 0; i < func_input_vbox->get_child_count(); i++) { @@ -1321,7 +1322,7 @@ void VisualScriptEditor::_create_function() { undo_redo->create_action(TTR("Add Function")); undo_redo->add_do_method(script.ptr(), "add_function", name, func_node_id); undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", func_node_id); undo_redo->add_do_method(this, "_update_members"); undo_redo->add_undo_method(this, "_update_members"); @@ -1416,18 +1417,18 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt } else if (p_button == 0) { String name = _validate_name("new_function"); selected = name; - Vector2 ofs = _get_available_pos(); + Vector2 pos = _get_available_pos(); Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(name); int fn_id = script->get_available_id(); undo_redo->create_action(TTR("Add Function")); undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_function", name); - undo_redo->add_do_method(script.ptr(), "remove_node", fn_id); + undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); undo_redo->add_do_method(this, "_update_members"); undo_redo->add_undo_method(this, "_update_members"); undo_redo->add_do_method(this, "_update_graph"); @@ -1620,17 +1621,19 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id updating_graph = false; } -Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const { - if (centered) { - ofs = graph->get_scroll_ofs() + graph->get_size() * 0.5; - } - +Vector2 VisualScriptEditor::_get_pos_in_graph(Vector2 p_point) const { + Vector2 pos = (graph->get_scroll_ofs() + p_point) / (graph->get_zoom() * EDSCALE); if (graph->is_using_snap()) { int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); + pos = pos.snapped(Vector2(snap, snap)); } + return pos; +} - ofs /= EDSCALE; +Vector2 VisualScriptEditor::_get_available_pos(bool p_centered, Vector2 p_pos) const { + if (p_centered) { + p_pos = _get_pos_in_graph(graph->get_size() * 0.5); + } while (true) { bool exists = false; @@ -1638,8 +1641,8 @@ Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const script->get_node_list(&existing); for (List<int>::Element *E = existing.front(); E; E = E->next()) { Point2 pos = script->get_node_position(E->get()); - if (pos.distance_to(ofs) < 50) { - ofs += Vector2(graph->get_snap(), graph->get_snap()); + if (pos.distance_to(p_pos) < 50) { + p_pos += Vector2(graph->get_snap(), graph->get_snap()); exists = true; break; } @@ -1650,7 +1653,7 @@ Vector2 VisualScriptEditor::_get_available_pos(bool centered, Vector2 ofs) const break; } - return ofs; + return p_pos; } String VisualScriptEditor::_validate_name(const String &p_name) const { @@ -1852,7 +1855,7 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) { } member_name = ti->get_text(0); } - if (ED_IS_SHORTCUT("visual_script_editor/delete_selected", p_event)) { + if (ED_IS_SHORTCUT("ui_graph_delete", p_event)) { _member_option(MEMBER_REMOVE); } if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) { @@ -2048,16 +2051,9 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da return; } - Vector2 ofs = graph->get_scroll_ofs() + p_point; - - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); - int new_id = _create_new_node_from_name(d["node_type"], ofs); + int new_id = _create_new_node_from_name(d["node_type"], pos); Node *node = graph->get_node(itos(new_id)); if (node) { @@ -2072,23 +2068,17 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da #else bool use_set = Input::get_singleton()->is_key_pressed(KEY_CTRL); #endif - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptNode> vnode; if (use_set) { Ref<VisualScriptVariableSet> vnodes; - vnodes.instance(); + vnodes.instantiate(); vnodes->set_variable(d["variable"]); vnode = vnodes; } else { Ref<VisualScriptVariableGet> vnodeg; - vnodeg.instance(); + vnodeg.instantiate(); vnodeg->set_variable(d["variable"]); vnode = vnodeg; } @@ -2096,7 +2086,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2110,22 +2100,16 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "visual_script_function_drag") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptFunctionCall> vnode; - vnode.instance(); + vnode.instantiate(); vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type()); undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]); @@ -2142,22 +2126,16 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "visual_script_signal_drag") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptEmitSignal> vnode; - vnode.instance(); + vnode.instantiate(); vnode->set_signal(d["signal"]); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2171,22 +2149,16 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "resource") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Ref<VisualScriptPreload> prnode; - prnode.instance(); + prnode.instantiate(); prnode->set_preload(d["resource"]); int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Preload Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2200,13 +2172,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } if (String(d["type"]) == "files") { - Vector2 ofs = graph->get_scroll_ofs() + p_point; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); Array files = d["files"]; @@ -2223,14 +2189,14 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } Ref<VisualScriptPreload> prnode; - prnode.instance(); + prnode.instantiate(); prnode->set_preload(res); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); new_ids.push_back(new_id); new_id++; - ofs += Vector2(20, 20) * EDSCALE; + pos += Vector2(20, 20); } undo_redo->add_do_method(this, "_update_graph"); @@ -2263,13 +2229,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da Array nodes = d["nodes"]; - Vector2 ofs = graph->get_scroll_ofs() + p_point; - - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - ofs /= EDSCALE; + Vector2 pos = _get_pos_in_graph(p_point); undo_redo->create_action(TTR("Add Node(s) From Tree")); int base_id = script->get_available_id(); @@ -2289,13 +2249,13 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da if (use_node) { Ref<VisualScriptSceneNode> scene_node; - scene_node.instance(); + scene_node.instantiate(); scene_node->set_node_path(sn->get_path_to(node)); n = scene_node; } else { // ! Doesn't work properly. Ref<VisualScriptFunctionCall> call; - call.instance(); + call.instantiate(); call->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH); call->set_base_path(sn->get_path_to(node)); call->set_base_type(node->get_class()); @@ -2304,11 +2264,11 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da selecting_method_id = base_id; } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", base_id); base_id++; - ofs += Vector2(25, 25); + pos += Vector2(25, 25); } undo_redo->add_do_method(this, "_update_graph"); undo_redo->add_undo_method(this, "_update_graph"); @@ -2330,14 +2290,8 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } Node *node = Object::cast_to<Node>(obj); - Vector2 ofs = graph->get_scroll_ofs() + p_point; - - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } + Vector2 pos = _get_pos_in_graph(p_point); - ofs /= EDSCALE; #ifdef OSX_ENABLED bool use_get = Input::get_singleton()->is_key_pressed(KEY_META); #else @@ -2357,7 +2311,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da if (!use_get) { Ref<VisualScriptPropertySet> pset; - pset.instance(); + pset.instantiate(); pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE); pset->set_base_type(obj->get_class()); /*if (use_value) { @@ -2367,14 +2321,14 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da vnode = pset; } else { Ref<VisualScriptPropertyGet> pget; - pget.instance(); + pget.instantiate(); pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE); pget->set_base_type(obj->get_class()); vnode = pget; } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); if (!use_get) { undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); @@ -2399,7 +2353,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da if (!use_get) { Ref<VisualScriptPropertySet> pset; - pset.instance(); + pset.instantiate(); if (sn == node) { pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF); } else { @@ -2410,7 +2364,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da vnode = pset; } else { Ref<VisualScriptPropertyGet> pget; - pget.instance(); + pget.instantiate(); if (sn == node) { pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF); } else { @@ -2419,7 +2373,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } vnode = pget; } - undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos); undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]); if (!use_get) { undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]); @@ -2665,7 +2619,7 @@ void VisualScriptEditor::add_callback(const String &p_function, PackedStringArra } Ref<VisualScriptFunction> func; - func.instance(); + func.instantiate(); for (int i = 0; i < p_args.size(); i++) { String name = p_args[i]; Variant::Type type = Variant::NIL; @@ -3008,7 +2962,7 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro if (!vsn.is_valid()) { return; } - if (vsn->get_output_value_port_count()) { + if (vsn->get_output_value_port_count() || vsn->get_output_sequence_port_count()) { port_action_pos = p_release_pos; } @@ -3074,19 +3028,12 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac } void VisualScriptEditor::_port_action_menu(int p_option) { - Vector2 ofs = graph->get_scroll_ofs() + port_action_pos; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - ofs /= EDSCALE; - Set<int> vn; switch (p_option) { case CREATE_CALL_SET_GET: { Ref<VisualScriptFunctionCall> n; - n.instance(); + n.instantiate(); VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn); @@ -3171,13 +3118,7 @@ void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<Visua } void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) { - Vector2 ofs = graph->get_scroll_ofs() + port_action_pos; - if (graph->is_using_snap()) { - int snap = graph->get_snap(); - ofs = ofs.snapped(Vector2(snap, snap)); - } - ofs /= EDSCALE; - ofs /= graph->get_zoom(); + Vector2 pos = _get_pos_in_graph(port_action_pos); Set<int> vn; @@ -3215,7 +3156,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri } undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, pos); if (vnode_old.is_valid() && p_connecting) { connect_seq(vnode_old, vnode_new, new_id); connect_data(vnode_old, vnode_new, new_id); @@ -3233,16 +3174,16 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri if (p_category == String("method")) { Ref<VisualScriptFunctionCall> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_category == String("set")) { Ref<VisualScriptPropertySet> n; - n.instance(); + n.instantiate(); vnode = n; script_prop_set = n; } else if (p_category == String("get")) { Ref<VisualScriptPropertyGet> n; - n.instance(); + n.instantiate(); n->set_property(p_text); vnode = n; } @@ -3250,35 +3191,35 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri if (p_category == String("action")) { if (p_text == "VisualScriptCondition") { Ref<VisualScriptCondition> n; - n.instance(); + n.instantiate(); vnode = n; } if (p_text == "VisualScriptSwitch") { Ref<VisualScriptSwitch> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptSequence") { Ref<VisualScriptSequence> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptIterator") { Ref<VisualScriptIterator> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptWhile") { Ref<VisualScriptWhile> n; - n.instance(); + n.instantiate(); vnode = n; } else if (p_text == "VisualScriptReturn") { Ref<VisualScriptReturn> n; - n.instance(); + n.instantiate(); vnode = n; } } int new_id = script->get_available_id(); undo_redo->create_action(TTR("Add Node")); - undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", new_id); undo_redo->add_do_method(this, "_update_graph", new_id); undo_redo->add_undo_method(this, "_update_graph", new_id); @@ -3467,7 +3408,7 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons selected = name; Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(name); int fn_id = script->get_available_id(); undo_redo->create_action(TTR("Add Function")); @@ -3477,18 +3418,18 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, cons func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string); } - Vector2 ofs = _get_available_pos(); + Vector2 pos = _get_available_pos(); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) { Ref<VisualScriptReturn> ret_node; - ret_node.instance(); + ret_node.instantiate(); ret_node->set_return_type(minfo.return_val.type); ret_node->set_enable_return_value(true); ret_node->set_name(name); int nid = script->get_available_id() + 1; - undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, ofs + Vector2(500, 0))); + undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, pos + Vector2(500, 0))); undo_redo->add_undo_method(script.ptr(), "remove_node", nid); } @@ -3992,16 +3933,16 @@ void VisualScriptEditor::_menu_option(int p_what) { { String new_fn = _validate_name("new_function"); - Vector2 ofs = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150)); + Vector2 pos = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150)); Ref<VisualScriptFunction> func_node; - func_node.instance(); + func_node.instantiate(); func_node->set_name(new_fn); undo_redo->create_action(TTR("Create Function")); undo_redo->add_do_method(script.ptr(), "add_function", new_fn, fn_id); - undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, ofs); + undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos); undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn); undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id); undo_redo->add_do_method(this, "_update_members"); @@ -4040,12 +3981,12 @@ void VisualScriptEditor::_menu_option(int p_what) { int m = 1; for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) { Ref<VisualScriptReturn> ret_node; - ret_node.instance(); + ret_node.instantiate(); int ret_id = fn_id + (m++); selections.insert(ret_id); - Vector2 ofsi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100)); - undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, ofsi); + Vector2 posi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100)); + undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi); undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id); undo_redo->add_do_method(script.ptr(), "sequence_connect", G->get(), 0, ret_id); @@ -4120,7 +4061,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { member_name = ti->get_text(0); member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE); + member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); member_popup->popup(); return; } @@ -4130,7 +4071,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { member_name = ti->get_text(0); member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE); + member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); member_popup->popup(); return; } @@ -4140,7 +4081,7 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) { member_name = ti->get_text(0); member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT); member_popup->add_separator(); - member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("visual_script_editor/delete_selected"), MEMBER_REMOVE); + member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE); member_popup->popup(); return; } @@ -4242,9 +4183,9 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name); - ClassDB::bind_method("get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw); - ClassDB::bind_method("can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw); - ClassDB::bind_method("drop_data_fw", &VisualScriptEditor::drop_data_fw); + ClassDB::bind_method("_get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw); + ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw); + ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw); ClassDB::bind_method("_input", &VisualScriptEditor::_input); @@ -4528,7 +4469,7 @@ void VisualScriptEditor::register_editor() { Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_name) { Ref<VisualScriptCustomNode> node; - node.instance(); + node.instantiate(); node->set_script(singleton->custom_nodes[p_name]); return node; } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index ef3a5d11c0..1f0f087be7 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -226,7 +226,8 @@ class VisualScriptEditor : public ScriptEditorBase { void _update_node_size(int p_id); void _port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input); - Vector2 _get_available_pos(bool centered = true, Vector2 ofs = Vector2()) const; + Vector2 _get_pos_in_graph(Vector2 p_point) const; + Vector2 _get_available_pos(bool p_centered = true, Vector2 p_pos = Vector2()) const; bool node_has_sequence_connections(int p_id); @@ -317,6 +318,7 @@ public: virtual void set_tooltip_request_func(String p_method, Object *p_obj) override; virtual Control *get_edit_menu() override; virtual void clear_edit_menu() override; + virtual void set_find_replace_bar(FindReplaceBar *p_bar) override { p_bar->hide(); }; // Not needed here. virtual bool can_lose_focus_on_node_selection() override { return false; } virtual void validate() override; diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp index cb4230bea9..d63fbeb726 100644 --- a/modules/visual_script/visual_script_expression.cpp +++ b/modules/visual_script/visual_script_expression.cpp @@ -1498,7 +1498,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptExpression::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptExpression::instantiate(VisualScriptInstance *p_instance) { _compile_expression(); VisualScriptNodeInstanceExpression *instance = memnew(VisualScriptNodeInstanceExpression); instance->instance = p_instance; diff --git a/modules/visual_script/visual_script_expression.h b/modules/visual_script/visual_script_expression.h index c35075ea53..ef16222b42 100644 --- a/modules/visual_script/visual_script_expression.h +++ b/modules/visual_script/visual_script_expression.h @@ -273,7 +273,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "operators"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptExpression(); ~VisualScriptExpression(); diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index e977f9c96b..af86f90b25 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -138,7 +138,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptReturn::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptReturn::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceReturn *instance = memnew(VisualScriptNodeInstanceReturn); instance->node = this; instance->instance = p_instance; @@ -154,7 +154,7 @@ VisualScriptReturn::VisualScriptReturn() { template <bool with_value> static Ref<VisualScriptNode> create_return_node(const String &p_name) { Ref<VisualScriptReturn> node; - node.instance(); + node.instantiate(); node->set_enable_return_value(with_value); return node; } @@ -231,7 +231,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptCondition::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptCondition::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceCondition *instance = memnew(VisualScriptNodeInstanceCondition); instance->node = this; instance->instance = p_instance; @@ -311,7 +311,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptWhile::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptWhile::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceWhile *instance = memnew(VisualScriptNodeInstanceWhile); instance->node = this; instance->instance = p_instance; @@ -435,7 +435,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptIterator::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptIterator::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIterator *instance = memnew(VisualScriptNodeInstanceIterator); instance->node = this; instance->instance = p_instance; @@ -534,7 +534,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSequence::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSequence::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSequence *instance = memnew(VisualScriptNodeInstanceSequence); instance->node = this; instance->instance = p_instance; @@ -618,7 +618,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSwitch::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSwitch::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSwitch *instance = memnew(VisualScriptNodeInstanceSwitch); instance->instance = p_instance; instance->case_count = case_values.size(); @@ -831,7 +831,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptTypeCast::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptTypeCast::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceTypeCast *instance = memnew(VisualScriptNodeInstanceTypeCast); instance->instance = p_instance; instance->base_type = base_type; diff --git a/modules/visual_script/visual_script_flow_control.h b/modules/visual_script/visual_script_flow_control.h index d9c4dedafd..73822fcc37 100644 --- a/modules/visual_script/visual_script_flow_control.h +++ b/modules/visual_script/visual_script_flow_control.h @@ -64,7 +64,7 @@ public: void set_enable_return_value(bool p_enable); bool is_return_value_enabled() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptReturn(); }; @@ -91,7 +91,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptCondition(); }; @@ -118,7 +118,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptWhile(); }; @@ -145,7 +145,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptIterator(); }; @@ -177,7 +177,7 @@ public: void set_steps(int p_steps); int get_steps() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSequence(); }; @@ -220,7 +220,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "flow_control"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSwitch(); }; @@ -258,7 +258,7 @@ public: virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptTypeCast(); }; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 9310b86627..8f7b514881 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -513,19 +513,19 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "singleton") { if (call_mode != CALL_MODE_SINGLETON) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { List<Engine::Singleton> names; Engine::get_singleton()->get_singletons(&names); @@ -543,7 +543,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -614,7 +614,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } if (mc == 0) { - property.usage = 0; //do not show + property.usage = PROPERTY_USAGE_NONE; //do not show } else { property.hint_string = "0," + itos(mc) + ",1"; } @@ -622,7 +622,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const if (property.name == "rpc_call_mode") { if (call_mode == CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -737,20 +737,22 @@ public: } int to_id = 0; - bool reliable = true; + //bool reliable = true; if (rpc_mode >= VisualScriptFunctionCall::RPC_RELIABLE_TO_ID) { to_id = *p_args[0]; p_args += 1; p_argcount -= 1; - if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { - reliable = false; - } - } else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) { - reliable = false; + //if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE_TO_ID) { + //reliable = false; + //} } + //else if (rpc_mode == VisualScriptFunctionCall::RPC_UNRELIABLE) { + //reliable = false; + //} - node->rpcp(to_id, !reliable, function, p_args, p_argcount); + // TODO reliable? + node->rpcp(to_id, function, p_args, p_argcount); return true; } @@ -854,7 +856,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptFunctionCall::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptFunctionCall::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceFunctionCall *instance = memnew(VisualScriptNodeInstanceFunctionCall); instance->node = this; instance->instance = p_instance; @@ -889,7 +891,7 @@ VisualScriptFunctionCall::VisualScriptFunctionCall() { template <VisualScriptFunctionCall::CallMode cmode> static Ref<VisualScriptNode> create_function_call_node(const String &p_name) { Ref<VisualScriptFunctionCall> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } @@ -1276,19 +1278,19 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -1350,7 +1352,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { property.hint_string = options; property.type = Variant::STRING; if (options == "") { - property.usage = 0; //hide if type has no usable index + property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index } } } @@ -1585,7 +1587,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptPropertySet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptPropertySet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePropertySet *instance = memnew(VisualScriptNodeInstancePropertySet); instance->node = this; instance->instance = p_instance; @@ -1616,7 +1618,7 @@ VisualScriptPropertySet::VisualScriptPropertySet() { template <VisualScriptPropertySet::CallMode cmode> static Ref<VisualScriptNode> create_property_set_node(const String &p_name) { Ref<VisualScriptPropertySet> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } @@ -1954,19 +1956,19 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { if (property.name == "base_script") { if (call_mode != CALL_MODE_INSTANCE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "basic_type") { if (call_mode != CALL_MODE_BASIC_TYPE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -2027,7 +2029,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { property.hint_string = options; property.type = Variant::STRING; if (options == "") { - property.usage = 0; //hide if type has no usable index + property.usage = PROPERTY_USAGE_NONE; //hide if type has no usable index } } } @@ -2173,7 +2175,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptPropertyGet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptPropertyGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePropertyGet *instance = memnew(VisualScriptNodeInstancePropertyGet); instance->node = this; instance->instance = p_instance; @@ -2195,7 +2197,7 @@ VisualScriptPropertyGet::VisualScriptPropertyGet() { template <VisualScriptPropertyGet::CallMode cmode> static Ref<VisualScriptNode> create_property_get_node(const String &p_name) { Ref<VisualScriptPropertyGet> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } @@ -2319,7 +2321,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptEmitSignal::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptEmitSignal::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEmitSignal *instance = memnew(VisualScriptNodeInstanceEmitSignal); instance->node = this; instance->instance = p_instance; @@ -2338,7 +2340,7 @@ static Ref<VisualScriptNode> create_basic_type_call_node(const String &p_name) { String method = path[3]; Ref<VisualScriptFunctionCall> node; - node.instance(); + node.instantiate(); Variant::Type type = Variant::VARIANT_MAX; diff --git a/modules/visual_script/visual_script_func_nodes.h b/modules/visual_script/visual_script_func_nodes.h index 2ff9b7a981..eb17be1fbe 100644 --- a/modules/visual_script/visual_script_func_nodes.h +++ b/modules/visual_script/visual_script_func_nodes.h @@ -125,7 +125,7 @@ public: void set_rpc_call_mode(RPCCallMode p_mode); RPCCallMode get_rpc_call_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -231,7 +231,7 @@ public: void set_assign_op(AssignOp p_op); AssignOp get_assign_op() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; VisualScriptPropertySet(); @@ -314,7 +314,7 @@ public: void set_index(const StringName &p_type); StringName get_index() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptPropertyGet(); }; @@ -351,7 +351,7 @@ public: void set_signal(const StringName &p_type); StringName get_signal() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptEmitSignal(); }; diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp index fed6637acb..b93c710652 100644 --- a/modules/visual_script/visual_script_nodes.cpp +++ b/modules/visual_script/visual_script_nodes.cpp @@ -296,7 +296,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptFunction::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptFunction::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceFunction *instance = memnew(VisualScriptNodeInstanceFunction); instance->node = this; instance->instance = p_instance; @@ -791,7 +791,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptComposeArray::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptComposeArray::instantiate(VisualScriptInstance *p_instance) { VisualScriptComposeArrayNode *instance = memnew(VisualScriptComposeArrayNode); instance->input_count = inputports.size(); return instance; @@ -912,73 +912,135 @@ PropertyInfo VisualScriptOperator::get_output_value_port_info(int p_idx) const { return pinfo; } -static const char *op_names[] = { - //comparison - "Are Equal", //OP_EQUAL, - "Are Not Equal", //OP_NOT_EQUAL, - "Less Than", //OP_LESS, - "Less Than or Equal", //OP_LESS_EQUAL, - "Greater Than", //OP_GREATER, - "Greater Than or Equal", //OP_GREATER_EQUAL, - //mathematic - "Add", //OP_ADD, - "Subtract", //OP_SUBTRACT, - "Multiply", //OP_MULTIPLY, - "Divide", //OP_DIVIDE, - "Negate", //OP_NEGATE, - "Positive", //OP_POSITIVE, - "Remainder", //OP_MODULE, - "Concatenate", //OP_STRING_CONCAT, - //bitwise - "Bit Shift Left", //OP_SHIFT_LEFT, - "Bit Shift Right", //OP_SHIFT_RIGHT, - "Bit And", //OP_BIT_AND, - "Bit Or", //OP_BIT_OR, - "Bit Xor", //OP_BIT_XOR, - "Bit Negate", //OP_BIT_NEGATE, - //logic - "And", //OP_AND, - "Or", //OP_OR, - "Xor", //OP_XOR, - "Not", //OP_NOT, - //containment - "In", //OP_IN, -}; - String VisualScriptOperator::get_caption() const { - static const char32_t *op_names[] = { - //comparison - U"A = B", //OP_EQUAL, - U"A \u2260 B", //OP_NOT_EQUAL, - U"A < B", //OP_LESS, - U"A \u2264 B", //OP_LESS_EQUAL, - U"A > B", //OP_GREATER, - U"A \u2265 B", //OP_GREATER_EQUAL, - //mathematic - U"A + B", //OP_ADD, - U"A - B", //OP_SUBTRACT, - U"A \u00D7 B", //OP_MULTIPLY, - U"A \u00F7 B", //OP_DIVIDE, - U"\u00AC A", //OP_NEGATE, - U"+ A", //OP_POSITIVE, - U"A mod B", //OP_MODULE, - U"A .. B", //OP_STRING_CONCAT, - //bitwise - U"A << B", //OP_SHIFT_LEFT, - U"A >> B", //OP_SHIFT_RIGHT, - U"A & B", //OP_BIT_AND, - U"A | B", //OP_BIT_OR, - U"A ^ B", //OP_BIT_XOR, - U"~A", //OP_BIT_NEGATE, - //logic - U"A and B", //OP_AND, - U"A or B", //OP_OR, - U"A xor B", //OP_XOR, - U"not A", //OP_NOT, - U"A in B", //OP_IN, - - }; - return op_names[op]; + switch (op) { + // comparison + case Variant::OP_EQUAL: + return U"A = B"; + case Variant::OP_NOT_EQUAL: + return U"A \u2260 B"; + case Variant::OP_LESS: + return U"A < B"; + case Variant::OP_LESS_EQUAL: + return U"A \u2264 B"; + case Variant::OP_GREATER: + return U"A > B"; + case Variant::OP_GREATER_EQUAL: + return U"A \u2265 B"; + + // mathematic + case Variant::OP_ADD: + return U"A + B"; + case Variant::OP_SUBTRACT: + return U"A - B"; + case Variant::OP_MULTIPLY: + return U"A \u00D7 B"; + case Variant::OP_DIVIDE: + return U"A \u00F7 B"; + case Variant::OP_NEGATE: + return U"\u00AC A"; + case Variant::OP_POSITIVE: + return U"+ A"; + case Variant::OP_MODULE: + return U"A mod B"; + + // bitwise + case Variant::OP_SHIFT_LEFT: + return U"A << B"; + case Variant::OP_SHIFT_RIGHT: + return U"A >> B"; + case Variant::OP_BIT_AND: + return U"A & B"; + case Variant::OP_BIT_OR: + return U"A | B"; + case Variant::OP_BIT_XOR: + return U"A ^ B"; + case Variant::OP_BIT_NEGATE: + return U"~A"; + + // logic + case Variant::OP_AND: + return U"A and B"; + case Variant::OP_OR: + return U"A or B"; + case Variant::OP_XOR: + return U"A xor B"; + case Variant::OP_NOT: + return U"not A"; + case Variant::OP_IN: + return U"A in B"; + + default: { + ERR_FAIL_V_MSG( + U"Unknown node", + U"Unknown node type encountered, caption not available."); + } + } +} + +String VisualScriptOperator::get_operator_name(Variant::Operator p_op) { + switch (p_op) { + // comparison + case Variant::OP_EQUAL: + return "Are Equal"; + case Variant::OP_NOT_EQUAL: + return "Are Not Equal"; + case Variant::OP_LESS: + return "Less Than"; + case Variant::OP_LESS_EQUAL: + return "Less Than or Equal"; + case Variant::OP_GREATER: + return "Greater Than"; + case Variant::OP_GREATER_EQUAL: + return "Greater Than or Equal"; + + // mathematic + case Variant::OP_ADD: + return "Add"; + case Variant::OP_SUBTRACT: + return "Subtract"; + case Variant::OP_MULTIPLY: + return "Multiply"; + case Variant::OP_DIVIDE: + return "Divide"; + case Variant::OP_NEGATE: + return "Negate"; + case Variant::OP_POSITIVE: + return "Positive"; + case Variant::OP_MODULE: + return "Remainder"; + + // bitwise + case Variant::OP_SHIFT_LEFT: + return "Bit Shift Left"; + case Variant::OP_SHIFT_RIGHT: + return "Bit Shift Right"; + case Variant::OP_BIT_AND: + return "Bit And"; + case Variant::OP_BIT_OR: + return "Bit Or"; + case Variant::OP_BIT_XOR: + return "Bit Xor"; + case Variant::OP_BIT_NEGATE: + return "Bit Negate"; + + // logic + case Variant::OP_AND: + return "And"; + case Variant::OP_OR: + return "Or"; + case Variant::OP_XOR: + return "Xor"; + case Variant::OP_NOT: + return "Not"; + case Variant::OP_IN: + return "In"; + + default: { + ERR_FAIL_INDEX_V(p_op, Variant::OP_MAX, ""); + return "Unknown Operator"; + } + } } void VisualScriptOperator::set_operator(Variant::Operator p_op) { @@ -1018,7 +1080,7 @@ void VisualScriptOperator::_bind_methods() { if (i > 0) { types += ","; } - types += op_names[i]; + types += get_operator_name(static_cast<Variant::Operator>(i)); } String argt = "Any"; @@ -1051,9 +1113,9 @@ public: r_error_str = *p_outputs[0]; } else { if (unary) { - r_error_str = String(op_names[op]) + RTR(": Invalid argument of type: ") + Variant::get_type_name(p_inputs[0]->get_type()); + r_error_str = String(Variant::get_operator_name(op)) + RTR(": Invalid argument of type: ") + Variant::get_type_name(p_inputs[0]->get_type()); } else { - r_error_str = String(op_names[op]) + RTR(": Invalid arguments: ") + "A: " + Variant::get_type_name(p_inputs[0]->get_type()) + " B: " + Variant::get_type_name(p_inputs[1]->get_type()); + r_error_str = String(Variant::get_operator_name(op)) + RTR(": Invalid arguments: ") + "A: " + Variant::get_type_name(p_inputs[0]->get_type()) + " B: " + Variant::get_type_name(p_inputs[1]->get_type()); } } } @@ -1062,7 +1124,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptOperator::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptOperator::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceOperator *instance = memnew(VisualScriptNodeInstanceOperator); instance->unary = get_input_value_port_count() == 1; instance->op = op; @@ -1077,7 +1139,7 @@ VisualScriptOperator::VisualScriptOperator() { template <Variant::Operator OP> static Ref<VisualScriptNode> create_op_node(const String &p_name) { Ref<VisualScriptOperator> node; - node.instance(); + node.instantiate(); node->set_operator(OP); return node; } @@ -1169,7 +1231,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSelect::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSelect::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSelect *instance = memnew(VisualScriptNodeInstanceSelect); return instance; } @@ -1277,7 +1339,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptVariableGet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptVariableGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceVariableGet *instance = memnew(VisualScriptNodeInstanceVariableGet); instance->node = this; instance->instance = p_instance; @@ -1389,7 +1451,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptVariableSet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptVariableSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceVariableSet *instance = memnew(VisualScriptNodeInstanceVariableSet); instance->node = this; instance->instance = p_instance; @@ -1472,7 +1534,7 @@ void VisualScriptConstant::_validate_property(PropertyInfo &property) const { if (property.name == "value") { property.type = type; if (type == Variant::NIL) { - property.usage = 0; //do not save if nil + property.usage = PROPERTY_USAGE_NONE; //do not save if nil } } } @@ -1504,7 +1566,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceConstant *instance = memnew(VisualScriptNodeInstanceConstant); instance->constant = value; return instance; @@ -1597,7 +1659,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptPreload::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptPreload::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstancePreload *instance = memnew(VisualScriptNodeInstancePreload); instance->preload = preload; return instance; @@ -1662,7 +1724,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptIndexGet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptIndexGet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIndexGet *instance = memnew(VisualScriptNodeInstanceIndexGet); return instance; } @@ -1732,7 +1794,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptIndexSet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptIndexSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceIndexSet *instance = memnew(VisualScriptNodeInstanceIndexSet); return instance; } @@ -1798,7 +1860,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptGlobalConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptGlobalConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceGlobalConstant *instance = memnew(VisualScriptNodeInstanceGlobalConstant); instance->index = index; return instance; @@ -1916,7 +1978,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptClassConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptClassConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceClassConstant *instance = memnew(VisualScriptNodeInstanceClassConstant); instance->value = ClassDB::get_integer_constant(base_type, name, &instance->valid); return instance; @@ -2050,7 +2112,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptBasicTypeConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceBasicTypeConstant *instance = memnew(VisualScriptNodeInstanceBasicTypeConstant); instance->value = Variant::get_constant_value(type, name, &instance->valid); return instance; @@ -2062,7 +2124,7 @@ void VisualScriptBasicTypeConstant::_validate_property(PropertyInfo &property) c Variant::get_constants_for_type(type, &constants); if (constants.size() == 0) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } property.hint_string = ""; @@ -2174,7 +2236,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptMathConstant::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptMathConstant::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceMathConstant *instance = memnew(VisualScriptNodeInstanceMathConstant); instance->value = const_value[constant]; return instance; @@ -2268,7 +2330,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptEngineSingleton::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptEngineSingleton::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceEngineSingleton *instance = memnew(VisualScriptNodeInstanceEngineSingleton); instance->singleton = Engine::get_singleton()->get_singleton_object(singleton); return instance; @@ -2394,7 +2456,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSceneNode::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSceneNode::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSceneNode *instance = memnew(VisualScriptNodeInstanceSceneNode); instance->node = this; instance->instance = p_instance; @@ -2574,7 +2636,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSceneTree::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSceneTree::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSceneTree *instance = memnew(VisualScriptNodeInstanceSceneTree); instance->node = this; instance->instance = p_instance; @@ -2655,7 +2717,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptResourcePath::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptResourcePath::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceResourcePath *instance = memnew(VisualScriptNodeInstanceResourcePath); instance->path = path; return instance; @@ -2727,7 +2789,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSelf::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSelf::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSelf *instance = memnew(VisualScriptNodeInstanceSelf); instance->instance = p_instance; return instance; @@ -2908,7 +2970,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptCustomNode::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptCustomNode::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceCustomNode *instance = memnew(VisualScriptNodeInstanceCustomNode); instance->instance = p_instance; instance->node = this; @@ -3059,7 +3121,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptSubCall::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptSubCall::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceSubCall *instance = memnew(VisualScriptNodeInstanceSubCall); instance->instance = p_instance; Ref<Script> script = get_script(); @@ -3172,7 +3234,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptComment::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptComment::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceComment *instance = memnew(VisualScriptNodeInstanceComment); instance->instance = p_instance; return instance; @@ -3279,7 +3341,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptConstructor::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptConstructor::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceConstructor *instance = memnew(VisualScriptNodeInstanceConstructor); instance->instance = p_instance; instance->type = type; @@ -3308,7 +3370,7 @@ static Ref<VisualScriptNode> create_constructor_node(const String &p_name) { ERR_FAIL_COND_V(!constructor_map.has(p_name), Ref<VisualScriptNode>()); Ref<VisualScriptConstructor> vsc; - vsc.instance(); + vsc.instantiate(); vsc->set_constructor_type(constructor_map[p_name].first); vsc->set_constructor(constructor_map[p_name].second); @@ -3389,7 +3451,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptLocalVar::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptLocalVar::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceLocalVar *instance = memnew(VisualScriptNodeInstanceLocalVar); instance->instance = p_instance; instance->name = name; @@ -3497,7 +3559,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptLocalVarSet::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptLocalVarSet::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceLocalVarSet *instance = memnew(VisualScriptNodeInstanceLocalVarSet); instance->instance = p_instance; instance->name = name; @@ -3634,7 +3696,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptInputAction::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptInputAction::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceInputAction *instance = memnew(VisualScriptNodeInstanceInputAction); instance->instance = p_instance; instance->action = name; @@ -3812,7 +3874,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptDeconstruct::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptDeconstruct::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceDeconstruct *instance = memnew(VisualScriptNodeInstanceDeconstruct); instance->instance = p_instance; instance->outputs.resize(elements.size()); @@ -3849,7 +3911,7 @@ VisualScriptDeconstruct::VisualScriptDeconstruct() { template <Variant::Type T> static Ref<VisualScriptNode> create_node_deconst_typed(const String &p_name) { Ref<VisualScriptDeconstruct> node; - node.instance(); + node.instantiate(); node->set_deconstruct_type(T); return node; } @@ -3918,10 +3980,10 @@ void register_visual_script_nodes() { VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2I), create_node_deconst_typed<Variant::Type::RECT2I>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUAT), create_node_deconst_typed<Variant::Type::QUAT>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUATERNION), create_node_deconst_typed<Variant::Type::QUATERNION>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::AABB), create_node_deconst_typed<Variant::Type::AABB>); VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::BASIS), create_node_deconst_typed<Variant::Type::BASIS>); - VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM), create_node_deconst_typed<Variant::Type::TRANSFORM>); + VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM3D), create_node_deconst_typed<Variant::Type::TRANSFORM3D>); VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>); for (int i = 1; i < Variant::VARIANT_MAX; i++) { diff --git a/modules/visual_script/visual_script_nodes.h b/modules/visual_script/visual_script_nodes.h index 7392443e4e..b599b92b3a 100644 --- a/modules/visual_script/visual_script_nodes.h +++ b/modules/visual_script/visual_script_nodes.h @@ -97,7 +97,7 @@ public: void set_rpc_mode(MultiplayerAPI::RPCMode p_mode); MultiplayerAPI::RPCMode get_rpc_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual void reset_state() override; @@ -192,7 +192,7 @@ public: virtual String get_text() const override; virtual String get_category() const override { return "functions"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptComposeArray(); }; @@ -227,7 +227,9 @@ public: void set_typed(Variant::Type p_op); Variant::Type get_typed() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + static String get_operator_name(Variant::Operator p_op); + + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptOperator(); }; @@ -259,7 +261,7 @@ public: void set_typed(Variant::Type p_op); Variant::Type get_typed() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSelect(); }; @@ -291,7 +293,7 @@ public: void set_variable(StringName p_variable); StringName get_variable() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptVariableGet(); }; @@ -323,7 +325,7 @@ public: void set_variable(StringName p_variable); StringName get_variable() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptVariableSet(); }; @@ -359,7 +361,7 @@ public: void set_constant_value(Variant p_value); Variant get_constant_value() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptConstant(); }; @@ -390,7 +392,7 @@ public: void set_preload(const Ref<Resource> &p_preload); Ref<Resource> get_preload() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptPreload(); }; @@ -413,7 +415,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "operators"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptIndexGet(); }; @@ -436,7 +438,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "operators"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptIndexSet(); }; @@ -466,7 +468,7 @@ public: void set_global_constant(int p_which); int get_global_constant(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptGlobalConstant(); }; @@ -502,7 +504,7 @@ public: void set_base_type(const StringName &p_which); StringName get_base_type(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptClassConstant(); }; @@ -539,7 +541,7 @@ public: void set_basic_type(Variant::Type p_which); Variant::Type get_basic_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptBasicTypeConstant(); }; @@ -586,7 +588,7 @@ public: void set_math_constant(MathConstant p_which); MathConstant get_math_constant(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptMathConstant(); }; @@ -621,7 +623,7 @@ public: void set_singleton(const String &p_string); String get_singleton(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -655,7 +657,7 @@ public: void set_node_path(const NodePath &p_path); NodePath get_node_path(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -684,7 +686,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "data"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -717,7 +719,7 @@ public: void set_resource_path(const String &p_path); String get_resource_path(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptResourcePath(); }; @@ -743,7 +745,7 @@ public: virtual String get_caption() const override; virtual String get_category() const override { return "data"; } - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; virtual TypeGuess guess_output_type(TypeGuess *p_inputs, int p_output) const override; @@ -788,7 +790,7 @@ public: virtual String get_text() const override; virtual String get_category() const override; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; void _script_changed(); @@ -819,7 +821,7 @@ public: virtual String get_text() const override; virtual String get_category() const override; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptSubCall(); }; @@ -859,7 +861,7 @@ public: void set_size(const Size2 &p_size); Size2 get_size() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptComment(); }; @@ -894,7 +896,7 @@ public: void set_constructor(const Dictionary &p_info); Dictionary get_constructor() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptConstructor(); }; @@ -929,7 +931,7 @@ public: void set_var_type(Variant::Type p_type); Variant::Type get_var_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptLocalVar(); }; @@ -965,7 +967,7 @@ public: void set_var_type(Variant::Type p_type); Variant::Type get_var_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptLocalVarSet(); }; @@ -1010,7 +1012,7 @@ public: void set_action_mode(Mode p_mode); Mode get_action_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptInputAction(); }; @@ -1056,7 +1058,7 @@ public: void set_deconstruct_type(Variant::Type p_type); Variant::Type get_deconstruct_type() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptDeconstruct(); }; diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp index 93e14f60d0..79addc5828 100644 --- a/modules/visual_script/visual_script_property_selector.cpp +++ b/modules/visual_script/visual_script_property_selector.cpp @@ -108,10 +108,10 @@ void VisualScriptPropertySelector::_update_search() { vbc->get_theme_icon("Vector3", "EditorIcons"), vbc->get_theme_icon("Transform2D", "EditorIcons"), vbc->get_theme_icon("Plane", "EditorIcons"), - vbc->get_theme_icon("Quat", "EditorIcons"), + vbc->get_theme_icon("Quaternion", "EditorIcons"), vbc->get_theme_icon("AABB", "EditorIcons"), vbc->get_theme_icon("Basis", "EditorIcons"), - vbc->get_theme_icon("Transform", "EditorIcons"), + vbc->get_theme_icon("Transform3D", "EditorIcons"), vbc->get_theme_icon("Color", "EditorIcons"), vbc->get_theme_icon("Path", "EditorIcons"), vbc->get_theme_icon("RID", "EditorIcons"), @@ -469,10 +469,11 @@ void VisualScriptPropertySelector::_item_selected() { at_class = ClassDB::get_parent_class_nocheck(at_class); } - Map<String, DocData::ClassDoc>::Element *T = dd->class_list.find(class_type); + Vector<String> functions = name.rsplit("/", false); + at_class = functions.size() > 3 ? functions[functions.size() - 2] : class_type; + Map<String, DocData::ClassDoc>::Element *T = dd->class_list.find(at_class); if (T) { for (int i = 0; i < T->get().methods.size(); i++) { - Vector<String> functions = name.rsplit("/", false, 1); if (T->get().methods[i].name == functions[functions.size() - 1]) { text = DTR(T->get().methods[i].description); } diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp index 52fe659983..d8bc926a1d 100644 --- a/modules/visual_script/visual_script_yield_nodes.cpp +++ b/modules/visual_script/visual_script_yield_nodes.cpp @@ -113,7 +113,7 @@ public: } Ref<VisualScriptFunctionState> state; - state.instance(); + state.instantiate(); int ret = STEP_YIELD_BIT; switch (mode) { @@ -138,7 +138,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptYield::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptYield::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceYield *instance = memnew(VisualScriptNodeInstanceYield); //instance->instance=p_instance; instance->mode = yield_mode; @@ -174,7 +174,7 @@ float VisualScriptYield::get_wait_time() { void VisualScriptYield::_validate_property(PropertyInfo &property) const { if (property.name == "wait_time") { if (yield_mode != YIELD_WAIT) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -202,7 +202,7 @@ VisualScriptYield::VisualScriptYield() { template <VisualScriptYield::YieldMode MODE> static Ref<VisualScriptNode> create_yield_node(const String &p_name) { Ref<VisualScriptYield> node; - node.instance(); + node.instantiate(); node->set_yield_mode(MODE); return node; } @@ -421,7 +421,7 @@ void VisualScriptYieldSignal::_validate_property(PropertyInfo &property) const { if (property.name == "node_path") { if (call_mode != CALL_MODE_NODE_PATH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } else { Node *bnode = _get_base_node(); if (bnode) { @@ -548,7 +548,7 @@ public: } Ref<VisualScriptFunctionState> state; - state.instance(); + state.instantiate(); state->connect_to_signal(object, signal, Array()); @@ -559,7 +559,7 @@ public: } }; -VisualScriptNodeInstance *VisualScriptYieldSignal::instance(VisualScriptInstance *p_instance) { +VisualScriptNodeInstance *VisualScriptYieldSignal::instantiate(VisualScriptInstance *p_instance) { VisualScriptNodeInstanceYieldSignal *instance = memnew(VisualScriptNodeInstanceYieldSignal); instance->node = this; instance->instance = p_instance; @@ -578,7 +578,7 @@ VisualScriptYieldSignal::VisualScriptYieldSignal() { template <VisualScriptYieldSignal::CallMode cmode> static Ref<VisualScriptNode> create_yield_signal_node(const String &p_name) { Ref<VisualScriptYieldSignal> node; - node.instance(); + node.instantiate(); node->set_call_mode(cmode); return node; } diff --git a/modules/visual_script/visual_script_yield_nodes.h b/modules/visual_script/visual_script_yield_nodes.h index cc7ce0a1c6..fa596173a6 100644 --- a/modules/visual_script/visual_script_yield_nodes.h +++ b/modules/visual_script/visual_script_yield_nodes.h @@ -76,7 +76,7 @@ public: void set_wait_time(float p_time); float get_wait_time(); - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptYield(); }; @@ -135,7 +135,7 @@ public: void set_call_mode(CallMode p_mode); CallMode get_call_mode() const; - virtual VisualScriptNodeInstance *instance(VisualScriptInstance *p_instance) override; + virtual VisualScriptNodeInstance *instantiate(VisualScriptInstance *p_instance) override; VisualScriptYieldSignal(); }; diff --git a/modules/webm/register_types.cpp b/modules/webm/register_types.cpp index 82157a71c9..9cfaba83c1 100644 --- a/modules/webm/register_types.cpp +++ b/modules/webm/register_types.cpp @@ -35,7 +35,7 @@ static Ref<ResourceFormatLoaderWebm> resource_loader_webm; void register_webm_types() { - resource_loader_webm.instance(); + resource_loader_webm.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_webm, true); ClassDB::register_class<VideoStreamWebm>(); diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp index 34addb5c9f..12e0f5bd25 100644 --- a/modules/webm/video_stream_webm.cpp +++ b/modules/webm/video_stream_webm.cpp @@ -31,7 +31,7 @@ #include "video_stream_webm.h" #include "core/config/project_settings.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "servers/audio_server.h" @@ -116,7 +116,7 @@ bool VideoStreamPlaybackWebm::open_file(const String &p_file) { frame_data.resize((webm->getWidth() * webm->getHeight()) << 2); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(webm->getWidth(), webm->getHeight(), false, Image::FORMAT_RGBA8); texture->create_from_image(img); diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp index 1f2a456619..5bebad2b53 100644 --- a/modules/webp/image_loader_webp.cpp +++ b/modules/webp/image_loader_webp.cpp @@ -30,6 +30,7 @@ #include "image_loader_webp.h" +#include "core/config/project_settings.h" #include "core/io/marshalls.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -69,12 +70,77 @@ static Vector<uint8_t> _webp_lossy_pack(const Ref<Image> &p_image, float p_quali w[2] = 'B'; w[3] = 'P'; memcpy(&w[4], dst_buff, dst_size); - free(dst_buff); + WebPFree(dst_buff); return dst; } -static Ref<Image> _webp_lossy_unpack(const Vector<uint8_t> &p_buffer) { +static Vector<uint8_t> _webp_lossless_pack(const Ref<Image> &p_image) { + ERR_FAIL_COND_V(p_image.is_null() || p_image->is_empty(), Vector<uint8_t>()); + + int compression_level = ProjectSettings::get_singleton()->get("rendering/textures/lossless_compression/webp_compression_level"); + compression_level = CLAMP(compression_level, 0, 9); + + Ref<Image> img = p_image->duplicate(); + if (img->detect_alpha()) { + img->convert(Image::FORMAT_RGBA8); + } else { + img->convert(Image::FORMAT_RGB8); + } + + Size2 s(img->get_width(), img->get_height()); + Vector<uint8_t> data = img->get_data(); + const uint8_t *r = data.ptr(); + + // we need to use the more complex API in order to access the 'exact' flag... + + WebPConfig config; + WebPPicture pic; + if (!WebPConfigInit(&config) || !WebPConfigLosslessPreset(&config, compression_level) || !WebPPictureInit(&pic)) { + ERR_FAIL_V(Vector<uint8_t>()); + } + + WebPMemoryWriter wrt; + config.exact = 1; + pic.use_argb = 1; + pic.width = s.width; + pic.height = s.height; + pic.writer = WebPMemoryWrite; + pic.custom_ptr = &wrt; + WebPMemoryWriterInit(&wrt); + + bool success_import = false; + if (img->get_format() == Image::FORMAT_RGB8) { + success_import = WebPPictureImportRGB(&pic, r, 3 * s.width); + } else { + success_import = WebPPictureImportRGBA(&pic, r, 4 * s.width); + } + bool success_encode = false; + if (success_import) { + success_encode = WebPEncode(&config, &pic); + } + WebPPictureFree(&pic); + + if (!success_encode) { + WebPMemoryWriterClear(&wrt); + ERR_FAIL_V_MSG(Vector<uint8_t>(), "WebP packing failed."); + } + + // copy from wrt + Vector<uint8_t> dst; + dst.resize(4 + wrt.size); + uint8_t *w = dst.ptrw(); + w[0] = 'W'; + w[1] = 'E'; + w[2] = 'B'; + w[3] = 'P'; + memcpy(&w[4], wrt.mem, wrt.size); + WebPMemoryWriterClear(&wrt); + + return dst; +} + +static Ref<Image> _webp_unpack(const Vector<uint8_t> &p_buffer) { int size = p_buffer.size() - 4; ERR_FAIL_COND_V(size <= 0, Ref<Image>()); const uint8_t *r = p_buffer.ptr(); @@ -139,7 +205,7 @@ Error webp_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) { Ref<Image> img; - img.instance(); + img.instantiate(); Error err = webp_load_image_from_buffer(img.ptr(), p_png, p_size); ERR_FAIL_COND_V(err, Ref<Image>()); return img; @@ -168,6 +234,7 @@ void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) cons ImageLoaderWEBP::ImageLoaderWEBP() { Image::_webp_mem_loader_func = _webp_mem_loader_func; - Image::lossy_packer = _webp_lossy_pack; - Image::lossy_unpacker = _webp_lossy_unpack; + Image::webp_lossy_packer = _webp_lossy_pack; + Image::webp_lossless_packer = _webp_lossless_pack; + Image::webp_unpacker = _webp_unpack; } diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py index 0a075ccef1..3281415f38 100644 --- a/modules/webrtc/config.py +++ b/modules/webrtc/config.py @@ -10,7 +10,7 @@ def get_doc_classes(): return [ "WebRTCPeerConnection", "WebRTCDataChannel", - "WebRTCMultiplayer", + "WebRTCMultiplayerPeer", ] diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml index 5b9459bc27..26c5bfa6ce 100644 --- a/modules/webrtc/doc_classes/WebRTCMultiplayer.xml +++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml @@ -1,12 +1,12 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCMultiplayer" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="WebRTCMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> A simple interface to create a peer-to-peer mesh network composed of [WebRTCPeerConnection] that is compatible with the [MultiplayerAPI]. </brief_description> <description> This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.network_peer]. You can add each [WebRTCPeerConnection] via [method add_peer] or remove them via [method remove_peer]. Peers must be added in [constant WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate channels. This class will not create offers nor set descriptions, it will only poll them, and notify connections and disconnections. - [signal NetworkedMultiplayerPeer.connection_succeeded] and [signal NetworkedMultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [NetworkedMultiplayerPeer]. + [signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [MultiplayerPeer]. </description> <tutorials> </tutorials> @@ -66,8 +66,8 @@ </argument> <description> Initialize the multiplayer peer with the given [code]peer_id[/code] (must be between 1 and 2147483647). - If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant NetworkedMultiplayerPeer.CONNECTION_CONNECTED] and [signal NetworkedMultiplayerPeer.connection_succeeded] will not be emitted. - If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal NetworkedMultiplayerPeer.peer_connected] signals until a peer with id [constant NetworkedMultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal NetworkedMultiplayerPeer.connection_succeeded]. After that the signal [signal NetworkedMultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal NetworkedMultiplayerPeer.server_disconnected] will be emitted and state will become [constant NetworkedMultiplayerPeer.CONNECTION_CONNECTED]. + If [code]server_compatibilty[/code] is [code]false[/code] (default), the multiplayer peer will be immediately in state [constant MultiplayerPeer.CONNECTION_CONNECTED] and [signal MultiplayerPeer.connection_succeeded] will not be emitted. + If [code]server_compatibilty[/code] is [code]true[/code] the peer will suppress all [signal MultiplayerPeer.peer_connected] signals until a peer with id [constant MultiplayerPeer.TARGET_PEER_SERVER] connects and then emit [signal MultiplayerPeer.connection_succeeded]. After that the signal [signal MultiplayerPeer.peer_connected] will be emitted for every already connected peer, and any new peer that might connect. If the server peer disconnects after that, signal [signal MultiplayerPeer.server_disconnected] will be emitted and state will become [constant MultiplayerPeer.CONNECTION_CONNECTED]. </description> </method> <method name="remove_peer"> @@ -76,13 +76,13 @@ <argument index="0" name="peer_id" type="int"> </argument> <description> - Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal NetworkedMultiplayerPeer.peer_connected] was emitted for it, then [signal NetworkedMultiplayerPeer.peer_disconnected] will be emitted. + Remove the peer with given [code]peer_id[/code] from the mesh. If the peer was connected, and [signal MultiplayerPeer.peer_connected] was emitted for it, then [signal MultiplayerPeer.peer_disconnected] will be emitted. </description> </method> </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> </members> <constants> </constants> diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml index 3b53892a3d..62e524825d 100644 --- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml +++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebRTCPeerConnection" inherits="Reference" version="4.0"> +<class name="WebRTCPeerConnection" inherits="RefCounted" version="4.0"> <brief_description> Interface to a WebRTC peer connection. </brief_description> diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp index ecfaed9089..fcdf04fc2b 100644 --- a/modules/webrtc/register_types.cpp +++ b/modules/webrtc/register_types.cpp @@ -41,7 +41,7 @@ #include "webrtc_data_channel_gdnative.h" #include "webrtc_peer_connection_gdnative.h" #endif -#include "webrtc_multiplayer.h" +#include "webrtc_multiplayer_peer.h" void register_webrtc_types() { #define _SET_HINT(NAME, _VAL_, _MAX_) \ @@ -62,7 +62,7 @@ void register_webrtc_types() { ClassDB::register_class<WebRTCDataChannelGDNative>(); #endif ClassDB::register_virtual_class<WebRTCDataChannel>(); - ClassDB::register_class<WebRTCMultiplayer>(); + ClassDB::register_class<WebRTCMultiplayerPeer>(); } void unregister_webrtc_types() {} diff --git a/modules/webrtc/webrtc_multiplayer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp index 741cad5640..ac75f9e860 100644 --- a/modules/webrtc/webrtc_multiplayer.cpp +++ b/modules/webrtc/webrtc_multiplayer_peer.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_multiplayer.cpp */ +/* webrtc_multiplayer_peer.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,43 +28,43 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "webrtc_multiplayer.h" +#include "webrtc_multiplayer_peer.h" #include "core/io/marshalls.h" #include "core/os/os.h" -void WebRTCMultiplayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayer::initialize, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayer::add_peer, DEFVAL(1)); - ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayer::remove_peer); - ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayer::has_peer); - ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayer::get_peer); - ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayer::get_peers); - ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayer::close); +void WebRTCMultiplayerPeer::_bind_methods() { + ClassDB::bind_method(D_METHOD("initialize", "peer_id", "server_compatibility"), &WebRTCMultiplayerPeer::initialize, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("add_peer", "peer", "peer_id", "unreliable_lifetime"), &WebRTCMultiplayerPeer::add_peer, DEFVAL(1)); + ClassDB::bind_method(D_METHOD("remove_peer", "peer_id"), &WebRTCMultiplayerPeer::remove_peer); + ClassDB::bind_method(D_METHOD("has_peer", "peer_id"), &WebRTCMultiplayerPeer::has_peer); + ClassDB::bind_method(D_METHOD("get_peer", "peer_id"), &WebRTCMultiplayerPeer::get_peer); + ClassDB::bind_method(D_METHOD("get_peers"), &WebRTCMultiplayerPeer::get_peers); + ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close); } -void WebRTCMultiplayer::set_transfer_mode(TransferMode p_mode) { +void WebRTCMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { transfer_mode = p_mode; } -NetworkedMultiplayerPeer::TransferMode WebRTCMultiplayer::get_transfer_mode() const { +MultiplayerPeer::TransferMode WebRTCMultiplayerPeer::get_transfer_mode() const { return transfer_mode; } -void WebRTCMultiplayer::set_target_peer(int p_peer_id) { +void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) { target_peer = p_peer_id; } -/* Returns the ID of the NetworkedMultiplayerPeer who sent the most recent packet: */ -int WebRTCMultiplayer::get_packet_peer() const { +/* Returns the ID of the MultiplayerPeer who sent the most recent packet: */ +int WebRTCMultiplayerPeer::get_packet_peer() const { return next_packet_peer; } -bool WebRTCMultiplayer::is_server() const { +bool WebRTCMultiplayerPeer::is_server() const { return unique_id == TARGET_PEER_SERVER; } -void WebRTCMultiplayer::poll() { +void WebRTCMultiplayerPeer::poll() { if (peer_map.size() == 0) { return; } @@ -147,7 +147,7 @@ void WebRTCMultiplayer::poll() { } } -void WebRTCMultiplayer::_find_next_peer() { +void WebRTCMultiplayerPeer::_find_next_peer() { Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer); if (E) { E = E->next(); @@ -180,19 +180,19 @@ void WebRTCMultiplayer::_find_next_peer() { next_packet_peer = 0; } -void WebRTCMultiplayer::set_refuse_new_connections(bool p_enable) { +void WebRTCMultiplayerPeer::set_refuse_new_connections(bool p_enable) { refuse_connections = p_enable; } -bool WebRTCMultiplayer::is_refusing_new_connections() const { +bool WebRTCMultiplayerPeer::is_refusing_new_connections() const { return refuse_connections; } -NetworkedMultiplayerPeer::ConnectionStatus WebRTCMultiplayer::get_connection_status() const { +MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() const { return connection_status; } -Error WebRTCMultiplayer::initialize(int p_self_id, bool p_server_compat) { +Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat) { ERR_FAIL_COND_V(p_self_id < 0 || p_self_id > ~(1 << 31), ERR_INVALID_PARAMETER); unique_id = p_self_id; server_compat = p_server_compat; @@ -206,12 +206,12 @@ Error WebRTCMultiplayer::initialize(int p_self_id, bool p_server_compat) { return OK; } -int WebRTCMultiplayer::get_unique_id() const { +int WebRTCMultiplayerPeer::get_unique_id() const { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, 1); return unique_id; } -void WebRTCMultiplayer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { +void WebRTCMultiplayerPeer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict) { Array channels; for (List<Ref<WebRTCDataChannel>>::Element *F = p_connected_peer->channels.front(); F; F = F->next()) { channels.push_back(F->get()); @@ -221,18 +221,18 @@ void WebRTCMultiplayer::_peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dicti r_dict["channels"] = channels; } -bool WebRTCMultiplayer::has_peer(int p_peer_id) { +bool WebRTCMultiplayerPeer::has_peer(int p_peer_id) { return peer_map.has(p_peer_id); } -Dictionary WebRTCMultiplayer::get_peer(int p_peer_id) { +Dictionary WebRTCMultiplayerPeer::get_peer(int p_peer_id) { ERR_FAIL_COND_V(!peer_map.has(p_peer_id), Dictionary()); Dictionary out; _peer_to_dict(peer_map[p_peer_id], out); return out; } -Dictionary WebRTCMultiplayer::get_peers() { +Dictionary WebRTCMultiplayerPeer::get_peers() { Dictionary out; for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) { Dictionary d; @@ -242,7 +242,7 @@ Dictionary WebRTCMultiplayer::get_peers() { return out; } -Error WebRTCMultiplayer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { +Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) { ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(refuse_connections, ERR_UNAUTHORIZED); @@ -277,7 +277,7 @@ Error WebRTCMultiplayer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_i return OK; } -void WebRTCMultiplayer::remove_peer(int p_peer_id) { +void WebRTCMultiplayerPeer::remove_peer(int p_peer_id) { ERR_FAIL_COND(!peer_map.has(p_peer_id)); Ref<ConnectedPeer> peer = peer_map[p_peer_id]; peer_map.erase(p_peer_id); @@ -291,7 +291,7 @@ void WebRTCMultiplayer::remove_peer(int p_peer_id) { } } -Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { +Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { // Peer not available if (next_packet_peer == 0 || !peer_map.has(next_packet_peer)) { _find_next_peer(); @@ -309,7 +309,7 @@ Error WebRTCMultiplayer::get_packet(const uint8_t **r_buffer, int &r_buffer_size ERR_FAIL_V(ERR_BUG); } -Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { +Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) { ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED); int ch = CH_RELIABLE; @@ -351,7 +351,7 @@ Error WebRTCMultiplayer::put_packet(const uint8_t *p_buffer, int p_buffer_size) return OK; } -int WebRTCMultiplayer::get_available_packet_count() const { +int WebRTCMultiplayerPeer::get_available_packet_count() const { if (next_packet_peer == 0) { return 0; // To be sure next call to get_packet works if size > 0 . } @@ -364,11 +364,11 @@ int WebRTCMultiplayer::get_available_packet_count() const { return size; } -int WebRTCMultiplayer::get_max_packet_size() const { +int WebRTCMultiplayerPeer::get_max_packet_size() const { return 1200; } -void WebRTCMultiplayer::close() { +void WebRTCMultiplayerPeer::close() { peer_map.clear(); unique_id = 0; next_packet_peer = 0; @@ -376,7 +376,7 @@ void WebRTCMultiplayer::close() { connection_status = CONNECTION_DISCONNECTED; } -WebRTCMultiplayer::WebRTCMultiplayer() { +WebRTCMultiplayerPeer::WebRTCMultiplayerPeer() { unique_id = 0; next_packet_peer = 0; target_peer = 0; @@ -387,6 +387,6 @@ WebRTCMultiplayer::WebRTCMultiplayer() { server_compat = false; } -WebRTCMultiplayer::~WebRTCMultiplayer() { +WebRTCMultiplayerPeer::~WebRTCMultiplayerPeer() { close(); } diff --git a/modules/webrtc/webrtc_multiplayer.h b/modules/webrtc/webrtc_multiplayer_peer.h index 6b4ae6fcc8..1d9387b6dc 100644 --- a/modules/webrtc/webrtc_multiplayer.h +++ b/modules/webrtc/webrtc_multiplayer_peer.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* webrtc_multiplayer.h */ +/* webrtc_multiplayer_peer.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -31,11 +31,11 @@ #ifndef WEBRTC_MULTIPLAYER_H #define WEBRTC_MULTIPLAYER_H -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "webrtc_peer_connection.h" -class WebRTCMultiplayer : public NetworkedMultiplayerPeer { - GDCLASS(WebRTCMultiplayer, NetworkedMultiplayerPeer); +class WebRTCMultiplayerPeer : public MultiplayerPeer { + GDCLASS(WebRTCMultiplayerPeer, MultiplayerPeer); protected: static void _bind_methods(); @@ -48,7 +48,7 @@ private: CH_RESERVED_MAX = 3 }; - class ConnectedPeer : public Reference { + class ConnectedPeer : public RefCounted { public: Ref<WebRTCPeerConnection> connection; List<Ref<WebRTCDataChannel>> channels; @@ -77,8 +77,8 @@ private: void _find_next_peer(); public: - WebRTCMultiplayer(); - ~WebRTCMultiplayer(); + WebRTCMultiplayerPeer(); + ~WebRTCMultiplayerPeer(); Error initialize(int p_self_id, bool p_server_compat = false); Error add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime = 1); @@ -94,7 +94,7 @@ public: int get_available_packet_count() const override; int get_max_packet_size() const override; - // NetworkedMultiplayerPeer + // MultiplayerPeer void set_transfer_mode(TransferMode p_mode) override; TransferMode get_transfer_mode() const override; void set_target_peer(int p_peer_id) override; diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h index ae75864489..fcfb9ae9ae 100644 --- a/modules/webrtc/webrtc_peer_connection.h +++ b/modules/webrtc/webrtc_peer_connection.h @@ -34,8 +34,8 @@ #include "core/io/packet_peer.h" #include "modules/webrtc/webrtc_data_channel.h" -class WebRTCPeerConnection : public Reference { - GDCLASS(WebRTCPeerConnection, Reference); +class WebRTCPeerConnection : public RefCounted { + GDCLASS(WebRTCPeerConnection, RefCounted); public: enum ConnectionState { diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml index d362bcc10f..40c0ad17ad 100644 --- a/modules/websocket/doc_classes/WebSocketClient.xml +++ b/modules/websocket/doc_classes/WebSocketClient.xml @@ -6,7 +6,7 @@ <description> This class implements a WebSocket client compatible with any RFC 6455-compliant WebSocket server. This client can be optionally used as a network peer for the [MultiplayerAPI]. - After starting the client ([method connect_to_url]), you will need to [method NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). + After starting the client ([method connect_to_url]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). You will receive appropriate signals when connecting, disconnecting, or when new data is available. </description> <tutorials> @@ -17,11 +17,11 @@ </return> <argument index="0" name="url" type="String"> </argument> - <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()"> </argument> <argument index="2" name="gd_mp_api" type="bool" default="false"> </argument> - <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="3" name="custom_headers" type="PackedStringArray" default="PackedStringArray()"> </argument> <description> Connects to the given URL requesting one of the given [code]protocols[/code] as sub-protocol. If the list empty (default), no sub-protocol will be requested. diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml index 0679acf78a..ee1b60f739 100644 --- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml +++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="WebSocketMultiplayerPeer" inherits="NetworkedMultiplayerPeer" version="4.0"> +<class name="WebSocketMultiplayerPeer" inherits="MultiplayerPeer" version="4.0"> <brief_description> Base class for WebSocket server and client. </brief_description> @@ -39,7 +39,7 @@ </methods> <members> <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" /> - <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="NetworkedMultiplayerPeer.TransferMode" default="2" /> + <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="MultiplayerPeer.TransferMode" default="2" /> </members> <signals> <signal name="peer_packet"> diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml index f7805209e2..26e09fd8b3 100644 --- a/modules/websocket/doc_classes/WebSocketServer.xml +++ b/modules/websocket/doc_classes/WebSocketServer.xml @@ -5,7 +5,7 @@ </brief_description> <description> This class implements a WebSocket server that can also support the high-level multiplayer API. - After starting the server ([method listen]), you will need to [method NetworkedMultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal. + After starting the server ([method listen]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal. [b]Note:[/b] Not available in HTML5 exports. </description> <tutorials> @@ -63,7 +63,7 @@ </return> <argument index="0" name="port" type="int"> </argument> - <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray( )"> + <argument index="1" name="protocols" type="PackedStringArray" default="PackedStringArray()"> </argument> <argument index="2" name="gd_mp_api" type="bool" default="false"> </argument> @@ -89,6 +89,9 @@ <member name="ca_chain" type="X509Certificate" setter="set_ca_chain" getter="get_ca_chain"> When using SSL (see [member private_key] and [member ssl_certificate]), you can set this to a valid [X509Certificate] to be provided as additional CA chain information during the SSL handshake. </member> + <member name="handshake_timeout" type="float" setter="set_handshake_timeout" getter="get_handshake_timeout" default="3.0"> + The time in seconds before a pending client (i.e. a client that has not yet finished the HTTP handshake) is considered stale and forcefully disconnected. + </member> <member name="private_key" type="CryptoKey" setter="set_private_key" getter="get_private_key"> When set to a valid [CryptoKey] (along with [member ssl_certificate]) will cause the server to require SSL instead of regular TCP (i.e. the [code]wss://[/code] protocol). </member> diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor_debugger_server_websocket.cpp index b02d212c42..2e61cbfc08 100644 --- a/modules/websocket/editor_debugger_server_websocket.cpp +++ b/modules/websocket/editor_debugger_server_websocket.cpp @@ -50,9 +50,9 @@ void EditorDebuggerServerWebSocket::poll() { Error EditorDebuggerServerWebSocket::start() { int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port"); - Vector<String> protocols; - protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer. - return server->listen(remote_port, protocols); + Vector<String> compatible_protocols; + compatible_protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer. + return server->listen(remote_port, compatible_protocols); } void EditorDebuggerServerWebSocket::stop() { diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp index 626498e1ae..744053b6e2 100644 --- a/modules/websocket/emws_client.cpp +++ b/modules/websocket/emws_client.cpp @@ -107,7 +107,7 @@ Ref<WebSocketPeer> EMWSClient::get_peer(int p_peer_id) const { return _peer; } -NetworkedMultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const { +MultiplayerPeer::ConnectionStatus EMWSClient::get_connection_status() const { if (_peer->is_connected_to_host()) { if (_is_connecting) return CONNECTION_CONNECTING; diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h index e7285ccb86..d36e3a3557 100644 --- a/modules/websocket/emws_server.h +++ b/modules/websocket/emws_server.h @@ -33,7 +33,7 @@ #ifdef JAVASCRIPT_ENABLED -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "emws_peer.h" #include "websocket_server.h" diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp index 1e9183ebfa..af1dc8ff54 100644 --- a/modules/websocket/websocket_client.cpp +++ b/modules/websocket/websocket_client.cpp @@ -42,9 +42,9 @@ Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_proto _is_multiplayer = gd_mp_api; String host = p_url; - String path = "/"; - String scheme = ""; - int port = 80; + String path; + String scheme; + int port = 0; Error err = p_url.parse_url(scheme, host, port, path); ERR_FAIL_COND_V_MSG(err != OK, err, "Invalid URL: " + p_url); @@ -55,6 +55,9 @@ Error WebSocketClient::connect_to_url(String p_url, const Vector<String> p_proto if (port == 0) { port = ssl ? 443 : 80; } + if (path.is_empty()) { + path = "/"; + } return connect_to_host(host, path, port, ssl, p_protocols, p_custom_headers); } @@ -123,12 +126,12 @@ void WebSocketClient::_bind_methods() { ClassDB::bind_method(D_METHOD("set_verify_ssl_enabled", "enabled"), &WebSocketClient::set_verify_ssl_enabled); ClassDB::bind_method(D_METHOD("is_verify_ssl_enabled"), &WebSocketClient::is_verify_ssl_enabled); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", 0), "set_verify_ssl_enabled", "is_verify_ssl_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_verify_ssl_enabled", "is_verify_ssl_enabled"); ClassDB::bind_method(D_METHOD("get_trusted_ssl_certificate"), &WebSocketClient::get_trusted_ssl_certificate); ClassDB::bind_method(D_METHOD("set_trusted_ssl_certificate"), &WebSocketClient::set_trusted_ssl_certificate); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_trusted_ssl_certificate", "get_trusted_ssl_certificate"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_trusted_ssl_certificate", "get_trusted_ssl_certificate"); ADD_SIGNAL(MethodInfo("data_received")); ADD_SIGNAL(MethodInfo("connection_established", PropertyInfo(Variant::STRING, "protocol"))); diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp index fa0ef7060f..1beeb67b91 100644 --- a/modules/websocket/websocket_multiplayer_peer.cpp +++ b/modules/websocket/websocket_multiplayer_peer.cpp @@ -123,13 +123,13 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer } // -// NetworkedMultiplayerPeer +// MultiplayerPeer // void WebSocketMultiplayerPeer::set_transfer_mode(TransferMode p_mode) { // Websocket uses TCP, reliable } -NetworkedMultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { +MultiplayerPeer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const { // Websocket uses TCP, reliable return TRANSFER_MODE_RELIABLE; } diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h index 48a6607d89..e3ccd1a795 100644 --- a/modules/websocket/websocket_multiplayer_peer.h +++ b/modules/websocket/websocket_multiplayer_peer.h @@ -32,12 +32,12 @@ #define WEBSOCKET_MULTIPLAYER_PEER_H #include "core/error/error_list.h" -#include "core/io/networked_multiplayer_peer.h" +#include "core/io/multiplayer_peer.h" #include "core/templates/list.h" #include "websocket_peer.h" -class WebSocketMultiplayerPeer : public NetworkedMultiplayerPeer { - GDCLASS(WebSocketMultiplayerPeer, NetworkedMultiplayerPeer); +class WebSocketMultiplayerPeer : public MultiplayerPeer { + GDCLASS(WebSocketMultiplayerPeer, MultiplayerPeer); private: Vector<uint8_t> _make_pkt(uint8_t p_type, int32_t p_from, int32_t p_to, const uint8_t *p_data, uint32_t p_data_size); @@ -78,7 +78,7 @@ protected: int _gen_unique_id() const; public: - /* NetworkedMultiplayerPeer */ + /* MultiplayerPeer */ void set_transfer_mode(TransferMode p_mode) override; TransferMode get_transfer_mode() const override; void set_target_peer(int p_target_peer) override; diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp index 7cf68b835c..b996852f28 100644 --- a/modules/websocket/websocket_server.cpp +++ b/modules/websocket/websocket_server.cpp @@ -55,15 +55,19 @@ void WebSocketServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key); ClassDB::bind_method(D_METHOD("set_private_key"), &WebSocketServer::set_private_key); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", 0), "set_private_key", "get_private_key"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", PROPERTY_USAGE_NONE), "set_private_key", "get_private_key"); ClassDB::bind_method(D_METHOD("get_ssl_certificate"), &WebSocketServer::get_ssl_certificate); ClassDB::bind_method(D_METHOD("set_ssl_certificate"), &WebSocketServer::set_ssl_certificate); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_ssl_certificate", "get_ssl_certificate"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ssl_certificate", "get_ssl_certificate"); ClassDB::bind_method(D_METHOD("get_ca_chain"), &WebSocketServer::get_ca_chain); ClassDB::bind_method(D_METHOD("set_ca_chain"), &WebSocketServer::set_ca_chain); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", 0), "set_ca_chain", "get_ca_chain"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ca_chain", "get_ca_chain"); + + ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketServer::get_handshake_timeout); + ClassDB::bind_method(D_METHOD("set_handshake_timeout", "timeout"), &WebSocketServer::set_handshake_timeout); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handshake_timeout"), "set_handshake_timeout", "get_handshake_timeout"); ADD_SIGNAL(MethodInfo("client_close_request", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::INT, "code"), PropertyInfo(Variant::STRING, "reason"))); ADD_SIGNAL(MethodInfo("client_disconnected", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::BOOL, "was_clean_close"))); @@ -108,7 +112,16 @@ void WebSocketServer::set_ca_chain(Ref<X509Certificate> p_ca_chain) { ca_chain = p_ca_chain; } -NetworkedMultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const { +float WebSocketServer::get_handshake_timeout() const { + return handshake_timeout / 1000.0; +} + +void WebSocketServer::set_handshake_timeout(float p_timeout) { + ERR_FAIL_COND(p_timeout <= 0.0); + handshake_timeout = p_timeout * 1000; +} + +MultiplayerPeer::ConnectionStatus WebSocketServer::get_connection_status() const { if (is_listening()) { return CONNECTION_CONNECTED; } diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h index 10da51fce5..26864f3085 100644 --- a/modules/websocket/websocket_server.h +++ b/modules/websocket/websocket_server.h @@ -32,7 +32,7 @@ #define WEBSOCKET_H #include "core/crypto/crypto.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "websocket_multiplayer_peer.h" #include "websocket_peer.h" @@ -48,6 +48,7 @@ protected: Ref<CryptoKey> private_key; Ref<X509Certificate> ssl_cert; Ref<X509Certificate> ca_chain; + uint32_t handshake_timeout = 3000; public: virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0; @@ -78,6 +79,9 @@ public: Ref<X509Certificate> get_ca_chain() const; void set_ca_chain(Ref<X509Certificate> p_ca_chain); + float get_handshake_timeout() const; + void set_handshake_timeout(float p_timeout); + WebSocketServer(); ~WebSocketServer(); }; diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp index 111d2178d6..49997b42d3 100644 --- a/modules/websocket/wsl_client.cpp +++ b/modules/websocket/wsl_client.cpp @@ -158,6 +158,7 @@ bool WSLClient::_verify_headers(String &r_protocol) { Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocols, const Vector<String> p_custom_headers) { ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(p_path.is_empty(), ERR_INVALID_PARAMETER); _peer = Ref<WSLPeer>(memnew(WSLPeer)); IPAddress addr; @@ -287,7 +288,7 @@ Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const { return _peer; } -NetworkedMultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const { +MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const { if (_peer->is_connected_to_host()) { return CONNECTION_CONNECTED; } @@ -337,8 +338,8 @@ Error WSLClient::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer } WSLClient::WSLClient() { - _peer.instance(); - _tcp.instance(); + _peer.instantiate(); + _tcp.instantiate(); disconnect_from_host(); } diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp index dc5b23c31e..c889562732 100644 --- a/modules/websocket/wsl_server.cpp +++ b/modules/websocket/wsl_server.cpp @@ -95,28 +95,33 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols) { return true; } -Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols) { - if (OS::get_singleton()->get_ticks_msec() - time > WSL_SERVER_TIMEOUT) { +Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout) { + if (OS::get_singleton()->get_ticks_msec() - time > p_timeout) { + print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", p_timeout * 0.001)); return ERR_TIMEOUT; } + if (use_ssl) { Ref<StreamPeerSSL> ssl = static_cast<Ref<StreamPeerSSL>>(connection); if (ssl.is_null()) { - return FAILED; + ERR_FAIL_V_MSG(ERR_BUG, "Couldn't get StreamPeerSSL for WebSocket handshake."); } ssl->poll(); if (ssl->get_status() == StreamPeerSSL::STATUS_HANDSHAKING) { return ERR_BUSY; } else if (ssl->get_status() != StreamPeerSSL::STATUS_CONNECTED) { + print_verbose(vformat("WebSocket SSL connection error during handshake (StreamPeerSSL status code %d).", ssl->get_status())); return FAILED; } } + if (!has_request) { int read = 0; while (true) { - ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "Response headers too big."); + ERR_FAIL_COND_V_MSG(req_pos >= WSL_MAX_HEADER_SIZE, ERR_OUT_OF_MEMORY, "WebSocket response headers are too big."); Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); if (err != OK) { // Got an error + print_verbose(vformat("WebSocket error while getting partial data (StreamPeer error code %d).", err)); return FAILED; } else if (read != 1) { // Busy, wait next poll return ERR_BUSY; @@ -143,17 +148,21 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols) { req_pos += 1; } } + if (has_request && response_sent < response.size() - 1) { int sent = 0; Error err = connection->put_partial_data((const uint8_t *)response.get_data() + response_sent, response.size() - response_sent - 1, sent); if (err != OK) { + print_verbose(vformat("WebSocket error while putting partial data (StreamPeer error code %d).", err)); return err; } response_sent += sent; } + if (response_sent < response.size() - 1) { return ERR_BUSY; } + return OK; } @@ -188,7 +197,7 @@ void WSLServer::poll() { List<Ref<PendingPeer>> remove_peers; for (List<Ref<PendingPeer>>::Element *E = _pending.front(); E; E = E->next()) { Ref<PendingPeer> ppeer = E->get(); - Error err = ppeer->do_handshake(_protocols); + Error err = ppeer->do_handshake(_protocols, handshake_timeout); if (err == ERR_BUSY) { continue; } else if (err != OK) { @@ -301,7 +310,7 @@ Error WSLServer::set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer } WSLServer::WSLServer() { - _server.instance(); + _server.instantiate(); } WSLServer::~WSLServer() { diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h index c2cf9df58b..a428c89f4f 100644 --- a/modules/websocket/wsl_server.h +++ b/modules/websocket/wsl_server.h @@ -40,13 +40,11 @@ #include "core/io/stream_peer_tcp.h" #include "core/io/tcp_server.h" -#define WSL_SERVER_TIMEOUT 1000 - class WSLServer : public WebSocketServer { GDCIIMPL(WSLServer, WebSocketServer); private: - class PendingPeer : public Reference { + class PendingPeer : public RefCounted { private: bool _parse_request(const Vector<String> p_protocols); @@ -64,7 +62,7 @@ private: CharString response; int response_sent = 0; - Error do_handshake(const Vector<String> p_protocols); + Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout); }; int _in_buf_size = DEF_BUF_SHIFT; diff --git a/modules/webxr/config.py b/modules/webxr/config.py index 9efebed4e6..f676ef3483 100644 --- a/modules/webxr/config.py +++ b/modules/webxr/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return True + return not env["disable_3d"] def configure(env): diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp index 8baf7e05b8..6df0234811 100644 --- a/modules/webxr/register_types.cpp +++ b/modules/webxr/register_types.cpp @@ -38,7 +38,7 @@ void register_webxr_types() { #ifdef JAVASCRIPT_ENABLED Ref<WebXRInterfaceJS> webxr; - webxr.instance(); + webxr.instantiate(); XRServer::get_singleton()->add_interface(webxr); #endif } diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 06f3fe6284..2eab0cdb07 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -265,8 +265,8 @@ void WebXRInterfaceJS::uninitialize() { }; }; -Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { - Transform transform; +Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { + Transform3D transform; transform.basis.elements[0].x = p_js_matrix[0]; transform.basis.elements[1].x = p_js_matrix[1]; @@ -305,13 +305,30 @@ Size2 WebXRInterfaceJS::get_render_targetsize() { return render_targetsize; }; -Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { - Transform transform_for_eye; +Transform3D WebXRInterfaceJS::get_camera_transform() { + Transform3D transform_for_eye; XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, transform_for_eye); - float *js_matrix = godot_webxr_get_transform_for_eye(p_eye); + float *js_matrix = godot_webxr_get_transform_for_eye(0); + if (!initialized || js_matrix == nullptr) { + return transform_for_eye; + } + + transform_for_eye = _js_matrix_to_transform(js_matrix); + free(js_matrix); + + return xr_server->get_reference_frame() * transform_for_eye; +}; + +Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + Transform3D transform_for_eye; + + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, transform_for_eye); + + float *js_matrix = godot_webxr_get_transform_for_eye(p_view + 1); if (!initialized || js_matrix == nullptr) { transform_for_eye = p_cam_transform; return transform_for_eye; @@ -323,10 +340,10 @@ Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye; }; -CameraMatrix WebXRInterfaceJS::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { CameraMatrix eye; - float *js_matrix = godot_webxr_get_projection_for_eye(p_eye); + float *js_matrix = godot_webxr_get_projection_for_eye(p_view + 1); if (!initialized || js_matrix == nullptr) { return eye; } @@ -383,7 +400,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1); if (godot_webxr_is_controller_connected(p_controller_id)) { if (tracker.is_null()) { - tracker.instance(); + tracker.instantiate(); tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); // Controller id's 0 and 1 are always the left and right hands. if (p_controller_id < 2) { @@ -399,7 +416,7 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id); if (tracker_matrix) { - Transform transform = _js_matrix_to_transform(tracker_matrix); + Transform3D transform = _js_matrix_to_transform(tracker_matrix); tracker->set_position(transform.origin); tracker->set_orientation(transform.basis); free(tracker_matrix); diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h index 7c841c1911..723ab952cd 100644 --- a/modules/webxr/webxr_interface_js.h +++ b/modules/webxr/webxr_interface_js.h @@ -56,7 +56,7 @@ private: bool controllers_state[2]; Size2 render_targetsize; - Transform _js_matrix_to_transform(float *p_js_matrix); + Transform3D _js_matrix_to_transform(float *p_js_matrix); void _update_tracker(int p_controller_id); public: @@ -84,8 +84,9 @@ public: virtual Size2 get_render_targetsize() override; virtual bool is_stereo() override; - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) override; - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual Transform3D get_camera_transform() override; + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override; virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override; diff --git a/platform/android/SCsub b/platform/android/SCsub index 7e9dac926c..56fbd2f7e4 100644 --- a/platform/android/SCsub +++ b/platform/android/SCsub @@ -9,7 +9,6 @@ android_files = [ "dir_access_jandroid.cpp", "thread_jandroid.cpp", "net_socket_android.cpp", - "audio_driver_jandroid.cpp", "java_godot_lib_jni.cpp", "java_class_wrapper.cpp", "java_godot_wrapper.cpp", diff --git a/platform/android/api/java_class_wrapper.h b/platform/android/api/java_class_wrapper.h index d6c7a1abe5..ff7bf43573 100644 --- a/platform/android/api/java_class_wrapper.h +++ b/platform/android/api/java_class_wrapper.h @@ -31,7 +31,7 @@ #ifndef JAVA_CLASS_WRAPPER_H #define JAVA_CLASS_WRAPPER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #ifdef ANDROID_ENABLED #include <android/log.h> @@ -42,8 +42,8 @@ class JavaObject; #endif -class JavaClass : public Reference { - GDCLASS(JavaClass, Reference); +class JavaClass : public RefCounted { + GDCLASS(JavaClass, RefCounted); #ifdef ANDROID_ENABLED enum ArgumentType{ @@ -184,8 +184,8 @@ public: JavaClass(); }; -class JavaObject : public Reference { - GDCLASS(JavaObject, Reference); +class JavaObject : public RefCounted { + GDCLASS(JavaObject, RefCounted); #ifdef ANDROID_ENABLED Ref<JavaClass> base_class; diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp deleted file mode 100644 index 3a2ccac481..0000000000 --- a/platform/android/audio_driver_jandroid.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/*************************************************************************/ -/* audio_driver_jandroid.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "audio_driver_jandroid.h" - -#include "core/config/project_settings.h" -#include "core/os/os.h" -#include "thread_jandroid.h" - -AudioDriverAndroid *AudioDriverAndroid::s_ad = nullptr; - -jobject AudioDriverAndroid::io; -jmethodID AudioDriverAndroid::_init_audio; -jmethodID AudioDriverAndroid::_write_buffer; -jmethodID AudioDriverAndroid::_quit; -jmethodID AudioDriverAndroid::_pause; -bool AudioDriverAndroid::active = false; -jclass AudioDriverAndroid::cls; -int AudioDriverAndroid::audioBufferFrames = 0; -int AudioDriverAndroid::mix_rate = 44100; -bool AudioDriverAndroid::quit = false; -jobject AudioDriverAndroid::audioBuffer = nullptr; -void *AudioDriverAndroid::audioBufferPinned = nullptr; -Mutex AudioDriverAndroid::mutex; -int32_t *AudioDriverAndroid::audioBuffer32 = nullptr; - -const char *AudioDriverAndroid::get_name() const { - return "Android"; -} - -Error AudioDriverAndroid::init() { - /* - // TODO: pass in/return a (Java) device ID, also whether we're opening for input or output - this->spec.samples = Android_JNI_OpenAudioDevice(this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples); - SDL_CalculateAudioSpec(&this->spec); - - if (this->spec.samples == 0) { - // Init failed? - SDL_SetError("Java-side initialization failed!"); - return 0; - } -*/ - - //Android_JNI_SetupThread(); - - // __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device"); - - JNIEnv *env = get_jni_env(); - int mix_rate = GLOBAL_GET("audio/driver/mix_rate"); - - int latency = GLOBAL_GET("audio/driver/output_latency"); - unsigned int buffer_size = next_power_of_2(latency * mix_rate / 1000); - print_verbose("Audio buffer size: " + itos(buffer_size)); - - audioBuffer = env->CallObjectMethod(io, _init_audio, mix_rate, buffer_size); - - ERR_FAIL_COND_V(audioBuffer == nullptr, ERR_INVALID_PARAMETER); - - audioBuffer = env->NewGlobalRef(audioBuffer); - - jboolean isCopy = JNI_FALSE; - audioBufferPinned = env->GetShortArrayElements((jshortArray)audioBuffer, &isCopy); - audioBufferFrames = env->GetArrayLength((jshortArray)audioBuffer); - audioBuffer32 = memnew_arr(int32_t, audioBufferFrames); - - return OK; -} - -void AudioDriverAndroid::start() { - active = true; -} - -void AudioDriverAndroid::setup(jobject p_io) { - JNIEnv *env = get_jni_env(); - io = p_io; - - jclass c = env->GetObjectClass(io); - cls = (jclass)env->NewGlobalRef(c); - - _init_audio = env->GetMethodID(cls, "audioInit", "(II)Ljava/lang/Object;"); - _write_buffer = env->GetMethodID(cls, "audioWriteShortBuffer", "([S)V"); - _quit = env->GetMethodID(cls, "audioQuit", "()V"); - _pause = env->GetMethodID(cls, "audioPause", "(Z)V"); -} - -void AudioDriverAndroid::thread_func(JNIEnv *env) { - jclass cls = env->FindClass("org/godotengine/godot/Godot"); - if (cls) { - cls = (jclass)env->NewGlobalRef(cls); - } - jfieldID fid = env->GetStaticFieldID(cls, "io", "Lorg/godotengine/godot/GodotIO;"); - jobject ob = env->GetStaticObjectField(cls, fid); - jobject gob = env->NewGlobalRef(ob); - jclass c = env->GetObjectClass(gob); - jclass lcls = (jclass)env->NewGlobalRef(c); - _write_buffer = env->GetMethodID(lcls, "audioWriteShortBuffer", "([S)V"); - - while (!quit) { - int16_t *ptr = (int16_t *)audioBufferPinned; - int fc = audioBufferFrames; - - if (!s_ad->active || mutex.try_lock() != OK) { - for (int i = 0; i < fc; i++) { - ptr[i] = 0; - } - - } else { - s_ad->audio_server_process(fc / 2, audioBuffer32); - - mutex.unlock(); - - for (int i = 0; i < fc; i++) { - ptr[i] = audioBuffer32[i] >> 16; - } - } - env->ReleaseShortArrayElements((jshortArray)audioBuffer, (jshort *)ptr, JNI_COMMIT); - env->CallVoidMethod(gob, _write_buffer, (jshortArray)audioBuffer); - } -} - -int AudioDriverAndroid::get_mix_rate() const { - return mix_rate; -} - -AudioDriver::SpeakerMode AudioDriverAndroid::get_speaker_mode() const { - return SPEAKER_MODE_STEREO; -} - -void AudioDriverAndroid::lock() { - mutex.lock(); -} - -void AudioDriverAndroid::unlock() { - mutex.unlock(); -} - -void AudioDriverAndroid::finish() { - JNIEnv *env = get_jni_env(); - env->CallVoidMethod(io, _quit); - - if (audioBuffer) { - env->DeleteGlobalRef(audioBuffer); - audioBuffer = nullptr; - audioBufferPinned = nullptr; - } - - active = false; -} - -void AudioDriverAndroid::set_pause(bool p_pause) { - JNIEnv *env = get_jni_env(); - env->CallVoidMethod(io, _pause, p_pause); -} - -AudioDriverAndroid::AudioDriverAndroid() { - s_ad = this; - active = false; -} diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h deleted file mode 100644 index 9007fd2f81..0000000000 --- a/platform/android/audio_driver_jandroid.h +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************/ -/* audio_driver_jandroid.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#ifndef AUDIO_DRIVER_ANDROID_H -#define AUDIO_DRIVER_ANDROID_H - -#include "servers/audio_server.h" - -#include "java_godot_lib_jni.h" - -class AudioDriverAndroid : public AudioDriver { - static Mutex mutex; - static AudioDriverAndroid *s_ad; - static jobject io; - static jmethodID _init_audio; - static jmethodID _write_buffer; - static jmethodID _quit; - static jmethodID _pause; - static bool active; - static bool quit; - - static jclass cls; - - static jobject audioBuffer; - static void *audioBufferPinned; - static int32_t *audioBuffer32; - static int audioBufferFrames; - static int mix_rate; - -public: - void set_singleton(); - - virtual const char *get_name() const; - - virtual Error init(); - virtual void start(); - virtual int get_mix_rate() const; - virtual SpeakerMode get_speaker_mode() const; - virtual void lock(); - virtual void unlock(); - virtual void finish(); - - virtual void set_pause(bool p_pause); - - static void setup(jobject p_io); - static void thread_func(JNIEnv *env); - - AudioDriverAndroid(); -}; - -#endif // AUDIO_DRIVER_ANDROID_H diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h index 7b9cbeea47..cdf98187ed 100644 --- a/platform/android/dir_access_jandroid.h +++ b/platform/android/dir_access_jandroid.h @@ -31,7 +31,7 @@ #ifndef DIR_ACCESS_JANDROID_H #define DIR_ACCESS_JANDROID_H -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "java_godot_lib_jni.h" #include <stdio.h> diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index ff61eeaee1..1fcc3d4a5c 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -358,8 +358,8 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() { return drivers; } -DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { ds->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver"); } @@ -377,10 +377,11 @@ void DisplayServerAndroid::reset_window() { ERR_FAIL_COND(!native_window); ERR_FAIL_COND(!context_vulkan); + VSyncMode last_vsync_mode = context_vulkan->get_vsync_mode(MAIN_WINDOW_ID); context_vulkan->window_destroy(MAIN_WINDOW_ID); Size2i display_size = OS_Android::get_singleton()->get_display_size(); - if (context_vulkan->window_create(native_window, display_size.width, display_size.height) == -1) { + if (context_vulkan->window_create(native_window, last_vsync_mode, display_size.width, display_size.height) == -1) { memdelete(context_vulkan); context_vulkan = nullptr; ERR_FAIL_MSG("Failed to reset Vulkan window."); @@ -402,7 +403,7 @@ void DisplayServerAndroid::notify_surface_changed(int p_width, int p_height) { rect_changed_callback.call(reinterpret_cast<const Variant **>(&sizep), 1, ret, ce); } -DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; // TODO: rendering_driver is broken, change when different drivers are supported again @@ -410,8 +411,6 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on"); - buttons_state = 0; - #if defined(OPENGL_ENABLED) if (rendering_driver == "opengl") { bool gl_initialization_error = false; @@ -448,7 +447,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis } Size2i display_size = OS_Android::get_singleton()->get_display_size(); - if (context_vulkan->window_create(native_window, display_size.width, display_size.height) == -1) { + if (context_vulkan->window_create(native_window, p_vsync_mode, display_size.width, display_size.height) == -1) { memdelete(context_vulkan); context_vulkan = nullptr; ERR_FAIL_MSG("Failed to create Vulkan window."); @@ -484,16 +483,16 @@ DisplayServerAndroid::~DisplayServerAndroid() { void DisplayServerAndroid::process_joy_event(DisplayServerAndroid::JoypadEvent p_event) { switch (p_event.type) { case JOY_EVENT_BUTTON: - Input::get_singleton()->joy_button(p_event.device, p_event.index, p_event.pressed); + Input::get_singleton()->joy_button(p_event.device, (JoyButton)p_event.index, p_event.pressed); break; case JOY_EVENT_AXIS: Input::JoyAxisValue value; value.min = -1; value.value = p_event.value; - Input::get_singleton()->joy_axis(p_event.device, p_event.index, value); + Input::get_singleton()->joy_axis(p_event.device, (JoyAxis)p_event.index, value); break; case JOY_EVENT_HAT: - Input::get_singleton()->joy_hat(p_event.device, p_event.hat); + Input::get_singleton()->joy_hat(p_event.device, (HatMask)p_event.hat); break; default: return; @@ -528,7 +527,7 @@ void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int } Ref<InputEventKey> ev; - ev.instance(); + ev.instantiate(); int val = unicode; int keycode = android_get_keysym(p_keycode); int phy_keycode = android_get_keysym(p_scancode); @@ -575,7 +574,7 @@ void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vecto //end all if exist for (int i = 0; i < touch.size(); i++) { Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); ev->set_index(touch[i].id); ev->set_pressed(false); ev->set_position(touch[i].pos); @@ -592,7 +591,7 @@ void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vecto //send touch for (int i = 0; i < touch.size(); i++) { Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); ev->set_index(touch[i].id); ev->set_pressed(true); ev->set_position(touch[i].pos); @@ -618,7 +617,7 @@ void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vecto continue; //no move unncesearily Ref<InputEventScreenDrag> ev; - ev.instance(); + ev.instantiate(); ev->set_index(touch[i].id); ev->set_position(p_points[idx].pos); ev->set_relative(p_points[idx].pos - touch[i].pos); @@ -633,7 +632,7 @@ void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vecto //end all if exist for (int i = 0; i < touch.size(); i++) { Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); ev->set_index(touch[i].id); ev->set_pressed(false); ev->set_position(touch[i].pos); @@ -649,7 +648,7 @@ void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vecto touch.push_back(tp); Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); ev->set_index(tp.id); ev->set_pressed(true); @@ -664,7 +663,7 @@ void DisplayServerAndroid::process_touch(int p_event, int p_pointer, const Vecto for (int i = 0; i < touch.size(); i++) { if (touch[i].id == p_pointer) { Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); ev->set_index(touch[i].id); ev->set_pressed(false); ev->set_position(touch[i].pos); @@ -685,7 +684,7 @@ void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) { case AMOTION_EVENT_ACTION_HOVER_ENTER: // hover enter case AMOTION_EVENT_ACTION_HOVER_EXIT: { // hover exit Ref<InputEventMouseMotion> ev; - ev.instance(); + ev.instantiate(); _set_key_modifier_state(ev); ev->set_position(p_pos); ev->set_global_position(p_pos); @@ -697,12 +696,12 @@ void DisplayServerAndroid::process_hover(int p_type, Point2 p_pos) { } void DisplayServerAndroid::process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor, float event_horizontal_factor) { - int event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); + MouseButton event_buttons_mask = _android_button_mask_to_godot_button_mask(event_android_buttons_mask); switch (event_action) { case AMOTION_EVENT_ACTION_BUTTON_PRESS: case AMOTION_EVENT_ACTION_BUTTON_RELEASE: { Ref<InputEventMouseButton> ev; - ev.instance(); + ev.instantiate(); _set_key_modifier_state(ev); if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { ev->set_position(event_pos); @@ -712,7 +711,7 @@ void DisplayServerAndroid::process_mouse_event(int input_device, int event_actio ev->set_global_position(hover_prev_pos); } ev->set_pressed(event_action == AMOTION_EVENT_ACTION_BUTTON_PRESS); - int changed_button_mask = buttons_state ^ event_buttons_mask; + MouseButton changed_button_mask = MouseButton(buttons_state ^ event_buttons_mask); buttons_state = event_buttons_mask; @@ -723,7 +722,7 @@ void DisplayServerAndroid::process_mouse_event(int input_device, int event_actio case AMOTION_EVENT_ACTION_MOVE: { Ref<InputEventMouseMotion> ev; - ev.instance(); + ev.instantiate(); _set_key_modifier_state(ev); if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { ev->set_position(event_pos); @@ -740,7 +739,7 @@ void DisplayServerAndroid::process_mouse_event(int input_device, int event_actio } break; case AMOTION_EVENT_ACTION_SCROLL: { Ref<InputEventMouseButton> ev; - ev.instance(); + ev.instantiate(); if ((input_device & AINPUT_SOURCE_MOUSE) == AINPUT_SOURCE_MOUSE) { ev->set_position(event_pos); ev->set_global_position(event_pos); @@ -765,11 +764,11 @@ void DisplayServerAndroid::process_mouse_event(int input_device, int event_actio } } -void DisplayServerAndroid::_wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor) { +void DisplayServerAndroid::_wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor) { Ref<InputEventMouseButton> evd = ev->duplicate(); _set_key_modifier_state(evd); evd->set_button_index(wheel_button); - evd->set_button_mask(event_buttons_mask ^ (1 << (wheel_button - 1))); + evd->set_button_mask(MouseButton(event_buttons_mask ^ (1 << (wheel_button - 1)))); evd->set_factor(factor); Input::get_singleton()->accumulate_input_event(evd); Ref<InputEventMouseButton> evdd = evd->duplicate(); @@ -779,9 +778,9 @@ void DisplayServerAndroid::_wheel_button_click(int event_buttons_mask, const Ref } void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Point2 p_pos) { - int event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask); + MouseButton event_button_mask = _android_button_mask_to_godot_button_mask(event_android_button_mask); Ref<InputEventMouseButton> ev; - ev.instance(); + ev.instantiate(); _set_key_modifier_state(ev); ev->set_position(p_pos); ev->set_global_position(p_pos); @@ -792,7 +791,7 @@ void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Poi Input::get_singleton()->accumulate_input_event(ev); } -int DisplayServerAndroid::_button_index_from_mask(int button_mask) { +MouseButton DisplayServerAndroid::_button_index_from_mask(MouseButton button_mask) { switch (button_mask) { case MOUSE_BUTTON_MASK_LEFT: return MOUSE_BUTTON_LEFT; @@ -805,13 +804,13 @@ int DisplayServerAndroid::_button_index_from_mask(int button_mask) { case MOUSE_BUTTON_MASK_XBUTTON2: return MOUSE_BUTTON_XBUTTON2; default: - return 0; + return MOUSE_BUTTON_NONE; } } void DisplayServerAndroid::process_scroll(Point2 p_pos) { Ref<InputEventPanGesture> ev; - ev.instance(); + ev.instantiate(); _set_key_modifier_state(ev); ev->set_position(p_pos); ev->set_delta(p_pos - scroll_prev_pos); @@ -863,12 +862,12 @@ Point2i DisplayServerAndroid::mouse_get_position() const { return hover_prev_pos; } -int DisplayServerAndroid::mouse_get_button_state() const { +MouseButton DisplayServerAndroid::mouse_get_button_state() const { return buttons_state; } -int DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) { - int godot_button_mask = 0; +MouseButton DisplayServerAndroid::_android_button_mask_to_godot_button_mask(int android_button_mask) { + MouseButton godot_button_mask = MOUSE_BUTTON_NONE; if (android_button_mask & AMOTION_EVENT_BUTTON_PRIMARY) { godot_button_mask |= MOUSE_BUTTON_MASK_LEFT; } @@ -903,3 +902,17 @@ void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const { return cursor_shape; } + +void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { +#if defined(VULKAN_ENABLED) + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); +#endif +} + +DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_window) const { +#if defined(VULKAN_ENABLED) + return context_vulkan->get_vsync_mode(p_window); +#else + return DisplayServer::VSYNC_ENABLED; +#endif +} diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 1379baf154..bd5bed31cd 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -68,7 +68,7 @@ private: bool control_mem = false; bool meta_mem = false; - int buttons_state; + MouseButton buttons_state = MOUSE_BUTTON_NONE; // https://developer.android.com/reference/android/view/PointerIcon // mapping between Godot's cursor shape to Android's' @@ -81,7 +81,7 @@ private: 1004, //CURSOR_BUSY 1021, //CURSOR_DRAG 1021, //CURSOR_CAN_DRO - 1000, //CURSOR_FORBIDD (no corresponding icon in Android's icon so fallback to default) + 1000, //CURSOR_FORBIDD (no corresponding icon in Android's icon so fallback to default) 1015, //CURSOR_VSIZE 1014, //CURSOR_HSIZE 1017, //CURSOR_BDIAGSI @@ -92,7 +92,7 @@ private: 1003, //CURSOR_HELP }; const int CURSOR_TYPE_NULL = 0; - MouseMode mouse_mode; + MouseMode mouse_mode = MouseMode::MOUSE_MODE_VISIBLE; bool keep_screen_on; @@ -120,11 +120,11 @@ private: void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); - static int _button_index_from_mask(int button_mask); + static MouseButton _button_index_from_mask(MouseButton button_mask); - static int _android_button_mask_to_godot_button_mask(int android_button_mask); + static MouseButton _android_button_mask_to_godot_button_mask(int android_button_mask); - void _wheel_button_click(int event_buttons_mask, const Ref<InputEventMouseButton> &ev, int wheel_button, float factor); + void _wheel_button_click(MouseButton event_buttons_mask, const Ref<InputEventMouseButton> &ev, MouseButton wheel_button, float factor); public: static DisplayServerAndroid *get_singleton(); @@ -188,6 +188,8 @@ public: virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID); virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const; virtual bool can_any_window_draw() const; + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID); + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const; virtual void alert(const String &p_alert, const String &p_title); @@ -211,7 +213,7 @@ public: void mouse_set_mode(MouseMode p_mode); MouseMode mouse_get_mode() const; - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_android_driver(); @@ -219,9 +221,9 @@ public: void notify_surface_changed(int p_width, int p_height); virtual Point2i mouse_get_position() const; - virtual int mouse_get_button_state() const; + virtual MouseButton mouse_get_button_state() const; - DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); ~DisplayServerAndroid(); }; diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index c45828e194..6661698d3e 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -31,11 +31,12 @@ #include "export.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/image_loader.h" +#include "core/io/json.h" #include "core/io/marshalls.h" #include "core/io/zip_io.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/templates/safe_refcount.h" #include "core/version.h" @@ -206,6 +207,7 @@ static const char *LEGACY_BUILD_SPLASH_IMAGE_EXPORT_PATH = "res/drawable-nodpi-v static const char *SPLASH_BG_COLOR_PATH = "res/drawable-nodpi/splash_bg_color.png"; static const char *LEGACY_BUILD_SPLASH_BG_COLOR_PATH = "res/drawable-nodpi-v4/splash_bg_color.png"; static const char *SPLASH_CONFIG_PATH = "res://android/build/res/drawable/splash_drawable.xml"; +static const char *GDNATIVE_LIBS_PATH = "res://android/build/libs/gdnativelibs.json"; const String SPLASH_CONFIG_XML_CONTENT = R"SPLASH(<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android"> @@ -277,6 +279,11 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { EditorProgress *ep = nullptr; }; + struct CustomExportData { + bool debug; + Vector<String> libs; + }; + Vector<PluginConfigAndroid> plugins; String last_plugin_names; uint64_t last_custom_build_time = 0; @@ -609,9 +616,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { zip_fileinfo zipfi; zipfi.tmz_date.tm_hour = time.hour; zipfi.tmz_date.tm_mday = date.day; - zipfi.tmz_date.tm_min = time.min; + zipfi.tmz_date.tm_min = time.minute; zipfi.tmz_date.tm_mon = date.month - 1; // tm_mon is zero indexed - zipfi.tmz_date.tm_sec = time.sec; + zipfi.tmz_date.tm_sec = time.second; zipfi.tmz_date.tm_year = date.year; zipfi.dosDate = 0; zipfi.external_fa = 0; @@ -757,6 +764,33 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { return OK; } + static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so) { + ERR_FAIL_COND_V_MSG(!p_so.path.get_file().begins_with("lib"), FAILED, + "Android .so file names must start with \"lib\", but got: " + p_so.path); + Vector<String> abis = get_abis(); + CustomExportData *export_data = (CustomExportData *)p_userdata; + bool exported = false; + for (int i = 0; i < p_so.tags.size(); ++i) { + int abi_index = abis.find(p_so.tags[i]); + if (abi_index != -1) { + exported = true; + String base = "res://android/build/libs"; + String type = export_data->debug ? "debug" : "release"; + String abi = abis[abi_index]; + String filename = p_so.path.get_file(); + String dst_path = base.plus_file(type).plus_file(abi).plus_file(filename); + Vector<uint8_t> data = FileAccess::get_file_as_array(p_so.path); + print_verbose("Copying .so file from " + p_so.path + " to " + dst_path); + Error err = store_file_at_path(dst_path, data); + ERR_FAIL_COND_V_MSG(err, err, "Failed to copy .so file from " + p_so.path + " to " + dst_path); + export_data->libs.push_back(dst_path); + } + } + ERR_FAIL_COND_V_MSG(!exported, FAILED, + "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + String(" ").join(abis)); + return OK; + } + void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) { const char **aperms = android_perms; while (*aperms) { @@ -858,6 +892,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { int xr_mode_index = p_preset->get("xr_features/xr_mode"); bool backup_allowed = p_preset->get("user_data_backup/allow"); + bool classify_as_game = p_preset->get("package/classify_as_game"); Vector<String> perms; // Write permissions into the perms variable. @@ -955,6 +990,10 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]); } + if (tname == "application" && attrname == "isGame") { + encode_uint32(classify_as_game, &p_manifest.write[iofs + 16]); + } + if (tname == "instrumentation" && attrname == "targetPackage") { string_table.write[attr_value] = get_package_name(package_name); } @@ -1461,7 +1500,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); if (!project_splash_path.is_empty()) { - splash_image.instance(); + splash_image.instantiate(); print_verbose("Loading splash image: " + project_splash_path); const Error err = ImageLoader::load_image(project_splash_path, splash_image); if (err) { @@ -1501,7 +1540,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { } print_verbose("Creating splash background color image."); - splash_bg_color_image.instance(); + splash_bg_color_image.instantiate(); splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format()); splash_bg_color_image->fill(bg_color); @@ -1512,9 +1551,9 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { void load_icon_refs(const Ref<EditorExportPreset> &p_preset, Ref<Image> &icon, Ref<Image> &foreground, Ref<Image> &background) { String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon"); - icon.instance(); - foreground.instance(); - background.instance(); + icon.instantiate(); + foreground.instantiate(); + background.instantiate(); // Regular icon: user selection -> project icon -> default. String path = static_cast<String>(p_preset->get(launcher_icon_option)).strip_edges(); @@ -1673,6 +1712,7 @@ public: r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/classify_as_game"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), "")); @@ -1849,7 +1889,7 @@ public: err = OS::get_singleton()->execute(adb, args, &output, &rv, true); print_verbose(output); if (err || rv != 0) { - EditorNode::add_io_error("Could not install to device."); + EditorNode::add_io_error("Could not install to device: " + output); CLEANUP_AND_RETURN(ERR_CANT_CREATE); } @@ -2380,6 +2420,28 @@ public: } } + void _remove_copied_libs() { + print_verbose("Removing previously installed libraries..."); + Error error; + String libs_json = FileAccess::get_file_as_string(GDNATIVE_LIBS_PATH, &error); + if (error || libs_json.is_empty()) { + print_verbose("No previously installed libraries found"); + return; + } + + JSON json; + error = json.parse(libs_json); + ERR_FAIL_COND_MSG(error, "Error parsing \"" + libs_json + "\" on line " + itos(json.get_error_line()) + ": " + json.get_error_message()); + + Vector<String> libs = json.get_data(); + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + for (int i = 0; i < libs.size(); i++) { + print_verbose("Removing previously installed library " + libs[i]); + da->remove(libs[i]); + } + da->remove(GDNATIVE_LIBS_PATH); + } + String join_list(List<String> parts, const String &separator) const { String ret; for (int i = 0; i < parts.size(); ++i) { @@ -2491,13 +2553,22 @@ public: //stores all the project files inside the Gradle project directory. Also includes all ABIs _clear_assets_directory(); + _remove_copied_libs(); if (!apk_expansion) { print_verbose("Exporting project files.."); - err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, nullptr, ignore_so_file); + CustomExportData user_data; + user_data.debug = p_debug; + err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so); if (err != OK) { EditorNode::add_io_error("Could not export project files to gradle project\n"); return err; } + if (user_data.libs.size() > 0) { + FileAccessRef fa = FileAccess::open(GDNATIVE_LIBS_PATH, FileAccess::WRITE); + JSON json; + fa->store_string(json.stringify(user_data.libs, "\t")); + fa->close(); + } } else { print_verbose("Saving apk expansion file.."); err = save_apk_expansion_file(p_preset, p_path); @@ -2568,19 +2639,35 @@ public: // Sensitive additions must be done below the logging statement. print_verbose("Build Android project using gradle command: " + String("\n") + build_command + " " + join_list(cmdline, String(" "))); - if (should_sign && !p_debug) { - // Pass the release keystore info as well - String release_keystore = p_preset->get("keystore/release"); - String release_username = p_preset->get("keystore/release_user"); - String release_password = p_preset->get("keystore/release_password"); - if (!FileAccess::exists(release_keystore)) { - EditorNode::add_io_error("Could not find keystore, unable to export."); - return ERR_FILE_CANT_OPEN; - } + if (should_sign) { + if (p_debug) { + String debug_keystore = p_preset->get("keystore/debug"); + String debug_password = p_preset->get("keystore/debug_password"); + String debug_user = p_preset->get("keystore/debug_user"); + + if (debug_keystore.is_empty()) { + debug_keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore"); + debug_password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); + debug_user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); + } - cmdline.push_back("-Prelease_keystore_file=" + release_keystore); // argument to specify the release keystore file. - cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias. - cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specity the release keystore password. + cmdline.push_back("-Pdebug_keystore_file=" + debug_keystore); // argument to specify the debug keystore file. + cmdline.push_back("-Pdebug_keystore_alias=" + debug_user); // argument to specify the debug keystore alias. + cmdline.push_back("-Pdebug_keystore_password=" + debug_password); // argument to specify the debug keystore password. + } else { + // Pass the release keystore info as well + String release_keystore = p_preset->get("keystore/release"); + String release_username = p_preset->get("keystore/release_user"); + String release_password = p_preset->get("keystore/release_password"); + if (!FileAccess::exists(release_keystore)) { + EditorNode::add_io_error("Could not find keystore, unable to export."); + return ERR_FILE_CANT_OPEN; + } + + cmdline.push_back("-Prelease_keystore_file=" + release_keystore); // argument to specify the release keystore file. + cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias. + cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specify the release keystore password. + } } int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline); @@ -2941,11 +3028,11 @@ public: EditorExportPlatformAndroid() { Ref<Image> img = memnew(Image(_android_logo)); - logo.instance(); + logo.instantiate(); logo->create_from_image(img); img = Ref<Image>(memnew(Image(_android_run_icon))); - run_icon.instance(); + run_icon.instantiate(); run_icon->create_from_image(img); devices_changed.set(); diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 0bb94dcc97..52a7e4c5cf 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -31,9 +31,9 @@ #ifndef GODOT_GRADLE_EXPORT_UTIL_H #define GODOT_GRADLE_EXPORT_UTIL_H +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/zip_io.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "editor/editor_export.h" @@ -96,14 +96,6 @@ Error create_directory(const String &p_dir) { return OK; } -// Implementation of EditorExportSaveSharedObject. -// This method will only be called as an input to export_project_files. -// This method lets the .so files for all ABIs to be copied -// into the gradle project from the .AAR file -Error ignore_so_file(void *p_userdata, const SharedObject &p_so) { - return OK; -} - // Writes p_data into a file at p_path, creating directories if necessary. // Note: this will overwrite the file at p_path if it already exists. Error store_file_at_path(const String &p_path, const Vector<uint8_t> &p_data) { @@ -260,9 +252,13 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) { String _get_application_tag(const Ref<EditorExportPreset> &p_preset) { String manifest_application_text = vformat( " <application android:label=\"@string/godot_project_name_string\"\n" - " android:allowBackup=\"%s\" tools:ignore=\"GoogleAppIndexingWarning\"\n" - " android:icon=\"@mipmap/icon\">\n\n", - bool_to_string(p_preset->get("user_data_backup/allow"))); + " android:allowBackup=\"%s\"\n" + " android:icon=\"@mipmap/icon\"\n" + " android:isGame=\"%s\"\n" + " tools:replace=\"android:allowBackup,android:isGame\"\n" + " tools:ignore=\"GoogleAppIndexingWarning\">\n\n", + bool_to_string(p_preset->get("user_data_backup/allow")), + bool_to_string(p_preset->get("package/classify_as_game"))); manifest_application_text += _get_activity_tag(p_preset); manifest_application_text += " </application>\n"; diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index 8890e0f645..bb4ce36947 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -31,7 +31,7 @@ #ifndef FILE_ACCESS_ANDROID_H #define FILE_ACCESS_ANDROID_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include <android/asset_manager.h> #include <android/log.h> #include <stdio.h> diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml index 15feea15a4..0874d77645 100644 --- a/platform/android/java/app/AndroidManifest.xml +++ b/platform/android/java/app/AndroidManifest.xml @@ -19,8 +19,9 @@ <application android:label="@string/godot_project_name_string" android:allowBackup="false" - tools:ignore="GoogleAppIndexingWarning" - android:icon="@mipmap/icon" > + android:icon="@mipmap/icon" + android:isGame="true" + tools:ignore="GoogleAppIndexingWarning" > <!-- Records the version of the Godot editor used for building --> <meta-data diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle index 1b1fb47bd8..18e07c3762 100644 --- a/platform/android/java/app/build.gradle +++ b/platform/android/java/app/build.gradle @@ -6,7 +6,7 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { classpath libraries.androidGradlePlugin @@ -18,9 +18,8 @@ apply plugin: 'com.android.application' allprojects { repositories { - mavenCentral() google() - jcenter() + mavenCentral() // Godot user plugins custom maven repos String[] mavenRepos = getGodotPluginsMavenRepos() @@ -113,6 +112,15 @@ android { } signingConfigs { + debug { + if (hasCustomDebugKeystore()) { + storeFile new File(getDebugKeystoreFile()) + storePassword getDebugKeystorePassword() + keyAlias getDebugKeyAlias() + keyPassword getDebugKeystorePassword() + } + } + release { File keystoreFile = new File(getReleaseKeystoreFile()) if (keystoreFile.isFile()) { diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index b278d15bdf..81fc87b7ef 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -1,11 +1,11 @@ ext.versions = [ - androidGradlePlugin: '4.0.1', + androidGradlePlugin: '4.2.1', compileSdk : 29, minSdk : 18, targetSdk : 29, buildTools : '30.0.3', supportCoreUtils : '1.0.0', - kotlinVersion : '1.4.10', + kotlinVersion : '1.5.10', v4Support : '1.0.0', javaVersion : 1.8, ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated. @@ -191,6 +191,35 @@ ext.getGodotPluginsLocalBinaries = { -> return binDeps } +ext.getDebugKeystoreFile = { -> + String keystoreFile = project.hasProperty("debug_keystore_file") ? project.property("debug_keystore_file") : "" + if (keystoreFile == null || keystoreFile.isEmpty()) { + keystoreFile = "." + } + return keystoreFile +} + +ext.hasCustomDebugKeystore = { -> + File keystoreFile = new File(getDebugKeystoreFile()) + return keystoreFile.isFile() +} + +ext.getDebugKeystorePassword = { -> + String keystorePassword = project.hasProperty("debug_keystore_password") ? project.property("debug_keystore_password") : "" + if (keystorePassword == null || keystorePassword.isEmpty()) { + keystorePassword = "android" + } + return keystorePassword +} + +ext.getDebugKeyAlias = { -> + String keyAlias = project.hasProperty("debug_keystore_alias") ? project.property("debug_keystore_alias") : "" + if (keyAlias == null || keyAlias.isEmpty()) { + keyAlias = "androiddebugkey" + } + return keyAlias +} + ext.getReleaseKeystoreFile = { -> String keystoreFile = project.hasProperty("release_keystore_file") ? project.property("release_keystore_file") : "" if (keystoreFile == null || keystoreFile.isEmpty()) { diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle index a7fe500be2..ee24a46d9f 100644 --- a/platform/android/java/build.gradle +++ b/platform/android/java/build.gradle @@ -5,7 +5,7 @@ buildscript { repositories { google() - jcenter() + mavenCentral() } dependencies { classpath libraries.androidGradlePlugin @@ -16,7 +16,6 @@ buildscript { allprojects { repositories { google() - jcenter() mavenCentral() } } @@ -118,8 +117,8 @@ task zipCustomBuild(type: Zip) { } from(fileTree(dir: 'app', excludes: ['**/build/**', '**/.gradle/**', '**/*.iml']), fileTree(dir: '.', includes: ['gradle.properties', 'gradlew', 'gradlew.bat', 'gradle/**'])) include '**/*' - archiveName 'android_source.zip' - destinationDir(file(binDir)) + archiveFileName = 'android_source.zip' + destinationDirectory = file(binDir) } def templateExcludedBuildTask() { diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties index a7d8a0f310..74c5636f8a 100644 --- a/platform/android/java/gradle/wrapper/gradle-wrapper.properties +++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Sep 02 02:44:30 PDT 2019 +#Wed Jun 23 23:42:22 PDT 2021 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +zipStoreBase=GRADLE_USER_HOME diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat index f9553162f1..11cc30edb0 100644 --- a/platform/android/java/gradlew.bat +++ b/platform/android/java/gradlew.bat @@ -1,7 +1,7 @@ @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem -@rem Gradle startup script for Windows +@rem Gradle startup script for Windows @rem @rem ########################################################################## @@ -75,7 +75,7 @@ if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd diff --git a/platform/android/java/lib/res/values/strings.xml b/platform/android/java/lib/res/values/strings.xml index 590b066d8a..010006b81e 100644 --- a/platform/android/java/lib/res/values/strings.xml +++ b/platform/android/java/lib/res/values/strings.xml @@ -6,7 +6,7 @@ <string name="text_button_resume_cellular">Resume download</string> <string name="text_button_wifi_settings">Wi-Fi settings</string> <string name="text_verifying_download">Verifying Download</string> - <string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string> + <string name="text_validation_complete">XAPK File Validation Complete. Select OK to exit.</string> <string name="text_validation_failed">XAPK File Validation Failed.</string> <string name="text_button_pause">Pause Download</string> <string name="text_button_resume">Resume Download</string> diff --git a/platform/android/java/lib/src/org/godotengine/godot/Dictionary.java b/platform/android/java/lib/src/org/godotengine/godot/Dictionary.java index 0572cf3589..b12844702a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Dictionary.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Dictionary.java @@ -43,10 +43,10 @@ public class Dictionary extends HashMap<String, Object> { for (String key : keys) { ret[i] = key; i++; - }; + } return ret; - }; + } public Object[] get_values() { Object[] ret = new Object[size()]; @@ -55,21 +55,21 @@ public class Dictionary extends HashMap<String, Object> { for (String key : keys) { ret[i] = get(key); i++; - }; + } return ret; - }; + } public void set_keys(String[] keys) { keys_cache = keys; - }; + } public void set_values(Object[] vals) { int i = 0; for (String key : keys_cache) { put(key, vals[i]); i++; - }; + } keys_cache = null; - }; -}; + } +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java index 1ed16e04ca..89497d1526 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java +++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java @@ -96,14 +96,6 @@ public abstract class FullScreenGodotApp extends FragmentActivity implements God } } - @Override - public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { - if (godotFragment != null && godotFragment.onKeyMultiple(inKeyCode, repeatCount, event)) { - return true; - } - return super.onKeyMultiple(inKeyCode, repeatCount, event); - } - /** * Used to initialize the Godot fragment instance in {@link FullScreenGodotApp#onCreate(Bundle)}. */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 0c16214c8a..8ffa4a9249 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -70,10 +70,8 @@ import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings.Secure; import android.view.Display; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.LayoutInflater; -import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -175,7 +173,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public static GodotNetUtils netUtils; public interface ResultCallback { - public void callback(int requestCode, int resultCode, Intent data); + void callback(int requestCode, int resultCode, Intent data); } public ResultCallback result_callback; @@ -220,7 +218,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC for (int i = 0; i < permissions.length; i++) { GodotLib.requestPermissionResult(permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED); } - }; + } /** * Invoked on the render thread when the Godot setup is complete. @@ -281,29 +279,20 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC editText.setView(mRenderView); io.setEdit(editText); - view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - Point fullSize = new Point(); - activity.getWindowManager().getDefaultDisplay().getSize(fullSize); - Rect gameSize = new Rect(); - mRenderView.getView().getWindowVisibleDisplayFrame(gameSize); - - final int keyboardHeight = fullSize.y - gameSize.bottom; - GodotLib.setVirtualKeyboardHeight(keyboardHeight); - } + view.getViewTreeObserver().addOnGlobalLayoutListener(() -> { + Point fullSize = new Point(); + activity.getWindowManager().getDefaultDisplay().getSize(fullSize); + Rect gameSize = new Rect(); + mRenderView.getView().getWindowVisibleDisplayFrame(gameSize); + final int keyboardHeight = fullSize.y - gameSize.bottom; + GodotLib.setVirtualKeyboardHeight(keyboardHeight); }); - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - // Must occur after GodotLib.setup has completed. - for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { - plugin.onRegisterPluginWithGodotNative(); - } - - setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); + mRenderView.queueOnRenderThread(() -> { + for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { + plugin.onRegisterPluginWithGodotNative(); } + setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); }); // Include the returned non-null views in the Godot view hierarchy. @@ -316,14 +305,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } public void setKeepScreenOn(final boolean p_enabled) { - runOnUiThread(new Runnable() { - @Override - public void run() { - if (p_enabled) { - getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } + runOnUiThread(() -> { + if (p_enabled) { + getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } }); } @@ -370,21 +356,14 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public void alert(final String message, final String title) { final Activity activity = getActivity(); - runOnUiThread(new Runnable() { - @Override - public void run() { - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setMessage(message).setTitle(title); - builder.setPositiveButton( - "OK", - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - AlertDialog dialog = builder.create(); - dialog.show(); - } + runOnUiThread(() -> { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setMessage(message).setTitle(title); + builder.setPositiveButton( + "OK", + (dialog, id) -> dialog.cancel()); + AlertDialog dialog = builder.create(); + dialog.show(); }); } @@ -534,7 +513,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC String main_pack_md5 = null; String main_pack_key = null; - List<String> new_args = new LinkedList<String>(); + List<String> new_args = new LinkedList<>(); for (int i = 0; i < command_line.length; i++) { boolean has_extra = i < command_line.length - 1; @@ -755,19 +734,16 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC public void UiChangeListener() { final View decorView = getActivity().getWindow().getDecorView(); - decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { - @Override - public void onSystemUiVisibilityChange(int visibility) { - if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - decorView.setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } + decorView.setOnSystemUiVisibilityChangeListener(visibility -> { + if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + decorView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_LAYOUT_STABLE | + View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | + View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } } }); @@ -780,7 +756,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC int displayRotation = display.getRotation(); float[] adjustedValues = new float[3]; - final int axisSwap[][] = { + final int[][] axisSwap = { { 1, -1, 0, 1 }, // ROTATION_0 { -1, -1, 1, 0 }, // ROTATION_90 { -1, 1, 0, 1 }, // ROTATION_180 @@ -798,21 +774,18 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC final int typeOfSensor = event.sensor.getType(); if (mRenderView != null) { - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) { - GodotLib.accelerometer(-x, y, -z); - } - if (typeOfSensor == Sensor.TYPE_GRAVITY) { - GodotLib.gravity(-x, y, -z); - } - if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) { - GodotLib.magnetometer(-x, y, -z); - } - if (typeOfSensor == Sensor.TYPE_GYROSCOPE) { - GodotLib.gyroscope(x, -y, z); - } + mRenderView.queueOnRenderThread(() -> { + if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) { + GodotLib.accelerometer(-x, y, -z); + } + if (typeOfSensor == Sensor.TYPE_GRAVITY) { + GodotLib.gravity(-x, y, -z); + } + if (typeOfSensor == Sensor.TYPE_MAGNETIC_FIELD) { + GodotLib.magnetometer(-x, y, -z); + } + if (typeOfSensor == Sensor.TYPE_GYROSCOPE) { + GodotLib.gyroscope(x, -y, z); } }); } @@ -847,12 +820,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } if (shouldQuit && mRenderView != null) { - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - GodotLib.back(); - } - }); + mRenderView.queueOnRenderThread(GodotLib::back); } } @@ -897,7 +865,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC byte[] messageDigest = complete.digest(); // Create Hex String - StringBuffer hexString = new StringBuffer(); + StringBuilder hexString = new StringBuilder(); for (int i = 0; i < messageDigest.length; i++) { String s = Integer.toHexString(0xFF & messageDigest[i]); @@ -918,33 +886,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC } } - public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) { - String s = event.getCharacters(); - if (s == null || s.length() == 0) - return false; - - final char[] cc = s.toCharArray(); - int cnt = 0; - for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0) - ; - if (cnt == 0) - return false; - mRenderView.queueOnRenderThread(new Runnable() { - // This method will be called on the rendering thread: - public void run() { - for (int i = 0, n = cc.length; i < n; i++) { - int keyCode; - if ((keyCode = cc[i]) != 0) { - // Simulate key down and up... - GodotLib.key(0, 0, keyCode, true); - GodotLib.key(0, 0, keyCode, false); - } - } - } - }); - return true; - } - public boolean requestPermission(String p_name) { return PermissionsUtil.requestPermission(p_name, getActivity()); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index b3ee55ea64..a9d45c943b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -232,13 +232,10 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView public void onResume() { super.onResume(); - queueEvent(new Runnable() { - @Override - public void run() { - // Resume the renderer - godotRenderer.onActivityResumed(); - GodotLib.focusin(); - } + queueEvent(() -> { + // Resume the renderer + godotRenderer.onActivityResumed(); + GodotLib.focusin(); }); } @@ -246,13 +243,10 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView public void onPause() { super.onPause(); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.focusout(); - // Pause the renderer - godotRenderer.onActivityPaused(); - } + queueEvent(() -> { + GodotLib.focusout(); + // Pause the renderer + godotRenderer.onActivityPaused(); }); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index c7c7c1b40c..66882e8e72 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -34,11 +34,9 @@ import org.godotengine.godot.input.*; import android.app.Activity; import android.content.*; -import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.AssetManager; import android.graphics.Point; -import android.media.*; import android.net.Uri; import android.os.*; import android.util.DisplayMetrics; @@ -73,7 +71,7 @@ public class GodotIO { public int last_file_id = 1; - class AssetData { + static class AssetData { public boolean eof = false; public String path; public InputStream is; @@ -232,7 +230,7 @@ public class GodotIO { /// DIRECTORIES ///////////////////////// - class AssetDir { + static class AssetDir { public String[] files; public int current; public String path; @@ -323,97 +321,8 @@ public class GodotIO { am = p_activity.getAssets(); activity = p_activity; //streams = new HashMap<Integer, AssetData>(); - streams = new SparseArray<AssetData>(); - dirs = new SparseArray<AssetDir>(); - } - - ///////////////////////// - // AUDIO - ///////////////////////// - - private Object buf; - private Thread mAudioThread; - private AudioTrack mAudioTrack; - - public Object audioInit(int sampleRate, int desiredFrames) { - int channelConfig = AudioFormat.CHANNEL_OUT_STEREO; - int audioFormat = AudioFormat.ENCODING_PCM_16BIT; - int frameSize = 4; - - System.out.printf("audioInit: initializing audio:\n"); - - //Log.v("Godot", "Godot audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer"); - - // Let the user pick a larger buffer if they really want -- but ye - // gods they probably shouldn't, the minimums are horrifyingly high - // latency already - desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize); - - mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, - channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM); - - audioStartThread(); - - //Log.v("Godot", "Godot audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer"); - - buf = new short[desiredFrames * 2]; - return buf; - } - - public void audioStartThread() { - mAudioThread = new Thread(new Runnable() { - public void run() { - mAudioTrack.play(); - GodotLib.audio(); - } - }); - - // I'd take REALTIME if I could get it! - mAudioThread.setPriority(Thread.MAX_PRIORITY); - mAudioThread.start(); - } - - public void audioWriteShortBuffer(short[] buffer) { - for (int i = 0; i < buffer.length;) { - int result = mAudioTrack.write(buffer, i, buffer.length - i); - if (result > 0) { - i += result; - } else if (result == 0) { - try { - Thread.sleep(1); - } catch (InterruptedException e) { - // Nom nom - } - } else { - Log.w("Godot", "Godot audio: error return from write(short)"); - return; - } - } - } - - public void audioQuit() { - if (mAudioThread != null) { - try { - mAudioThread.join(); - } catch (Exception e) { - Log.v("Godot", "Problem stopping audio thread: " + e); - } - mAudioThread = null; - - //Log.v("Godot", "Finished waiting for audio thread"); - } - - if (mAudioTrack != null) { - mAudioTrack.stop(); - mAudioTrack = null; - } - } - - public void audioPause(boolean p_pause) { - if (p_pause) - mAudioTrack.pause(); - else - mAudioTrack.play(); + streams = new SparseArray<>(); + dirs = new SparseArray<>(); } ///////////////////////// @@ -452,6 +361,10 @@ public class GodotIO { return activity.getFilesDir().getAbsolutePath(); } + public String getExternalDataDir() { + return activity.getExternalFilesDir(null).getAbsolutePath(); + } + public String getLocale() { return Locale.getDefault().toString(); } @@ -471,7 +384,7 @@ public class GodotIO { Point size = new Point(); display.getRealSize(size); - int result[] = { 0, 0, size.x, size.y }; + int[] result = { 0, 0, size.x, size.y }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets(); DisplayCutout cutout = insets.getDisplayCutout(); @@ -493,12 +406,12 @@ public class GodotIO { //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); //inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); - }; + } public void hideKeyboard() { if (edit != null) edit.hideKeyboard(); - }; + } public void setScreenOrientation(int p_orientation) { switch (p_orientation) { diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 534a50e9ed..95870acda1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -34,7 +34,6 @@ import android.app.Activity; import android.hardware.SensorEvent; import android.view.Surface; -import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; /** @@ -175,11 +174,6 @@ public class GodotLib { public static native void focusout(); /** - * Invoked when the audio thread is started. - */ - public static native void audio(); - - /** * Used to access Godot global properties. * @param p_key Property key * @return String value of the property diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java index ac333dd827..79007764a7 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java @@ -35,18 +35,18 @@ import org.godotengine.godot.input.GodotInputHandler; import android.view.SurfaceView; public interface GodotRenderView { - abstract public SurfaceView getView(); + SurfaceView getView(); - abstract public void initInputDevices(); + void initInputDevices(); - abstract public void queueOnRenderThread(Runnable event); + void queueOnRenderThread(Runnable event); - abstract public void onActivityPaused(); - abstract public void onActivityResumed(); + void onActivityPaused(); + void onActivityResumed(); - abstract public void onBackPressed(); + void onBackPressed(); - abstract public GodotInputHandler getInputHandler(); + GodotInputHandler getInputHandler(); - abstract public void setPointerIcon(int pointerType); + void setPointerIcon(int pointerType); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java index 59bdbf7f8d..878a119c5c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java @@ -34,7 +34,6 @@ import org.godotengine.godot.plugin.GodotPlugin; import org.godotengine.godot.plugin.GodotPluginRegistry; import org.godotengine.godot.utils.GLUtils; -import android.content.Context; import android.opengl.GLSurfaceView; import javax.microedition.khronos.egl.EGLConfig; diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java index 169c6cf770..6fca7f2a57 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -39,7 +39,6 @@ import android.annotation.SuppressLint; import android.content.Context; import android.os.Build; import android.view.GestureDetector; -import android.view.InputDevice; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.PointerIcon; @@ -150,13 +149,10 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV public void onResume() { super.onResume(); - queueOnVkThread(new Runnable() { - @Override - public void run() { - // Resume the renderer - mRenderer.onVkResume(); - GodotLib.focusin(); - } + queueOnVkThread(() -> { + // Resume the renderer + mRenderer.onVkResume(); + GodotLib.focusin(); }); } @@ -164,13 +160,10 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV public void onPause() { super.onPause(); - queueOnVkThread(new Runnable() { - @Override - public void run() { - GodotLib.focusout(); - // Pause the renderer - mRenderer.onVkPause(); - } + queueOnVkThread(() -> { + GodotLib.focusout(); + // Pause the renderer + mRenderer.onVkPause(); }); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java index 2c39d06832..1d60c21c60 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java @@ -75,12 +75,7 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener final int x = Math.round(event.getX()); final int y = Math.round(event.getY()); final int buttonMask = event.getButtonState(); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.doubleTap(buttonMask, x, y); - } - }); + queueEvent(() -> GodotLib.doubleTap(buttonMask, x, y)); return true; } @@ -89,12 +84,7 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener //Log.i("GodotGesture", "onScroll"); final int x = Math.round(distanceX); final int y = Math.round(distanceY); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.scroll(x, y); - } - }); + queueEvent(() -> GodotLib.scroll(x, y)); return true; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java index 435b8b325f..4dc9157545 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java @@ -45,13 +45,9 @@ import android.view.InputDevice.MotionRange; import android.view.KeyEvent; import android.view.MotionEvent; -import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; import java.util.HashSet; -import java.util.List; -import java.util.Map; import java.util.Set; /** @@ -64,7 +60,7 @@ public class GodotInputHandler implements InputDeviceListener { private final String tag = this.getClass().getSimpleName(); private final SparseIntArray mJoystickIds = new SparseIntArray(4); - private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<Joystick>(4); + private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4); public GodotInputHandler(GodotRenderView godotView) { mRenderView = godotView; @@ -101,22 +97,12 @@ public class GodotInputHandler implements InputDeviceListener { final int button = getGodotButton(keyCode); final int godotJoyId = mJoystickIds.get(deviceId); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joybutton(godotJoyId, button, false); - } - }); + queueEvent(() -> GodotLib.joybutton(godotJoyId, button, false)); } } else { final int scanCode = event.getScanCode(); final int chr = event.getUnicodeChar(0); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.key(keyCode, scanCode, chr, false); - } - }); + queueEvent(() -> GodotLib.key(keyCode, scanCode, chr, false)); } return true; @@ -147,22 +133,12 @@ public class GodotInputHandler implements InputDeviceListener { final int button = getGodotButton(keyCode); final int godotJoyId = mJoystickIds.get(deviceId); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joybutton(godotJoyId, button, true); - } - }); + queueEvent(() -> GodotLib.joybutton(godotJoyId, button, true)); } } else { final int scanCode = event.getScanCode(); final int chr = event.getUnicodeChar(0); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.key(keyCode, scanCode, chr, true); - } - }); + queueEvent(() -> GodotLib.key(keyCode, scanCode, chr, true)); } return true; @@ -194,19 +170,16 @@ public class GodotInputHandler implements InputDeviceListener { final int action = event.getActionMasked(); final int pointer_idx = event.getPointerId(event.getActionIndex()); - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_MOVE: - case MotionEvent.ACTION_POINTER_UP: - case MotionEvent.ACTION_POINTER_DOWN: { - GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr); - } break; - } + mRenderView.queueOnRenderThread(() -> { + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_MOVE: + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_POINTER_DOWN: { + GodotLib.touch(event.getSource(), action, pointer_idx, evcount, arr); + } break; } }); } @@ -232,13 +205,7 @@ public class GodotInputHandler implements InputDeviceListener { // save value to prevent repeats joystick.axesValues.put(axis, value); final int godotAxisIdx = i; - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joyaxis(godotJoyId, godotAxisIdx, value); - //Log.i(tag, "GodotLib.joyaxis("+godotJoyId+", "+godotAxisIdx+", "+value+");"); - } - }); + queueEvent(() -> GodotLib.joyaxis(godotJoyId, godotAxisIdx, value)); } } @@ -248,13 +215,7 @@ public class GodotInputHandler implements InputDeviceListener { if (joystick.hatX != hatX || joystick.hatY != hatY) { joystick.hatX = hatX; joystick.hatY = hatY; - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joyhat(godotJoyId, hatX, hatY); - //Log.i(tag, "GodotLib.joyhat("+godotJoyId+", "+hatX+", "+hatY+");"); - } - }); + queueEvent(() -> GodotLib.joyhat(godotJoyId, hatX, hatY)); } } return true; @@ -263,12 +224,7 @@ public class GodotInputHandler implements InputDeviceListener { final float x = event.getX(); final float y = event.getY(); final int type = event.getAction(); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.hover(type, x, y); - } - }); + queueEvent(() -> GodotLib.hover(type, x, y)); return true; } else if (event.isFromSource(InputDevice.SOURCE_MOUSE) || event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)) { @@ -333,7 +289,7 @@ public class GodotInputHandler implements InputDeviceListener { //Helps with creating new joypad mappings. Log.i(tag, "=== New Input Device: " + joystick.name); - Set<Integer> already = new HashSet<Integer>(); + Set<Integer> already = new HashSet<>(); for (InputDevice.MotionRange range : device.getMotionRanges()) { boolean isJoystick = range.isFromSource(InputDevice.SOURCE_JOYSTICK); boolean isGamepad = range.isFromSource(InputDevice.SOURCE_GAMEPAD); @@ -360,12 +316,7 @@ public class GodotInputHandler implements InputDeviceListener { } mJoysticksDevices.put(deviceId, joystick); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joyconnectionchanged(id, true, joystick.name); - } - }); + queueEvent(() -> GodotLib.joyconnectionchanged(id, true, joystick.name)); } @Override @@ -378,12 +329,7 @@ public class GodotInputHandler implements InputDeviceListener { mJoystickIds.delete(deviceId); mJoysticksDevices.delete(deviceId); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.joyconnectionchanged(godotJoyId, false, ""); - } - }); + queueEvent(() -> GodotLib.joyconnectionchanged(godotJoyId, false, "")); } @Override @@ -472,12 +418,7 @@ public class GodotInputHandler implements InputDeviceListener { final float x = event.getX(); final float y = event.getY(); final int type = event.getAction(); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.hover(type, x, y); - } - }); + queueEvent(() -> GodotLib.hover(type, x, y)); return true; } case MotionEvent.ACTION_BUTTON_PRESS: @@ -487,12 +428,7 @@ public class GodotInputHandler implements InputDeviceListener { final float y = event.getY(); final int buttonsMask = event.getButtonState(); final int action = event.getAction(); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask); - } - }); + queueEvent(() -> GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask)); return true; } case MotionEvent.ACTION_SCROLL: { @@ -502,12 +438,7 @@ public class GodotInputHandler implements InputDeviceListener { final int action = event.getAction(); final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL); final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL); - queueEvent(new Runnable() { - @Override - public void run() { - GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor); - } - }); + queueEvent(() -> GodotLib.touch(event.getSource(), action, 0, 1, new float[] { 0, x, y }, buttonsMask, verticalFactor, horizontalFactor)); } case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_UP: { diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java index 3e0e6a65fd..020870a110 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -94,17 +94,14 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) { //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after); - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - for (int i = 0; i < count; ++i) { - GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); - GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); - - if (mHasSelection) { - mHasSelection = false; - break; - } + mRenderView.queueOnRenderThread(() -> { + for (int i = 0; i < count; ++i) { + GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, true); + GodotLib.key(KeyEvent.KEYCODE_DEL, KeyEvent.KEYCODE_DEL, 0, false); + + if (mHasSelection) { + mHasSelection = false; + break; } } }); @@ -118,18 +115,15 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene for (int i = start; i < start + count; ++i) { newChars[i - start] = pCharSequence.charAt(i); } - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - for (int i = 0; i < count; ++i) { - int key = newChars[i]; - if ((key == '\n') && !mEdit.isMultiline()) { - // Return keys are handled through action events - continue; - } - GodotLib.key(0, 0, key, true); - GodotLib.key(0, 0, key, false); + mRenderView.queueOnRenderThread(() -> { + for (int i = 0; i < count; ++i) { + int key = newChars[i]; + if ((key == '\n') && !mEdit.isMultiline()) { + // Return keys are handled through action events + continue; } + GodotLib.key(0, 0, key, true); + GodotLib.key(0, 0, key, false); } }); } @@ -139,23 +133,21 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene if (mEdit == pTextView && isFullScreenEdit()) { final String characters = pKeyEvent.getCharacters(); - mRenderView.queueOnRenderThread(new Runnable() { - @Override - public void run() { - for (int i = 0; i < characters.length(); i++) { - final int ch = characters.codePointAt(i); - GodotLib.key(0, 0, ch, true); - GodotLib.key(0, 0, ch, false); - } + mRenderView.queueOnRenderThread(() -> { + for (int i = 0; i < characters.length(); i++) { + final int ch = characters.codePointAt(i); + GodotLib.key(0, 0, ch, true); + GodotLib.key(0, 0, ch, false); } }); } if (pActionID == EditorInfo.IME_ACTION_DONE) { // Enter key has been pressed - GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true); - GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false); - + mRenderView.queueOnRenderThread(() -> { + GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true); + GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false); + }); mRenderView.getView().requestFocus(); return true; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java b/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java index 62810ad3a4..21fdc658bb 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerCompat.java @@ -28,14 +28,14 @@ public interface InputManagerCompat { * @param id The device id * @return The input device or null if not found */ - public InputDevice getInputDevice(int id); + InputDevice getInputDevice(int id); /** * Gets the ids of all input devices in the system. * * @return The input device ids. */ - public int[] getInputDeviceIds(); + int[] getInputDeviceIds(); /** * Registers an input device listener to receive notifications about when @@ -46,7 +46,7 @@ public interface InputManagerCompat { * null if the listener should be invoked on the calling thread's * looper. */ - public void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener, + void registerInputDeviceListener(InputManagerCompat.InputDeviceListener listener, Handler handler); /** @@ -54,7 +54,7 @@ public interface InputManagerCompat { * * @param listener The listener to unregister. */ - public void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener); + void unregisterInputDeviceListener(InputManagerCompat.InputDeviceListener listener); /* * The following three calls are to simulate V16 behavior on pre-Jellybean @@ -69,7 +69,7 @@ public interface InputManagerCompat { * * @param event the motion event from the app */ - public void onGenericMotionEvent(MotionEvent event); + void onGenericMotionEvent(MotionEvent event); /** * Tell the V9 input manager that it should stop polling for disconnected @@ -77,7 +77,7 @@ public interface InputManagerCompat { * might want to call it whenever your game is not active (or whenever you * don't care about being notified of new input devices) */ - public void onPause(); + void onPause(); /** * Tell the V9 input manager that it should start polling for disconnected @@ -85,9 +85,9 @@ public interface InputManagerCompat { * might want to call it less often (only when the gameplay is actually * active) */ - public void onResume(); + void onResume(); - public interface InputDeviceListener { + interface InputDeviceListener { /** * Called whenever the input manager detects that a device has been * added. This will only be called in the V9 version when a motion event @@ -119,7 +119,7 @@ public interface InputManagerCompat { /** * Use this to construct a compatible InputManager. */ - public static class Factory { + class Factory { /** * Constructs and returns a compatible InputManger * diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java b/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java index 61828dccae..0dbc13c77b 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java @@ -34,7 +34,7 @@ public class InputManagerV16 implements InputManagerCompat { public InputManagerV16(Context context) { mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE); - mListeners = new HashMap<InputManagerCompat.InputDeviceListener, V16InputDeviceListener>(); + mListeners = new HashMap<>(); } @Override diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java b/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java index 4b7318c718..bff90d7ce9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java @@ -41,12 +41,12 @@ import java.util.List; class Joystick { int device_id; String name; - List<Integer> axes = new ArrayList<Integer>(); + List<Integer> axes = new ArrayList<>(); protected boolean hasAxisHat = false; /* * Keep track of values so we can prevent flooding the engine with useless events. */ - protected final SparseArray axesValues = new SparseArray<Float>(4); + protected final SparseArray<Float> axesValues = new SparseArray<>(4); protected int hatX; protected int hatY; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java index 6c8a3d4219..2dc8359615 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java @@ -136,7 +136,7 @@ public abstract class GodotPlugin { nativeRegisterSingleton(pluginName, pluginObject); Set<Method> filteredMethods = new HashSet<>(); - Class clazz = pluginObject.getClass(); + Class<?> clazz = pluginObject.getClass(); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { @@ -157,8 +157,8 @@ public abstract class GodotPlugin { for (Method method : filteredMethods) { List<String> ptr = new ArrayList<>(); - Class[] paramTypes = method.getParameterTypes(); - for (Class c : paramTypes) { + Class<?>[] paramTypes = method.getParameterTypes(); + for (Class<?> c : paramTypes) { ptr.add(c.getName()); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/Crypt.java b/platform/android/java/lib/src/org/godotengine/godot/utils/Crypt.java index d6e49bb635..2b6e4ad2be 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/Crypt.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/Crypt.java @@ -39,10 +39,10 @@ public class Crypt { // Create MD5 Hash MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); digest.update(input.getBytes()); - byte messageDigest[] = digest.digest(); + byte[] messageDigest = digest.digest(); // Create Hex String - StringBuffer hexString = new StringBuffer(); + StringBuilder hexString = new StringBuilder(); for (int i = 0; i < messageDigest.length; i++) hexString.append(Integer.toHexString(0xFF & messageDigest[i])); return hexString.toString(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt index f0e37d80b8..b01dc2653a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt @@ -115,7 +115,7 @@ open internal class VkSurfaceView(context: Context) : SurfaceView(context), Surf /** * Tear down the rendering thread. * - * Must not be called before a [VkRenderer] has been set. + * Must not be called before a [VkRenderer] has been set. */ fun onDestroy() { vkThread.blockingExit() diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index 71610d2d00..c852e8759a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -30,7 +30,6 @@ package org.godotengine.godot.xr.regular; -import org.godotengine.godot.GodotLib; import org.godotengine.godot.utils.GLUtils; import android.opengl.GLSurfaceView; diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp index f49b0e843a..ed6b5c3e14 100644 --- a/platform/android/java_class_wrapper.cpp +++ b/platform/android/java_class_wrapper.cpp @@ -102,7 +102,7 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method, if (p_args[i]->get_type() != Variant::OBJECT) arg_expected = Variant::OBJECT; else { - Ref<Reference> ref = *p_args[i]; + Ref<RefCounted> ref = *p_args[i]; if (!ref.is_null()) { if (Object::cast_to<JavaObject>(ref.ptr())) { Ref<JavaObject> jo = ref; @@ -488,7 +488,7 @@ Variant JavaClass::call(const StringName &p_method, const Variant **p_args, int return ret; } - return Reference::call(p_method, p_args, p_argcount, r_error); + return RefCounted::call(p_method, p_args, p_argcount, r_error); } JavaClass::JavaClass() { diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index ec3b6f8ac0..5e99135498 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -49,6 +49,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc _open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I"); _get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;"); + _get_external_data_dir = p_env->GetMethodID(cls, "getExternalDataDir", "()Ljava/lang/String;"); _get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;"); _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;"); _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I"); @@ -92,6 +93,17 @@ String GodotIOJavaWrapper::get_user_data_dir() { } } +String GodotIOJavaWrapper::get_external_data_dir() { + if (_get_external_data_dir) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_COND_V(env == nullptr, String()); + jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_external_data_dir); + return jstring_to_string(s, env); + } else { + return String(); + } +} + String GodotIOJavaWrapper::get_locale() { if (_get_locale) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index 394e97effa..e4c0a4b2c7 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -47,6 +47,7 @@ private: jmethodID _open_URI = 0; jmethodID _get_data_dir = 0; + jmethodID _get_external_data_dir = 0; jmethodID _get_locale = 0; jmethodID _get_model = 0; jmethodID _get_screen_DPI = 0; @@ -66,6 +67,7 @@ public: Error open_uri(const String &p_uri); String get_user_data_dir(); + String get_external_data_dir(); String get_locale(); String get_model(); int get_screen_dpi(); diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index c7ff6cb2c0..4c66789a83 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -36,7 +36,6 @@ #include "android/asset_manager_jni.h" #include "api/java_class_wrapper.h" #include "api/jni_singleton.h" -#include "audio_driver_jandroid.h" #include "core/config/engine.h" #include "core/config/project_settings.h" #include "core/input/input.h" @@ -94,7 +93,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en FileAccessAndroid::asset_manager = AAssetManager_fromJava(env, amgr); DirAccessJAndroid::setup(godot_io_java->get_instance()); - AudioDriverAndroid::setup(godot_io_java->get_instance()); NetSocketAndroid::setup(godot_java->get_member_object("netUtils", "Lorg/godotengine/godot/utils/GodotNetUtils;", env)); os_android = new OS_Android(godot_java, godot_io_java, p_use_apk_expansion); @@ -326,15 +324,15 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, j int hat = 0; if (p_hat_x != 0) { if (p_hat_x < 0) - hat |= Input::HAT_MASK_LEFT; + hat |= HatMask::HAT_MASK_LEFT; else - hat |= Input::HAT_MASK_RIGHT; + hat |= HatMask::HAT_MASK_RIGHT; } if (p_hat_y != 0) { if (p_hat_y < 0) - hat |= Input::HAT_MASK_UP; + hat |= HatMask::HAT_MASK_UP; else - hat |= Input::HAT_MASK_DOWN; + hat |= HatMask::HAT_MASK_DOWN; } jevent.hat = hat; @@ -385,11 +383,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, os_android->main_loop_focusout(); } -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz) { - setup_android_thread(); - AudioDriverAndroid::thread_func(env); -} - JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path) { String js = jstring_to_string(path, env); diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index a3e2933185..63e9e6d8e5 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -56,7 +56,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyhat(JNIEnv *env, jclass clazz, jint p_device, jint p_hat_x, jint p_hat_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyconnectionchanged(JNIEnv *env, jclass clazz, jint p_device, jboolean p_connected, jstring p_name); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gravity(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnetometer(JNIEnv *env, jclass clazz, jfloat x, jfloat y, jfloat z); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 422814dd50..222976d948 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -45,6 +45,23 @@ #include "java_godot_io_wrapper.h" #include "java_godot_wrapper.h" +String _remove_symlink(const String &dir) { + // Workaround for Android 6.0+ using a symlink. + // Save the current directory. + char current_dir_name[2048]; + getcwd(current_dir_name, 2048); + // Change directory to the external data directory. + chdir(dir.utf8().get_data()); + // Get the actual directory without the potential symlink. + char dir_name_wihout_symlink[2048]; + getcwd(dir_name_wihout_symlink, 2048); + // Convert back to a String. + String dir_without_symlink(dir_name_wihout_symlink); + // Restore original current directory. + chdir(current_dir_name); + return dir_without_symlink; +} + class AndroidLogger : public Logger { public: virtual void logv(const char *p_format, va_list p_list, bool p_err) { @@ -199,26 +216,18 @@ String OS_Android::get_user_data_dir() const { String data_dir = godot_io_java->get_user_data_dir(); if (data_dir != "") { - //store current dir - char real_current_dir_name[2048]; - getcwd(real_current_dir_name, 2048); - - //go to data dir - chdir(data_dir.utf8().get_data()); - - //get actual data dir, so we resolve potential symlink (Android 6.0+ seems to use symlink) - char data_current_dir_name[2048]; - getcwd(data_current_dir_name, 2048); - - //cache by parsing utf8 - data_dir_cache.parse_utf8(data_current_dir_name); - - //restore original dir so we don't mess things up - chdir(real_current_dir_name); - + data_dir_cache = _remove_symlink(data_dir); return data_dir_cache; } + return "."; +} +String OS_Android::get_external_data_dir() const { + String data_dir = godot_io_java->get_external_data_dir(); + if (data_dir != "") { + data_dir = _remove_symlink(data_dir); + return data_dir; + } return "."; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index dd14b69cf9..1e89e9211d 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -31,7 +31,6 @@ #ifndef OS_ANDROID_H #define OS_ANDROID_H -#include "audio_driver_jandroid.h" #include "audio_driver_opensl.h" #include "core/os/main_loop.h" #include "drivers/unix/os_unix.h" @@ -59,7 +58,6 @@ private: mutable String data_dir_cache; - //AudioDriverAndroid audio_driver_android; AudioDriverOpenSL audio_driver_android; MainLoop *main_loop; @@ -111,6 +109,7 @@ public: virtual Error shell_open(String p_uri) override; virtual String get_user_data_dir() const override; + virtual String get_external_data_dir() const override; virtual String get_resource_dir() const override; virtual String get_locale() const override; virtual String get_model_name() const override; diff --git a/platform/android/plugin/godot_plugin_config.h b/platform/android/plugin/godot_plugin_config.h index 173ac115a2..6b708548ae 100644 --- a/platform/android/plugin/godot_plugin_config.h +++ b/platform/android/plugin/godot_plugin_config.h @@ -37,8 +37,8 @@ /* The `config` section and fields are required and defined as follow: -- **name**: name of the plugin -- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field +- **name**: name of the plugin. +- **binary_type**: can be either `local` or `remote`. The type affects the **binary** field. - **binary**: - if **binary_type** is `local`, then this should be the filename of the plugin `aar` file in the `res://android/plugins` directory (e.g: `MyPlugin.aar`). - if **binary_type** is `remote`, then this should be a declaration for a remote gradle binary (e.g: "org.godot.example:my-plugin:0.0.0"). @@ -102,7 +102,7 @@ struct PluginConfigAndroid { static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) { String absolute_path; if (!dependency_path.is_empty()) { - if (dependency_path.is_abs_path()) { + if (dependency_path.is_absolute_path()) { absolute_path = ProjectSettings::get_singleton()->globalize_path(dependency_path); } else { absolute_path = plugin_config_dir.plus_file(dependency_path); diff --git a/platform/android/plugin/godot_plugin_jni.cpp b/platform/android/plugin/godot_plugin_jni.cpp index ba3e9fa20f..cf0c02e2bf 100644 --- a/platform/android/plugin/godot_plugin_jni.cpp +++ b/platform/android/plugin/godot_plugin_jni.cpp @@ -43,7 +43,7 @@ extern "C" { JNIEXPORT void JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeRegisterSingleton(JNIEnv *env, jclass clazz, jstring name, jobject obj) { String singname = jstring_to_string(name, env); - JNISingleton *s = (JNISingleton *)ClassDB::instance("JNISingleton"); + JNISingleton *s = (JNISingleton *)ClassDB::instantiate("JNISingleton"); s->set_instance(env->NewGlobalRef(obj)); jni_singletons[singname] = s; diff --git a/platform/android/vulkan/vulkan_context_android.cpp b/platform/android/vulkan/vulkan_context_android.cpp index 63f2026fae..a031f3beee 100644 --- a/platform/android/vulkan/vulkan_context_android.cpp +++ b/platform/android/vulkan/vulkan_context_android.cpp @@ -36,7 +36,7 @@ const char *VulkanContextAndroid::_get_platform_surface_extension() const { return VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; } -int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, int p_height) { +int VulkanContextAndroid::window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height) { VkAndroidSurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; @@ -49,7 +49,7 @@ int VulkanContextAndroid::window_create(ANativeWindow *p_window, int p_width, in ERR_FAIL_V_MSG(-1, "vkCreateAndroidSurfaceKHR failed with error " + itos(err)); } - return _window_create(DisplayServer::MAIN_WINDOW_ID, surface, p_width, p_height); + return _window_create(DisplayServer::MAIN_WINDOW_ID, p_vsync_mode, surface, p_width, p_height); } bool VulkanContextAndroid::_use_validation_layers() { diff --git a/platform/android/vulkan/vulkan_context_android.h b/platform/android/vulkan/vulkan_context_android.h index 5a84eaf8f3..182ce33c97 100644 --- a/platform/android/vulkan/vulkan_context_android.h +++ b/platform/android/vulkan/vulkan_context_android.h @@ -39,7 +39,7 @@ class VulkanContextAndroid : public VulkanContext { virtual const char *_get_platform_surface_extension() const override; public: - int window_create(ANativeWindow *p_window, int p_width, int p_height); + int window_create(ANativeWindow *p_window, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height); VulkanContextAndroid() = default; ~VulkanContextAndroid() override = default; diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h index 34c56382a4..6f64130b23 100644 --- a/platform/iphone/display_server_iphone.h +++ b/platform/iphone/display_server_iphone.h @@ -67,7 +67,7 @@ class DisplayServerIPhone : public DisplayServer { void perform_event(const Ref<InputEvent> &p_event); - DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); ~DisplayServerIPhone(); public: @@ -76,7 +76,7 @@ public: static DisplayServerIPhone *get_singleton(); static void register_iphone_driver(); - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); // MARK: - Events @@ -176,6 +176,9 @@ public: virtual bool can_any_window_draw() const override; + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual bool screen_is_touchscreen(int p_screen) const override; virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect, bool p_multiline, int p_max_length, int p_cursor_start, int p_cursor_end) override; diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index 9e74de0842..bd95e2c703 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -48,7 +48,7 @@ DisplayServerIPhone *DisplayServerIPhone::get_singleton() { return (DisplayServerIPhone *)DisplayServer::get_singleton(); } -DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; #if defined(OPENGL_ENABLED) @@ -108,7 +108,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Displ } Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale(); - if (context_vulkan->window_create(MAIN_WINDOW_ID, layer, size.width, size.height) != OK) { + if (context_vulkan->window_create(MAIN_WINDOW_ID, p_vsync_mode, layer, size.width, size.height) != OK) { memdelete(context_vulkan); context_vulkan = nullptr; ERR_FAIL_MSG("Failed to create Vulkan window."); @@ -147,8 +147,8 @@ DisplayServerIPhone::~DisplayServerIPhone() { #endif } -DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerIPhone::create_func(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + return memnew(DisplayServerIPhone(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); } Vector<String> DisplayServerIPhone::get_rendering_drivers_func() { @@ -224,7 +224,7 @@ void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Var void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) { if (!GLOBAL_DEF("debug/disable_touch", false)) { Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); ev->set_index(p_idx); ev->set_pressed(p_pressed); @@ -236,7 +236,7 @@ void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_presse void DisplayServerIPhone::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y) { if (!GLOBAL_DEF("debug/disable_touch", false)) { Ref<InputEventScreenDrag> ev; - ev.instance(); + ev.instantiate(); ev->set_index(p_idx); ev->set_position(Vector2(p_x, p_y)); ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y)); @@ -256,7 +256,7 @@ void DisplayServerIPhone::touches_cancelled(int p_idx) { void DisplayServerIPhone::key(uint32_t p_key, bool p_pressed) { Ref<InputEventKey> ev; - ev.instance(); + ev.instantiate(); ev->set_echo(false); ev->set_pressed(p_pressed); ev->set_keycode(p_key); @@ -581,3 +581,19 @@ void DisplayServerIPhone::resize_window(CGSize viewSize) { Variant resize_rect = Rect2i(Point2i(), size); _window_callback(window_resize_callback, resize_rect); } + +void DisplayServerIPhone::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); +#endif +} + +DisplayServer::VSyncMode DisplayServerIPhone::window_get_vsync_mode(WindowID p_window) const { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + return context_vulkan->get_vsync_mode(p_window); +#else + return DisplayServer::VSYNC_ENABLED; +#endif +} diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 73723b98a0..1d1961ac2f 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -31,11 +31,11 @@ #include "export.h" #include "core/config/project_settings.h" +#include "core/io/file_access.h" #include "core/io/image_loader.h" #include "core/io/marshalls.h" #include "core/io/resource_saver.h" #include "core/io/zip_io.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/templates/safe_refcount.h" #include "core/version.h" @@ -367,6 +367,26 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) for (int i = 0; i < found_plugins.size(); i++) { r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false)); } + + for (int i = 0; i < found_plugins.size(); i++) { + // Editable plugin plist values + PluginConfigIOS plugin = found_plugins[i]; + const String *K = nullptr; + + while ((K = plugin.plist.next(K))) { + String key = *K; + PluginConfigIOS::PlistItem item = plugin.plist[key]; + switch (item.type) { + case PluginConfigIOS::PlistItemType::STRING_INPUT: { + String preset_name = "plugins_plist/" + key; + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, preset_name), item.value)); + } break; + default: + continue; + } + } + } + plugins_changed.clear(); plugins = found_plugins; @@ -820,7 +840,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) { Ref<Image> image; String image_path = p_dest_dir.plus_file("splash@2x.png"); - image.instance(); + image.instantiate(); Error err = image->load(custom_launch_image_2x); if (err) { @@ -834,7 +854,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor image.unref(); image_path = p_dest_dir.plus_file("splash@3x.png"); - image.instance(); + image.instantiate(); err = image->load(custom_launch_image_3x); if (err) { @@ -851,7 +871,7 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); if (!splash_path.is_empty()) { - splash.instance(); + splash.instantiate(); const Error err = splash->load(splash_path); if (err) { splash.unref(); @@ -1467,13 +1487,28 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> while ((K = plugin.plist.next(K))) { String key = *K; - String value = plugin.plist[key]; + PluginConfigIOS::PlistItem item = plugin.plist[key]; + + String value; + + switch (item.type) { + case PluginConfigIOS::PlistItemType::STRING_INPUT: { + String preset_name = "plugins_plist/" + key; + String input_value = p_preset->get(preset_name); + value = "<string>" + input_value + "</string>"; + } break; + default: + value = item.value; + break; + } if (key.is_empty() || value.is_empty()) { continue; } - plist_values[key] = value; + String plist_key = "<key>" + key + "</key>"; + + plist_values[plist_key] = value; } // CPP Code @@ -1500,7 +1535,7 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> continue; } - p_config_data.plist_content += "<key>" + key + "</key><string>" + value + "</string>\n"; + p_config_data.plist_content += key + value + "\n"; } } @@ -1999,7 +2034,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset EditorExportPlatformIOS::EditorExportPlatformIOS() { Ref<Image> img = memnew(Image(_iphone_logo)); - logo.instance(); + logo.instantiate(); logo->create_from_image(img); plugins_changed.set(); @@ -2014,7 +2049,7 @@ EditorExportPlatformIOS::~EditorExportPlatformIOS() { void register_iphone_exporter() { Ref<EditorExportPlatformIOS> platform; - platform.instance(); + platform.instantiate(); EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index 458834ce3a..1f08901082 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -33,9 +33,9 @@ #include "os_iphone.h" #import "app_delegate.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/file_access_pack.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "display_server_iphone.h" #include "drivers/unix/syslog_logger.h" #import "godot_view.h" diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/plugin/godot_plugin_config.h index e2546e733c..06770260aa 100644 --- a/platform/iphone/plugin/godot_plugin_config.h +++ b/platform/iphone/plugin/godot_plugin_config.h @@ -70,6 +70,20 @@ struct PluginConfigIOS { inline static const char *PLIST_SECTION = "plist"; + enum PlistItemType { + UNKNOWN, + STRING, + INTEGER, + BOOLEAN, + RAW, + STRING_INPUT, + }; + + struct PlistItem { + PlistItemType type; + String value; + }; + // Set to true when the config file is properly loaded. bool valid_config = false; bool supports_targets = false; @@ -93,8 +107,10 @@ struct PluginConfigIOS { Vector<String> linker_flags; // Optional plist section - // Supports only string types for now - HashMap<String, String> plist; + // String value is default value. + // Currently supports `string`, `boolean`, `integer`, `raw`, `string_input` types + // <name>:<type> = <value> + HashMap<String, PlistItem> plist; }; static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) { @@ -104,7 +120,7 @@ static inline String resolve_local_dependency_path(String plugin_config_dir, Str return absolute_path; } - if (dependency_path.is_abs_path()) { + if (dependency_path.is_absolute_path()) { return dependency_path; } @@ -121,7 +137,7 @@ static inline String resolve_system_dependency_path(String dependency_path) { return absolute_path; } - if (dependency_path.is_abs_path()) { + if (dependency_path.is_absolute_path()) { return dependency_path; } @@ -273,13 +289,68 @@ static inline PluginConfigIOS load_plugin_config(Ref<ConfigFile> config_file, co config_file->get_section_keys(PluginConfigIOS::PLIST_SECTION, &keys); for (int i = 0; i < keys.size(); i++) { - String value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, keys[i], String()); + Vector<String> key_components = keys[i].split(":"); + + String key_value = ""; + PluginConfigIOS::PlistItemType key_type = PluginConfigIOS::PlistItemType::UNKNOWN; + + if (key_components.size() == 1) { + key_value = key_components[0]; + key_type = PluginConfigIOS::PlistItemType::STRING; + } else if (key_components.size() == 2) { + key_value = key_components[0]; + + if (key_components[1].to_lower() == "string") { + key_type = PluginConfigIOS::PlistItemType::STRING; + } else if (key_components[1].to_lower() == "integer") { + key_type = PluginConfigIOS::PlistItemType::INTEGER; + } else if (key_components[1].to_lower() == "boolean") { + key_type = PluginConfigIOS::PlistItemType::BOOLEAN; + } else if (key_components[1].to_lower() == "raw") { + key_type = PluginConfigIOS::PlistItemType::RAW; + } else if (key_components[1].to_lower() == "string_input") { + key_type = PluginConfigIOS::PlistItemType::STRING_INPUT; + } + } - if (value.is_empty()) { + if (key_value.is_empty() || key_type == PluginConfigIOS::PlistItemType::UNKNOWN) { continue; } - plugin_config.plist[keys[i]] = value; + String value; + + switch (key_type) { + case PluginConfigIOS::PlistItemType::STRING: { + String raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, keys[i], String()); + value = "<string>" + raw_value + "</string>"; + } break; + case PluginConfigIOS::PlistItemType::INTEGER: { + int raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, keys[i], 0); + Dictionary value_dictionary; + String value_format = "<integer>$value</integer>"; + value_dictionary["value"] = raw_value; + value = value_format.format(value_dictionary, "$_"); + } break; + case PluginConfigIOS::PlistItemType::BOOLEAN: + if (config_file->get_value(PluginConfigIOS::PLIST_SECTION, keys[i], false)) { + value = "<true/>"; + } else { + value = "<false/>"; + } + break; + case PluginConfigIOS::PlistItemType::RAW: { + String raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, keys[i], String()); + value = raw_value; + } break; + case PluginConfigIOS::PlistItemType::STRING_INPUT: { + String raw_value = config_file->get_value(PluginConfigIOS::PLIST_SECTION, keys[i], String()); + value = raw_value; + } break; + default: + continue; + } + + plugin_config.plist[key_value] = PluginConfigIOS::PlistItem{ key_type, value }; } } diff --git a/platform/iphone/vulkan_context_iphone.h b/platform/iphone/vulkan_context_iphone.h index 88764e270e..ec6aaf46e8 100644 --- a/platform/iphone/vulkan_context_iphone.h +++ b/platform/iphone/vulkan_context_iphone.h @@ -39,7 +39,7 @@ class VulkanContextIPhone : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - Error window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height); VulkanContextIPhone(); ~VulkanContextIPhone(); diff --git a/platform/iphone/vulkan_context_iphone.mm b/platform/iphone/vulkan_context_iphone.mm index 08c9007fbb..17f2b167b3 100644 --- a/platform/iphone/vulkan_context_iphone.mm +++ b/platform/iphone/vulkan_context_iphone.mm @@ -35,7 +35,7 @@ const char *VulkanContextIPhone::_get_platform_surface_extension() const { return VK_MVK_IOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CALayer *p_metal_layer, int p_width, int p_height) { +Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, CALayer *p_metal_layer, int p_width, int p_height) { VkIOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = nullptr; @@ -47,7 +47,7 @@ Error VulkanContextIPhone::window_create(DisplayServer::WindowID p_window_id, CA vkCreateIOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - return _window_create(p_window_id, surface, p_width, p_height); + return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } VulkanContextIPhone::VulkanContextIPhone() {} diff --git a/platform/javascript/api/javascript_singleton.h b/platform/javascript/api/javascript_singleton.h index 1615efa87e..9d7a392278 100644 --- a/platform/javascript/api/javascript_singleton.h +++ b/platform/javascript/api/javascript_singleton.h @@ -32,11 +32,11 @@ #define JAVASCRIPT_SINGLETON_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" -class JavaScriptObject : public Reference { +class JavaScriptObject : public RefCounted { private: - GDCLASS(JavaScriptObject, Reference); + GDCLASS(JavaScriptObject, RefCounted); protected: virtual bool _set(const StringName &p_name, const Variant &p_value) { return false; } diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp index b35ccd087f..54f541f607 100644 --- a/platform/javascript/api/javascript_tools_editor_plugin.cpp +++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp @@ -33,15 +33,15 @@ #include "core/config/engine.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "editor/editor_node.h" #include <emscripten/emscripten.h> // JavaScript functions defined in library_godot_editor_tools.js extern "C" { -extern int godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime); +extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime); } static void _javascript_editor_init_callback() { diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index 1cc05a2e19..f1b92264e2 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -128,7 +128,7 @@ void DisplayServerJavaScript::dom2godot_mod(T *emscripten_event_ptr, Ref<InputEv Ref<InputEventKey> DisplayServerJavaScript::setup_key_event(const EmscriptenKeyboardEvent *emscripten_event) { Ref<InputEventKey> ev; - ev.instance(); + ev.instantiate(); ev->set_echo(emscripten_event->repeat); dom2godot_mod(emscripten_event, ev); ev->set_keycode(dom_code2godot_scancode(emscripten_event->code, emscripten_event->key, false)); @@ -181,7 +181,7 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E DisplayServerJavaScript *display = get_singleton(); Ref<InputEventMouseButton> ev; - ev.instance(); + ev.instantiate(); ev->set_pressed(p_event_type == EMSCRIPTEN_EVENT_MOUSEDOWN); ev->set_position(compute_position_in_canvas(p_event->clientX, p_event->clientY)); ev->set_global_position(ev->get_position()); @@ -229,8 +229,8 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E } Input *input = Input::get_singleton(); - int mask = input->get_mouse_button_mask(); - int button_flag = 1 << (ev->get_button_index() - 1); + MouseButton mask = input->get_mouse_button_mask(); + MouseButton button_flag = MouseButton(1 << (ev->get_button_index() - 1)); if (ev->is_pressed()) { // Since the event is consumed, focus manually. The containing iframe, // if exists, may not have focus yet, so focus even if already focused. @@ -261,7 +261,7 @@ EM_BOOL DisplayServerJavaScript::mousemove_callback(int p_event_type, const Emsc return false; Ref<InputEventMouseMotion> ev; - ev.instance(); + ev.instantiate(); dom2godot_mod(p_event, ev); ev->set_button_mask(input_mask); @@ -452,7 +452,7 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript Input *input = Input::get_singleton(); Ref<InputEventMouseButton> ev; - ev.instance(); + ev.instantiate(); ev->set_position(input->get_mouse_position()); ev->set_global_position(ev->get_position()); @@ -478,11 +478,11 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript int button_flag = 1 << (ev->get_button_index() - 1); ev->set_pressed(true); - ev->set_button_mask(input->get_mouse_button_mask() | button_flag); + ev->set_button_mask(MouseButton(input->get_mouse_button_mask() | button_flag)); input->parse_input_event(ev); ev->set_pressed(false); - ev->set_button_mask(input->get_mouse_button_mask() & ~button_flag); + ev->set_button_mask(MouseButton(input->get_mouse_button_mask() & ~button_flag)); input->parse_input_event(ev); return true; @@ -492,7 +492,7 @@ EM_BOOL DisplayServerJavaScript::wheel_callback(int p_event_type, const Emscript EM_BOOL DisplayServerJavaScript::touch_press_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) { DisplayServerJavaScript *display = get_singleton(); Ref<InputEventScreenTouch> ev; - ev.instance(); + ev.instantiate(); int lowest_id_index = -1; for (int i = 0; i < p_event->numTouches; ++i) { const EmscriptenTouchPoint &touch = p_event->touches[i]; @@ -514,7 +514,7 @@ EM_BOOL DisplayServerJavaScript::touch_press_callback(int p_event_type, const Em EM_BOOL DisplayServerJavaScript::touchmove_callback(int p_event_type, const EmscriptenTouchEvent *p_event, void *p_user_data) { DisplayServerJavaScript *display = get_singleton(); Ref<InputEventScreenDrag> ev; - ev.instance(); + ev.instantiate(); int lowest_id_index = -1; for (int i = 0; i < p_event->numTouches; ++i) { const EmscriptenTouchPoint &touch = p_event->touches[i]; @@ -553,12 +553,12 @@ void DisplayServerJavaScript::vk_input_text_callback(const char *p_text, int p_c Input *input = Input::get_singleton(); Ref<InputEventKey> k; for (int i = 0; i < p_cursor; i++) { - k.instance(); + k.instantiate(); k->set_pressed(true); k->set_echo(false); k->set_keycode(KEY_RIGHT); input->parse_input_event(k); - k.instance(); + k.instantiate(); k->set_pressed(false); k->set_echo(false); k->set_keycode(KEY_RIGHT); diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 8ce294f31b..bf4244eda4 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -29,7 +29,6 @@ /*************************************************************************/ #include "core/io/image_loader.h" -#include "core/io/json.h" #include "core/io/stream_peer_ssl.h" #include "core/io/tcp_server.h" #include "core/io/zip_io.h" @@ -39,7 +38,7 @@ #include "platform/javascript/logo.gen.h" #include "platform/javascript/run_icon.gen.h" -class EditorHTTPServer : public Reference { +class EditorHTTPServer : public RefCounted { private: Ref<TCPServer> server; Map<String, String> mimes; @@ -91,7 +90,7 @@ public: mimes["png"] = "image/png"; mimes["svg"] = "image/svg"; mimes["wasm"] = "application/wasm"; - server.instance(); + server.instantiate(); stop(); } @@ -136,8 +135,11 @@ public: // Wrong protocol ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version."); - const String req_file = req[1].get_file(); - const String req_ext = req[1].get_extension(); + const int query_index = req[1].find_char('?'); + const String path = (query_index == -1) ? req[1] : req[1].substr(0, query_index); + + const String req_file = path.get_file(); + const String req_ext = path.get_extension(); const String cache_path = EditorPaths::get_singleton()->get_cache_dir().plus_file("web"); const String filepath = cache_path.plus_file(req_file); @@ -290,7 +292,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { Ref<Image> _get_project_icon() const { Ref<Image> icon; - icon.instance(); + icon.instantiate(); const String icon_path = String(GLOBAL_GET("application/config/icon")).strip_edges(); if (icon_path.is_empty() || ImageLoader::load_image(icon_path, icon) != OK) { return EditorNode::get_singleton()->get_editor_theme()->get_icon("DefaultProjectIcon", "EditorIcons")->get_image(); @@ -300,7 +302,7 @@ class EditorExportPlatformJavaScript : public EditorExportPlatform { Ref<Image> _get_project_splash() const { Ref<Image> splash; - splash.instance(); + splash.instantiate(); const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges(); if (splash_path.is_empty() || ImageLoader::load_image(splash_path, splash) != OK) { return Ref<Image>(memnew(Image(boot_splash_png))); @@ -448,6 +450,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re } config["canvasResizePolicy"] = p_preset->get("html/canvas_resize_policy"); config["experimentalVK"] = p_preset->get("html/experimental_virtual_keyboard"); + config["focusCanvas"] = p_preset->get("html/focus_canvas_on_start"); config["gdnativeLibs"] = libs; config["executable"] = p_name; config["args"] = args; @@ -465,7 +468,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re } // Replaces HTML string - const String str_config = JSON::print(config); + const String str_config = Variant(config).to_json_string(); const String custom_head_include = p_preset->get("html/head_include"); Map<String, String> replaces; replaces["$GODOT_URL"] = p_name + ".js"; @@ -482,7 +485,7 @@ Error EditorExportPlatformJavaScript::_add_manifest_icon(const String &p_path, c Ref<Image> icon; if (!p_icon.is_empty()) { - icon.instance(); + icon.instantiate(); const Error err = ImageLoader::load_image(p_icon, icon); if (err != OK) { EditorNode::get_singleton()->show_warning(TTR("Could not read file:") + "\n" + p_icon); @@ -518,7 +521,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & replaces["@GODOT_NAME@"] = name; replaces["@GODOT_OFFLINE_PAGE@"] = name + ".offline.html"; Array files; - replaces["@GODOT_OPT_CACHE@"] = JSON::print(files); + replaces["@GODOT_OPT_CACHE@"] = Variant(files).to_json_string(); files.push_back(name + ".html"); files.push_back(name + ".js"); files.push_back(name + ".wasm"); @@ -537,7 +540,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & files.push_back(p_shared_objects[i].path.get_file()); } } - replaces["@GODOT_CACHE@"] = JSON::print(files); + replaces["@GODOT_CACHE@"] = Variant(files).to_json_string(); const String sw_path = dir.plus_file(name + ".service.worker.js"); Vector<uint8_t> sw; @@ -605,7 +608,7 @@ Error EditorExportPlatformJavaScript::_build_pwa(const Ref<EditorExportPreset> & } manifest["icons"] = icons_arr; - CharString cs = JSON::print(manifest).utf8(); + CharString cs = Variant(manifest).to_json_string().utf8(); err = _write_or_error((const uint8_t *)cs.get_data(), cs.length(), dir.plus_file(name + ".manifest.json")); if (err != OK) { return err; @@ -648,6 +651,7 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "html/canvas_resize_policy", PROPERTY_HINT_ENUM, "None,Project,Adaptive"), 2)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/focus_canvas_on_start"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/experimental_virtual_keyboard"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "progressive_web_app/enabled"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "progressive_web_app/offline_page", PROPERTY_HINT_FILE, "*.html"), "")); @@ -965,22 +969,22 @@ void EditorExportPlatformJavaScript::_server_thread_poll(void *data) { } EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { - server.instance(); + server.instantiate(); server_thread.start(_server_thread_poll, this); Ref<Image> img = memnew(Image(_javascript_logo)); - logo.instance(); + logo.instantiate(); logo->create_from_image(img); img = Ref<Image>(memnew(Image(_javascript_run_icon))); - run_icon.instance(); + run_icon.instantiate(); run_icon->create_from_image(img); Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); if (theme.is_valid()) { stop_icon = theme->get_icon("Stop", "EditorIcons"); } else { - stop_icon.instance(); + stop_icon.instantiate(); } } @@ -1001,6 +1005,6 @@ void register_javascript_exporter() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/web/ssl_certificate", PROPERTY_HINT_GLOBAL_FILE, "*.crt,*.pem")); Ref<EditorExportPlatformJavaScript> platform; - platform.instance(); + platform.instantiate(); EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/javascript/godot_js.h b/platform/javascript/godot_js.h index 8927a83cb3..d332af2c31 100644 --- a/platform/javascript/godot_js.h +++ b/platform/javascript/godot_js.h @@ -84,7 +84,7 @@ extern void godot_js_display_cursor_set_custom_shape(const char *p_shape, const extern void godot_js_display_cursor_set_visible(int p_visible); // Display gamepad -extern char *godot_js_display_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid)); +extern void godot_js_display_gamepad_cb(void (*p_on_change)(int p_index, int p_connected, const char *p_id, const char *p_guid)); extern int godot_js_display_gamepad_sample(); extern int godot_js_display_gamepad_sample_count(); extern int godot_js_display_gamepad_sample_get(int p_idx, float r_btns[16], int32_t *r_btns_num, float r_axes[10], int32_t *r_axes_num, int32_t *r_standard); diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc deleted file mode 100644 index 6544d41c98..0000000000 --- a/platform/javascript/http_client.h.inc +++ /dev/null @@ -1,51 +0,0 @@ -/*************************************************************************/ -/* http_client.h.inc */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -// HTTPClient's additional private members in the javascript platform - -Error make_request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len); -static void _parse_headers(int p_len, const char **p_headers, void *p_ref); - -int js_id = 0; -// 64 KiB by default (favors fast download speeds at the cost of memory usage). -int read_limit = 65536; -Status status = STATUS_DISCONNECTED; - -String host; -int port = -1; -bool use_tls = false; - -int polled_response_code = 0; -Vector<String> response_headers; -Vector<uint8_t> response_buffer; - -#ifdef DEBUG_ENABLED -uint64_t last_polling_frame = 0; -#endif diff --git a/platform/javascript/http_client_javascript.cpp b/platform/javascript/http_client_javascript.cpp index a6cf4b0eb8..f7d78abcea 100644 --- a/platform/javascript/http_client_javascript.cpp +++ b/platform/javascript/http_client_javascript.cpp @@ -28,45 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/io/http_client.h" +#include "http_client_javascript.h" -#ifdef __cplusplus -extern "C" { -#endif - -#include "stddef.h" - -typedef enum { - GODOT_JS_FETCH_STATE_REQUESTING = 0, - GODOT_JS_FETCH_STATE_BODY = 1, - GODOT_JS_FETCH_STATE_DONE = 2, - GODOT_JS_FETCH_STATE_ERROR = -1, -} godot_js_fetch_state_t; - -extern int godot_js_fetch_create(const char *p_method, const char *p_url, const char **p_headers, int p_headers_len, const uint8_t *p_body, int p_body_len); -extern int godot_js_fetch_read_headers(int p_id, void (*parse_callback)(int p_size, const char **p_headers, void *p_ref), void *p_ref); -extern int godot_js_fetch_read_chunk(int p_id, uint8_t *p_buf, int p_buf_size); -extern void godot_js_fetch_free(int p_id); -extern godot_js_fetch_state_t godot_js_fetch_state_get(int p_id); -extern int godot_js_fetch_body_length_get(int p_id); -extern int godot_js_fetch_http_status_get(int p_id); -extern int godot_js_fetch_is_chunked(int p_id); - -#ifdef __cplusplus -} -#endif - -void HTTPClient::_parse_headers(int p_len, const char **p_headers, void *p_ref) { - HTTPClient *client = static_cast<HTTPClient *>(p_ref); +void HTTPClientJavaScript::_parse_headers(int p_len, const char **p_headers, void *p_ref) { + HTTPClientJavaScript *client = static_cast<HTTPClientJavaScript *>(p_ref); for (int i = 0; i < p_len; i++) { client->response_headers.push_back(String::utf8(p_headers[i])); } } -Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { +Error HTTPClientJavaScript::connect_to_host(const String &p_host, int p_port, bool p_ssl, bool p_verify_host) { close(); if (p_ssl && !p_verify_host) { - WARN_PRINT("Disabling HTTPClient's host verification is not supported for the HTML5 platform, host will be verified"); + WARN_PRINT("Disabling HTTPClientJavaScript's host verification is not supported for the HTML5 platform, host will be verified"); } port = p_port; @@ -97,15 +71,15 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl, return OK; } -void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) { - ERR_FAIL_MSG("Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform."); +void HTTPClientJavaScript::set_connection(const Ref<StreamPeer> &p_connection) { + ERR_FAIL_MSG("Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform."); } -Ref<StreamPeer> HTTPClient::get_connection() const { - ERR_FAIL_V_MSG(REF(), "Accessing an HTTPClient's StreamPeer is not supported for the HTML5 platform."); +Ref<StreamPeer> HTTPClientJavaScript::get_connection() const { + ERR_FAIL_V_MSG(REF(), "Accessing an HTTPClientJavaScript's StreamPeer is not supported for the HTML5 platform."); } -Error HTTPClient::make_request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) { +Error HTTPClientJavaScript::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_len) { ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER); ERR_FAIL_COND_V_MSG(p_method == METHOD_TRACE || p_method == METHOD_CONNECT, ERR_UNAVAILABLE, "HTTP methods TRACE and CONNECT are not supported for the HTML5 platform."); ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER); @@ -128,22 +102,7 @@ Error HTTPClient::make_request(Method p_method, const String &p_url, const Vecto return OK; } -Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) { - if (p_body.is_empty()) { - return make_request(p_method, p_url, p_headers, nullptr, 0); - } - return make_request(p_method, p_url, p_headers, p_body.ptr(), p_body.size()); -} - -Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) { - if (p_body.is_empty()) { - return make_request(p_method, p_url, p_headers, nullptr, 0); - } - const CharString cs = p_body.utf8(); - return make_request(p_method, p_url, p_headers, (const uint8_t *)cs.get_data(), cs.size() - 1); -} - -void HTTPClient::close() { +void HTTPClientJavaScript::close() { host = ""; port = -1; use_tls = false; @@ -157,23 +116,23 @@ void HTTPClient::close() { } } -HTTPClient::Status HTTPClient::get_status() const { +HTTPClientJavaScript::Status HTTPClientJavaScript::get_status() const { return status; } -bool HTTPClient::has_response() const { +bool HTTPClientJavaScript::has_response() const { return response_headers.size() > 0; } -bool HTTPClient::is_response_chunked() const { +bool HTTPClientJavaScript::is_response_chunked() const { return godot_js_fetch_is_chunked(js_id); } -int HTTPClient::get_response_code() const { +int HTTPClientJavaScript::get_response_code() const { return polled_response_code; } -Error HTTPClient::get_response_headers(List<String> *r_response) { +Error HTTPClientJavaScript::get_response_headers(List<String> *r_response) { if (!response_headers.size()) { return ERR_INVALID_PARAMETER; } @@ -184,11 +143,11 @@ Error HTTPClient::get_response_headers(List<String> *r_response) { return OK; } -int HTTPClient::get_response_body_length() const { +int HTTPClientJavaScript::get_response_body_length() const { return godot_js_fetch_body_length_get(js_id); } -PackedByteArray HTTPClient::read_response_body_chunk() { +PackedByteArray HTTPClientJavaScript::read_response_body_chunk() { ERR_FAIL_COND_V(status != STATUS_BODY, PackedByteArray()); if (response_buffer.size() != read_limit) { @@ -213,23 +172,23 @@ PackedByteArray HTTPClient::read_response_body_chunk() { return chunk; } -void HTTPClient::set_blocking_mode(bool p_enable) { - ERR_FAIL_COND_MSG(p_enable, "HTTPClient blocking mode is not supported for the HTML5 platform."); +void HTTPClientJavaScript::set_blocking_mode(bool p_enable) { + ERR_FAIL_COND_MSG(p_enable, "HTTPClientJavaScript blocking mode is not supported for the HTML5 platform."); } -bool HTTPClient::is_blocking_mode_enabled() const { +bool HTTPClientJavaScript::is_blocking_mode_enabled() const { return false; } -void HTTPClient::set_read_chunk_size(int p_size) { +void HTTPClientJavaScript::set_read_chunk_size(int p_size) { read_limit = p_size; } -int HTTPClient::get_read_chunk_size() const { +int HTTPClientJavaScript::get_read_chunk_size() const { return read_limit; } -Error HTTPClient::poll() { +Error HTTPClientJavaScript::poll() { switch (status) { case STATUS_DISCONNECTED: return ERR_UNCONFIGURED; @@ -263,7 +222,7 @@ Error HTTPClient::poll() { #ifdef DEBUG_ENABLED // forcing synchronous requests is not possible on the web if (last_polling_frame == Engine::get_singleton()->get_process_frames()) { - WARN_PRINT("HTTPClient polled multiple times in one frame, " + WARN_PRINT("HTTPClientJavaScript polled multiple times in one frame, " "but request cannot progress more than once per " "frame on the HTML5 platform."); } @@ -294,9 +253,15 @@ Error HTTPClient::poll() { return OK; } -HTTPClient::HTTPClient() { +HTTPClient *HTTPClientJavaScript::_create_func() { + return memnew(HTTPClientJavaScript); +} + +HTTPClient *(*HTTPClient::_create)() = HTTPClientJavaScript::_create_func; + +HTTPClientJavaScript::HTTPClientJavaScript() { } -HTTPClient::~HTTPClient() { +HTTPClientJavaScript::~HTTPClientJavaScript() { close(); } diff --git a/platform/javascript/http_client_javascript.h b/platform/javascript/http_client_javascript.h new file mode 100644 index 0000000000..33f91f67b6 --- /dev/null +++ b/platform/javascript/http_client_javascript.h @@ -0,0 +1,108 @@ +/*************************************************************************/ +/* http_client_javascript.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef HTTP_CLIENT_JAVASCRIPT_H +#define HTTP_CLIENT_JAVASCRIPT_H + +#include "core/io/http_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stddef.h" + +typedef enum { + GODOT_JS_FETCH_STATE_REQUESTING = 0, + GODOT_JS_FETCH_STATE_BODY = 1, + GODOT_JS_FETCH_STATE_DONE = 2, + GODOT_JS_FETCH_STATE_ERROR = -1, +} godot_js_fetch_state_t; + +extern int godot_js_fetch_create(const char *p_method, const char *p_url, const char **p_headers, int p_headers_len, const uint8_t *p_body, int p_body_len); +extern int godot_js_fetch_read_headers(int p_id, void (*parse_callback)(int p_size, const char **p_headers, void *p_ref), void *p_ref); +extern int godot_js_fetch_read_chunk(int p_id, uint8_t *p_buf, int p_buf_size); +extern void godot_js_fetch_free(int p_id); +extern godot_js_fetch_state_t godot_js_fetch_state_get(int p_id); +extern int godot_js_fetch_body_length_get(int p_id); +extern int godot_js_fetch_http_status_get(int p_id); +extern int godot_js_fetch_is_chunked(int p_id); + +#ifdef __cplusplus +} +#endif + +class HTTPClientJavaScript : public HTTPClient { +private: + int js_id = 0; + Status status = STATUS_DISCONNECTED; + + // 64 KiB by default (favors fast download speeds at the cost of memory usage). + int read_limit = 65536; + + String host; + int port = -1; + bool use_tls = false; + + int polled_response_code = 0; + Vector<String> response_headers; + Vector<uint8_t> response_buffer; + +#ifdef DEBUG_ENABLED + uint64_t last_polling_frame = 0; +#endif + + static void _parse_headers(int p_len, const char **p_headers, void *p_ref); + +public: + static HTTPClient *_create_func(); + + Error request(Method p_method, const String &p_url, const Vector<String> &p_headers, const uint8_t *p_body, int p_body_size) override; + + Error connect_to_host(const String &p_host, int p_port = -1, bool p_ssl = false, bool p_verify_host = true) override; + void set_connection(const Ref<StreamPeer> &p_connection) override; + Ref<StreamPeer> get_connection() const override; + void close() override; + Status get_status() const override; + bool has_response() const override; + bool is_response_chunked() const override; + int get_response_code() const override; + Error get_response_headers(List<String> *r_response) override; + int get_response_body_length() const override; + PackedByteArray read_response_body_chunk() override; + void set_blocking_mode(bool p_enable) override; + bool is_blocking_mode_enabled() const override; + void set_read_chunk_size(int p_size) override; + int get_read_chunk_size() const override; + Error poll() override; + HTTPClientJavaScript(); + ~HTTPClientJavaScript(); +}; +#endif // HTTP_CLIENT_JAVASCRIPT_H diff --git a/platform/javascript/javascript_singleton.cpp b/platform/javascript/javascript_singleton.cpp index 5ef67c0cdd..1dd73ef8e9 100644 --- a/platform/javascript/javascript_singleton.cpp +++ b/platform/javascript/javascript_singleton.cpp @@ -28,12 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef JAVASCRIPT_EVAL_ENABLED - #include "api/javascript_singleton.h" #include "emscripten.h" extern "C" { +extern void godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime); +} + +#ifdef JAVASCRIPT_EVAL_ENABLED + +extern "C" { typedef union { int64_t i; double r; @@ -50,6 +54,7 @@ extern int godot_js_wrapper_object_setvar(int p_id, int p_key_type, godot_js_wra extern void godot_js_wrapper_object_set(int p_id, const char *p_name, int p_type, godot_js_wrapper_ex *p_val); extern void godot_js_wrapper_object_unref(int p_id); extern int godot_js_wrapper_create_cb(void *p_ref, void (*p_callback)(void *p_ref, int p_arg_id, int p_argc)); +extern void godot_js_wrapper_object_set_cb_ret(int p_type, godot_js_wrapper_ex *p_val); extern int godot_js_wrapper_create_object(const char *p_method, void **p_args, int p_argc, GodotJSWrapperVariant2JSCallback p_variant2js_callback, godot_js_wrapper_ex *p_cb_rval, void **p_lock, GodotJSWrapperFreeLockCallback p_lock_callback); }; @@ -178,7 +183,7 @@ Variant JavaScriptObjectImpl::_js2variant(int p_type, godot_js_wrapper_ex *p_val case Variant::FLOAT: return p_val->r; case Variant::STRING: { - String out((const char *)p_val->p); + String out = String::utf8((const char *)p_val->p); free(p_val->p); return out; } @@ -253,6 +258,16 @@ void JavaScriptObjectImpl::_callback(void *p_ref, int p_args_id, int p_argc) { Callable::CallError err; Variant ret; obj->_callable.call(argv, 1, ret, err); + + // Set return value + godot_js_wrapper_ex exchange; + void *lock = nullptr; + const Variant *v = &ret; + int type = _variant2js((const void **)&v, 0, &exchange, &lock); + godot_js_wrapper_object_set_cb_ret(type, &exchange); + if (lock) { + _free_lock(&lock, type); + } } Ref<JavaScriptObject> JavaScript::create_callback(const Callable &p_callable) { @@ -301,7 +316,6 @@ union js_eval_ret { }; extern int godot_js_eval(const char *p_js, int p_use_global_ctx, union js_eval_ret *p_union_ptr, void *p_byte_arr, void *p_byte_arr_write, void *(*p_callback)(void *p_ptr, void *p_ptr2, int p_len)); -extern int godot_js_os_download_buffer(const uint8_t *p_buf, int p_buf_size, const char *p_name, const char *p_mime); } void *resize_PackedByteArray_and_open_write(void *p_arr, void *r_write, int p_len) { diff --git a/platform/javascript/js/engine/config.js b/platform/javascript/js/engine/config.js index 6072782875..ba61b14eb7 100644 --- a/platform/javascript/js/engine/config.js +++ b/platform/javascript/js/engine/config.js @@ -91,6 +91,14 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- */ args: [], /** + * When enabled, the game canvas will automatically grab the focus when the engine starts. + * + * @memberof EngineConfig + * @type {boolean} + * @default + */ + focusCanvas: true, + /** * When enabled, this will turn on experimental virtual keyboard support on mobile. * * @memberof EngineConfig @@ -238,6 +246,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- this.persistentPaths = parse('persistentPaths', this.persistentPaths); this.persistentDrops = parse('persistentDrops', this.persistentDrops); this.experimentalVK = parse('experimentalVK', this.experimentalVK); + this.focusCanvas = parse('focusCanvas', this.focusCanvas); this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs); this.fileSizes = parse('fileSizes', this.fileSizes); this.args = parse('args', this.args); @@ -324,6 +333,7 @@ const InternalConfig = function (initConfig) { // eslint-disable-line no-unused- 'locale': locale, 'persistentDrops': this.persistentDrops, 'virtualKeyboard': this.experimentalVK, + 'focusCanvas': this.focusCanvas, 'onExecute': this.onExecute, 'onExit': function (p_code) { cleanup(); // We always need to call the cleanup callback to free memory. diff --git a/platform/javascript/js/libs/library_godot_display.js b/platform/javascript/js/libs/library_godot_display.js index 91cab5eacc..affae90370 100644 --- a/platform/javascript/js/libs/library_godot_display.js +++ b/platform/javascript/js/libs/library_godot_display.js @@ -683,7 +683,7 @@ const GodotDisplay = { return GodotDisplayScreen.exitFullscreen(); }, - godot_js_display_desired_size_set__sig: 'v', + godot_js_display_desired_size_set__sig: 'vii', godot_js_display_desired_size_set: function (width, height) { GodotDisplayScreen.desired_size = [width, height]; GodotDisplayScreen.updateSize(); diff --git a/platform/javascript/js/libs/library_godot_fetch.js b/platform/javascript/js/libs/library_godot_fetch.js index de5ae2b1ae..615f9de8b0 100644 --- a/platform/javascript/js/libs/library_godot_fetch.js +++ b/platform/javascript/js/libs/library_godot_fetch.js @@ -29,7 +29,7 @@ /*************************************************************************/ const GodotFetch = { - $GodotFetch__deps: ['$GodotRuntime'], + $GodotFetch__deps: ['$IDHandler', '$GodotRuntime'], $GodotFetch: { onread: function (id, result) { @@ -126,7 +126,7 @@ const GodotFetch = { }, }, - godot_js_fetch_create__sig: 'iii', + godot_js_fetch_create__sig: 'iiiiiii', godot_js_fetch_create: function (p_method, p_url, p_headers, p_headers_size, p_body, p_body_size) { const method = GodotRuntime.parseString(p_method); const url = GodotRuntime.parseString(p_url); @@ -176,7 +176,7 @@ const GodotFetch = { return obj.status; }, - godot_js_fetch_read_headers__sig: 'iii', + godot_js_fetch_read_headers__sig: 'iiii', godot_js_fetch_read_headers: function (p_id, p_parse_cb, p_ref) { const obj = IDHandler.get(p_id); if (!obj || !obj.response) { @@ -193,7 +193,7 @@ const GodotFetch = { return 0; }, - godot_js_fetch_read_chunk__sig: 'ii', + godot_js_fetch_read_chunk__sig: 'iiii', godot_js_fetch_read_chunk: function (p_id, p_buf, p_buf_size) { const obj = IDHandler.get(p_id); if (!obj || !obj.response) { diff --git a/platform/javascript/js/libs/library_godot_javascript_singleton.js b/platform/javascript/js/libs/library_godot_javascript_singleton.js index 09ef4a1a5d..22ce003cd2 100644 --- a/platform/javascript/js/libs/library_godot_javascript_singleton.js +++ b/platform/javascript/js/libs/library_godot_javascript_singleton.js @@ -34,6 +34,7 @@ const GodotJSWrapper = { $GodotJSWrapper__postset: 'GodotJSWrapper.proxies = new Map();', $GodotJSWrapper: { proxies: null, + cb_ret: null, MyProxy: function (val) { const id = IDHandler.add(this); @@ -196,21 +197,33 @@ const GodotJSWrapper = { } }, - godot_js_wrapper_create_cb__sig: 'vii', + godot_js_wrapper_create_cb__sig: 'iii', godot_js_wrapper_create_cb: function (p_ref, p_func) { const func = GodotRuntime.get_func(p_func); let id = 0; const cb = function () { if (!GodotJSWrapper.get_proxied_value(id)) { - return; + return undefined; } + // The callback will store the returned value in this variable via + // "godot_js_wrapper_object_set_cb_ret" upon calling the user function. + // This is safe! JavaScript is single threaded (and using it in threads is not a good idea anyway). + GodotJSWrapper.cb_ret = null; const args = Array.from(arguments); func(p_ref, GodotJSWrapper.get_proxied(args), args.length); + const ret = GodotJSWrapper.cb_ret; + GodotJSWrapper.cb_ret = null; + return ret; }; id = GodotJSWrapper.get_proxied(cb); return id; }, + godot_js_wrapper_object_set_cb_ret__sig: 'vii', + godot_js_wrapper_object_set_cb_ret: function (p_val_type, p_val_ex) { + GodotJSWrapper.cb_ret = GodotJSWrapper.variant2js(p_val_type, p_val_ex); + }, + godot_js_wrapper_object_getvar__sig: 'iiii', godot_js_wrapper_object_getvar: function (p_id, p_type, p_exchange) { const obj = GodotJSWrapper.get_proxied_value(p_id); diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js index 7414b8cc47..5aa750757c 100644 --- a/platform/javascript/js/libs/library_godot_os.js +++ b/platform/javascript/js/libs/library_godot_os.js @@ -72,6 +72,9 @@ const GodotConfig = { GodotConfig.persistent_drops = !!p_opts['persistentDrops']; GodotConfig.on_execute = p_opts['onExecute']; GodotConfig.on_exit = p_opts['onExit']; + if (p_opts['focusCanvas']) { + GodotConfig.canvas.focus(); + } }, locate_file: function (file) { diff --git a/platform/javascript/package-lock.json b/platform/javascript/package-lock.json index 8bf5c52ff6..8003619576 100644 --- a/platform/javascript/package-lock.json +++ b/platform/javascript/package-lock.json @@ -5,27 +5,27 @@ "requires": true, "dependencies": { "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "dev": true, "requires": { "@babel/highlight": "^7.10.4" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", "dev": true }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -40,39 +40,38 @@ "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true } } }, "@babel/parser": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.1.tgz", - "integrity": "sha512-muUGEKu8E/ftMTPlNp+mc6zL3E9zKWmF5sDHZ5MSsoTP9Wyz64AhEf9kD08xYJ7w6Hdcu8H550ircnPyWSIF0Q==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.14.5.tgz", + "integrity": "sha512-TM8C+xtH/9n1qzX+JNHi7AN2zHMTiPUtspO0ZdHflW8KaskkALhMmuMHb4bCmNdv9VAPzJX3/bXqkVLnAvsPfg==", "dev": true }, "@eslint/eslintrc": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz", - "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.1.1", "espree": "^7.3.0", - "globals": "^12.1.0", + "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" } }, - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", - "dev": true - }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -80,9 +79,9 @@ "dev": true }, "acorn": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz", - "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, "acorn-jsx": { @@ -92,9 +91,9 @@ "dev": true }, "ajv": { - "version": "6.12.5", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", - "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -134,78 +133,39 @@ } }, "array-includes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.1.tgz", - "integrity": "sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", "is-string": "^1.0.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } } }, "array.prototype.flat": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz", - "integrity": "sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.18.0-next.1" } }, "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "bluebird": { @@ -224,6 +184,16 @@ "concat-map": "0.0.1" } }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -231,18 +201,18 @@ "dev": true }, "catharsis": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.8.11.tgz", - "integrity": "sha512-a+xUyMV7hD1BrDQA/3iPV7oc+6W26BgVJO05PGEoatMyIuPScQKsde6i3YorWX1qs+AZjnJ18NqdKoCtKiNh1g==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", + "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", "dev": true, "requires": { - "lodash": "^4.17.14" + "lodash": "^4.17.15" } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -250,12 +220,11 @@ }, "dependencies": { "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" } }, @@ -313,15 +282,9 @@ "dev": true }, "confusing-browser-globals": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz", - "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", - "dev": true - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz", + "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", "dev": true }, "cross-spawn": { @@ -336,12 +299,12 @@ } }, "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "deep-is": { @@ -369,9 +332,9 @@ } }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "enquirer": { @@ -399,23 +362,27 @@ } }, "es-abstract": { - "version": "1.18.0-next.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", - "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" } }, "es-to-primitive": { @@ -430,35 +397,37 @@ } }, "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, "eslint": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz", - "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz", + "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.1.3", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.0.1", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "eslint-scope": "^5.1.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^1.3.0", - "espree": "^7.3.0", - "esquery": "^1.2.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -466,7 +435,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -475,19 +444,19 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^5.2.3", + "table": "^6.0.9", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" } }, "eslint-config-airbnb-base": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz", - "integrity": "sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==", + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz", + "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==", "dev": true, "requires": { - "confusing-browser-globals": "^1.0.9", - "object.assign": "^4.1.0", + "confusing-browser-globals": "^1.0.10", + "object.assign": "^4.1.2", "object.entries": "^1.1.2" } }, @@ -519,50 +488,46 @@ } }, "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", "dev": true, "requires": { - "debug": "^2.6.9", + "debug": "^3.2.7", "pkg-dir": "^2.0.0" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, "eslint-plugin-import": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz", - "integrity": "sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==", + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", "dev": true, "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.3", - "eslint-module-utils": "^2.6.0", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", "has": "^1.0.3", + "is-core-module": "^2.4.0", "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", "tsconfig-paths": "^3.9.0" }, "dependencies": { @@ -576,13 +541,12 @@ } }, "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "esutils": "^2.0.2" } }, "ms": { @@ -610,23 +574,39 @@ "dev": true, "requires": { "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", + "acorn-jsx": "^5.3.1", "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } } }, "esprima": { @@ -636,9 +616,9 @@ "dev": true }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -700,12 +680,12 @@ "dev": true }, "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" } }, "find-up": { @@ -718,20 +698,19 @@ } }, "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, "fs.realpath": { @@ -752,10 +731,21 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -767,27 +757,27 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "has": { @@ -799,6 +789,12 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -806,9 +802,9 @@ "dev": true }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "hosted-git-info": { @@ -824,9 +820,9 @@ "dev": true }, "import-fresh": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", - "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -861,16 +857,40 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-callable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", - "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", "dev": true }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", "dev": true }, "is-extglob": { @@ -880,9 +900,9 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-glob": { @@ -895,41 +915,42 @@ } }, "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", "dev": true }, "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" } }, "is-string": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", "dev": true }, "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, "requires": { - "has-symbols": "^1.0.1" + "has-symbols": "^1.0.2" } }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -943,9 +964,9 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -962,13 +983,14 @@ } }, "jsdoc": { - "version": "github:jsdoc/jsdoc#544a992824631fc652183d8b0b4b1281dc961560", - "from": "github:jsdoc/jsdoc#544a992824631fc652183d8b0b4b1281dc961560", + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-3.6.7.tgz", + "integrity": "sha512-sxKt7h0vzCd+3Y81Ey2qinupL6DpRSZJclS04ugHDNmRUXGzqicMJ6iwayhSA0S0DwwX30c5ozyUthr1QKF6uw==", "dev": true, "requires": { "@babel/parser": "^7.9.4", "bluebird": "^3.7.2", - "catharsis": "^0.8.11", + "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.1", "klaw": "^3.0.0", @@ -979,7 +1001,7 @@ "requizzle": "^0.2.3", "strip-json-comments": "^3.1.0", "taffydb": "2.6.2", - "underscore": "~1.12.1" + "underscore": "~1.13.1" }, "dependencies": { "escape-string-regexp": { @@ -987,15 +1009,15 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true } } }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1046,14 +1068,14 @@ } }, "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", + "parse-json": "^4.0.0", + "pify": "^3.0.0", "strip-bom": "^3.0.0" } }, @@ -1073,6 +1095,33 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "markdown-it": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", @@ -1093,9 +1142,9 @@ "dev": true }, "marked": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.3.tgz", - "integrity": "sha512-5otztIIcJfPc2qGTN8cVtOJEjNJZ0jwa46INMagrYfk0EvqtRuEHLsEe0LrFS0/q+ZRKT0+kXK7P2T1AN5lWRA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/marked/-/marked-2.0.7.tgz", + "integrity": "sha512-BJXxkuIfJchcXOJWTT2DOL+yFWifFv2yGYOUzvXg8Qz610QKw+sHCvTMYwA+qWGhlA2uivBezChZ/pBy1tWdkQ==", "dev": true }, "mdurl": { @@ -1120,13 +1169,10 @@ "dev": true }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true }, "ms": { "version": "2.1.2", @@ -1161,9 +1207,9 @@ } }, "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", "dev": true }, "object-keys": { @@ -1173,80 +1219,37 @@ "dev": true }, "object.assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", - "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.0", "has-symbols": "^1.0.1", "object-keys": "^1.1.1" } }, "object.entries": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", - "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.4.tgz", + "integrity": "sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", - "has": "^1.0.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.18.2" } }, "object.values": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz", - "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1", - "function-bind": "^1.1.1", - "has": "^1.0.3" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "es-abstract": "^1.18.2" } }, "once": { @@ -1306,12 +1309,13 @@ } }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { - "error-ex": "^1.2.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } }, "path-exists": { @@ -1333,24 +1337,24 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { - "pify": "^2.0.0" + "pify": "^3.0.0" } }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "pkg-dir": { @@ -1362,6 +1366,15 @@ "find-up": "^2.1.0" } }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1381,30 +1394,36 @@ "dev": true }, "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { - "load-json-file": "^2.0.0", + "load-json-file": "^4.0.0", "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" + "path-type": "^3.0.0" } }, "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", "dev": true, "requires": { "find-up": "^2.0.0", - "read-pkg": "^2.0.0" + "read-pkg": "^3.0.0" } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, "requizzle": { @@ -1417,11 +1436,12 @@ } }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -1432,19 +1452,22 @@ "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "shebang-command": { "version": "2.0.0", @@ -1462,14 +1485,40 @@ "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "spdx-correct": { @@ -1499,9 +1548,9 @@ } }, "spdx-license-ids": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", - "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", "dev": true }, "sprintf-js": { @@ -1511,93 +1560,34 @@ "dev": true }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "strip-ansi": { @@ -1631,15 +1621,37 @@ } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } } }, "taffydb": { @@ -1676,9 +1688,9 @@ } }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "uc.micro": { @@ -1687,25 +1699,37 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "underscore": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", + "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", "dev": true }, "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" } }, "v8-compile-cache": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", - "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "validate-npm-package-license": { @@ -1727,6 +1751,19 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -1739,20 +1776,17 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "xmlcreate": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.3.tgz", "integrity": "sha512-HgS+X6zAztGa9zIK3Y3LXuJes33Lz9x+YyTxgrkIdabu2vqcGOWwdfCpf1hWLRrd553wd4QCDf6BBO6FfdsRiQ==", "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/platform/javascript/package.json b/platform/javascript/package.json index 53748503f9..9dafae30c5 100644 --- a/platform/javascript/package.json +++ b/platform/javascript/package.json @@ -20,9 +20,9 @@ "author": "Godot Engine contributors", "license": "MIT", "devDependencies": { - "eslint": "^7.9.0", - "eslint-config-airbnb-base": "^14.2.0", - "eslint-plugin-import": "^2.22.0", - "jsdoc": "github:jsdoc/jsdoc#544a992824631fc652183d8b0b4b1281dc961560" + "eslint": "^7.28.0", + "eslint-config-airbnb-base": "^14.2.1", + "eslint-plugin-import": "^2.23.4", + "jsdoc": "^3.6.7" } } diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index 1751d56e71..8aebd57fd2 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -9,6 +9,7 @@ common_linuxbsd = [ "crash_handler_linuxbsd.cpp", "os_linuxbsd.cpp", "joypad_linux.cpp", + "freedesktop_screensaver.cpp", ] if "x11" in env and env["x11"]: diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 1487210174..eba672ddcb 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -72,6 +72,7 @@ def get_opts(): BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False), BoolVariable("pulseaudio", "Detect and use PulseAudio", True), + BoolVariable("dbus", "Detect and use D-Bus to handle screensaver", True), BoolVariable("udev", "Use udev for gamepad connection callbacks", True), BoolVariable("x11", "Enable X11 display", True), BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), @@ -347,6 +348,14 @@ def configure(env): else: print("PulseAudio development libraries not found, disabling driver") + if env["dbus"]: + if os.system("pkg-config --exists dbus-1") == 0: # 0 means found + print("Enabling D-Bus") + env.Append(CPPDEFINES=["DBUS_ENABLED"]) + env.ParseConfig("pkg-config --cflags --libs dbus-1") + else: + print("D-Bus development libraries not found, disabling dependent features") + if platform.system() == "Linux": env.Append(CPPDEFINES=["JOYDEV_ENABLED"]) if env["udev"]: diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 8b6922699c..8f0742041c 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -121,6 +121,9 @@ bool DisplayServerX11::has_feature(Feature p_feature) const { case FEATURE_ICON: case FEATURE_NATIVE_ICON: case FEATURE_SWAP_BUFFERS: +#ifdef DBUS_ENABLED + case FEATURE_KEEP_SCREEN_ON: +#endif return true; default: { } @@ -450,7 +453,7 @@ Point2i DisplayServerX11::mouse_get_absolute_position() const { return Vector2i(); } -int DisplayServerX11::mouse_get_button_state() const { +MouseButton DisplayServerX11::mouse_get_button_state() const { return last_button_state; } @@ -822,6 +825,26 @@ bool DisplayServerX11::screen_is_touchscreen(int p_screen) const { return DisplayServer::screen_is_touchscreen(p_screen); } +#ifdef DBUS_ENABLED +void DisplayServerX11::screen_set_keep_on(bool p_enable) { + if (screen_is_kept_on() == p_enable) { + return; + } + + if (p_enable) { + screensaver->inhibit(); + } else { + screensaver->uninhibit(); + } + + keep_screen_on = p_enable; +} + +bool DisplayServerX11::screen_is_kept_on() const { + return keep_screen_on; +} +#endif + Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const { _THREAD_SAFE_METHOD_ @@ -832,10 +855,10 @@ Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ - WindowID id = _create_window(p_mode, p_flags, p_rect); + WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); @@ -2172,13 +2195,13 @@ void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<Inp state->set_meta_pressed((p_x11_state & Mod4Mask)); } -unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) { - unsigned int mask = 1 << (p_x11_button - 1); +MouseButton DisplayServerX11::_get_mouse_button_state(MouseButton p_x11_button, int p_x11_type) { + MouseButton mask = MouseButton(1 << (p_x11_button - 1)); if (p_x11_type == ButtonPress) { last_button_state |= mask; } else { - last_button_state &= ~mask; + last_button_state &= MouseButton(~mask); } return last_button_state; @@ -2255,7 +2278,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, tmp.parse_utf8(utf8string, utf8bytes); for (int i = 0; i < tmp.length(); i++) { Ref<InputEventKey> k; - k.instance(); + k.instantiate(); if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) { continue; } @@ -2346,7 +2369,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, //print_verbose("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask)); Ref<InputEventKey> k; - k.instance(); + k.instantiate(); k->set_window_id(p_window); _get_key_modifier_state(xkeyevent->state, k); @@ -2904,7 +2927,7 @@ void DisplayServerX11::process_events() { bool is_begin = event_data->evtype == XI_TouchBegin; Ref<InputEventScreenTouch> st; - st.instance(); + st.instantiate(); st->set_window_id(window_id); st->set_index(index); st->set_position(pos); @@ -2938,7 +2961,7 @@ void DisplayServerX11::process_events() { if (curr_pos_elem->value() != pos) { Ref<InputEventScreenDrag> sd; - sd.instance(); + sd.instantiate(); sd->set_window_id(window_id); sd->set_index(index); sd->set_position(pos); @@ -3091,7 +3114,7 @@ void DisplayServerX11::process_events() { // Release every pointer to avoid sticky points for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) { Ref<InputEventScreenTouch> st; - st.instance(); + st.instantiate(); st->set_index(E->key()); st->set_window_id(window_id); st->set_position(E->get()); @@ -3126,15 +3149,15 @@ void DisplayServerX11::process_events() { } Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_window_id(window_id); _get_key_modifier_state(event.xbutton.state, mb); - mb->set_button_index(event.xbutton.button); - if (mb->get_button_index() == 2) { - mb->set_button_index(3); - } else if (mb->get_button_index() == 3) { - mb->set_button_index(2); + mb->set_button_index((MouseButton)event.xbutton.button); + if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { + mb->set_button_index(MOUSE_BUTTON_MIDDLE); + } else if (mb->get_button_index() == MOUSE_BUTTON_MIDDLE) { + mb->set_button_index(MOUSE_BUTTON_RIGHT); } mb->set_button_mask(_get_mouse_button_state(mb->get_button_index(), event.xbutton.type)); mb->set_position(Vector2(event.xbutton.x, event.xbutton.y)); @@ -3291,13 +3314,13 @@ void DisplayServerX11::process_events() { } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); if (xi.pressure_supported) { mm->set_pressure(xi.pressure); } else { - mm->set_pressure((mouse_get_button_state() & (1 << (MOUSE_BUTTON_LEFT - 1))) ? 1.0f : 0.0f); + mm->set_pressure((mouse_get_button_state() & MOUSE_BUTTON_MASK_LEFT) ? 1.0f : 0.0f); } mm->set_tilt(xi.tilt); @@ -3618,6 +3641,22 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) { XSetErrorHandler(oldHandler); } +void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); +#endif +} + +DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + return context_vulkan->get_vsync_mode(p_window); +#else + return DisplayServer::VSYNC_ENABLED; +#endif +} + Vector<String> DisplayServerX11::get_rendering_drivers_func() { Vector<String> drivers; @@ -3631,8 +3670,8 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() { return drivers; } -DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n" "Please update your drivers or if you have a very old or integrated GPU upgrade it.", @@ -3641,7 +3680,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W return ds; } -DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { //Create window long visualMask = VisualScreenMask; @@ -3805,7 +3844,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u #if defined(VULKAN_ENABLED) if (context_vulkan) { - Error err = context_vulkan->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); + Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window"); } #endif @@ -3842,7 +3881,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u return id; } -DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); r_error = OK; @@ -3855,8 +3894,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode img[i] = nullptr; } - last_button_state = 0; - xmbstring = nullptr; last_click_ms = 0; @@ -4080,7 +4117,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode Point2i window_position( (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); - WindowID main_window = _create_window(p_mode, p_flags, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution)); if (main_window == INVALID_WINDOW_ID) { r_error = ERR_CANT_CREATE; return; @@ -4272,6 +4309,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode _update_real_mouse_position(windows[MAIN_WINDOW_ID]); +#ifdef DBUS_ENABLED + screensaver = memnew(FreeDesktopScreenSaver); + screen_set_keep_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); +#endif + r_error = OK; } @@ -4336,6 +4378,10 @@ DisplayServerX11::~DisplayServerX11() { if (xmbstring) { memfree(xmbstring); } + +#ifdef DBUS_ENABLED + memdelete(screensaver); +#endif } void DisplayServerX11::register_x11_driver() { diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 10686d8424..c5cf5ee4cb 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -55,6 +55,10 @@ #include "platform/linuxbsd/vulkan_context_x11.h" #endif +#if defined(DBUS_ENABLED) +#include "freedesktop_screensaver.h" +#endif + #include <X11/Xcursor/Xcursor.h> #include <X11/Xlib.h> #include <X11/extensions/XInput2.h> @@ -103,6 +107,11 @@ class DisplayServerX11 : public DisplayServer { RenderingDeviceVulkan *rendering_device_vulkan; #endif +#if defined(DBUS_ENABLED) + FreeDesktopScreenSaver *screensaver; + bool keep_screen_on = false; +#endif + struct WindowData { Window x11_window; ::XIC xic; @@ -143,7 +152,7 @@ class DisplayServerX11 : public DisplayServer { Map<WindowID, WindowData> windows; WindowID window_id_counter = MAIN_WINDOW_ID; - WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); String internal_clipboard; Window xdnd_source_window; @@ -162,7 +171,7 @@ class DisplayServerX11 : public DisplayServer { Point2i last_click_pos; uint64_t last_click_ms; int last_click_button_index; - uint32_t last_button_state; + MouseButton last_button_state = MOUSE_BUTTON_NONE; bool app_focused = false; uint64_t time_since_no_focus = 0; @@ -187,7 +196,7 @@ class DisplayServerX11 : public DisplayServer { bool _refresh_device_info(); - unsigned int _get_mouse_button_state(unsigned int p_x11_button, int p_x11_type); + MouseButton _get_mouse_button_state(MouseButton p_x11_button, int p_x11_type); void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state); void _flush_mouse_motion(); @@ -279,7 +288,7 @@ public: virtual void mouse_warp_to_position(const Point2i &p_to); virtual Point2i mouse_get_position() const; virtual Point2i mouse_get_absolute_position() const; - virtual int mouse_get_button_state() const; + virtual MouseButton mouse_get_button_state() const; virtual void clipboard_set(const String &p_text); virtual String clipboard_get() const; @@ -291,9 +300,14 @@ public: virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; +#if defined(DBUS_ENABLED) + virtual void screen_set_keep_on(bool p_enable); + virtual bool screen_is_kept_on() const; +#endif + virtual Vector<DisplayServer::WindowID> get_window_list() const; - virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); @@ -348,6 +362,9 @@ public: virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual void cursor_set_shape(CursorShape p_shape); virtual CursorShape cursor_get_shape() const; virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); @@ -369,12 +386,12 @@ public: virtual void set_native_icon(const String &p_filename); virtual void set_icon(const Ref<Image> &p_icon); - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_x11_driver(); - DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); ~DisplayServerX11(); }; diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index cb95068314..5c6be2d7d4 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -30,7 +30,7 @@ #include "export.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "editor/editor_export.h" #include "platform/linuxbsd/logo.gen.h" #include "scene/resources/texture.h" @@ -39,11 +39,11 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, void register_linuxbsd_exporter() { Ref<EditorExportPlatformPC> platform; - platform.instance(); + platform.instantiate(); Ref<Image> img = memnew(Image(_linuxbsd_logo)); Ref<ImageTexture> logo; - logo.instance(); + logo.instantiate(); logo->create_from_image(img); platform->set_logo(logo); platform->set_name("Linux/X11"); diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp new file mode 100644 index 0000000000..a6a3b27d76 --- /dev/null +++ b/platform/linuxbsd/freedesktop_screensaver.cpp @@ -0,0 +1,125 @@ +/*************************************************************************/ +/* freedesktop_screensaver.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "freedesktop_screensaver.h" + +#ifdef DBUS_ENABLED + +#include "core/config/project_settings.h" + +#include <dbus/dbus.h> + +#define BUS_OBJECT_NAME "org.freedesktop.ScreenSaver" +#define BUS_OBJECT_PATH "/org/freedesktop/ScreenSaver" +#define BUS_INTERFACE "org.freedesktop.ScreenSaver" + +void FreeDesktopScreenSaver::inhibit() { + if (unsupported) { + return; + } + + DBusError error; + dbus_error_init(&error); + + DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (dbus_error_is_set(&error)) { + unsupported = true; + return; + } + + String app_name_string = ProjectSettings::get_singleton()->get("application/config/name"); + CharString app_name_utf8 = app_name_string.utf8(); + const char *app_name = app_name_string.is_empty() ? "Godot Engine" : app_name_utf8.get_data(); + + const char *reason = "Running Godot Engine project"; + + DBusMessage *message = dbus_message_new_method_call( + BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE, + "Inhibit"); + dbus_message_append_args( + message, + DBUS_TYPE_STRING, &app_name, + DBUS_TYPE_STRING, &reason, + DBUS_TYPE_INVALID); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error); + dbus_message_unref(message); + if (dbus_error_is_set(&error)) { + dbus_connection_unref(bus); + unsupported = false; + return; + } + + DBusMessageIter reply_iter; + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &cookie); + print_verbose("FreeDesktopScreenSaver: Acquired screensaver inhibition cookie: " + uitos(cookie)); + + dbus_message_unref(reply); + dbus_connection_unref(bus); +} + +void FreeDesktopScreenSaver::uninhibit() { + if (unsupported) { + return; + } + + DBusError error; + dbus_error_init(&error); + + DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (dbus_error_is_set(&error)) { + unsupported = true; + return; + } + + DBusMessage *message = dbus_message_new_method_call( + BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE, + "UnInhibit"); + dbus_message_append_args( + message, + DBUS_TYPE_UINT32, &cookie, + DBUS_TYPE_INVALID); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error); + if (dbus_error_is_set(&error)) { + dbus_connection_unref(bus); + unsupported = true; + return; + } + + print_verbose("FreeDesktopScreenSaver: Released screensaver inhibition cookie: " + uitos(cookie)); + + dbus_message_unref(message); + dbus_message_unref(reply); + dbus_connection_unref(bus); +} + +#endif // DBUS_ENABLED diff --git a/platform/linuxbsd/freedesktop_screensaver.h b/platform/linuxbsd/freedesktop_screensaver.h new file mode 100644 index 0000000000..f27e60fce4 --- /dev/null +++ b/platform/linuxbsd/freedesktop_screensaver.h @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* freedesktop_screensaver.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifdef DBUS_ENABLED + +#include <dbus/dbus.h> +#include <stdint.h> + +class FreeDesktopScreenSaver { +private: + uint32_t cookie = 0; + bool unsupported = false; + +public: + FreeDesktopScreenSaver() {} + void inhibit(); + void uninhibit(); +}; + +#endif // DBUS_ENABLED diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index e8f4352dff..8b6dbc4c20 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -475,7 +475,7 @@ void JoypadLinux::process_joypads() { switch (ev.type) { case EV_KEY: - input->joy_button(i, joy->key_map[ev.code], ev.value); + input->joy_button(i, (JoyButton)joy->key_map[ev.code], ev.value); break; case EV_ABS: @@ -484,29 +484,29 @@ void JoypadLinux::process_joypads() { case ABS_HAT0X: if (ev.value != 0) { if (ev.value < 0) { - joy->dpad = (joy->dpad | Input::HAT_MASK_LEFT) & ~Input::HAT_MASK_RIGHT; + joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_LEFT) & ~HatMask::HAT_MASK_RIGHT); } else { - joy->dpad = (joy->dpad | Input::HAT_MASK_RIGHT) & ~Input::HAT_MASK_LEFT; + joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_RIGHT) & ~HatMask::HAT_MASK_LEFT); } } else { - joy->dpad &= ~(Input::HAT_MASK_LEFT | Input::HAT_MASK_RIGHT); + joy->dpad &= ~(HatMask::HAT_MASK_LEFT | HatMask::HAT_MASK_RIGHT); } - input->joy_hat(i, joy->dpad); + input->joy_hat(i, (HatMask)joy->dpad); break; case ABS_HAT0Y: if (ev.value != 0) { if (ev.value < 0) { - joy->dpad = (joy->dpad | Input::HAT_MASK_UP) & ~Input::HAT_MASK_DOWN; + joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_UP) & ~HatMask::HAT_MASK_DOWN); } else { - joy->dpad = (joy->dpad | Input::HAT_MASK_DOWN) & ~Input::HAT_MASK_UP; + joy->dpad = (HatMask)((joy->dpad | HatMask::HAT_MASK_DOWN) & ~HatMask::HAT_MASK_UP); } } else { - joy->dpad &= ~(Input::HAT_MASK_UP | Input::HAT_MASK_DOWN); + joy->dpad &= ~(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_DOWN); } - input->joy_hat(i, joy->dpad); + input->joy_hat(i, (HatMask)joy->dpad); break; default: @@ -526,7 +526,7 @@ void JoypadLinux::process_joypads() { for (int j = 0; j < MAX_ABS; j++) { int index = joy->abs_map[j]; if (index != -1) { - input->joy_axis(i, index, joy->curr_axis[index]); + input->joy_axis(i, (JoyAxis)index, joy->curr_axis[index]); } } if (len == 0 || (len < 0 && errno != EAGAIN)) { diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 23e448fbd7..c6a2fa5be7 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -30,7 +30,7 @@ #include "os_linuxbsd.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "main/main.h" #ifdef X11_ENABLED @@ -166,7 +166,7 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) { String OS_LinuxBSD::get_config_path() const { if (has_environment("XDG_CONFIG_HOME")) { - if (get_environment("XDG_CONFIG_HOME").is_abs_path()) { + if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { return get_environment("XDG_CONFIG_HOME"); } else { WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification."); @@ -181,7 +181,7 @@ String OS_LinuxBSD::get_config_path() const { String OS_LinuxBSD::get_data_path() const { if (has_environment("XDG_DATA_HOME")) { - if (get_environment("XDG_DATA_HOME").is_abs_path()) { + if (get_environment("XDG_DATA_HOME").is_absolute_path()) { return get_environment("XDG_DATA_HOME"); } else { WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification."); @@ -196,7 +196,7 @@ String OS_LinuxBSD::get_data_path() const { String OS_LinuxBSD::get_cache_path() const { if (has_environment("XDG_CACHE_HOME")) { - if (get_environment("XDG_CACHE_HOME").is_abs_path()) { + if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { return get_environment("XDG_CACHE_HOME"); } else { WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification."); @@ -425,8 +425,8 @@ Error OS_LinuxBSD::move_to_trash(const String &p_path) { // Generates the .trashinfo file OS::Date date = OS::get_singleton()->get_date(false); OS::Time time = OS::get_singleton()->get_time(false); - String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, date.month, date.day, time.hour, time.min); - timestamp = vformat("%s%02d", timestamp, time.sec); // vformat only supports up to 6 arguments. + String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, date.month, date.day, time.hour, time.minute); + timestamp = vformat("%s%02d", timestamp, time.second); // vformat only supports up to 6 arguments. String trash_info = "[Trash Info]\nPath=" + p_path.uri_encode() + "\nDeletionDate=" + timestamp + "\n"; { Error err; diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/vulkan_context_x11.cpp index 021db630e0..88cb00a8a1 100644 --- a/platform/linuxbsd/vulkan_context_x11.cpp +++ b/platform/linuxbsd/vulkan_context_x11.cpp @@ -35,7 +35,7 @@ const char *VulkanContextX11::_get_platform_surface_extension() const { return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; } -Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { +Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height) { VkXlibSurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; @@ -46,7 +46,7 @@ Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Win VkSurfaceKHR surface; VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - return _window_create(p_window_id, surface, p_width, p_height); + return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } VulkanContextX11::VulkanContextX11() { diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h index 26472444ad..de4a9c7b90 100644 --- a/platform/linuxbsd/vulkan_context_x11.h +++ b/platform/linuxbsd/vulkan_context_x11.h @@ -38,7 +38,7 @@ class VulkanContextX11 : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height); VulkanContextX11(); ~VulkanContextX11(); diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h index f61581979f..a894723e64 100644 --- a/platform/osx/dir_access_osx.h +++ b/platform/osx/dir_access_osx.h @@ -38,7 +38,7 @@ #include <sys/types.h> #include <unistd.h> -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "drivers/unix/dir_access_unix.h" class DirAccessOSX : public DirAccessUnix { diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index 9fac99810b..c7b9e411b8 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -145,7 +145,7 @@ public: WindowID window_id_counter = MAIN_WINDOW_ID; - WindowID _create_window(WindowMode p_mode, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect); void _update_window(WindowData p_wd); void _send_window_event(const WindowData &wd, WindowEvent p_event); static void _dispatch_input_events(const Ref<InputEvent> &p_event); @@ -173,7 +173,7 @@ public: MouseMode mouse_mode; Point2i last_mouse_pos; - uint32_t last_button_state; + MouseButton last_button_state = MOUSE_BUTTON_NONE; bool window_focused; bool drop_events; @@ -217,7 +217,7 @@ public: virtual void mouse_warp_to_position(const Point2i &p_to) override; virtual Point2i mouse_get_position() const override; virtual Point2i mouse_get_absolute_position() const override; - virtual int mouse_get_button_state() const override; + virtual MouseButton mouse_get_button_state() const override; virtual void clipboard_set(const String &p_text) override; virtual String clipboard_get() const override; @@ -232,7 +232,7 @@ public: virtual Vector<int> get_window_list() const override; - virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; virtual void show_window(WindowID p_id) override; virtual void delete_sub_window(WindowID p_id) override; @@ -286,6 +286,9 @@ public: virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual Point2i ime_get_selection() const override; virtual String ime_get_text() const override; @@ -314,12 +317,12 @@ public: virtual void console_set_visible(bool p_enabled) override; virtual bool is_console_visible() const override; - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_osx_driver(); - DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); ~DisplayServerOSX(); }; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 408feb4db9..dec6da42fe 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -119,7 +119,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { if ([event type] == NSEventTypeKeyDown) { if (([event modifierFlags] & NSEventModifierFlagCommand) && [event keyCode] == 0x2f) { Ref<InputEventKey> k; - k.instance(); + k.instantiate(); _get_key_modifier_state([event modifierFlags], k); k->set_window_id(DisplayServerOSX::INVALID_WINDOW_ID); @@ -813,18 +813,18 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; DS_OSX->cursor_set_shape(p_shape); } -static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, int index, int mask, bool pressed) { +static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, MouseButton index, MouseButton mask, bool pressed) { ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; if (pressed) { DS_OSX->last_button_state |= mask; } else { - DS_OSX->last_button_state &= ~mask; + DS_OSX->last_button_state &= (MouseButton)~mask; } Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_window_id(window_id); const Vector2 pos = _get_mouse_pos(wd, [event locationInWindow]); _get_key_modifier_state([event modifierFlags], mb); @@ -928,7 +928,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); mm->set_button_mask(DS_OSX->last_button_state); @@ -1016,7 +1016,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; Ref<InputEventMagnifyGesture> ev; - ev.instance(); + ev.instantiate(); ev->set_window_id(window_id); _get_key_modifier_state([event modifierFlags], ev); ev->set_position(_get_mouse_pos(wd, [event locationInWindow])); @@ -1485,14 +1485,14 @@ static int remapKey(unsigned int key, unsigned int state) { } } -inline void sendScrollEvent(DisplayServer::WindowID window_id, int button, double factor, int modifierFlags) { +inline void sendScrollEvent(DisplayServer::WindowID window_id, MouseButton button, double factor, int modifierFlags) { ERR_FAIL_COND(!DS_OSX->windows.has(window_id)); DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; - unsigned int mask = 1 << (button - 1); + MouseButton mask = MouseButton(1 << (button - 1)); Ref<InputEventMouseButton> sc; - sc.instance(); + sc.instantiate(); sc->set_window_id(window_id); _get_key_modifier_state(modifierFlags, sc); @@ -1501,19 +1501,19 @@ inline void sendScrollEvent(DisplayServer::WindowID window_id, int button, doubl sc->set_pressed(true); sc->set_position(wd.mouse_pos); sc->set_global_position(wd.mouse_pos); - DS_OSX->last_button_state |= mask; + DS_OSX->last_button_state |= (MouseButton)mask; sc->set_button_mask(DS_OSX->last_button_state); Input::get_singleton()->accumulate_input_event(sc); - sc.instance(); + sc.instantiate(); sc->set_window_id(window_id); sc->set_button_index(button); sc->set_factor(factor); sc->set_pressed(false); sc->set_position(wd.mouse_pos); sc->set_global_position(wd.mouse_pos); - DS_OSX->last_button_state &= ~mask; + DS_OSX->last_button_state &= (MouseButton)~mask; sc->set_button_mask(DS_OSX->last_button_state); Input::get_singleton()->accumulate_input_event(sc); @@ -1524,7 +1524,7 @@ inline void sendPanEvent(DisplayServer::WindowID window_id, double dx, double dy DisplayServerOSX::WindowData &wd = DS_OSX->windows[window_id]; Ref<InputEventPanGesture> pg; - pg.instance(); + pg.instantiate(); pg->set_window_id(window_id); _get_key_modifier_state(modifierFlags, pg); @@ -2120,6 +2120,12 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) { ignore_warp = true; warp_events.clear(); mouse_mode = p_mode; + + if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { + CursorShape p_shape = cursor_shape; + cursor_shape = DisplayServer::CURSOR_MAX; + cursor_set_shape(p_shape); + } } DisplayServer::MouseMode DisplayServerOSX::mouse_get_mode() const { @@ -2173,7 +2179,7 @@ Point2i DisplayServerOSX::mouse_get_absolute_position() const { return Vector2i(); } -int DisplayServerOSX::mouse_get_button_state() const { +MouseButton DisplayServerOSX::mouse_get_button_state() const { return last_button_state; } @@ -2382,10 +2388,10 @@ Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const { return ret; } -DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerOSX::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ - WindowID id = _create_window(p_mode, p_rect); + WindowID id = _create_window(p_mode, p_vsync_mode, p_rect); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); @@ -3375,7 +3381,7 @@ void DisplayServerOSX::_process_key_events() { const KeyEvent &ke = key_event_buffer[i]; if (ke.raw) { // Non IME input - no composite characters, pass events as is - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); _get_key_modifier_state(ke.osx_state, k); @@ -3389,7 +3395,7 @@ void DisplayServerOSX::_process_key_events() { } else { // IME input if ((i == 0 && ke.keycode == 0) || (i > 0 && key_event_buffer[i - 1].keycode == 0)) { - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); _get_key_modifier_state(ke.osx_state, k); @@ -3402,7 +3408,7 @@ void DisplayServerOSX::_process_key_events() { _push_input(k); } if (ke.keycode != 0) { - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); _get_key_modifier_state(ke.osx_state, k); @@ -3540,6 +3546,22 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { [nsimg release]; } +void DisplayServerOSX::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); +#endif +} + +DisplayServer::VSyncMode DisplayServerOSX::window_get_vsync_mode(WindowID p_window) const { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + return context_vulkan->get_vsync_mode(p_window); +#else + return DisplayServer::VSYNC_ENABLED; +#endif +} + Vector<String> DisplayServerOSX::get_rendering_drivers_func() { Vector<String> drivers; @@ -3590,15 +3612,15 @@ ObjectID DisplayServerOSX::window_get_attached_instance_id(WindowID p_window) co return windows[p_window].instance_id; } -DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerOSX::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerOSX(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { ds->alert("Your video card driver does not support any of the supported Metal versions.", "Unable to initialize Video driver"); } return ds; } -DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, const Rect2i &p_rect) { +DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect) { WindowID id; const float scale = screen_get_max_scale(); { @@ -3645,7 +3667,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, c #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { if (context_vulkan) { - Error err = context_vulkan->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height); + Error err = context_vulkan->window_create(window_id_counter, p_vsync_mode, wd.window_view, p_rect.size.width, p_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan context"); } } @@ -3744,7 +3766,7 @@ bool DisplayServerOSX::is_console_visible() const { return isatty(STDIN_FILENO); } -DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); r_error = OK; @@ -3755,7 +3777,6 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode key_event_pos = 0; mouse_mode = MOUSE_MODE_VISIBLE; - last_button_state = 0; autoreleasePool = [[NSAutoreleasePool alloc] init]; @@ -3881,7 +3902,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode Point2i window_position( screen_get_position(0).x + (screen_get_size(0).width - p_resolution.width) / 2, screen_get_position(0).y + (screen_get_size(0).height - p_resolution.height) / 2); - WindowID main_window = _create_window(p_mode, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, Rect2i(window_position, p_resolution)); ERR_FAIL_COND(main_window == INVALID_WINDOW_ID); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 6d995412ab..ea34b8a24e 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -31,11 +31,11 @@ #include "export.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/marshalls.h" #include "core/io/resource_saver.h" #include "core/io/zip_io.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/version.h" #include "editor/editor_export.h" @@ -147,6 +147,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_category", PROPERTY_HINT_ENUM, "Business,Developer-tools,Education,Entertainment,Finance,Games,Action-games,Adventure-games,Arcade-games,Board-games,Card-games,Casino-games,Dice-games,Educational-games,Family-games,Kids-games,Music-games,Puzzle-games,Racing-games,Role-playing-games,Simulation-games,Sports-games,Strategy-games,Trivia-games,Word-games,Graphics-design,Healthcare-fitness,Lifestyle,Medical,Music,News,Photography,Productivity,Reference,Social-networking,Sports,Travel,Utilities,Video,Weather"), "Games")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); @@ -162,9 +163,13 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/replace_existing_signature"), true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/custom_file", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false)); + if (!Engine::get_singleton()->has_singleton("GodotSharp")) { + // These entitlements are required to run managed code, and are always enabled in Mono builds. + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_jit_code_execution"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_unsigned_executable_memory"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/allow_dyld_environment_variables"), false)); + } + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/disable_library_validation"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/audio_input"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/entitlements/camera"), false)); @@ -386,6 +391,9 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n"; } else if (lines[i].find("$signature") != -1) { strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; + } else if (lines[i].find("$app_category") != -1) { + String cat = p_preset->get("application/app_category"); + strnew += lines[i].replace("$app_category", cat.to_lower()) + "\n"; } else if (lines[i].find("$copyright") != -1) { strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; } else if (lines[i].find("$highres") != -1) { @@ -696,7 +704,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } } else { Ref<Image> icon; - icon.instance(); + icon.instantiate(); icon->load(iconpath); if (!icon->is_empty()) { _make_icon(icon, data); @@ -782,18 +790,29 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p ent_f->store_line("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"); ent_f->store_line("<plist version=\"1.0\">"); ent_f->store_line("<dict>"); - if ((bool)p_preset->get("codesign/entitlements/allow_jit_code_execution")) { + if (Engine::get_singleton()->has_singleton("GodotSharp")) { + // These entitlements are required to run managed code, and are always enabled in Mono builds. ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>"); ent_f->store_line("<true/>"); - } - if ((bool)p_preset->get("codesign/entitlements/allow_unsigned_executable_memory")) { ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>"); ent_f->store_line("<true/>"); - } - if ((bool)p_preset->get("codesign/entitlements/allow_dyld_environment_variables")) { ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>"); ent_f->store_line("<true/>"); + } else { + if ((bool)p_preset->get("codesign/entitlements/allow_jit_code_execution")) { + ent_f->store_line("<key>com.apple.security.cs.allow-jit</key>"); + ent_f->store_line("<true/>"); + } + if ((bool)p_preset->get("codesign/entitlements/allow_unsigned_executable_memory")) { + ent_f->store_line("<key>com.apple.security.cs.allow-unsigned-executable-memory</key>"); + ent_f->store_line("<true/>"); + } + if ((bool)p_preset->get("codesign/entitlements/allow_dyld_environment_variables")) { + ent_f->store_line("<key>com.apple.security.cs.allow-dyld-environment-variables</key>"); + ent_f->store_line("<true/>"); + } } + if ((bool)p_preset->get("codesign/entitlements/disable_library_validation")) { ent_f->store_line("<key>com.apple.security.cs.disable-library-validation</key>"); ent_f->store_line("<true/>"); @@ -1000,9 +1019,9 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String zip_fileinfo zipfi; zipfi.tmz_date.tm_hour = time.hour; zipfi.tmz_date.tm_mday = date.day; - zipfi.tmz_date.tm_min = time.min; + zipfi.tmz_date.tm_min = time.minute; zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/ - zipfi.tmz_date.tm_sec = time.sec; + zipfi.tmz_date.tm_sec = time.second; zipfi.tmz_date.tm_year = date.year; zipfi.dosDate = 0; // 0120000: symbolic link type @@ -1045,9 +1064,9 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String zip_fileinfo zipfi; zipfi.tmz_date.tm_hour = time.hour; zipfi.tmz_date.tm_mday = date.day; - zipfi.tmz_date.tm_min = time.min; + zipfi.tmz_date.tm_min = time.minute; zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/ - zipfi.tmz_date.tm_sec = time.sec; + zipfi.tmz_date.tm_sec = time.second; zipfi.tmz_date.tm_year = date.year; zipfi.dosDate = 0; // 0100000: regular file type @@ -1147,7 +1166,7 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset EditorExportPlatformOSX::EditorExportPlatformOSX() { Ref<Image> img = memnew(Image(_osx_logo)); - logo.instance(); + logo.instantiate(); logo->create_from_image(img); } @@ -1156,7 +1175,7 @@ EditorExportPlatformOSX::~EditorExportPlatformOSX() { void register_osx_exporter() { Ref<EditorExportPlatformOSX> platform; - platform.instance(); + platform.instantiate(); EditorExport::get_singleton()->add_export_platform(platform); } diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp index b12526915f..126ebc1908 100644 --- a/platform/osx/joypad_osx.cpp +++ b/platform/osx/joypad_osx.cpp @@ -390,38 +390,38 @@ bool joypad::check_ff_features() { static int process_hat_value(int p_min, int p_max, int p_value) { int range = (p_max - p_min + 1); int value = p_value - p_min; - int hat_value = Input::HAT_MASK_CENTER; + int hat_value = HatMask::HAT_MASK_CENTER; if (range == 4) { value *= 2; } switch (value) { case 0: - hat_value = Input::HAT_MASK_UP; + hat_value = (HatMask)HatMask::HAT_MASK_UP; break; case 1: - hat_value = Input::HAT_MASK_UP | Input::HAT_MASK_RIGHT; + hat_value = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_RIGHT); break; case 2: - hat_value = Input::HAT_MASK_RIGHT; + hat_value = (HatMask)HatMask::HAT_MASK_RIGHT; break; case 3: - hat_value = Input::HAT_MASK_DOWN | Input::HAT_MASK_RIGHT; + hat_value = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_RIGHT); break; case 4: - hat_value = Input::HAT_MASK_DOWN; + hat_value = (HatMask)HatMask::HAT_MASK_DOWN; break; case 5: - hat_value = Input::HAT_MASK_DOWN | Input::HAT_MASK_LEFT; + hat_value = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_LEFT); break; case 6: - hat_value = Input::HAT_MASK_LEFT; + hat_value = (HatMask)HatMask::HAT_MASK_LEFT; break; case 7: - hat_value = Input::HAT_MASK_UP | Input::HAT_MASK_LEFT; + hat_value = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_LEFT); break; default: - hat_value = Input::HAT_MASK_CENTER; + hat_value = (HatMask)HatMask::HAT_MASK_CENTER; break; } return hat_value; @@ -458,17 +458,17 @@ void JoypadOSX::process_joypads() { for (int j = 0; j < joy.axis_elements.size(); j++) { rec_element &elem = joy.axis_elements.write[j]; int value = joy.get_hid_element_state(&elem); - input->joy_axis(joy.id, j, axis_correct(value, elem.min, elem.max)); + input->joy_axis(joy.id, (JoyAxis)j, axis_correct(value, elem.min, elem.max)); } for (int j = 0; j < joy.button_elements.size(); j++) { int value = joy.get_hid_element_state(&joy.button_elements.write[j]); - input->joy_button(joy.id, j, (value >= 1)); + input->joy_button(joy.id, (JoyButton)j, (value >= 1)); } for (int j = 0; j < joy.hat_elements.size(); j++) { rec_element &elem = joy.hat_elements.write[j]; int value = joy.get_hid_element_state(&elem); int hat_value = process_hat_value(elem.min, elem.max, value); - input->joy_hat(joy.id, hat_value); + input->joy_hat(joy.id, (HatMask)hat_value); } if (joy.ffservice) { diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 9e3f0350e9..b65d84d900 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -190,7 +190,7 @@ MainLoop *OS_OSX::get_main_loop() const { String OS_OSX::get_config_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_CONFIG_HOME")) { - if (get_environment("XDG_CONFIG_HOME").is_abs_path()) { + if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { return get_environment("XDG_CONFIG_HOME"); } else { WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/Library/Application Support` or `.` per the XDG Base Directory specification."); @@ -205,7 +205,7 @@ String OS_OSX::get_config_path() const { String OS_OSX::get_data_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_DATA_HOME")) { - if (get_environment("XDG_DATA_HOME").is_abs_path()) { + if (get_environment("XDG_DATA_HOME").is_absolute_path()) { return get_environment("XDG_DATA_HOME"); } else { WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification."); @@ -217,7 +217,7 @@ String OS_OSX::get_data_path() const { String OS_OSX::get_cache_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on macOS as well. if (has_environment("XDG_CACHE_HOME")) { - if (get_environment("XDG_CACHE_HOME").is_abs_path()) { + if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { return get_environment("XDG_CACHE_HOME"); } else { WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/Libary/Caches` or `get_config_path()` per the XDG Base Directory specification."); diff --git a/platform/osx/vulkan_context_osx.h b/platform/osx/vulkan_context_osx.h index 8b6a75adfb..22d43688a3 100644 --- a/platform/osx/vulkan_context_osx.h +++ b/platform/osx/vulkan_context_osx.h @@ -38,7 +38,7 @@ class VulkanContextOSX : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - Error window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height); VulkanContextOSX(); ~VulkanContextOSX(); diff --git a/platform/osx/vulkan_context_osx.mm b/platform/osx/vulkan_context_osx.mm index 6b87fbd489..7e18e177c1 100644 --- a/platform/osx/vulkan_context_osx.mm +++ b/platform/osx/vulkan_context_osx.mm @@ -35,7 +35,7 @@ const char *VulkanContextOSX::_get_platform_surface_extension() const { return VK_MVK_MACOS_SURFACE_EXTENSION_NAME; } -Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_window, int p_width, int p_height) { +Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, id p_window, int p_width, int p_height) { VkMacOSSurfaceCreateInfoMVK createInfo; createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; createInfo.pNext = nullptr; @@ -45,7 +45,7 @@ Error VulkanContextOSX::window_create(DisplayServer::WindowID p_window_id, id p_ VkSurfaceKHR surface; VkResult err = vkCreateMacOSSurfaceMVK(_get_instance(), &createInfo, nullptr, &surface); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - return _window_create(p_window_id, surface, p_width, p_height); + return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } VulkanContextOSX::VulkanContextOSX() { diff --git a/platform/uwp/app.cpp b/platform/uwp/app.cpp index bac8620086..1da17ffc5d 100644 --- a/platform/uwp/app.cpp +++ b/platform/uwp/app.cpp @@ -34,8 +34,8 @@ #include "app.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/os/keyboard.h" #include "main/main.h" @@ -145,7 +145,7 @@ void App::SetWindow(CoreWindow ^ p_window) { Main::setup2(); } -static int _get_button(Windows::UI::Input::PointerPoint ^ pt) { +static MouseButton _get_button(Windows::UI::Input::PointerPoint ^ pt) { using namespace Windows::UI::Input; #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP @@ -177,7 +177,7 @@ static int _get_button(Windows::UI::Input::PointerPoint ^ pt) { } #endif - return 0; + return MOUSE_BUTTON_NONE; }; static bool _is_touch(Windows::UI::Input::PointerPoint ^ pointerPoint) { @@ -241,10 +241,10 @@ static int _get_finger(uint32_t p_touch_id) { void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::PointerEventArgs ^ args, bool p_pressed, bool p_is_wheel) { Windows::UI::Input::PointerPoint ^ point = args->CurrentPoint; Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os); - int but = _get_button(point); + MouseButton but = _get_button(point); if (_is_touch(point)) { Ref<InputEventScreenTouch> screen_touch; - screen_touch.instance(); + screen_touch.instantiate(); screen_touch->set_device(0); screen_touch->set_pressed(p_pressed); screen_touch->set_position(Vector2(pos.X, pos.Y)); @@ -256,7 +256,7 @@ void App::pointer_event(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Cor os->input_event(screen_touch); } else { Ref<InputEventMouseButton> mouse_button; - mouse_button.instance(); + mouse_button.instantiate(); mouse_button->set_device(0); mouse_button->set_pressed(p_pressed); mouse_button->set_button_index(but); @@ -324,7 +324,7 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co if (_is_touch(point)) { Ref<InputEventScreenDrag> screen_drag; - screen_drag.instance(); + screen_drag.instantiate(); screen_drag->set_device(0); screen_drag->set_position(Vector2(pos.X, pos.Y)); screen_drag->set_index(_get_finger(point->PointerId)); @@ -338,7 +338,7 @@ void App::OnPointerMoved(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Co } Ref<InputEventMouseMotion> mouse_motion; - mouse_motion.instance(); + mouse_motion.instantiate(); mouse_motion->set_device(0); mouse_motion->set_position(Vector2(pos.X, pos.Y)); mouse_motion->set_global_position(Vector2(pos.X, pos.Y)); @@ -361,7 +361,7 @@ void App::OnMouseMoved(MouseDevice ^ mouse_device, MouseEventArgs ^ args) { pos.Y = last_mouse_pos.Y + args->MouseDelta.Y; Ref<InputEventMouseMotion> mouse_motion; - mouse_motion.instance(); + mouse_motion.instantiate(); mouse_motion->set_device(0); mouse_motion->set_position(Vector2(pos.X, pos.Y)); mouse_motion->set_global_position(Vector2(pos.X, pos.Y)); diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp index 351aaa5957..1075ae38ce 100644 --- a/platform/uwp/export/export.cpp +++ b/platform/uwp/export/export.cpp @@ -33,11 +33,11 @@ #include "core/config/project_settings.h" #include "core/core_bind.h" #include "core/crypto/crypto_core.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/marshalls.h" #include "core/io/zip_io.h" #include "core/object/class_db.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/version.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -1049,19 +1049,19 @@ public: // Capabilities const char **basic = uwp_capabilities; while (*basic) { - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic).camelcase_to_underscore(false)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*basic)), false)); basic++; } const char **uap = uwp_uap_capabilities; while (*uap) { - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap).camelcase_to_underscore(false)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*uap)), false)); uap++; } const char **device = uwp_device_capabilities; while (*device) { - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device).camelcase_to_underscore(false)), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/" + String(*device)), false)); device++; } } @@ -1429,7 +1429,7 @@ public: EditorExportPlatformUWP() { Ref<Image> img = memnew(Image(_uwp_logo)); - logo.instance(); + logo.instantiate(); logo->create_from_image(img); } }; @@ -1446,6 +1446,6 @@ void register_uwp_exporter() { #endif // WINDOWS_ENABLED Ref<EditorExportPlatformUWP> exporter; - exporter.instance(); + exporter.instantiate(); EditorExport::get_singleton()->add_export_platform(exporter); } diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 65934b6681..e26e204f5f 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -126,8 +126,6 @@ void OS_UWP::set_keep_screen_on(bool p_enabled) { } void OS_UWP::initialize_core() { - last_button_state = 0; - //RedirectIOToConsole(); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); @@ -423,7 +421,7 @@ Point2 OS_UWP::get_mouse_position() const { return Point2(old_x, old_y); } -int OS_UWP::get_mouse_button_state() const { +MouseButton OS_UWP::get_mouse_button_state() const { return last_button_state; } @@ -562,7 +560,7 @@ void OS_UWP::process_key_events() { KeyEvent &kev = key_event_buffer[i]; Ref<InputEventKey> key_event; - key_event.instance(); + key_event.instantiate(); key_event->set_alt_pressed(kev.alt); key_event->set_shift_pressed(kev.shift); key_event->set_ctrl_pressed(kev.control); diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index a4d3d6d52a..3a735889b0 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -106,7 +106,7 @@ private: bool control_mem; bool meta_mem; bool force_quit; - uint32_t last_button_state; + MouseButton last_button_state = MOUSE_BUTTON_NONE; CursorShape cursor_shape; @@ -173,7 +173,7 @@ public: MouseMode get_mouse_mode() const; virtual Point2 get_mouse_position() const; - virtual int get_mouse_button_state() const; + virtual MouseButton get_mouse_button_state() const; virtual void set_window_title(const String &p_title); virtual void set_video_mode(const VideoMode &p_video_mode, int p_screen = 0); diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp index 207b0a1168..74b12cbb3b 100644 --- a/platform/windows/context_gl_windows.cpp +++ b/platform/windows/context_gl_windows.cpp @@ -66,46 +66,13 @@ int ContextGL_Windows::get_window_height() { return OS::get_singleton()->get_video_mode().height; } -bool ContextGL_Windows::should_vsync_via_compositor() { - if (OS::get_singleton()->is_window_fullscreen() || !OS::get_singleton()->is_vsync_via_compositor_enabled()) { - return false; - } - - // Note: All Windows versions supported by Godot have a compositor. - // It can be disabled on earlier Windows versions. - BOOL dwm_enabled; - - if (SUCCEEDED(DwmIsCompositionEnabled(&dwm_enabled))) { - return dwm_enabled; - } - - return false; -} - void ContextGL_Windows::swap_buffers() { SwapBuffers(hDC); - - if (use_vsync) { - bool vsync_via_compositor_now = should_vsync_via_compositor(); - - if (vsync_via_compositor_now && wglGetSwapIntervalEXT() == 0) { - DwmFlush(); - } - - if (vsync_via_compositor_now != vsync_via_compositor) { - // The previous frame had a different operating mode than this - // frame. Set the 'vsync_via_compositor' member variable and the - // OpenGL swap interval to their proper values. - set_use_vsync(true); - } - } } void ContextGL_Windows::set_use_vsync(bool p_use) { - vsync_via_compositor = p_use && should_vsync_via_compositor(); - if (wglSwapIntervalEXT) { - int swap_interval = (p_use && !vsync_via_compositor) ? 1 : 0; + int swap_interval = p_use ? 1 : 0; wglSwapIntervalEXT(swap_interval); } @@ -210,7 +177,6 @@ ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) { opengl_3_context = p_opengl_3_context; hWnd = hwnd; use_vsync = false; - vsync_via_compositor = false; pixel_format = 0; } diff --git a/platform/windows/context_gl_windows.h b/platform/windows/context_gl_windows.h index e44e2945ca..c8e8a0891d 100644 --- a/platform/windows/context_gl_windows.h +++ b/platform/windows/context_gl_windows.h @@ -50,13 +50,10 @@ class ContextGL_Windows { HWND hWnd; bool opengl_3_context; bool use_vsync; - bool vsync_via_compositor; PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; - static bool should_vsync_via_compositor(); - public: void release_current(); diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 03ccf6c059..4f64809abc 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -161,7 +161,7 @@ Point2i DisplayServerWindows::mouse_get_position() const { //return Point2(old_x, old_y); } -int DisplayServerWindows::mouse_get_button_state() const { +MouseButton DisplayServerWindows::mouse_get_button_state() const { return last_button_state; } @@ -477,10 +477,10 @@ DisplayServer::WindowID DisplayServerWindows::get_window_at_screen_position(cons return INVALID_WINDOW_ID; } -DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ - WindowID window_id = _create_window(p_mode, p_flags, p_rect); + WindowID window_id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); ERR_FAIL_COND_V_MSG(window_id == INVALID_WINDOW_ID, INVALID_WINDOW_ID, "Failed to create sub window."); WindowData &wd = windows[window_id]; @@ -1697,11 +1697,20 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) { SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon); } -void DisplayServerWindows::vsync_set_use_via_compositor(bool p_enable) { +void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); +#endif } -bool DisplayServerWindows::vsync_is_using_via_compositor() const { - return false; +DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + return context_vulkan->get_vsync_mode(p_window); +#else + return DisplayServer::VSYNC_ENABLED; +#endif } void DisplayServerWindows::set_context(Context p_context) { @@ -1727,7 +1736,7 @@ void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float } Ref<InputEventScreenTouch> event; - event.instance(); + event.instantiate(); event->set_index(idx); event->set_window_id(p_window); event->set_pressed(p_pressed); @@ -1746,7 +1755,7 @@ void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, return; Ref<InputEventScreenDrag> event; - event.instance(); + event.instantiate(); event->set_window_id(p_window); event->set_index(idx); event->set_position(Vector2(p_x, p_y)); @@ -1891,7 +1900,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA // Run a timer to prevent event catching warning if the focused window is closing. windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr); } - return 0; // Return To The Message Loop + return 0; // Return To The Message Loop } case WM_GETMINMAXINFO: { if (windows[window_id].resizable && !windows[window_id].fullscreen) { @@ -1965,7 +1974,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (raw->header.dwType == RIM_TYPEMOUSE) { Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); mm->set_ctrl_pressed(control_mem); @@ -2062,7 +2071,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA break; Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); mm->set_ctrl_pressed(GetKeyState(VK_CONTROL) < 0); mm->set_shift_pressed(GetKeyState(VK_SHIFT) < 0); @@ -2196,7 +2205,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); if (pen_info.penMask & PEN_MASK_PRESSURE) { @@ -2302,7 +2311,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); mm->set_ctrl_pressed((wParam & MK_CONTROL) != 0); mm->set_shift_pressed((wParam & MK_SHIFT) != 0); @@ -2385,47 +2394,47 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA case WM_XBUTTONDOWN: case WM_XBUTTONUP: { Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_window_id(window_id); switch (uMsg) { case WM_LBUTTONDOWN: { mb->set_pressed(true); - mb->set_button_index(1); + mb->set_button_index(MOUSE_BUTTON_LEFT); } break; case WM_LBUTTONUP: { mb->set_pressed(false); - mb->set_button_index(1); + mb->set_button_index(MOUSE_BUTTON_LEFT); } break; case WM_MBUTTONDOWN: { mb->set_pressed(true); - mb->set_button_index(3); + mb->set_button_index(MOUSE_BUTTON_MIDDLE); } break; case WM_MBUTTONUP: { mb->set_pressed(false); - mb->set_button_index(3); + mb->set_button_index(MOUSE_BUTTON_MIDDLE); } break; case WM_RBUTTONDOWN: { mb->set_pressed(true); - mb->set_button_index(2); + mb->set_button_index(MOUSE_BUTTON_RIGHT); } break; case WM_RBUTTONUP: { mb->set_pressed(false); - mb->set_button_index(2); + mb->set_button_index(MOUSE_BUTTON_RIGHT); } break; case WM_LBUTTONDBLCLK: { mb->set_pressed(true); - mb->set_button_index(1); + mb->set_button_index(MOUSE_BUTTON_LEFT); mb->set_double_click(true); } break; case WM_RBUTTONDBLCLK: { mb->set_pressed(true); - mb->set_button_index(2); + mb->set_button_index(MOUSE_BUTTON_RIGHT); mb->set_double_click(true); } break; case WM_MBUTTONDBLCLK: { mb->set_pressed(true); - mb->set_button_index(3); + mb->set_button_index(MOUSE_BUTTON_MIDDLE); mb->set_double_click(true); } break; case WM_MOUSEWHEEL: { @@ -2492,9 +2501,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA mb->set_alt_pressed(alt_mem); //mb->is_alt_pressed()=(wParam&MK_MENU)!=0; if (mb->is_pressed()) { - last_button_state |= (1 << (mb->get_button_index() - 1)); + last_button_state |= MouseButton(1 << (mb->get_button_index() - 1)); } else { - last_button_state &= ~(1 << (mb->get_button_index() - 1)); + last_button_state &= (MouseButton) ~(1 << (mb->get_button_index() - 1)); } mb->set_button_mask(last_button_state); @@ -2534,7 +2543,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA //send release for mouse wheel Ref<InputEventMouseButton> mbd = mb->duplicate(); mbd->set_window_id(window_id); - last_button_state &= ~(1 << (mbd->get_button_index() - 1)); + last_button_state &= (MouseButton) ~(1 << (mbd->get_button_index() - 1)); mbd->set_button_mask(last_button_state); mbd->set_pressed(false); Input::get_singleton()->accumulate_input_event(mbd); @@ -2843,7 +2852,7 @@ void DisplayServerWindows::_process_key_events() { prev_wc = 0; } Ref<InputEventKey> k; - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); k->set_shift_pressed(ke.shift); @@ -2870,7 +2879,7 @@ void DisplayServerWindows::_process_key_events() { case WM_KEYUP: case WM_KEYDOWN: { Ref<InputEventKey> k; - k.instance(); + k.instantiate(); k->set_window_id(ke.window_id); k->set_shift_pressed(ke.shift); @@ -2968,7 +2977,7 @@ void DisplayServerWindows::_update_tablet_ctx(const String &p_old_driver, const } } -DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { DWORD dwExStyle; DWORD dwStyle; @@ -3030,7 +3039,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { - if (context_vulkan->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) { + if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) { memdelete(context_vulkan); context_vulkan = nullptr; windows.erase(id); @@ -3151,7 +3160,7 @@ void DisplayServerWindows::tablet_set_current_driver(const String &p_driver) { } } -DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { drop_events = false; key_event_pos = 0; @@ -3270,7 +3279,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } context_gles2->set_use_vsync(video_mode.use_vsync); - set_vsync_via_compositor(video_mode.vsync_via_compositor); if (RasterizerGLES2::is_viable() == OK) { RasterizerGLES2::register_config(); @@ -3286,7 +3294,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); - WindowID main_window = _create_window(p_mode, 0, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution)); ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window."); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { @@ -3347,8 +3355,8 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() { return drivers; } -DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerWindows(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n" "Please update your drivers or if you have a very old or integrated GPU upgrade it.", diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index a734077e59..394bed79b0 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -389,7 +389,7 @@ class DisplayServerWindows : public DisplayServer { JoypadWindows *joypad; - WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); WindowID window_id_counter = MAIN_WINDOW_ID; Map<WindowID, WindowData> windows; @@ -408,7 +408,7 @@ class DisplayServerWindows : public DisplayServer { bool shift_mem = false; bool control_mem = false; bool meta_mem = false; - uint32_t last_button_state = 0; + MouseButton last_button_state = MOUSE_BUTTON_NONE; bool use_raw_input = false; bool drop_events = false; bool in_dispatch_input_event = false; @@ -449,7 +449,7 @@ public: virtual void mouse_warp_to_position(const Point2i &p_to); virtual Point2i mouse_get_position() const; - virtual int mouse_get_button_state() const; + virtual MouseButton mouse_get_button_state() const; virtual void clipboard_set(const String &p_text); virtual String clipboard_get() const; @@ -469,7 +469,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const; - virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); virtual void show_window(WindowID p_window); virtual void delete_sub_window(WindowID p_window); @@ -525,6 +525,9 @@ public: virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; + virtual void console_set_visible(bool p_enabled); virtual bool is_console_visible() const; @@ -558,16 +561,13 @@ public: virtual void set_native_icon(const String &p_filename); virtual void set_icon(const Ref<Image> &p_icon); - virtual void vsync_set_use_via_compositor(bool p_enable); - virtual bool vsync_is_using_via_compositor() const; - virtual void set_context(Context p_context); - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_windows_driver(); - DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerWindows(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); ~DisplayServerWindows(); }; diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 222597b3ff..10f953f2ec 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/os.h" #include "editor/editor_export.h" #include "editor/editor_node.h" @@ -310,7 +310,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p args.push_back(p_path); #ifndef WINDOWS_ENABLED args.push_back("-out"); - args.push_back(p_path); + args.push_back(p_path + "_signed"); #endif String str; @@ -326,6 +326,16 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p return FAILED; } +#ifndef WINDOWS_ENABLED + DirAccessRef tmp_dir = DirAccess::create_for_path(p_path.get_base_dir()); + + err = tmp_dir->remove(p_path); + ERR_FAIL_COND_V(err != OK, err); + + err = tmp_dir->rename(p_path + "_signed", p_path); + ERR_FAIL_COND_V(err != OK, err); +#endif + return OK; } @@ -344,11 +354,11 @@ void register_windows_exporter() { #endif Ref<EditorExportPlatformWindows> platform; - platform.instance(); + platform.instantiate(); Ref<Image> img = memnew(Image(_windows_logo)); Ref<ImageTexture> logo; - logo.instance(); + logo.instantiate(); logo->create_from_image(img); platform->set_logo(logo); platform->set_name("Windows Desktop"); diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis index 857c6a88f1..bb855e4ac8 100644 --- a/platform/windows/godot.natvis +++ b/platform/windows/godot.natvis @@ -40,13 +40,13 @@ <DisplayString Condition="type == Variant::TRANSFORM2D">{_data._transform2d}</DisplayString> <DisplayString Condition="type == Variant::AABB">{_data._aabb}</DisplayString> <DisplayString Condition="type == Variant::BASIS">{_data._basis}</DisplayString> - <DisplayString Condition="type == Variant::TRANSFORM">{_data._transform}</DisplayString> + <DisplayString Condition="type == Variant::TRANSFORM3D">{_data._transform}</DisplayString> <DisplayString Condition="type == Variant::STRING">{*(String *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR2">{*(Vector2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::RECT2">{*(Rect2 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::VECTOR3">{*(Vector3 *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::PLANE">{*(Plane *)_data._mem}</DisplayString> - <DisplayString Condition="type == Variant::QUAT">{*(Quat *)_data._mem}</DisplayString> + <DisplayString Condition="type == Variant::QUATERNION">{*(Quaternion *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::COLOR">{*(Color *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::NODE_PATH">{*(NodePath *)_data._mem}</DisplayString> <DisplayString Condition="type == Variant::RID">{*(::RID *)_data._mem}</DisplayString> @@ -72,13 +72,13 @@ <Item Name="[value]" Condition="type == Variant::TRANSFORM2D">_data._transform2d</Item> <Item Name="[value]" Condition="type == Variant::AABB">_data._aabb</Item> <Item Name="[value]" Condition="type == Variant::BASIS">_data._basis</Item> - <Item Name="[value]" Condition="type == Variant::TRANSFORM">_data._transform</Item> + <Item Name="[value]" Condition="type == Variant::TRANSFORM3D">_data._transform</Item> <Item Name="[value]" Condition="type == Variant::STRING">*(String *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::VECTOR2">*(Vector2 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::RECT2">*(Rect2 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::VECTOR3">*(Vector3 *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::PLANE">*(Plane *)_data._mem</Item> - <Item Name="[value]" Condition="type == Variant::QUAT">*(Quat *)_data._mem</Item> + <Item Name="[value]" Condition="type == Variant::QUATERNION">*(Quaternion *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::COLOR">*(Color *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::NODE_PATH">*(NodePath *)_data._mem</Item> <Item Name="[value]" Condition="type == Variant::RID">*(::RID *)_data._mem</Item> @@ -128,8 +128,8 @@ </Expand> </Type> - <Type Name="Quat"> - <DisplayString>Quat {{{x},{y},{z},{w}}}</DisplayString> + <Type Name="Quaternion"> + <DisplayString>Quaternion {{{x},{y},{z},{w}}}</DisplayString> <Expand> <Item Name="x">x</Item> <Item Name="y">y</Item> diff --git a/platform/windows/joypad_windows.cpp b/platform/windows/joypad_windows.cpp index da36dc1f2b..94da63e49d 100644 --- a/platform/windows/joypad_windows.cpp +++ b/platform/windows/joypad_windows.cpp @@ -330,7 +330,7 @@ void JoypadWindows::process_joypads() { if (joy.state.dwPacketNumber != joy.last_packet) { int button_mask = XINPUT_GAMEPAD_DPAD_UP; for (int j = 0; j <= 16; j++) { - input->joy_button(joy.id, j, joy.state.Gamepad.wButtons & button_mask); + input->joy_button(joy.id, (JoyButton)j, joy.state.Gamepad.wButtons & button_mask); button_mask = button_mask * 2; } @@ -381,12 +381,12 @@ void JoypadWindows::process_joypads() { for (int j = 0; j < 128; j++) { if (js.rgbButtons[j] & 0x80) { if (!joy->last_buttons[j]) { - input->joy_button(joy->id, j, true); + input->joy_button(joy->id, (JoyButton)j, true); joy->last_buttons[j] = true; } } else { if (joy->last_buttons[j]) { - input->joy_button(joy->id, j, false); + input->joy_button(joy->id, (JoyButton)j, false); joy->last_buttons[j] = false; } } @@ -400,7 +400,7 @@ void JoypadWindows::process_joypads() { for (int j = 0; j < joy->joy_axis.size(); j++) { for (int k = 0; k < count; k++) { if (joy->joy_axis[j] == axes[k]) { - input->joy_axis(joy->id, j, axis_correct(values[k])); + input->joy_axis(joy->id, (JoyAxis)j, axis_correct(values[k])); break; }; }; @@ -410,38 +410,38 @@ void JoypadWindows::process_joypads() { } void JoypadWindows::post_hat(int p_device, DWORD p_dpad) { - int dpad_val = 0; + HatMask dpad_val = (HatMask)0; // Should be -1 when centered, but according to docs: // "Some drivers report the centered position of the POV indicator as 65,535. Determine whether the indicator is centered as follows: // BOOL POVCentered = (LOWORD(dwPOV) == 0xFFFF);" // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ee416628(v%3Dvs.85)#remarks if (LOWORD(p_dpad) == 0xFFFF) { - dpad_val = Input::HAT_MASK_CENTER; + dpad_val = (HatMask)HatMask::HAT_MASK_CENTER; } if (p_dpad == 0) { - dpad_val = Input::HAT_MASK_UP; + dpad_val = (HatMask)HatMask::HAT_MASK_UP; } else if (p_dpad == 4500) { - dpad_val = (Input::HAT_MASK_UP | Input::HAT_MASK_RIGHT); + dpad_val = (HatMask)(HatMask::HAT_MASK_UP | HatMask::HAT_MASK_RIGHT); } else if (p_dpad == 9000) { - dpad_val = Input::HAT_MASK_RIGHT; + dpad_val = (HatMask)HatMask::HAT_MASK_RIGHT; } else if (p_dpad == 13500) { - dpad_val = (Input::HAT_MASK_RIGHT | Input::HAT_MASK_DOWN); + dpad_val = (HatMask)(HatMask::HAT_MASK_RIGHT | HatMask::HAT_MASK_DOWN); } else if (p_dpad == 18000) { - dpad_val = Input::HAT_MASK_DOWN; + dpad_val = (HatMask)HatMask::HAT_MASK_DOWN; } else if (p_dpad == 22500) { - dpad_val = (Input::HAT_MASK_DOWN | Input::HAT_MASK_LEFT); + dpad_val = (HatMask)(HatMask::HAT_MASK_DOWN | HatMask::HAT_MASK_LEFT); } else if (p_dpad == 27000) { - dpad_val = Input::HAT_MASK_LEFT; + dpad_val = (HatMask)HatMask::HAT_MASK_LEFT; } else if (p_dpad == 31500) { - dpad_val = (Input::HAT_MASK_LEFT | Input::HAT_MASK_UP); + dpad_val = (HatMask)(HatMask::HAT_MASK_LEFT | HatMask::HAT_MASK_UP); } input->joy_hat(p_device, dpad_val); }; diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index ccf13488ab..56d673afc3 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -315,8 +315,8 @@ OS::Time OS_Windows::get_time(bool utc) const { Time time; time.hour = systemtime.wHour; - time.min = systemtime.wMinute; - time.sec = systemtime.wSecond; + time.minute = systemtime.wMinute; + time.second = systemtime.wSecond; return time; } @@ -633,14 +633,14 @@ MainLoop *OS_Windows::get_main_loop() const { String OS_Windows::get_config_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. if (has_environment("XDG_CONFIG_HOME")) { - if (get_environment("XDG_CONFIG_HOME").is_abs_path()) { - return get_environment("XDG_CONFIG_HOME"); + if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { + return get_environment("XDG_CONFIG_HOME").replace("\\", "/"); } else { WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `%APPDATA%` or `.` per the XDG Base Directory specification."); } } if (has_environment("APPDATA")) { - return get_environment("APPDATA"); + return get_environment("APPDATA").replace("\\", "/"); } return "."; } @@ -648,8 +648,8 @@ String OS_Windows::get_config_path() const { String OS_Windows::get_data_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. if (has_environment("XDG_DATA_HOME")) { - if (get_environment("XDG_DATA_HOME").is_abs_path()) { - return get_environment("XDG_DATA_HOME"); + if (get_environment("XDG_DATA_HOME").is_absolute_path()) { + return get_environment("XDG_DATA_HOME").replace("\\", "/"); } else { WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `get_config_path()` per the XDG Base Directory specification."); } @@ -660,14 +660,14 @@ String OS_Windows::get_data_path() const { String OS_Windows::get_cache_path() const { // The XDG Base Directory specification technically only applies on Linux/*BSD, but it doesn't hurt to support it on Windows as well. if (has_environment("XDG_CACHE_HOME")) { - if (get_environment("XDG_CACHE_HOME").is_abs_path()) { - return get_environment("XDG_CACHE_HOME"); + if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { + return get_environment("XDG_CACHE_HOME").replace("\\", "/"); } else { WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `%TEMP%` or `get_config_path()` per the XDG Base Directory specification."); } } if (has_environment("TEMP")) { - return get_environment("TEMP"); + return get_environment("TEMP").replace("\\", "/"); } return get_config_path(); } @@ -710,7 +710,7 @@ String OS_Windows::get_system_dir(SystemDir p_dir) const { PWSTR szPath; HRESULT res = SHGetKnownFolderPath(id, 0, nullptr, &szPath); ERR_FAIL_COND_V(res != S_OK, String()); - String path = String::utf16((const char16_t *)szPath); + String path = String::utf16((const char16_t *)szPath).replace("\\", "/"); CoTaskMemFree(szPath); return path; } diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp index e5e176ab93..191792b329 100644 --- a/platform/windows/vulkan_context_win.cpp +++ b/platform/windows/vulkan_context_win.cpp @@ -35,18 +35,17 @@ const char *VulkanContextWindows::_get_platform_surface_extension() const { return VK_KHR_WIN32_SURFACE_EXTENSION_NAME; } -int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) { +int VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height) { VkWin32SurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; createInfo.flags = 0; createInfo.hinstance = p_instance; createInfo.hwnd = p_window; - VkSurfaceKHR surface; VkResult err = vkCreateWin32SurfaceKHR(_get_instance(), &createInfo, nullptr, &surface); ERR_FAIL_COND_V(err, -1); - return _window_create(p_window_id, surface, p_width, p_height); + return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } VulkanContextWindows::VulkanContextWindows() { diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/vulkan_context_win.h index 4fe987218d..39dd2641fd 100644 --- a/platform/windows/vulkan_context_win.h +++ b/platform/windows/vulkan_context_win.h @@ -38,7 +38,7 @@ class VulkanContextWindows : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - int window_create(DisplayServer::WindowID p_window_id, HWND p_window, HINSTANCE p_instance, int p_width, int p_height); + int window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, HWND p_window, HINSTANCE p_instance, int p_width, int p_height); VulkanContextWindows(); ~VulkanContextWindows(); diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp index c1f3827d15..8cab7ca521 100644 --- a/platform/windows/windows_terminal_logger.cpp +++ b/platform/windows/windows_terminal_logger.cpp @@ -108,47 +108,47 @@ void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); switch (p_type) { case ERR_ERROR: - logf("ERROR:"); + logf_error("ERROR:"); break; case ERR_WARNING: - logf("WARNING:"); + logf_error("WARNING:"); break; case ERR_SCRIPT: - logf("SCRIPT ERROR:"); + logf_error("SCRIPT ERROR:"); break; case ERR_SHADER: - logf("SHADER ERROR:"); + logf_error("SHADER ERROR:"); break; } SetConsoleTextAttribute(hCon, basecol); if (p_rationale && p_rationale[0]) { - logf(" %s\n", p_rationale); + logf_error(" %s\n", p_rationale); } else { - logf(" %s\n", p_code); + logf_error(" %s\n", p_code); } // `FOREGROUND_INTENSITY` alone results in gray text. SetConsoleTextAttribute(hCon, FOREGROUND_INTENSITY); switch (p_type) { case ERR_ERROR: - logf(" at: "); + logf_error(" at: "); break; case ERR_WARNING: - logf(" at: "); + logf_error(" at: "); break; case ERR_SCRIPT: - logf(" at: "); + logf_error(" at: "); break; case ERR_SHADER: - logf(" at: "); + logf_error(" at: "); break; } if (p_rationale && p_rationale[0]) { - logf("(%s:%i)\n", p_file, p_line); + logf_error("(%s:%i)\n", p_file, p_line); } else { - logf("%s (%s:%i)\n", p_function, p_file, p_line); + logf_error("%s (%s:%i)\n", p_function, p_file, p_line); } SetConsoleTextAttribute(hCon, sbi.wAttributes); diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index 597693aa6a..cf84767151 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -551,7 +551,7 @@ void Area2D::_bind_methods() { ADD_GROUP("Physics Overrides", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_distance_scale", "get_gravity_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_vec"), "set_gravity_vector", "get_gravity_vector"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-4096,4096,0.001,or_lesser,or_greater"), "set_gravity", "get_gravity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 6d8d6058eb..860ccfec64 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -170,7 +170,6 @@ void AudioStreamPlayer2D::_notification(int p_what) { //update anything related to position first, if possible of course if (!output_ready.is_set()) { - List<Viewport *> viewports; Ref<World2D> world_2d = get_world_2d(); ERR_FAIL_COND(world_2d.is_null()); @@ -203,8 +202,9 @@ void AudioStreamPlayer2D::_notification(int p_what) { break; } - world_2d->get_viewport_list(&viewports); - for (List<Viewport *>::Element *E = viewports.front(); E; E = E->next()) { + const Set<Viewport *> viewports = world_2d->get_viewports(); + + for (Set<Viewport *>::Element *E = viewports.front(); E; E = E->next()) { Viewport *vp = E->get(); if (vp->is_audio_listener_2d()) { //compute matrix to convert to screen @@ -494,7 +494,7 @@ void AudioStreamPlayer2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "1,4096,1,or_greater"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "1,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index ca4b8d72a1..f293081987 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -178,20 +178,23 @@ Transform2D Camera2D::get_camera_transform() { } Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom); - if (screen_rect.position.x < limit[SIDE_LEFT]) { - screen_rect.position.x = limit[SIDE_LEFT]; - } - if (screen_rect.position.x + screen_rect.size.x > limit[SIDE_RIGHT]) { - screen_rect.position.x = limit[SIDE_RIGHT] - screen_rect.size.x; - } + if (!limit_smoothing_enabled) { + if (screen_rect.position.x < limit[SIDE_LEFT]) { + screen_rect.position.x = limit[SIDE_LEFT]; + } - if (screen_rect.position.y + screen_rect.size.y > limit[SIDE_BOTTOM]) { - screen_rect.position.y = limit[SIDE_BOTTOM] - screen_rect.size.y; - } + if (screen_rect.position.x + screen_rect.size.x > limit[SIDE_RIGHT]) { + screen_rect.position.x = limit[SIDE_RIGHT] - screen_rect.size.x; + } + + if (screen_rect.position.y + screen_rect.size.y > limit[SIDE_BOTTOM]) { + screen_rect.position.y = limit[SIDE_BOTTOM] - screen_rect.size.y; + } - if (screen_rect.position.y < limit[SIDE_TOP]) { - screen_rect.position.y = limit[SIDE_TOP]; + if (screen_rect.position.y < limit[SIDE_TOP]) { + screen_rect.position.y = limit[SIDE_TOP]; + } } if (offset != Vector2()) { @@ -724,7 +727,7 @@ void Camera2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback"); ADD_GROUP("Limit", "limit_"); diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 52eabefbcb..4de99959a3 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -81,7 +81,7 @@ TypedArray<String> CanvasModulate::get_configuration_warnings() const { get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); if (nodes.size() > 1) { - warnings.push_back(TTR("Only one visible CanvasModulate is allowed per scene (or set of instanced scenes). The first created one will work, while the rest will be ignored.")); + warnings.push_back(TTR("Only one visible CanvasModulate is allowed per scene (or set of instantiated scenes). The first created one will work, while the rest will be ignored.")); } } diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index de648d404c..93d154bb01 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -31,7 +31,6 @@ #include "collision_object_2d.h" #include "scene/scene_string_names.h" -#include "servers/physics_server_2d.h" void CollisionObject2D::_notification(int p_what) { switch (p_what) { @@ -44,16 +43,22 @@ void CollisionObject2D::_notification(int p_what) { PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform); } - RID space = get_world_2d()->get_space(); - if (area) { - PhysicsServer2D::get_singleton()->area_set_space(rid, space); - } else { - PhysicsServer2D::get_singleton()->body_set_space(rid, space); + bool disabled = !is_enabled(); + + if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { + _apply_disabled(); } - _update_pickable(); + if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { + RID space = get_world_2d()->get_space(); + if (area) { + PhysicsServer2D::get_singleton()->area_set_space(rid, space); + } else { + PhysicsServer2D::get_singleton()->body_set_space(rid, space); + } + } - //get space + _update_pickable(); } break; case NOTIFICATION_ENTER_CANVAS: { @@ -67,6 +72,7 @@ void CollisionObject2D::_notification(int p_what) { case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (only_update_transform_changes) { return; @@ -79,15 +85,22 @@ void CollisionObject2D::_notification(int p_what) { } else { PhysicsServer2D::get_singleton()->body_set_state(rid, PhysicsServer2D::BODY_STATE_TRANSFORM, global_transform); } - } break; + case NOTIFICATION_EXIT_TREE: { - if (area) { - PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); - } else { - PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + bool disabled = !is_enabled(); + + if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { + if (area) { + PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + } } + if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { + _apply_enabled(); + } } break; case NOTIFICATION_EXIT_CANVAS: { @@ -97,6 +110,14 @@ void CollisionObject2D::_notification(int p_what) { PhysicsServer2D::get_singleton()->body_attach_canvas_instance_id(rid, ObjectID()); } } break; + + case NOTIFICATION_DISABLED: { + _apply_disabled(); + } break; + + case NOTIFICATION_ENABLED: { + _apply_enabled(); + } break; } } @@ -158,6 +179,79 @@ bool CollisionObject2D::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } +void CollisionObject2D::set_disable_mode(DisableMode p_mode) { + if (disable_mode == p_mode) { + return; + } + + bool disabled = is_inside_tree() && !is_enabled(); + + if (disabled) { + // Cancel previous disable mode. + _apply_enabled(); + } + + disable_mode = p_mode; + + if (disabled) { + // Apply new disable mode. + _apply_disabled(); + } +} + +CollisionObject2D::DisableMode CollisionObject2D::get_disable_mode() const { + return disable_mode; +} + +void CollisionObject2D::_apply_disabled() { + switch (disable_mode) { + case DISABLE_MODE_REMOVE: { + if (is_inside_tree()) { + if (area) { + PhysicsServer2D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer2D::get_singleton()->body_set_space(rid, RID()); + } + } + } break; + + case DISABLE_MODE_MAKE_STATIC: { + if (!area && (body_mode != PhysicsServer2D::BODY_MODE_STATIC)) { + PhysicsServer2D::get_singleton()->body_set_mode(rid, PhysicsServer2D::BODY_MODE_STATIC); + } + } break; + + case DISABLE_MODE_KEEP_ACTIVE: { + // Nothing to do. + } break; + } +} + +void CollisionObject2D::_apply_enabled() { + switch (disable_mode) { + case DISABLE_MODE_REMOVE: { + if (is_inside_tree()) { + RID space = get_world_2d()->get_space(); + if (area) { + PhysicsServer2D::get_singleton()->area_set_space(rid, space); + } else { + PhysicsServer2D::get_singleton()->body_set_space(rid, space); + } + } + } break; + + case DISABLE_MODE_MAKE_STATIC: { + if (!area && (body_mode != PhysicsServer2D::BODY_MODE_STATIC)) { + PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode); + } + } break; + + case DISABLE_MODE_KEEP_ACTIVE: { + // Nothing to do. + } break; + } +} + uint32_t CollisionObject2D::create_shape_owner(Object *p_owner) { ShapeData sd; uint32_t id; @@ -408,6 +502,26 @@ void CollisionObject2D::set_only_update_transform_changes(bool p_enable) { only_update_transform_changes = p_enable; } +bool CollisionObject2D::is_only_update_transform_changes_enabled() const { + return only_update_transform_changes; +} + +void CollisionObject2D::set_body_mode(PhysicsServer2D::BodyMode p_mode) { + ERR_FAIL_COND(area); + + if (body_mode == p_mode) { + return; + } + + body_mode = p_mode; + + if (is_inside_tree() && !is_enabled() && (disable_mode == DISABLE_MODE_MAKE_STATIC)) { + return; + } + + PhysicsServer2D::get_singleton()->body_set_mode(rid, p_mode); +} + void CollisionObject2D::_update_pickable() { if (!is_inside_tree()) { return; @@ -441,6 +555,8 @@ void CollisionObject2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject2D::get_collision_layer_bit); ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject2D::set_collision_mask_bit); ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject2D::get_collision_mask_bit); + ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject2D::set_disable_mode); + ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject2D::get_disable_mode); ClassDB::bind_method(D_METHOD("set_pickable", "enabled"), &CollisionObject2D::set_pickable); ClassDB::bind_method(D_METHOD("is_pickable"), &CollisionObject2D::is_pickable); ClassDB::bind_method(D_METHOD("create_shape_owner", "owner"), &CollisionObject2D::create_shape_owner); @@ -469,12 +585,18 @@ void CollisionObject2D::_bind_methods() { ADD_SIGNAL(MethodInfo("mouse_entered")); ADD_SIGNAL(MethodInfo("mouse_exited")); + ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,MakeStatic,KeepActive"), "set_disable_mode", "get_disable_mode"); + ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_GROUP("Input", "input_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_pickable"), "set_pickable", "is_pickable"); + + BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE); + BIND_ENUM_CONSTANT(DISABLE_MODE_MAKE_STATIC); + BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); } CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { @@ -489,6 +611,7 @@ CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { PhysicsServer2D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id()); } else { PhysicsServer2D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id()); + PhysicsServer2D::get_singleton()->body_set_mode(rid, body_mode); } } diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index bb1a9dfcf5..7a71affbb5 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -33,10 +33,19 @@ #include "scene/2d/node_2d.h" #include "scene/resources/shape_2d.h" +#include "servers/physics_server_2d.h" class CollisionObject2D : public Node2D { GDCLASS(CollisionObject2D, Node2D); +public: + enum DisableMode { + DISABLE_MODE_REMOVE, + DISABLE_MODE_MAKE_STATIC, + DISABLE_MODE_KEEP_ACTIVE, + }; + +private: uint32_t collision_layer = 1; uint32_t collision_mask = 1; @@ -44,6 +53,10 @@ class CollisionObject2D : public Node2D { RID rid; bool pickable = false; + DisableMode disable_mode = DISABLE_MODE_REMOVE; + + PhysicsServer2D::BodyMode body_mode = PhysicsServer2D::BODY_MODE_STATIC; + struct ShapeData { Object *owner = nullptr; Transform2D xform; @@ -62,7 +75,10 @@ class CollisionObject2D : public Node2D { int total_subshapes = 0; Map<uint32_t, ShapeData> shapes; - bool only_update_transform_changes = false; //this is used for sync physics in KinematicBody + bool only_update_transform_changes = false; //this is used for sync physics in CharacterBody2D + + void _apply_disabled(); + void _apply_enabled(); protected: CollisionObject2D(RID p_rid, bool p_area); @@ -77,6 +93,9 @@ protected: void _mouse_exit(); void set_only_update_transform_changes(bool p_enable); + bool is_only_update_transform_changes_enabled() const; + + void set_body_mode(PhysicsServer2D::BodyMode p_mode); public: void set_collision_layer(uint32_t p_layer); @@ -91,6 +110,9 @@ public: void set_collision_mask_bit(int p_bit, bool p_value); bool get_collision_mask_bit(int p_bit) const; + void set_disable_mode(DisableMode p_mode); + DisableMode get_disable_mode() const; + uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); @@ -130,4 +152,6 @@ public: ~CollisionObject2D(); }; +VARIANT_ENUM_CAST(CollisionObject2D::DisableMode); + #endif // COLLISION_OBJECT_2D_H diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index a69ef73a54..2a2fde80e2 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -244,7 +244,7 @@ TypedArray<String> CollisionPolygon2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { - warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.")); + warnings.push_back(TTR("CollisionPolygon2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape.")); } int polygon_count = polygon.size(); diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index d9009ef85c..60780f1cc3 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -181,7 +181,7 @@ TypedArray<String> CollisionShape2D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { - warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape.")); + warnings.push_back(TTR("CollisionShape2D only serves to provide a collision shape to a CollisionObject2D derived node. Please only use it as a child of Area2D, StaticBody2D, RigidBody2D, CharacterBody2D, etc. to give them a shape.")); } if (!shape.is_valid()) { warnings.push_back(TTR("A shape must be provided for CollisionShape2D to function. Please create a shape resource for it!")); diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 1578643d14..24f3301ce1 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -464,31 +464,31 @@ Vector2 CPUParticles2D::get_gravity() const { void CPUParticles2D::_validate_property(PropertyInfo &property) const { if (property.name == "color" && color_ramp.is_valid()) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_rect_extents" && emission_shape != EMISSION_SHAPE_RECTANGLE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_points" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_colors" && emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -1202,7 +1202,7 @@ void CPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &CPUParticles2D::restart); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); @@ -1313,7 +1313,7 @@ void CPUParticles2D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); ADD_GROUP("Scale", ""); diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 066835ef0a..adfb94d574 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -115,7 +115,7 @@ void GPUParticles2D::set_use_local_coordinates(bool p_enable) { void GPUParticles2D::_update_particle_emission_transform() { Transform2D xf2d = get_global_transform(); - Transform xf; + Transform3D xf; xf.basis.set_axis(0, Vector3(xf2d.get_axis(0).x, xf2d.get_axis(0).y, 0)); xf.basis.set_axis(1, Vector3(xf2d.get_axis(1).x, xf2d.get_axis(1).y, 0)); xf.set_origin(Vector3(xf2d.get_origin().x, xf2d.get_origin().y, 0)); @@ -406,9 +406,9 @@ void GPUParticles2D::_notification(int p_what) { RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - Vector<Transform> xforms; + Vector<Transform3D> xforms; for (int i = 0; i <= trail_sections; i++) { - Transform xform; + Transform3D xform; /* xform.origin.y = depth / 2.0 - size.height * float(i); xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y */ @@ -446,12 +446,12 @@ void GPUParticles2D::_notification(int p_what) { arr[RS::ARRAY_INDEX] = indices; RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform>()); + RS::get_singleton()->particles_set_trail_bind_poses(particles, Vector<Transform3D>()); } RS::get_singleton()->canvas_item_add_particles(get_canvas_item(), particles, texture_rid); #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) { + if (Engine::get_singleton()->is_editor_hint() && (this == get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { draw_rect(visibility_rect, Color(0, 0.7, 0.9, 0.4), false); } #endif @@ -531,7 +531,7 @@ void GPUParticles2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_trail_section_subdivisions"), &GPUParticles2D::get_trail_section_subdivisions); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 8a4ccc2f96..dbba6917b5 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -274,7 +274,7 @@ void PinJoint2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_softness", "softness"), &PinJoint2D::set_softness); ClassDB::bind_method(D_METHOD("get_softness"), &PinJoint2D::get_softness); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_softness", "get_softness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "softness", PROPERTY_HINT_RANGE, "0.00,16,0.01,exp"), "set_softness", "get_softness"); } PinJoint2D::PinJoint2D() { @@ -336,8 +336,8 @@ void GrooveJoint2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_initial_offset", "offset"), &GrooveJoint2D::set_initial_offset); ClassDB::bind_method(D_METHOD("get_initial_offset"), &GrooveJoint2D::get_initial_offset); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_EXP_RANGE, "1,65535,1"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "initial_offset", PROPERTY_HINT_EXP_RANGE, "1,65535,1"), "set_initial_offset", "get_initial_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "initial_offset", PROPERTY_HINT_RANGE, "1,65535,1,exp"), "set_initial_offset", "get_initial_offset"); } GrooveJoint2D::GrooveJoint2D() { @@ -433,10 +433,10 @@ void DampedSpringJoint2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_damping", "damping"), &DampedSpringJoint2D::set_damping); ClassDB::bind_method(D_METHOD("get_damping"), &DampedSpringJoint2D::get_damping); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_EXP_RANGE, "1,65535,1"), "set_length", "get_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rest_length", PROPERTY_HINT_EXP_RANGE, "0,65535,1"), "set_rest_length", "get_rest_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness", PROPERTY_HINT_EXP_RANGE, "0.1,64,0.1"), "set_stiffness", "get_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_EXP_RANGE, "0.01,16,0.01"), "set_damping", "get_damping"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1,65535,1,exp"), "set_length", "get_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rest_length", PROPERTY_HINT_RANGE, "0,65535,1,exp"), "set_rest_length", "get_rest_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness", PROPERTY_HINT_RANGE, "0.1,64,0.1,exp"), "set_stiffness", "get_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0.01,16,0.01,exp"), "set_damping", "get_damping"); } DampedSpringJoint2D::DampedSpringJoint2D() { diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index b7a0028199..15008390b7 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "mesh_instance_2d.h" +#include "scene/scene_string_names.h" void MeshInstance2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { @@ -70,7 +71,7 @@ void MeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) { } texture = p_texture; update(); - emit_signal("texture_changed"); + emit_signal(SceneStringNames::get_singleton()->texture_changed); } void MeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) { diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index 72a899370e..1bff2f337d 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "multimesh_instance_2d.h" +#include "scene/scene_string_names.h" void MultiMeshInstance2D::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { @@ -70,7 +71,7 @@ void MultiMeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) { } texture = p_texture; update(); - emit_signal("texture_changed"); + emit_signal(SceneStringNames::get_singleton()->texture_changed); } Ref<Texture2D> MultiMeshInstance2D::get_texture() const { diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index d2caf5bea8..ea639ae3a3 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -169,7 +169,7 @@ Ref<NavigationMesh> NavigationPolygon::get_mesh() { MutexLock lock(navmesh_generation); if (navmesh.is_null()) { - navmesh.instance(); + navmesh.instantiate(); Vector<Vector3> verts; { verts.resize(get_vertices().size()); diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 8afc43ddc9..6fd383ddab 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -164,14 +164,6 @@ void Node2D::set_skew(real_t p_radians) { _update_transform(); } -void Node2D::set_rotation_degrees(real_t p_degrees) { - set_rotation(Math::deg2rad(p_degrees)); -} - -void Node2D::set_skew_degrees(real_t p_degrees) { - set_skew(Math::deg2rad(p_degrees)); -} - void Node2D::set_scale(const Size2 &p_scale) { if (_xform_dirty) { ((Node2D *)this)->_update_xform_values(); @@ -210,14 +202,6 @@ real_t Node2D::get_skew() const { return skew; } -real_t Node2D::get_rotation_degrees() const { - return Math::rad2deg(get_rotation()); -} - -real_t Node2D::get_skew_degrees() const { - return Math::rad2deg(get_skew()); -} - Size2 Node2D::get_scale() const { if (_xform_dirty) { ((Node2D *)this)->_update_xform_values(); @@ -293,14 +277,6 @@ void Node2D::set_global_rotation(real_t p_radians) { } } -real_t Node2D::get_global_rotation_degrees() const { - return Math::rad2deg(get_global_rotation()); -} - -void Node2D::set_global_rotation_degrees(real_t p_degrees) { - set_global_rotation(Math::deg2rad(p_degrees)); -} - Size2 Node2D::get_global_scale() const { return get_global_transform().get_scale(); } @@ -391,19 +367,24 @@ Point2 Node2D::to_global(Point2 p_local) const { return get_global_transform().xform(p_local); } +void Node2D::set_y_sort_enabled(bool p_enabled) { + y_sort_enabled = p_enabled; + RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), y_sort_enabled); +} + +bool Node2D::is_y_sort_enabled() const { + return y_sort_enabled; +} + void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_position", "position"), &Node2D::set_position); ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Node2D::set_rotation); - ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Node2D::set_rotation_degrees); ClassDB::bind_method(D_METHOD("set_skew", "radians"), &Node2D::set_skew); - ClassDB::bind_method(D_METHOD("set_skew_degrees", "degrees"), &Node2D::set_skew_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node2D::set_scale); ClassDB::bind_method(D_METHOD("get_position"), &Node2D::get_position); ClassDB::bind_method(D_METHOD("get_rotation"), &Node2D::get_rotation); - ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node2D::get_rotation_degrees); ClassDB::bind_method(D_METHOD("get_skew"), &Node2D::get_skew); - ClassDB::bind_method(D_METHOD("get_skew_degrees"), &Node2D::get_skew_degrees); ClassDB::bind_method(D_METHOD("get_scale"), &Node2D::get_scale); ClassDB::bind_method(D_METHOD("rotate", "radians"), &Node2D::rotate); @@ -417,8 +398,6 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_global_position"), &Node2D::get_global_position); ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node2D::set_global_rotation); ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node2D::get_global_rotation); - ClassDB::bind_method(D_METHOD("set_global_rotation_degrees", "degrees"), &Node2D::set_global_rotation_degrees); - ClassDB::bind_method(D_METHOD("get_global_rotation_degrees"), &Node2D::get_global_rotation_degrees); ClassDB::bind_method(D_METHOD("set_global_scale", "scale"), &Node2D::set_global_scale); ClassDB::bind_method(D_METHOD("get_global_scale"), &Node2D::get_global_scale); @@ -437,24 +416,25 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative); ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative); + ClassDB::bind_method(D_METHOD("set_y_sort_enabled", "enabled"), &Node2D::set_y_sort_enabled); + ClassDB::bind_method(D_METHOD("is_y_sort_enabled"), &Node2D::is_y_sort_enabled); + ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_skew", "get_skew"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew_degrees", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1", PROPERTY_USAGE_EDITOR), "set_skew_degrees", "get_skew_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_transform", "get_transform"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation_degrees", PROPERTY_HINT_NONE, "", 0), "set_global_rotation_degrees", "get_global_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "global_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_scale", "get_global_scale"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); - ADD_GROUP("Z Index", ""); + ADD_GROUP("Ordering", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(RS::CANVAS_ITEM_Z_MIN) + "," + itos(RS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "y_sort_enabled"), "set_y_sort_enabled", "is_y_sort_enabled"); } diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 358b7e6520..3e66541e32 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -42,6 +42,7 @@ class Node2D : public CanvasItem { real_t skew = 0.0; int z_index = 0; bool z_relative = true; + bool y_sort_enabled = false; Transform2D _mat; @@ -74,9 +75,7 @@ public: void set_position(const Point2 &p_pos); void set_rotation(real_t p_radians); - void set_rotation_degrees(real_t p_degrees); void set_skew(real_t p_radians); - void set_skew_degrees(real_t p_radians); void set_scale(const Size2 &p_scale); void rotate(real_t p_radians); @@ -89,20 +88,16 @@ public: Point2 get_position() const; real_t get_rotation() const; real_t get_skew() const; - real_t get_rotation_degrees() const; - real_t get_skew_degrees() const; Size2 get_scale() const; Point2 get_global_position() const; real_t get_global_rotation() const; - real_t get_global_rotation_degrees() const; Size2 get_global_scale() const; void set_transform(const Transform2D &p_transform); void set_global_transform(const Transform2D &p_transform); void set_global_position(const Point2 &p_pos); void set_global_rotation(real_t p_radians); - void set_global_rotation_degrees(real_t p_degrees); void set_global_scale(const Size2 &p_scale); void set_z_index(int p_z); @@ -117,6 +112,9 @@ public: void set_z_as_relative(bool p_enabled); bool is_z_relative() const; + virtual void set_y_sort_enabled(bool p_enabled); + virtual bool is_y_sort_enabled() const; + Transform2D get_relative_transform_to_parent(const Node *p_parent) const; Transform2D get_transform() const override; diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp new file mode 100644 index 0000000000..d547914e16 --- /dev/null +++ b/scene/2d/physical_bone_2d.cpp @@ -0,0 +1,307 @@ +/*************************************************************************/ +/* physical_bone_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "physical_bone_2d.h" + +void PhysicalBone2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + // Position the RigidBody in the correct position. + if (follow_bone_when_simulating) { + _position_at_bone2d(); + } + + // Keep the child joint in the correct position. + if (child_joint && auto_configure_joint) { + child_joint->set_global_position(get_global_position()); + } + } break; + + case NOTIFICATION_READY: { + _find_skeleton_parent(); + _find_joint_child(); + + // Configure joint. + if (child_joint && auto_configure_joint) { + _auto_configure_joint(); + } + + // Simulate physics if set. + if (simulate_physics) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } + + set_physics_process_internal(true); + } break; + } +} + +void PhysicalBone2D::_position_at_bone2d() { + // Reset to Bone2D position + if (parent_skeleton) { + Bone2D *bone_to_use = parent_skeleton->get_bone(bone2d_index); + ERR_FAIL_COND_MSG(bone_to_use == nullptr, "It's not possible to position the bone with ID: " + itos(bone2d_index)); + set_global_transform(bone_to_use->get_global_transform()); + } +} + +void PhysicalBone2D::_find_skeleton_parent() { + Node *current_parent = get_parent(); + + while (current_parent != nullptr) { + Skeleton2D *potential_skeleton = Object::cast_to<Skeleton2D>(current_parent); + if (potential_skeleton) { + parent_skeleton = potential_skeleton; + break; + } else { + PhysicalBone2D *potential_parent_bone = Object::cast_to<PhysicalBone2D>(current_parent); + if (potential_parent_bone) { + current_parent = potential_parent_bone->get_parent(); + } else { + current_parent = nullptr; + } + } + } +} + +void PhysicalBone2D::_find_joint_child() { + for (int i = 0; i < get_child_count(); i++) { + Node *child_node = get_child(i); + Joint2D *potential_joint = Object::cast_to<Joint2D>(child_node); + if (potential_joint) { + child_joint = potential_joint; + break; + } + } +} + +TypedArray<String> PhysicalBone2D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + if (!parent_skeleton) { + warnings.push_back(TTR("A PhysicalBone2D only works with a Skeleton2D or another PhysicalBone2D as a parent node!")); + } + if (parent_skeleton && bone2d_index <= -1) { + warnings.push_back(TTR("A PhysicalBone2D needs to be assigned to a Bone2D node in order to function! Please set a Bone2D node in the inspector.")); + } + if (!child_joint) { + PhysicalBone2D *parent_bone = Object::cast_to<PhysicalBone2D>(get_parent()); + if (parent_bone) { + warnings.push_back(TTR("A PhysicalBone2D node should have a Joint2D-based child node to keep bones connected! Please add a Joint2D-based node as a child to this node!")); + } + } + + return warnings; +} + +void PhysicalBone2D::_auto_configure_joint() { + if (!auto_configure_joint) { + return; + } + + if (child_joint) { + // Node A = parent | Node B = this node + Node *parent_node = get_parent(); + PhysicalBone2D *potential_parent_bone = Object::cast_to<PhysicalBone2D>(parent_node); + + if (potential_parent_bone) { + child_joint->set_node_a(child_joint->get_path_to(potential_parent_bone)); + child_joint->set_node_b(child_joint->get_path_to(this)); + } else { + WARN_PRINT("Cannot setup joint without a parent PhysicalBone2D node."); + } + + // Place the child joint at this node's position. + child_joint->set_global_position(get_global_position()); + } +} + +void PhysicalBone2D::_start_physics_simulation() { + if (_internal_simulate_physics) { + return; + } + + // Reset to Bone2D position + _position_at_bone2d(); + + // Apply the layers and masks + PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); + PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); + + // Apply the correct mode + RigidBody2D::Mode rigid_mode = get_mode(); + if (rigid_mode == RigidBody2D::MODE_STATIC) { + set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); + } else if (rigid_mode == RigidBody2D::MODE_DYNAMIC) { + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); + } else if (rigid_mode == RigidBody2D::MODE_KINEMATIC) { + set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); + } else if (rigid_mode == RigidBody2D::MODE_DYNAMIC_LOCKED) { + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED); + } else { + // Default to Dynamic. + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); + } + + _internal_simulate_physics = true; + set_physics_process_internal(true); +} + +void PhysicalBone2D::_stop_physics_simulation() { + if (_internal_simulate_physics) { + _internal_simulate_physics = false; + + // Reset to Bone2D position + _position_at_bone2d(); + + set_physics_process_internal(false); + PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC); + } +} + +Joint2D *PhysicalBone2D::get_joint() const { + return child_joint; +} + +bool PhysicalBone2D::get_auto_configure_joint() const { + return auto_configure_joint; +} + +void PhysicalBone2D::set_auto_configure_joint(bool p_auto_configure) { + auto_configure_joint = p_auto_configure; + _auto_configure_joint(); +} + +void PhysicalBone2D::set_simulate_physics(bool p_simulate) { + if (p_simulate == simulate_physics) { + return; + } + simulate_physics = p_simulate; + + if (simulate_physics) { + _start_physics_simulation(); + } else { + _stop_physics_simulation(); + } +} + +bool PhysicalBone2D::get_simulate_physics() const { + return simulate_physics; +} + +bool PhysicalBone2D::is_simulating_physics() const { + return _internal_simulate_physics; +} + +void PhysicalBone2D::set_bone2d_nodepath(const NodePath &p_nodepath) { + bone2d_nodepath = p_nodepath; + notify_property_list_changed(); +} + +NodePath PhysicalBone2D::get_bone2d_nodepath() const { + return bone2d_nodepath; +} + +void PhysicalBone2D::set_bone2d_index(int p_bone_idx) { + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (!is_inside_tree()) { + bone2d_index = p_bone_idx; + return; + } + + if (parent_skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, parent_skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + bone2d_index = p_bone_idx; + + bone2d_nodepath = get_path_to(parent_skeleton->get_bone(bone2d_index)); + } else { + WARN_PRINT("Cannot verify bone index..."); + bone2d_index = p_bone_idx; + } + + notify_property_list_changed(); +} + +int PhysicalBone2D::get_bone2d_index() const { + return bone2d_index; +} + +void PhysicalBone2D::set_follow_bone_when_simulating(bool p_follow_bone) { + follow_bone_when_simulating = p_follow_bone; + + if (_internal_simulate_physics) { + _stop_physics_simulation(); + _start_physics_simulation(); + } +} + +bool PhysicalBone2D::get_follow_bone_when_simulating() const { + return follow_bone_when_simulating; +} + +void PhysicalBone2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_joint"), &PhysicalBone2D::get_joint); + ClassDB::bind_method(D_METHOD("get_auto_configure_joint"), &PhysicalBone2D::get_auto_configure_joint); + ClassDB::bind_method(D_METHOD("set_auto_configure_joint", "auto_configure_joint"), &PhysicalBone2D::set_auto_configure_joint); + + ClassDB::bind_method(D_METHOD("set_simulate_physics", "simulate_physics"), &PhysicalBone2D::set_simulate_physics); + ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone2D::get_simulate_physics); + ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone2D::is_simulating_physics); + + ClassDB::bind_method(D_METHOD("set_bone2d_nodepath", "nodepath"), &PhysicalBone2D::set_bone2d_nodepath); + ClassDB::bind_method(D_METHOD("get_bone2d_nodepath"), &PhysicalBone2D::get_bone2d_nodepath); + ClassDB::bind_method(D_METHOD("set_bone2d_index", "bone_index"), &PhysicalBone2D::set_bone2d_index); + ClassDB::bind_method(D_METHOD("get_bone2d_index"), &PhysicalBone2D::get_bone2d_index); + ClassDB::bind_method(D_METHOD("set_follow_bone_when_simulating", "follow_bone"), &PhysicalBone2D::set_follow_bone_when_simulating); + ClassDB::bind_method(D_METHOD("get_follow_bone_when_simulating"), &PhysicalBone2D::get_follow_bone_when_simulating); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "bone2d_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D"), "set_bone2d_nodepath", "get_bone2d_nodepath"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "bone2d_index", PROPERTY_HINT_RANGE, "-1, 1000, 1"), "set_bone2d_index", "get_bone2d_index"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_configure_joint"), "set_auto_configure_joint", "get_auto_configure_joint"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simulate_physics"), "set_simulate_physics", "get_simulate_physics"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_bone_when_simulating"), "set_follow_bone_when_simulating", "get_follow_bone_when_simulating"); +} + +PhysicalBone2D::PhysicalBone2D() { + // Stop the RigidBody from executing its force integration. + PhysicsServer2D::get_singleton()->body_set_collision_layer(get_rid(), 0); + PhysicsServer2D::get_singleton()->body_set_collision_mask(get_rid(), 0); + PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BodyMode::BODY_MODE_STATIC); + + child_joint = nullptr; +} + +PhysicalBone2D::~PhysicalBone2D() { +} diff --git a/scene/2d/physical_bone_2d.h b/scene/2d/physical_bone_2d.h new file mode 100644 index 0000000000..46a2772bad --- /dev/null +++ b/scene/2d/physical_bone_2d.h @@ -0,0 +1,88 @@ +/*************************************************************************/ +/* physical_bone_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef PHYSICAL_BONE_2D_H +#define PHYSICAL_BONE_2D_H + +#include "scene/2d/joints_2d.h" +#include "scene/2d/physics_body_2d.h" + +#include "scene/2d/skeleton_2d.h" + +class PhysicalBone2D : public RigidBody2D { + GDCLASS(PhysicalBone2D, RigidBody2D); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +private: + Skeleton2D *parent_skeleton = nullptr; + int bone2d_index = -1; + NodePath bone2d_nodepath; + bool follow_bone_when_simulating = false; + + Joint2D *child_joint; + bool auto_configure_joint = true; + + bool simulate_physics = false; + bool _internal_simulate_physics = false; + + void _find_skeleton_parent(); + void _find_joint_child(); + void _auto_configure_joint(); + + void _start_physics_simulation(); + void _stop_physics_simulation(); + void _position_at_bone2d(); + +public: + Joint2D *get_joint() const; + bool get_auto_configure_joint() const; + void set_auto_configure_joint(bool p_auto_configure); + + void set_simulate_physics(bool p_simulate); + bool get_simulate_physics() const; + bool is_simulating_physics() const; + + void set_bone2d_nodepath(const NodePath &p_nodepath); + NodePath get_bone2d_nodepath() const; + void set_bone2d_index(int p_bone_idx); + int get_bone2d_index() const; + void set_follow_bone_when_simulating(bool p_follow); + bool get_follow_bone_when_simulating() const; + + TypedArray<String> get_configuration_warnings() const override; + + PhysicalBone2D(); + ~PhysicalBone2D(); +}; + +#endif // PHYSICAL_BONE_2D_H diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 4f52f62e99..be619ed60d 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -38,10 +38,10 @@ #include "core/templates/rid.h" #include "scene/scene_string_names.h" -void PhysicsBody2D::_notification(int p_what) { -} - void PhysicsBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody2D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.08)); + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody2D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody2D::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody2D::remove_collision_exception_with); @@ -49,10 +49,93 @@ void PhysicsBody2D::_bind_methods() { PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) : CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) { - PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), p_mode); + set_body_mode(p_mode); set_pickable(false); } +PhysicsBody2D::~PhysicsBody2D() { + if (motion_cache.is_valid()) { + motion_cache->owner = nullptr; + } +} + +Ref<KinematicCollision2D> PhysicsBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) { + PhysicsServer2D::MotionResult result; + + if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) { + if (motion_cache.is_null()) { + motion_cache.instantiate(); + motion_cache->owner = this; + } + + motion_cache->result = result; + + return motion_cache; + } + + return Ref<KinematicCollision2D>(); +} + +bool PhysicsBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) { + if (is_only_update_transform_changes_enabled()) { + ERR_PRINT("Move functions do not work together with 'sync to physics' option. Please read the documentation."); + } + Transform2D gt = get_global_transform(); + bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes); + + // Restore direction of motion to be along original motion, + // in order to avoid sliding due to recovery, + // but only if collision depth is low enough to avoid tunneling. + real_t motion_length = p_motion.length(); + if (motion_length > CMP_EPSILON) { + real_t precision = 0.001; + + if (colliding && p_cancel_sliding) { + // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, + // so even in normal resting cases the depth can be a bit more than the margin. + precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); + + if (r_result.collision_depth > (real_t)p_margin + precision) { + p_cancel_sliding = false; + } + } + + if (p_cancel_sliding) { + // Check depth of recovery. + Vector2 motion_normal = p_motion / motion_length; + real_t dot = r_result.motion.dot(motion_normal); + Vector2 recovery = r_result.motion - motion_normal * dot; + real_t recovery_length = recovery.length(); + // Fixes cases where canceling slide causes the motion to go too deep into the ground, + // Becauses we're only taking rest information into account and not general recovery. + if (recovery_length < (real_t)p_margin + precision) { + // Apply adjustment to motion. + r_result.motion = motion_normal * dot; + r_result.remainder = p_motion - r_result.motion; + } + } + } + + if (!p_test_only) { + gt.elements[2] += r_result.motion; + set_global_transform(gt); + } + + return colliding; +} + +bool PhysicsBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision2D> &r_collision, real_t p_margin) { + ERR_FAIL_COND_V(!is_inside_tree(), false); + + PhysicsServer2D::MotionResult *r = nullptr; + if (r_collision.is_valid()) { + // Needs const_cast because method bindings don't support non-const Ref. + r = const_cast<PhysicsServer2D::MotionResult *>(&r_collision->result); + } + + return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes); +} + TypedArray<PhysicsBody2D> PhysicsBody2D::get_collision_exceptions() { List<RID> exceptions; PhysicsServer2D::get_singleton()->body_get_collision_exceptions(get_rid(), &exceptions); @@ -83,12 +166,22 @@ void PhysicsBody2D::remove_collision_exception_with(Node *p_node) { void StaticBody2D::set_constant_linear_velocity(const Vector2 &p_vel) { constant_linear_velocity = p_vel; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); + + if (kinematic_motion) { + _update_kinematic_motion(); + } else { + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); + } } void StaticBody2D::set_constant_angular_velocity(real_t p_vel) { constant_angular_velocity = p_vel; - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); + + if (kinematic_motion) { + _update_kinematic_motion(); + } else { + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); + } } Vector2 StaticBody2D::get_constant_linear_velocity() const { @@ -118,27 +211,76 @@ Ref<PhysicsMaterial> StaticBody2D::get_physics_material_override() const { return physics_material_override; } +void StaticBody2D::set_kinematic_motion_enabled(bool p_enabled) { + if (p_enabled == kinematic_motion) { + return; + } + + kinematic_motion = p_enabled; + + if (kinematic_motion) { + set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); + } else { + set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); + } + + _update_kinematic_motion(); +} + +bool StaticBody2D::is_kinematic_motion_enabled() const { + return kinematic_motion; +} + +void StaticBody2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + ERR_FAIL_COND(!kinematic_motion); + + real_t delta_time = get_physics_process_delta_time(); + + Transform2D new_transform = get_global_transform(); + + new_transform.translate(constant_linear_velocity * delta_time); + new_transform.set_rotation(new_transform.get_rotation() + constant_angular_velocity * delta_time); + + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); + + // Propagate transform change to node. + set_block_transform_notify(true); + set_global_transform(new_transform); + set_block_transform_notify(false); + } break; + } +} + void StaticBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody2D::set_constant_linear_velocity); ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody2D::set_constant_angular_velocity); ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody2D::get_constant_linear_velocity); ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody2D::get_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody2D::set_kinematic_motion_enabled); + ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody2D::is_kinematic_motion_enabled); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody2D::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody2D::get_physics_material_override); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled"); } StaticBody2D::StaticBody2D() : PhysicsBody2D(PhysicsServer2D::BODY_MODE_STATIC) { } -StaticBody2D::~StaticBody2D() { -} - void StaticBody2D::_reload_physics_characteristics() { if (physics_material_override.is_null()) { PhysicsServer2D::get_singleton()->body_set_param(get_rid(), PhysicsServer2D::BODY_PARAM_BOUNCE, 0); @@ -149,6 +291,23 @@ void StaticBody2D::_reload_physics_characteristics() { } } +void StaticBody2D::_update_kinematic_motion() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + if (kinematic_motion) { + if (!Math::is_zero_approx(constant_angular_velocity) || !constant_linear_velocity.is_equal_approx(Vector2())) { + set_physics_process_internal(true); + return; + } + } + + set_physics_process_internal(false); +} + void RigidBody2D::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = Object::cast_to<Node>(obj); @@ -262,14 +421,6 @@ struct _RigidBody2DInOut { int local_shape = 0; }; -bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) { - PhysicsServer2D::MotionResult *r = nullptr; - if (p_result.is_valid()) { - r = p_result->get_result_ptr(); - } - return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r); -} - void RigidBody2D::_direct_state_changed(Object *p_state) { #ifdef DEBUG_ENABLED state = Object::cast_to<PhysicsDirectBodyState2D>(p_state); @@ -378,19 +529,19 @@ void RigidBody2D::_direct_state_changed(Object *p_state) { void RigidBody2D::set_mode(Mode p_mode) { mode = p_mode; switch (p_mode) { - case MODE_RIGID: { - PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_RIGID); + case MODE_DYNAMIC: { + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC); } break; case MODE_STATIC: { - PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_STATIC); + set_body_mode(PhysicsServer2D::BODY_MODE_STATIC); } break; case MODE_KINEMATIC: { - PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_KINEMATIC); + set_body_mode(PhysicsServer2D::BODY_MODE_KINEMATIC); } break; - case MODE_CHARACTER: { - PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), PhysicsServer2D::BODY_MODE_CHARACTER); + case MODE_DYNAMIC_LOCKED: { + set_body_mode(PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED); } break; } @@ -646,18 +797,19 @@ bool RigidBody2D::is_contact_monitor_enabled() const { void RigidBody2D::_notification(int p_what) { #ifdef TOOLS_ENABLED - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); //used for warnings and only in editor - } - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); //used for warnings and only in editor + } + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; } - #endif } @@ -666,8 +818,8 @@ TypedArray<String> RigidBody2D::get_configuration_warnings() const { TypedArray<String> warnings = CollisionObject2D::get_configuration_warnings(); - if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) { - warnings.push_back(TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.elements[0].length() - 1.0) > 0.05 || ABS(t.elements[1].length() - 1.0) > 0.05)) { + warnings.push_back(TTR("Size changes to RigidBody2D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } return warnings; @@ -734,15 +886,13 @@ void RigidBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep); - ClassDB::bind_method(D_METHOD("test_motion", "motion", "infinite_inertia", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(true), DEFVAL(0.08), DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody2D::get_colliding_bodies); BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState2D"))); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", 0), "set_inertia", "get_inertia"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inertia", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp", PROPERTY_USAGE_NONE), "set_inertia", "get_inertia"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); @@ -767,9 +917,9 @@ void RigidBody2D::_bind_methods() { ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - BIND_ENUM_CONSTANT(MODE_RIGID); + BIND_ENUM_CONSTANT(MODE_DYNAMIC); BIND_ENUM_CONSTANT(MODE_STATIC); - BIND_ENUM_CONSTANT(MODE_CHARACTER); + BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(MODE_KINEMATIC); BIND_ENUM_CONSTANT(CCD_MODE_DISABLED); @@ -778,7 +928,7 @@ void RigidBody2D::_bind_methods() { } RigidBody2D::RigidBody2D() : - PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) { + PhysicsBody2D(PhysicsServer2D::BODY_MODE_DYNAMIC) { PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody2D::_direct_state_changed)); } @@ -800,95 +950,13 @@ void RigidBody2D::_reload_physics_characteristics() { ////////////////////////// -Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) { - Collision col; - - if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) { - if (motion_cache.is_null()) { - motion_cache.instance(); - motion_cache->owner = this; - } - - motion_cache->collision = col; - - return motion_cache; - } - - return Ref<KinematicCollision2D>(); -} - -bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) { - PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays - - Transform2D gt = get_global_transform(); - - Vector2 recover; - int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); - int deepest = -1; - real_t deepest_depth; - for (int i = 0; i < hits; i++) { - if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) { - deepest = i; - deepest_depth = sep_res[i].collision_depth; - } - } - - gt.elements[2] += recover; - set_global_transform(gt); - - if (deepest != -1) { - r_collision.collider = sep_res[deepest].collider_id; - r_collision.collider_metadata = sep_res[deepest].collider_metadata; - r_collision.collider_shape = sep_res[deepest].collider_shape; - r_collision.collider_vel = sep_res[deepest].collider_velocity; - r_collision.collision = sep_res[deepest].collision_point; - r_collision.normal = sep_res[deepest].collision_normal; - r_collision.local_shape = sep_res[deepest].collision_local_shape; - r_collision.travel = recover; - r_collision.remainder = Vector2(); - - return true; - } else { - return false; - } -} - -bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { - if (sync_to_physics) { - ERR_PRINT("Functions move_and_slide and move_and_collide do not work together with 'sync to physics' option. Please read the documentation."); - } - Transform2D gt = get_global_transform(); - PhysicsServer2D::MotionResult result; - bool colliding = PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result, p_exclude_raycast_shapes); - - if (colliding) { - r_collision.collider_metadata = result.collider_metadata; - r_collision.collider_shape = result.collider_shape; - r_collision.collider_vel = result.collider_velocity; - r_collision.collision = result.collision_point; - r_collision.normal = result.collision_normal; - r_collision.collider = result.collider_id; - r_collision.collider_rid = result.collider; - r_collision.travel = result.motion; - r_collision.remainder = result.remainder; - r_collision.local_shape = result.collision_local_shape; - } - - if (!p_test_only) { - gt.elements[2] += result.motion; - set_global_transform(gt); - } - - return colliding; -} - //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { - Vector2 body_velocity = p_linear_velocity; - Vector2 body_velocity_normal = body_velocity.normalized(); - Vector2 up_direction = p_up_direction.normalized(); +void CharacterBody2D::move_and_slide() { + Vector2 body_velocity_normal = linear_velocity.normalized(); + + bool was_on_floor = on_floor; Vector2 current_floor_velocity = floor_velocity; if (on_floor && on_floor_body.is_valid()) { @@ -900,106 +968,104 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const } // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - Vector2 motion = (current_floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); + Vector2 motion = (current_floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); on_floor = false; on_floor_body = RID(); on_ceiling = false; on_wall = false; - colliders.clear(); + motion_results.clear(); floor_normal = Vector2(); floor_velocity = Vector2(); - while (p_max_slides) { - Collision collision; + // No sliding on first attempt to keep floor motion stable when possible. + bool sliding_enabled = false; + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer2D::MotionResult result; bool found_collision = false; for (int i = 0; i < 2; ++i) { bool collided; if (i == 0) { //collide - collided = move_and_collide(motion, p_infinite_inertia, collision); + collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled); if (!collided) { motion = Vector2(); //clear because no collision happened and motion completed } } else { //separate raycasts (if any) - collided = separate_raycast_shapes(p_infinite_inertia, collision); + collided = separate_raycast_shapes(result); if (collided) { - collision.remainder = motion; //keep - collision.travel = Vector2(); + result.remainder = motion; //keep + result.motion = Vector2(); } } if (collided) { found_collision = true; - colliders.push_back(collision); - motion = collision.remainder; + motion_results.push_back(result); if (up_direction == Vector2()) { //all is a wall on_wall = true; } else { - if (Math::acos(collision.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; - floor_normal = collision.normal; - on_floor_body = collision.collider_rid; - floor_velocity = collision.collider_vel; + floor_normal = result.collision_normal; + on_floor_body = result.collider; + floor_velocity = result.collider_velocity; - if (p_stop_on_slope) { - if ((body_velocity_normal + up_direction).length() < 0.01 && collision.travel.length() < 1) { + if (stop_on_slope) { + if ((body_velocity_normal + up_direction).length() < 0.01) { Transform2D gt = get_global_transform(); - gt.elements[2] -= collision.travel.slide(up_direction); + gt.elements[2] -= result.motion.slide(up_direction); set_global_transform(gt); - return Vector2(); + linear_velocity = Vector2(); + return; } } - } else if (Math::acos(collision.normal.dot(-up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; } } - motion = motion.slide(collision.normal); - body_velocity = body_velocity.slide(collision.normal); + if (sliding_enabled || !on_floor) { + motion = result.remainder.slide(result.collision_normal); + linear_velocity = linear_velocity.slide(result.collision_normal); + } else { + motion = result.remainder; + } } + + sliding_enabled = true; } if (!found_collision || motion == Vector2()) { break; } - - --p_max_slides; } - return body_velocity; -} - -Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { - Vector2 up_direction = p_up_direction.normalized(); - bool was_on_floor = on_floor; - - Vector2 ret = move_and_slide(p_linear_velocity, up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); - if (!was_on_floor || p_snap == Vector2()) { - return ret; + if (!was_on_floor || snap == Vector2()) { + return; } - Collision col; + // Apply snap. Transform2D gt = get_global_transform(); - - if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { + PhysicsServer2D::MotionResult result; + if (move_and_collide(snap, infinite_inertia, result, margin, false, true)) { bool apply = true; if (up_direction != Vector2()) { - if (Math::acos(col.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { on_floor = true; - floor_normal = col.normal; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; - if (p_stop_on_slope) { + floor_normal = result.collision_normal; + on_floor_body = result.collider; + floor_velocity = result.collider_velocity; + if (stop_on_slope) { // move and collide may stray the object a bit because of pre un-stucking, // so only ensure that motion happens on floor direction in this case. - col.travel = up_direction * up_direction.dot(col.travel); + result.motion = up_direction * up_direction.dot(result.motion); } } else { @@ -1008,73 +1074,101 @@ Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_veloci } if (apply) { - gt.elements[2] += col.travel; + gt.elements[2] += result.motion; set_global_transform(gt); } } - - return ret; } -bool KinematicBody2D::is_on_floor() const { - return on_floor; -} +bool CharacterBody2D::separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result) { + PhysicsServer2D::SeparationResult sep_res[8]; //max 8 rays -bool KinematicBody2D::is_on_wall() const { - return on_wall; + Transform2D gt = get_global_transform(); + + Vector2 recover; + int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin); + int deepest = -1; + real_t deepest_depth; + for (int i = 0; i < hits; i++) { + if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) { + deepest = i; + deepest_depth = sep_res[i].collision_depth; + } + } + + gt.elements[2] += recover; + set_global_transform(gt); + + if (deepest != -1) { + r_result.collider_id = sep_res[deepest].collider_id; + r_result.collider_metadata = sep_res[deepest].collider_metadata; + r_result.collider_shape = sep_res[deepest].collider_shape; + r_result.collider_velocity = sep_res[deepest].collider_velocity; + r_result.collision_point = sep_res[deepest].collision_point; + r_result.collision_normal = sep_res[deepest].collision_normal; + r_result.collision_local_shape = sep_res[deepest].collision_local_shape; + r_result.motion = recover; + r_result.remainder = Vector2(); + + return true; + } else { + return false; + } } -bool KinematicBody2D::is_on_ceiling() const { - return on_ceiling; +const Vector2 &CharacterBody2D::get_linear_velocity() const { + return linear_velocity; } -Vector2 KinematicBody2D::get_floor_normal() const { - return floor_normal; +void CharacterBody2D::set_linear_velocity(const Vector2 &p_velocity) { + linear_velocity = p_velocity; } -Vector2 KinematicBody2D::get_floor_velocity() const { - return floor_velocity; +bool CharacterBody2D::is_on_floor() const { + return on_floor; } -bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia) { - ERR_FAIL_COND_V(!is_inside_tree(), false); +bool CharacterBody2D::is_on_wall() const { + return on_wall; +} - return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin); +bool CharacterBody2D::is_on_ceiling() const { + return on_ceiling; } -void KinematicBody2D::set_safe_margin(real_t p_margin) { - margin = p_margin; +Vector2 CharacterBody2D::get_floor_normal() const { + return floor_normal; } -real_t KinematicBody2D::get_safe_margin() const { - return margin; +Vector2 CharacterBody2D::get_floor_velocity() const { + return floor_velocity; } -int KinematicBody2D::get_slide_count() const { - return colliders.size(); +int CharacterBody2D::get_slide_count() const { + return motion_results.size(); } -KinematicBody2D::Collision KinematicBody2D::get_slide_collision(int p_bounce) const { - ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision()); - return colliders[p_bounce]; +PhysicsServer2D::MotionResult CharacterBody2D::get_slide_collision(int p_bounce) const { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer2D::MotionResult()); + return motion_results[p_bounce]; } -Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) { - ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision2D>()); +Ref<KinematicCollision2D> CharacterBody2D::_get_slide_collision(int p_bounce) { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision2D>()); if (p_bounce >= slide_colliders.size()) { slide_colliders.resize(p_bounce + 1); } if (slide_colliders[p_bounce].is_null()) { - slide_colliders.write[p_bounce].instance(); + slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } - slide_colliders.write[p_bounce]->collision = colliders[p_bounce]; + slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; return slide_colliders[p_bounce]; } -void KinematicBody2D::set_sync_to_physics(bool p_enable) { +void CharacterBody2D::set_sync_to_physics(bool p_enable) { if (sync_to_physics == p_enable) { return; } @@ -1085,7 +1179,7 @@ void KinematicBody2D::set_sync_to_physics(bool p_enable) { } if (p_enable) { - PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &KinematicBody2D::_direct_state_changed)); + PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &CharacterBody2D::_direct_state_changed)); set_only_update_transform_changes(true); set_notify_local_transform(true); } else { @@ -1095,11 +1189,11 @@ void KinematicBody2D::set_sync_to_physics(bool p_enable) { } } -bool KinematicBody2D::is_sync_to_physics_enabled() const { +bool CharacterBody2D::is_sync_to_physics_enabled() const { return sync_to_physics; } -void KinematicBody2D::_direct_state_changed(Object *p_state) { +void CharacterBody2D::_direct_state_changed(Object *p_state) { if (!sync_to_physics) { return; } @@ -1113,71 +1207,137 @@ void KinematicBody2D::_direct_state_changed(Object *p_state) { set_notify_local_transform(true); } -void KinematicBody2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - last_valid_transform = get_global_transform(); +void CharacterBody2D::set_safe_margin(real_t p_margin) { + margin = p_margin; +} - // Reset move_and_slide() data. - on_floor = false; - on_floor_body = RID(); - on_ceiling = false; - on_wall = false; - colliders.clear(); - floor_velocity = Vector2(); - } +real_t CharacterBody2D::get_safe_margin() const { + return margin; +} - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - //used by sync to physics, send the new transform to the physics - Transform2D new_transform = get_global_transform(); - PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); - //but then revert changes - set_notify_local_transform(false); - set_global_transform(last_valid_transform); - set_notify_local_transform(true); - } +bool CharacterBody2D::is_stop_on_slope_enabled() const { + return stop_on_slope; } -void KinematicBody2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); +void CharacterBody2D::set_stop_on_slope_enabled(bool p_enabled) { + stop_on_slope = p_enabled; +} - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move, DEFVAL(true)); +bool CharacterBody2D::is_infinite_inertia_enabled() const { + return infinite_inertia; +} +void CharacterBody2D::set_infinite_inertia_enabled(bool p_enabled) { + infinite_inertia = p_enabled; +} - ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor); - ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling); - ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody2D::is_on_wall); - ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody2D::get_floor_normal); - ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody2D::get_floor_velocity); +int CharacterBody2D::get_max_slides() const { + return max_slides; +} + +void CharacterBody2D::set_max_slides(int p_max_slides) { + ERR_FAIL_COND(p_max_slides > 0); + max_slides = p_max_slides; +} - ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody2D::set_safe_margin); - ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody2D::get_safe_margin); +real_t CharacterBody2D::get_floor_max_angle() const { + return floor_max_angle; +} - ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody2D::get_slide_count); - ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody2D::_get_slide_collision); +void CharacterBody2D::set_floor_max_angle(real_t p_radians) { + floor_max_angle = p_radians; +} - ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &KinematicBody2D::set_sync_to_physics); - ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &KinematicBody2D::is_sync_to_physics_enabled); +const Vector2 &CharacterBody2D::get_snap() const { + return snap; +} - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); +void CharacterBody2D::set_snap(const Vector2 &p_snap) { + snap = p_snap; } -KinematicBody2D::KinematicBody2D() : - PhysicsBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { - margin = 0.08; +const Vector2 &CharacterBody2D::get_up_direction() const { + return up_direction; +} - on_floor = false; - on_ceiling = false; - on_wall = false; - sync_to_physics = false; +void CharacterBody2D::set_up_direction(const Vector2 &p_up_direction) { + up_direction = p_up_direction.normalized(); } -KinematicBody2D::~KinematicBody2D() { - if (motion_cache.is_valid()) { - motion_cache->owner = nullptr; +void CharacterBody2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + last_valid_transform = get_global_transform(); + + // Reset move_and_slide() data. + on_floor = false; + on_floor_body = RID(); + on_ceiling = false; + on_wall = false; + motion_results.clear(); + floor_velocity = Vector2(); + } break; + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + // Used by sync to physics, send the new transform to the physics. + Transform2D new_transform = get_global_transform(); + PhysicsServer2D::get_singleton()->body_set_state(get_rid(), PhysicsServer2D::BODY_STATE_TRANSFORM, new_transform); + // But then revert changes. + set_notify_local_transform(false); + set_global_transform(last_valid_transform); + set_notify_local_transform(true); + } break; } +} + +void CharacterBody2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody2D::move_and_slide); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody2D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody2D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody2D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody2D::get_safe_margin); + ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody2D::is_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody2D::set_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody2D::is_infinite_inertia_enabled); + ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody2D::set_infinite_inertia_enabled); + ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody2D::get_max_slides); + ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody2D::set_max_slides); + ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody2D::get_floor_max_angle); + ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody2D::set_floor_max_angle); + ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody2D::get_snap); + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody2D::set_snap); + ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody2D::get_up_direction); + ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody2D::set_up_direction); + + ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody2D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody2D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody2D::is_on_wall); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody2D::get_floor_normal); + ClassDB::bind_method(D_METHOD("get_floor_velocity"), &CharacterBody2D::get_floor_velocity); + ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody2D::get_slide_count); + ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody2D::_get_slide_collision); + + ClassDB::bind_method(D_METHOD("set_sync_to_physics", "enable"), &CharacterBody2D::set_sync_to_physics); + ClassDB::bind_method(D_METHOD("is_sync_to_physics_enabled"), &CharacterBody2D::is_sync_to_physics_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides"), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_floor_max_angle", "get_floor_max_angle"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap"), "set_snap", "get_snap"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "up_direction"), "set_up_direction", "get_up_direction"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "motion/sync_to_physics"), "set_sync_to_physics", "is_sync_to_physics_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); +} +CharacterBody2D::CharacterBody2D() : + PhysicsBody2D(PhysicsServer2D::BODY_MODE_KINEMATIC) { +} + +CharacterBody2D::~CharacterBody2D() { for (int i = 0; i < slide_colliders.size(); i++) { if (slide_colliders[i].is_valid()) { slide_colliders.write[i]->owner = nullptr; @@ -1188,39 +1348,43 @@ KinematicBody2D::~KinematicBody2D() { //////////////////////// Vector2 KinematicCollision2D::get_position() const { - return collision.collision; + return result.collision_point; } Vector2 KinematicCollision2D::get_normal() const { - return collision.normal; + return result.collision_normal; } Vector2 KinematicCollision2D::get_travel() const { - return collision.travel; + return result.motion; } Vector2 KinematicCollision2D::get_remainder() const { - return collision.remainder; + return result.remainder; } Object *KinematicCollision2D::get_local_shape() const { if (!owner) { return nullptr; } - uint32_t ownerid = owner->shape_find_owner(collision.local_shape); + uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape); return owner->shape_owner_get_owner(ownerid); } Object *KinematicCollision2D::get_collider() const { - if (collision.collider.is_valid()) { - return ObjectDB::get_instance(collision.collider); + if (result.collider_id.is_valid()) { + return ObjectDB::get_instance(result.collider_id); } return nullptr; } ObjectID KinematicCollision2D::get_collider_id() const { - return collision.collider; + return result.collider_id; +} + +RID KinematicCollision2D::get_collider_rid() const { + return result.collider; } Object *KinematicCollision2D::get_collider_shape() const { @@ -1228,7 +1392,7 @@ Object *KinematicCollision2D::get_collider_shape() const { if (collider) { CollisionObject2D *obj2d = Object::cast_to<CollisionObject2D>(collider); if (obj2d) { - uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape); + uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape); return obj2d->shape_owner_get_owner(ownerid); } } @@ -1237,11 +1401,11 @@ Object *KinematicCollision2D::get_collider_shape() const { } int KinematicCollision2D::get_collider_shape_index() const { - return collision.collider_shape; + return result.collider_shape; } Vector2 KinematicCollision2D::get_collider_velocity() const { - return collision.collider_vel; + return result.collider_velocity; } Variant KinematicCollision2D::get_collider_metadata() const { @@ -1256,6 +1420,7 @@ void KinematicCollision2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision2D::get_local_shape); ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision2D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision2D::get_collider_id); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision2D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision2D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision2D::get_collider_shape_index); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision2D::get_collider_velocity); @@ -1268,14 +1433,9 @@ void KinematicCollision2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity"); ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata"); } - -KinematicCollision2D::KinematicCollision2D() { - collision.collider_shape = 0; - collision.local_shape = 0; - owner = nullptr; -} diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 47d55d11fa..5a5417eaf3 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -42,17 +42,22 @@ class PhysicsBody2D : public CollisionObject2D { GDCLASS(PhysicsBody2D, CollisionObject2D); protected: - void _notification(int p_what); + static void _bind_methods(); PhysicsBody2D(PhysicsServer2D::BodyMode p_mode); - static void _bind_methods(); + Ref<KinematicCollision2D> motion_cache; + + Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.08); public: + bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, PhysicsServer2D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true); + bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision2D> &r_collision = Ref<KinematicCollision2D>(), real_t p_margin = 0.08); + TypedArray<PhysicsBody2D> get_collision_exceptions(); void add_collision_exception_with(Node *p_node); //must be physicsbody void remove_collision_exception_with(Node *p_node); - PhysicsBody2D(); + virtual ~PhysicsBody2D(); }; class StaticBody2D : public PhysicsBody2D { @@ -63,7 +68,10 @@ class StaticBody2D : public PhysicsBody2D { Ref<PhysicsMaterial> physics_material_override; + bool kinematic_motion = false; + protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -77,10 +85,14 @@ public: real_t get_constant_angular_velocity() const; StaticBody2D(); - ~StaticBody2D(); private: void _reload_physics_characteristics(); + + void _update_kinematic_motion(); + + void set_kinematic_motion_enabled(bool p_enabled); + bool is_kinematic_motion_enabled() const; }; class RigidBody2D : public PhysicsBody2D { @@ -88,9 +100,9 @@ class RigidBody2D : public PhysicsBody2D { public: enum Mode { - MODE_RIGID, + MODE_DYNAMIC, MODE_STATIC, - MODE_CHARACTER, + MODE_DYNAMIC_LOCKED, MODE_KINEMATIC, }; @@ -103,7 +115,7 @@ public: private: bool can_sleep = true; PhysicsDirectBodyState2D *state = nullptr; - Mode mode = MODE_RIGID; + Mode mode = MODE_DYNAMIC; real_t mass = 1.0; Ref<PhysicsMaterial> physics_material_override; @@ -163,8 +175,6 @@ private: void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_local_shape); void _direct_state_changed(Object *p_state); - bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>()); - protected: void _notification(int p_what); static void _bind_methods(); @@ -245,62 +255,70 @@ private: VARIANT_ENUM_CAST(RigidBody2D::Mode); VARIANT_ENUM_CAST(RigidBody2D::CCDMode); -class KinematicBody2D : public PhysicsBody2D { - GDCLASS(KinematicBody2D, PhysicsBody2D); - -public: - struct Collision { - Vector2 collision; - Vector2 normal; - Vector2 collider_vel; - ObjectID collider; - RID collider_rid; - int collider_shape = 0; - Variant collider_metadata; - Vector2 remainder; - Vector2 travel; - int local_shape = 0; - }; +class CharacterBody2D : public PhysicsBody2D { + GDCLASS(CharacterBody2D, PhysicsBody2D); private: - real_t margin; + real_t margin = 0.08; + + bool stop_on_slope = false; + bool infinite_inertia = true; + int max_slides = 4; + real_t floor_max_angle = Math::deg2rad((real_t)45.0); + Vector2 snap; + Vector2 up_direction = Vector2(0.0, -1.0); + + Vector2 linear_velocity; Vector2 floor_normal; Vector2 floor_velocity; RID on_floor_body; - bool on_floor; - bool on_ceiling; - bool on_wall; - bool sync_to_physics; + bool on_floor = false; + bool on_ceiling = false; + bool on_wall = false; + bool sync_to_physics = false; - Vector<Collision> colliders; + Vector<PhysicsServer2D::MotionResult> motion_results; Vector<Ref<KinematicCollision2D>> slide_colliders; - Ref<KinematicCollision2D> motion_cache; - - _FORCE_INLINE_ bool _ignores_mode(PhysicsServer2D::BodyMode) const; - Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false); Ref<KinematicCollision2D> _get_slide_collision(int p_bounce); + bool separate_raycast_shapes(PhysicsServer2D::MotionResult &r_result); + Transform2D last_valid_transform; void _direct_state_changed(Object *p_state); + void set_safe_margin(real_t p_margin); + real_t get_safe_margin() const; + + bool is_stop_on_slope_enabled() const; + void set_stop_on_slope_enabled(bool p_enabled); + + bool is_infinite_inertia_enabled() const; + void set_infinite_inertia_enabled(bool p_enabled); + + int get_max_slides() const; + void set_max_slides(int p_max_slides); + + real_t get_floor_max_angle() const; + void set_floor_max_angle(real_t p_radians); + + const Vector2 &get_snap() const; + void set_snap(const Vector2 &p_snap); + + const Vector2 &get_up_direction() const; + void set_up_direction(const Vector2 &p_up_direction); + protected: void _notification(int p_what); static void _bind_methods(); public: - bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false); - - bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia = true); - - bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision); + void move_and_slide(); - void set_safe_margin(real_t p_margin); - real_t get_safe_margin() const; + const Vector2 &get_linear_velocity() const; + void set_linear_velocity(const Vector2 &p_velocity); - Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); - Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; @@ -308,21 +326,22 @@ public: Vector2 get_floor_velocity() const; int get_slide_count() const; - Collision get_slide_collision(int p_bounce) const; + PhysicsServer2D::MotionResult get_slide_collision(int p_bounce) const; void set_sync_to_physics(bool p_enable); bool is_sync_to_physics_enabled() const; - KinematicBody2D(); - ~KinematicBody2D(); + CharacterBody2D(); + ~CharacterBody2D(); }; -class KinematicCollision2D : public Reference { - GDCLASS(KinematicCollision2D, Reference); +class KinematicCollision2D : public RefCounted { + GDCLASS(KinematicCollision2D, RefCounted); - KinematicBody2D *owner; - friend class KinematicBody2D; - KinematicBody2D::Collision collision; + PhysicsBody2D *owner = nullptr; + friend class PhysicsBody2D; + friend class CharacterBody2D; + PhysicsServer2D::MotionResult result; protected: static void _bind_methods(); @@ -335,12 +354,11 @@ public: Object *get_local_shape() const; Object *get_collider() const; ObjectID get_collider_id() const; + RID get_collider_rid() const; Object *get_collider_shape() const; int get_collider_shape_index() const; Vector2 get_collider_velocity() const; Variant get_collider_metadata() const; - - KinematicCollision2D(); }; #endif // PHYSICS_BODY_2D_H diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 21083e6a4b..7366be5a7d 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -365,7 +365,7 @@ void Polygon2D::_notification(int p_what) { arr[RS::ARRAY_INDEX] = index_array; RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); - RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(), texture.is_valid() ? texture->get_rid() : RID()); + RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(1, 1, 1), texture.is_valid() ? texture->get_rid() : RID()); } } break; @@ -462,14 +462,6 @@ real_t Polygon2D::get_texture_rotation() const { return tex_rot; } -void Polygon2D::set_texture_rotation_degrees(real_t p_rot) { - set_texture_rotation(Math::deg2rad(p_rot)); -} - -real_t Polygon2D::get_texture_rotation_degrees() const { - return Math::rad2deg(get_texture_rotation()); -} - void Polygon2D::set_texture_scale(const Size2 &p_scale) { tex_scale = p_scale; update(); @@ -613,9 +605,6 @@ void Polygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture_rotation", "texture_rotation"), &Polygon2D::set_texture_rotation); ClassDB::bind_method(D_METHOD("get_texture_rotation"), &Polygon2D::get_texture_rotation); - ClassDB::bind_method(D_METHOD("set_texture_rotation_degrees", "texture_rotation"), &Polygon2D::set_texture_rotation_degrees); - ClassDB::bind_method(D_METHOD("get_texture_rotation_degrees"), &Polygon2D::get_texture_rotation_degrees); - ClassDB::bind_method(D_METHOD("set_texture_scale", "texture_scale"), &Polygon2D::set_texture_scale); ClassDB::bind_method(D_METHOD("get_texture_scale"), &Polygon2D::get_texture_scale); @@ -657,8 +646,7 @@ void Polygon2D::_bind_methods() { ADD_GROUP("Texture2D", "texture_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_texture_rotation_degrees", "get_texture_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_texture_rotation", "get_texture_rotation"); ADD_GROUP("Skeleton", ""); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D"), "set_skeleton", "get_skeleton"); diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index f9f36ff9a2..bf386b9ace 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -120,9 +120,6 @@ public: void set_texture_rotation(real_t p_rot); real_t get_texture_rotation() const; - void set_texture_rotation_degrees(real_t p_rot); - real_t get_texture_rotation_degrees() const; - void set_texture_scale(const Size2 &p_scale); Size2 get_texture_scale() const; diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index 5c7d65e3e0..1019f85c8a 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -36,10 +36,41 @@ const real_t DEFAULT_GIZMO_EXTENTS = 10.0; void Position2D::_draw_cross() { - real_t extents = get_gizmo_extents(); - // Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`) - draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32)); - draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01)); + const real_t extents = get_gizmo_extents(); + + // Add more points to create a "hard stop" in the color gradient. + PackedVector2Array points_x; + points_x.push_back(Point2(+extents, 0)); + points_x.push_back(Point2()); + points_x.push_back(Point2()); + points_x.push_back(Point2(-extents, 0)); + + PackedVector2Array points_y; + points_y.push_back(Point2(0, +extents)); + points_y.push_back(Point2()); + points_y.push_back(Point2()); + points_y.push_back(Point2(0, -extents)); + + // Use the axis color which is brighter for the positive axis. + // Use a darkened axis color for the negative axis. + // This makes it possible to see in which direction the Position3D node is rotated + // (which can be important depending on how it's used). + // Axis colors are taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`). + PackedColorArray colors_x; + const Color color_x = Color(0.96, 0.20, 0.32); + colors_x.push_back(color_x); + colors_x.push_back(color_x); + colors_x.push_back(color_x.lerp(Color(0, 0, 0), 0.5)); + colors_x.push_back(color_x.lerp(Color(0, 0, 0), 0.5)); + draw_multiline_colors(points_x, colors_x); + + PackedColorArray colors_y; + const Color color_y = Color(0.53, 0.84, 0.01); + colors_y.push_back(color_y); + colors_y.push_back(color_y); + colors_y.push_back(color_y.lerp(Color(0, 0, 0), 0.5)); + colors_y.push_back(color_y.lerp(Color(0, 0, 0), 0.5)); + draw_multiline_colors(points_y, colors_y); } #ifdef TOOLS_ENABLED diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index a7613dc009..e7cef965fe 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -35,7 +35,7 @@ void RemoteTransform2D::_update_cache() { cache = ObjectID(); if (has_node(remote_node)) { Node *node = get_node(remote_node); - if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) { + if (!node || this == node || node->is_ancestor_of(this) || this->is_ancestor_of(node)) { return; } diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index 22180797f0..8f1f5fadbc 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -30,6 +30,69 @@ #include "skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#include "editor/plugins/canvas_item_editor_plugin.h" +#endif //TOOLS_ENABLED + +bool Bone2D::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("auto_calculate_length_and_angle")) { + set_autocalculate_length_and_angle(p_value); + } else if (path.begins_with("length")) { + set_length(p_value); + } else if (path.begins_with("bone_angle")) { + set_bone_angle(Math::deg2rad(float(p_value))); + } else if (path.begins_with("default_length")) { + set_length(p_value); + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor_settings/show_bone_gizmo")) { + _editor_set_show_bone_gizmo(p_value); + } +#endif // TOOLS_ENABLED + + return true; +} + +bool Bone2D::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("auto_calculate_length_and_angle")) { + r_ret = get_autocalculate_length_and_angle(); + } else if (path.begins_with("length")) { + r_ret = get_length(); + } else if (path.begins_with("bone_angle")) { + r_ret = Math::rad2deg(get_bone_angle()); + } else if (path.begins_with("default_length")) { + r_ret = get_length(); + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor_settings/show_bone_gizmo")) { + r_ret = _editor_get_show_bone_gizmo(); + } +#endif // TOOLS_ENABLED + + return true; +} + +void Bone2D::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::BOOL, "auto_calculate_length_and_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + if (!autocalculate_length_and_angle) { + p_list->push_back(PropertyInfo(Variant::FLOAT, "length", PROPERTY_HINT_RANGE, "1, 1024, 1", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::FLOAT, "bone_angle", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); + } + +#ifdef TOOLS_ENABLED + p_list->push_back(PropertyInfo(Variant::BOOL, "editor_settings/show_bone_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); +#endif // TOOLS_ENABLED +} + void Bone2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { Node *parent = get_parent(); @@ -53,19 +116,54 @@ void Bone2D::_notification(int p_what) { skeleton->bones.push_back(bone); skeleton->_make_bone_setup_dirty(); } + + cache_transform = get_transform(); + copy_transform_to_cache = true; + +#ifdef TOOLS_ENABLED + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } + + update(); +#endif // TOOLS_ENABLED } - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { + + else if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { if (skeleton) { skeleton->_make_transform_dirty(); } + if (copy_transform_to_cache) { + cache_transform = get_transform(); + } +#ifdef TOOLS_ENABLED + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } + + update(); + + if (get_parent()) { + Bone2D *parent_bone = Object::cast_to<Bone2D>(get_parent()); + if (parent_bone) { + parent_bone->update(); + } + } +#endif // TOOLS_ENABLED } - if (p_what == NOTIFICATION_MOVED_IN_PARENT) { + + else if (p_what == NOTIFICATION_MOVED_IN_PARENT) { if (skeleton) { skeleton->_make_bone_setup_dirty(); } + if (copy_transform_to_cache) { + cache_transform = get_transform(); + } } - if (p_what == NOTIFICATION_EXIT_TREE) { + else if (p_what == NOTIFICATION_EXIT_TREE) { if (skeleton) { for (int i = 0; i < skeleton->bones.size(); i++) { if (skeleton->bones[i].bone == this) { @@ -77,9 +175,200 @@ void Bone2D::_notification(int p_what) { skeleton = nullptr; } parent_bone = nullptr; + set_transform(cache_transform); } + + else if (p_what == NOTIFICATION_READY) { + if (autocalculate_length_and_angle) { + calculate_length_and_rotation(); + } + } +#ifdef TOOLS_ENABLED + else if (p_what == NOTIFICATION_EDITOR_PRE_SAVE || p_what == NOTIFICATION_EDITOR_POST_SAVE) { + Transform2D tmp_trans = get_transform(); + set_transform(cache_transform); + cache_transform = tmp_trans; + } + // Bone2D Editor gizmo drawing: +#ifndef _MSC_VER +#warning TODO Bone2D gizmo drawing needs to be moved to an editor plugin +#endif + else if (p_what == NOTIFICATION_DRAW) { + // Only draw the gizmo in the editor! + if (Engine::get_singleton()->is_editor_hint() == false) { + return; + } + + if (editor_gizmo_rid.is_null()) { + editor_gizmo_rid = RenderingServer::get_singleton()->canvas_item_create(); + RenderingServer::get_singleton()->canvas_item_set_parent(editor_gizmo_rid, get_canvas_item()); + RenderingServer::get_singleton()->canvas_item_set_z_as_relative_to_parent(editor_gizmo_rid, true); + RenderingServer::get_singleton()->canvas_item_set_z_index(editor_gizmo_rid, 10); + } + RenderingServer::get_singleton()->canvas_item_clear(editor_gizmo_rid); + + if (!_editor_show_bone_gizmo) { + return; + } + + // Undo scaling + Transform2D editor_gizmo_trans = Transform2D(); + editor_gizmo_trans.set_scale(Vector2(1, 1) / get_global_scale()); + RenderingServer::get_singleton()->canvas_item_set_transform(editor_gizmo_rid, editor_gizmo_trans); + + Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); + Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); + Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); + Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); + Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); + + bool Bone2D_found = false; + for (int i = 0; i < get_child_count(); i++) { + Bone2D *child_node = nullptr; + child_node = Object::cast_to<Bone2D>(get_child(i)); + if (!child_node) { + continue; + } + Bone2D_found = true; + + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + + _editor_get_bone_shape(&bone_shape, &bone_shape_outline, child_node); + + Vector<Color> colors; + if (has_meta("_local_pose_override_enabled_")) { + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } + + Vector<Color> outline_colors; + if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + } + + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); + } + + if (!Bone2D_found) { + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + + _editor_get_bone_shape(&bone_shape, &bone_shape_outline, nullptr); + + Vector<Color> colors; + if (has_meta("_local_pose_override_enabled_")) { + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + colors.push_back(bone_ik_color); + } else { + colors.push_back(bone_color1); + colors.push_back(bone_color2); + colors.push_back(bone_color1); + colors.push_back(bone_color2); + } + + Vector<Color> outline_colors; + if (CanvasItemEditor::get_singleton()->editor_selection->is_selected(this)) { + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + outline_colors.push_back(bone_selected_color); + } else { + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + outline_colors.push_back(bone_outline_color); + } + + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape_outline, outline_colors); + RenderingServer::get_singleton()->canvas_item_add_polygon(editor_gizmo_rid, bone_shape, colors); + } + } +#endif // TOOLS_ENALBED } +#ifdef TOOLS_ENABLED +bool Bone2D::_editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone) { + int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width"); + int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size"); + + if (!is_inside_tree()) { + return false; //may have been removed + } + if (!p_other_bone && length <= 0) { + return false; + } + + Vector2 rel; + if (p_other_bone) { + rel = (p_other_bone->get_global_transform().get_origin() - get_global_transform().get_origin()); + rel = rel.rotated(-get_global_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation + } else { + float angle_to_use = get_rotation() + bone_angle; + rel = Vector2(cos(angle_to_use), sin(angle_to_use)) * (length * MIN(get_global_scale().x, get_global_scale().y)); + rel = rel.rotated(-get_rotation()); // Undo Bone2D node's rotation so its drawn correctly regardless of the node's rotation + } + + Vector2 relt = rel.rotated(Math_PI * 0.5).normalized() * bone_width; + Vector2 reln = rel.normalized(); + Vector2 reltn = relt.normalized(); + + if (p_shape) { + p_shape->clear(); + p_shape->push_back(Vector2(0, 0)); + p_shape->push_back(rel * 0.2 + relt); + p_shape->push_back(rel); + p_shape->push_back(rel * 0.2 - relt); + } + + if (p_outline_shape) { + p_outline_shape->clear(); + p_outline_shape->push_back((-reln - reltn) * bone_outline_width); + p_outline_shape->push_back((-reln + reltn) * bone_outline_width); + p_outline_shape->push_back(rel * 0.2 + relt + reltn * bone_outline_width); + p_outline_shape->push_back(rel + (reln + reltn) * bone_outline_width); + p_outline_shape->push_back(rel + (reln - reltn) * bone_outline_width); + p_outline_shape->push_back(rel * 0.2 - relt - reltn * bone_outline_width); + } + return true; +} + +void Bone2D::_editor_set_show_bone_gizmo(bool p_show_gizmo) { + _editor_show_bone_gizmo = p_show_gizmo; + update(); +} + +bool Bone2D::_editor_get_show_bone_gizmo() const { + return _editor_show_bone_gizmo; +} +#endif // TOOLS_ENABLED + void Bone2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest); ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest); @@ -90,8 +379,14 @@ void Bone2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length); ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length); + ClassDB::bind_method(D_METHOD("set_autocalculate_length_and_angle", "auto_calculate"), &Bone2D::set_autocalculate_length_and_angle); + ClassDB::bind_method(D_METHOD("get_autocalculate_length_and_angle"), &Bone2D::get_autocalculate_length_and_angle); + ClassDB::bind_method(D_METHOD("set_length", "length"), &Bone2D::set_length); + ClassDB::bind_method(D_METHOD("get_length"), &Bone2D::get_length); + ClassDB::bind_method(D_METHOD("set_bone_angle", "angle"), &Bone2D::set_bone_angle); + ClassDB::bind_method(D_METHOD("get_bone_angle"), &Bone2D::get_bone_angle); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "rest"), "set_rest", "get_rest"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_length", PROPERTY_HINT_RANGE, "1,1024,1"), "set_default_length", "get_default_length"); } void Bone2D::set_rest(const Transform2D &p_rest) { @@ -119,12 +414,14 @@ void Bone2D::apply_rest() { set_transform(rest); } -void Bone2D::set_default_length(real_t p_length) { - default_length = p_length; +void Bone2D::set_default_length(float p_length) { + WARN_DEPRECATED_MSG("set_default_length is deprecated. Please use set_length instead!"); + set_length(p_length); } -real_t Bone2D::get_default_length() const { - return default_length; +float Bone2D::get_default_length() const { + WARN_DEPRECATED_MSG("get_default_length is deprecated. Please use get_length instead!"); + return get_length(); } int Bone2D::get_index_in_skeleton() const { @@ -150,16 +447,121 @@ TypedArray<String> Bone2D::get_configuration_warnings() const { return warnings; } +void Bone2D::calculate_length_and_rotation() { + // if there is at least a single child Bone2D node, we can calculate + // the length and direction. We will always just use the first Bone2D for this. + bool calculated = false; + int child_count = get_child_count(); + if (child_count > 0) { + for (int i = 0; i < child_count; i++) { + Bone2D *child = Object::cast_to<Bone2D>(get_child(i)); + if (child) { + Vector2 child_local_pos = to_local(child->get_global_transform().get_origin()); + length = child_local_pos.length(); + bone_angle = Math::atan2(child_local_pos.normalized().y, child_local_pos.normalized().x); + calculated = true; + break; + } + } + } + if (calculated) { + return; // Finished! + } else { + WARN_PRINT("No Bone2D children of node " + get_name() + ". Cannot calculate bone length or angle reliably.\nUsing transform rotation for bone angle"); + bone_angle = get_transform().get_rotation(); + return; + } +} + +void Bone2D::set_autocalculate_length_and_angle(bool p_autocalculate) { + autocalculate_length_and_angle = p_autocalculate; + if (autocalculate_length_and_angle) { + calculate_length_and_rotation(); + } + notify_property_list_changed(); +} + +bool Bone2D::get_autocalculate_length_and_angle() const { + return autocalculate_length_and_angle; +} + +void Bone2D::set_length(float p_length) { + length = p_length; + +#ifdef TOOLS_ENABLED + update(); +#endif // TOOLS_ENABLED +} + +float Bone2D::get_length() const { + return length; +} + +void Bone2D::set_bone_angle(float p_angle) { + bone_angle = p_angle; + +#ifdef TOOLS_ENABLED + update(); +#endif // TOOLS_ENABLED +} + +float Bone2D::get_bone_angle() const { + return bone_angle; +} + Bone2D::Bone2D() { + skeleton = nullptr; + parent_bone = nullptr; + skeleton_index = -1; + length = 16; + bone_angle = 0; + autocalculate_length_and_angle = true; set_notify_local_transform(true); //this is a clever hack so the bone knows no rest has been set yet, allowing to show an error. for (int i = 0; i < 3; i++) { rest[i] = Vector2(0, 0); } + copy_transform_to_cache = true; +} + +Bone2D::~Bone2D() { +#ifdef TOOLS_ENABLED + if (!editor_gizmo_rid.is_null()) { + RenderingServer::get_singleton()->free(editor_gizmo_rid); + } +#endif // TOOLS_ENABLED } ////////////////////////////////////// +bool Skeleton2D::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("modification_stack")) { + set_modification_stack(p_value); + return true; + } + return true; +} + +bool Skeleton2D::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("modification_stack")) { + r_ret = get_modification_stack(); + return true; + } + return true; +} + +void Skeleton2D::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back( + PropertyInfo(Variant::OBJECT, "modification_stack", + PROPERTY_HINT_RESOURCE_TYPE, + "SkeletonModificationStack2D", + PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); +} + void Skeleton2D::_make_bone_setup_dirty() { if (bone_setup_dirty) { return; @@ -189,6 +591,8 @@ void Skeleton2D::_update_bone_setup() { } else { bones.write[i].parent_index = -1; } + + bones.write[i].local_pose_override = bones[i].bone->get_skeleton_rest(); } transform_dirty = true; @@ -257,19 +661,121 @@ void Skeleton2D::_notification(int p_what) { if (transform_dirty) { _update_transform(); } - request_ready(); } if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { RS::get_singleton()->skeleton_set_base_transform_2d(skeleton, get_global_transform()); + } else if (p_what == NOTIFICATION_INTERNAL_PROCESS) { + if (modification_stack.is_valid()) { + execute_modifications(get_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process); + } + } else if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { + if (modification_stack.is_valid()) { + execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process); + } } +#ifdef TOOLS_ENABLED + else if (p_what == NOTIFICATION_DRAW) { + if (Engine::get_singleton()->is_editor_hint()) { + if (modification_stack.is_valid()) { + modification_stack->draw_editor_gizmos(); + } + } + } +#endif // TOOLS_ENABLED } RID Skeleton2D::get_skeleton() const { return skeleton; } +void Skeleton2D::set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent) { + ERR_FAIL_INDEX_MSG(p_bone_idx, bones.size(), "Bone index is out of range!"); + bones.write[p_bone_idx].local_pose_override = p_override; + bones.write[p_bone_idx].local_pose_override_amount = p_amount; + bones.write[p_bone_idx].local_pose_override_persistent = p_persistent; +} + +Transform2D Skeleton2D::get_bone_local_pose_override(int p_bone_idx) { + ERR_FAIL_INDEX_V_MSG(p_bone_idx, bones.size(), Transform2D(), "Bone index is out of range!"); + return bones[p_bone_idx].local_pose_override; +} + +void Skeleton2D::set_modification_stack(Ref<SkeletonModificationStack2D> p_stack) { + if (modification_stack.is_valid()) { + modification_stack->is_setup = false; + modification_stack->set_skeleton(nullptr); + + set_process_internal(false); + set_physics_process_internal(false); + } + modification_stack = p_stack; + if (modification_stack.is_valid()) { + modification_stack->set_skeleton(this); + modification_stack->setup(); + + set_process_internal(true); + set_physics_process_internal(true); + +#ifdef TOOLS_ENABLED + modification_stack->set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED + } +} + +Ref<SkeletonModificationStack2D> Skeleton2D::get_modification_stack() const { + return modification_stack; +} + +void Skeleton2D::execute_modifications(float p_delta, int p_execution_mode) { + if (!modification_stack.is_valid()) { + return; + } + + // Do not cache the transform changes caused by the modifications! + for (int i = 0; i < bones.size(); i++) { + bones[i].bone->copy_transform_to_cache = false; + } + + if (modification_stack->skeleton != this) { + modification_stack->set_skeleton(this); + } + + modification_stack->execute(p_delta, p_execution_mode); + + // Only apply the local pose override on _process. Otherwise, just calculate the local_pose_override and reset the transform. + if (p_execution_mode == SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_process) { + for (int i = 0; i < bones.size(); i++) { + if (bones[i].local_pose_override_amount > 0) { + bones[i].bone->set_meta("_local_pose_override_enabled_", true); + + Transform2D final_trans = bones[i].bone->cache_transform; + final_trans = final_trans.interpolate_with(bones[i].local_pose_override, bones[i].local_pose_override_amount); + bones[i].bone->set_transform(final_trans); + bones[i].bone->propagate_call("force_update_transform"); + + if (bones[i].local_pose_override_persistent) { + bones.write[i].local_pose_override_amount = 0.0; + } + } else { + // TODO: see if there is a way to undo the override without having to resort to setting every bone's transform. + bones[i].bone->remove_meta("_local_pose_override_enabled_"); + bones[i].bone->set_transform(bones[i].bone->cache_transform); + } + } + } + + // Cache any future transform changes + for (int i = 0; i < bones.size(); i++) { + bones[i].bone->copy_transform_to_cache = true; + } + +#ifdef TOOLS_ENABLED + modification_stack->set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED +} + void Skeleton2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup); ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform); @@ -279,6 +785,13 @@ void Skeleton2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton); + ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton2D::set_modification_stack); + ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton2D::get_modification_stack); + ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton2D::execute_modifications); + + ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "override_pose", "strength", "persistent"), &Skeleton2D::set_bone_local_pose_override); + ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton2D::get_bone_local_pose_override); + ADD_SIGNAL(MethodInfo("bone_setup_changed")); } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index fd62b87bde..59bd711960 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -32,6 +32,7 @@ #define SKELETON_2D_H #include "scene/2d/node_2d.h" +#include "scene/resources/skeleton_modification_2d.h" class Skeleton2D; @@ -46,15 +47,32 @@ class Bone2D : public Node2D { Bone2D *parent_bone = nullptr; Skeleton2D *skeleton = nullptr; Transform2D rest; - real_t default_length = 16.0; + + bool autocalculate_length_and_angle = true; + float length = 16; + float bone_angle = 0; int skeleton_index = -1; + void calculate_length_and_rotation(); + +#ifdef TOOLS_ENABLED + RID editor_gizmo_rid; + bool _editor_get_bone_shape(Vector<Vector2> *p_shape, Vector<Vector2> *p_outline_shape, Bone2D *p_other_bone); + bool _editor_show_bone_gizmo = true; +#endif // TOOLS ENABLED + protected: void _notification(int p_what); static void _bind_methods(); + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; public: + Transform2D cache_transform; + bool copy_transform_to_cache = true; + void set_rest(const Transform2D &p_rest); Transform2D get_rest() const; void apply_rest(); @@ -65,11 +83,26 @@ public: void set_default_length(real_t p_length); real_t get_default_length() const; + void set_autocalculate_length_and_angle(bool p_autocalculate); + bool get_autocalculate_length_and_angle() const; + void set_length(float p_length); + float get_length() const; + void set_bone_angle(float p_angle); + float get_bone_angle() const; + int get_index_in_skeleton() const; +#ifdef TOOLS_ENABLED + void _editor_set_show_bone_gizmo(bool p_show_gizmo); + bool _editor_get_show_bone_gizmo() const; +#endif // TOOLS_ENABLED + Bone2D(); + ~Bone2D(); }; +class SkeletonModificationStack2D; + class Skeleton2D : public Node2D { GDCLASS(Skeleton2D, Node2D); @@ -86,6 +119,11 @@ class Skeleton2D : public Node2D { int parent_index = 0; Transform2D accum_transform; Transform2D rest_inverse; + + //Transform2D local_pose_cache; + Transform2D local_pose_override; + float local_pose_override_amount = 0; + bool local_pose_override_persistent = false; }; Vector<Bone> bones; @@ -100,15 +138,28 @@ class Skeleton2D : public Node2D { RID skeleton; + Ref<SkeletonModificationStack2D> modification_stack; + protected: void _notification(int p_what); static void _bind_methods(); + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; public: int get_bone_count() const; Bone2D *get_bone(int p_idx); RID get_skeleton() const; + + void set_bone_local_pose_override(int p_bone_idx, Transform2D p_override, float p_amount, bool p_persistent = true); + Transform2D get_bone_local_pose_override(int p_bone_idx); + + Ref<SkeletonModificationStack2D> get_modification_stack() const; + void set_modification_stack(Ref<SkeletonModificationStack2D> p_stack); + void execute_modifications(float p_delta, int p_execution_mode); + Skeleton2D(); ~Skeleton2D(); }; diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index 20169b1075..40e0f4523f 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -153,7 +153,7 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) { } update(); - emit_signal("texture_changed"); + emit_signal(SceneStringNames::get_singleton()->texture_changed); item_rect_changed(); } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 24b907fe6c..e39c8841cd 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -334,6 +334,12 @@ TileMap::VisibilityMode TileMap::get_navigation_visibility_mode() { return show_navigation; } +void TileMap::set_y_sort_enabled(bool p_enable) { + Node2D::set_y_sort_enabled(p_enable); + _recreate_quadrants(); + emit_signal("changed"); +} + void TileMap::update_dirty_quadrants() { if (!pending_update) { return; @@ -705,12 +711,17 @@ Map<Vector2i, TileMapQuadrant> &TileMap::get_quadrant_map() { void TileMap::fix_invalid_tiles() { ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open."); + + Set<Vector2i> coords; for (Map<Vector2i, TileMapCell>::Element *E = tile_map.front(); E; E = E->next()) { TileSetSource *source = *tile_set->get_source(E->get().source_id); if (!source || !source->has_tile(E->get().get_atlas_coords()) || !source->has_alternative_tile(E->get().get_atlas_coords(), E->get().alternative_tile)) { - set_cell(E->key(), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + coords.insert(E->key()); } } + for (Set<Vector2i>::Element *E = coords.front(); E; E = E->next()) { + set_cell(E->get(), -1, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + } } void TileMap::_recreate_quadrants() { diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index f02455a84b..3001e6b471 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -279,6 +279,7 @@ public: int get_effective_quadrant_size() const; void update_dirty_quadrants(); + virtual void set_y_sort_enabled(bool p_enable) override; Vector2 map_to_world(const Vector2i &p_pos) const; Vector2i world_to_map(const Vector2 &p_pos) const; diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 4e58984b37..0a6393551c 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -288,7 +288,7 @@ void TouchScreenButton::_press(int p_finger_pressed) { if (action != StringName()) { Input::get_singleton()->action_press(action); Ref<InputEventAction> iea; - iea.instance(); + iea.instantiate(); iea->set_action(action); iea->set_pressed(true); get_viewport()->input(iea, true); @@ -305,7 +305,7 @@ void TouchScreenButton::_release(bool p_exiting_tree) { Input::get_singleton()->action_release(action); if (!p_exiting_tree) { Ref<InputEventAction> iea; - iea.instance(); + iea.instantiate(); iea->set_action(action); iea->set_pressed(false); get_viewport()->input(iea, true); diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp deleted file mode 100644 index 8feb47f1cc..0000000000 --- a/scene/2d/visibility_notifier_2d.cpp +++ /dev/null @@ -1,361 +0,0 @@ -/*************************************************************************/ -/* visibility_notifier_2d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "visibility_notifier_2d.h" - -#include "core/config/engine.h" -#include "gpu_particles_2d.h" -#include "scene/2d/animated_sprite_2d.h" -#include "scene/2d/physics_body_2d.h" -#include "scene/animation/animation_player.h" -#include "scene/main/window.h" -#include "scene/scene_string_names.h" - -#ifdef TOOLS_ENABLED -Rect2 VisibilityNotifier2D::_edit_get_rect() const { - return rect; -} - -bool VisibilityNotifier2D::_edit_use_rect() const { - return true; -} -#endif - -void VisibilityNotifier2D::_enter_viewport(Viewport *p_viewport) { - ERR_FAIL_COND(viewports.has(p_viewport)); - viewports.insert(p_viewport); - - if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { - return; - } - - if (viewports.size() == 1) { - emit_signal(SceneStringNames::get_singleton()->screen_entered); - - _screen_enter(); - } - emit_signal(SceneStringNames::get_singleton()->viewport_entered, p_viewport); -} - -void VisibilityNotifier2D::_exit_viewport(Viewport *p_viewport) { - ERR_FAIL_COND(!viewports.has(p_viewport)); - viewports.erase(p_viewport); - - if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) { - return; - } - - emit_signal(SceneStringNames::get_singleton()->viewport_exited, p_viewport); - if (viewports.size() == 0) { - emit_signal(SceneStringNames::get_singleton()->screen_exited); - - _screen_exit(); - } -} - -void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) { - rect = p_rect; - if (is_inside_tree()) { - get_world_2d()->_update_notifier(this, get_global_transform().xform(rect)); - if (Engine::get_singleton()->is_editor_hint()) { - update(); - item_rect_changed(); - } - } -} - -Rect2 VisibilityNotifier2D::get_rect() const { - return rect; -} - -void VisibilityNotifier2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - //get_world_2d()-> - get_world_2d()->_register_notifier(this, get_global_transform().xform(rect)); - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - //get_world_2d()-> - get_world_2d()->_update_notifier(this, get_global_transform().xform(rect)); - } break; - case NOTIFICATION_DRAW: { - if (Engine::get_singleton()->is_editor_hint()) { - draw_rect(rect, Color(1, 0.5, 1, 0.2)); - } - } break; - case NOTIFICATION_EXIT_TREE: { - get_world_2d()->_remove_notifier(this); - } break; - } -} - -bool VisibilityNotifier2D::is_on_screen() const { - return viewports.size() > 0; -} - -void VisibilityNotifier2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_rect", "rect"), &VisibilityNotifier2D::set_rect); - ClassDB::bind_method(D_METHOD("get_rect"), &VisibilityNotifier2D::get_rect); - ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibilityNotifier2D::is_on_screen); - - ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect"); - - ADD_SIGNAL(MethodInfo("viewport_entered", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport"))); - ADD_SIGNAL(MethodInfo("viewport_exited", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport"))); - ADD_SIGNAL(MethodInfo("screen_entered")); - ADD_SIGNAL(MethodInfo("screen_exited")); -} - -VisibilityNotifier2D::VisibilityNotifier2D() { - rect = Rect2(-10, -10, 20, 20); - set_notify_transform(true); -} - -////////////////////////////////////// - -void VisibilityEnabler2D::_screen_enter() { - for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), true); - } - - if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) { - get_parent()->set_physics_process(true); - } - if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) { - get_parent()->set_process(true); - } - - visible = true; -} - -void VisibilityEnabler2D::_screen_exit() { - for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), false); - } - - if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) { - get_parent()->set_physics_process(false); - } - if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) { - get_parent()->set_process(false); - } - - visible = false; -} - -void VisibilityEnabler2D::_find_nodes(Node *p_node) { - bool add = false; - Variant meta; - - { - RigidBody2D *rb2d = Object::cast_to<RigidBody2D>(p_node); - if (rb2d && ((rb2d->get_mode() == RigidBody2D::MODE_CHARACTER || rb2d->get_mode() == RigidBody2D::MODE_RIGID))) { - add = true; - meta = rb2d->get_mode(); - } - } - - { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); - if (ap) { - add = true; - } - } - - { - AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node); - if (as) { - add = true; - } - } - - { - GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node); - if (ps) { - add = true; - } - } - - if (add) { - p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed), varray(p_node), CONNECT_ONESHOT); - nodes[p_node] = meta; - _change_node_state(p_node, false); - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *c = p_node->get_child(i); - if (c->get_filename() != String()) { - continue; //skip, instance - } - - _find_nodes(c); - } -} - -void VisibilityEnabler2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - - Node *from = this; - //find where current scene starts - while (from->get_parent() && from->get_filename() == String()) { - from = from->get_parent(); - } - - _find_nodes(from); - - // We need to defer the call of set_process and set_physics_process, - // otherwise they are overwritten inside NOTIFICATION_READY. - // We can't use call_deferred, because it happens after a physics frame. - // The ready signal works as it's emitted immediately after NOTIFICATION_READY. - - if (enabler[ENABLER_PARENT_PHYSICS_PROCESS] && get_parent()) { - get_parent()->connect(SceneStringNames::get_singleton()->ready, - callable_mp(get_parent(), &Node::set_physics_process), varray(false), CONNECT_ONESHOT); - } - if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) { - get_parent()->connect(SceneStringNames::get_singleton()->ready, - callable_mp(get_parent(), &Node::set_process), varray(false), CONNECT_ONESHOT); - } - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - - for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) { - if (!visible) { - _change_node_state(E->key(), true); - } - E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler2D::_node_removed)); - } - - nodes.clear(); - } -} - -void VisibilityEnabler2D::_change_node_state(Node *p_node, bool p_enabled) { - ERR_FAIL_COND(!nodes.has(p_node)); - - if (enabler[ENABLER_FREEZE_BODIES]) { - RigidBody2D *rb = Object::cast_to<RigidBody2D>(p_node); - if (rb) { - rb->set_sleeping(!p_enabled); - } - } - - if (enabler[ENABLER_PAUSE_ANIMATIONS]) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); - - if (ap) { - ap->set_active(p_enabled); - } - } - - if (enabler[ENABLER_PAUSE_ANIMATED_SPRITES]) { - AnimatedSprite2D *as = Object::cast_to<AnimatedSprite2D>(p_node); - - if (as) { - if (p_enabled) { - as->play(); - } else { - as->stop(); - } - } - } - - if (enabler[ENABLER_PAUSE_PARTICLES]) { - GPUParticles2D *ps = Object::cast_to<GPUParticles2D>(p_node); - - if (ps) { - ps->set_emitting(p_enabled); - } - } -} - -void VisibilityEnabler2D::_node_removed(Node *p_node) { - if (!visible) { - _change_node_state(p_node, true); - } - nodes.erase(p_node); -} - -TypedArray<String> VisibilityEnabler2D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); - -#ifdef TOOLS_ENABLED - if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) { - warnings.push_back(TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent.")); - } -#endif - return warnings; -} - -void VisibilityEnabler2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler2D::set_enabler); - ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler2D::is_enabler_enabled); - ClassDB::bind_method(D_METHOD("_node_removed"), &VisibilityEnabler2D::_node_removed); - - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_particles"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_PARTICLES); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animated_sprites"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATED_SPRITES); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PROCESS); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "physics_process_parent"), "set_enabler", "is_enabler_enabled", ENABLER_PARENT_PHYSICS_PROCESS); - - BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS); - BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES); - BIND_ENUM_CONSTANT(ENABLER_PAUSE_PARTICLES); - BIND_ENUM_CONSTANT(ENABLER_PARENT_PROCESS); - BIND_ENUM_CONSTANT(ENABLER_PARENT_PHYSICS_PROCESS); - BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATED_SPRITES); - BIND_ENUM_CONSTANT(ENABLER_MAX); -} - -void VisibilityEnabler2D::set_enabler(Enabler p_enabler, bool p_enable) { - ERR_FAIL_INDEX(p_enabler, ENABLER_MAX); - enabler[p_enabler] = p_enable; -} - -bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const { - ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false); - return enabler[p_enabler]; -} - -VisibilityEnabler2D::VisibilityEnabler2D() { - for (int i = 0; i < ENABLER_MAX; i++) { - enabler[i] = true; - } - enabler[ENABLER_PARENT_PROCESS] = false; - enabler[ENABLER_PARENT_PHYSICS_PROCESS] = false; -} diff --git a/scene/2d/visible_on_screen_notifier_2d.cpp b/scene/2d/visible_on_screen_notifier_2d.cpp new file mode 100644 index 0000000000..25237edacf --- /dev/null +++ b/scene/2d/visible_on_screen_notifier_2d.cpp @@ -0,0 +1,213 @@ +/*************************************************************************/ +/* visible_on_screen_notifier_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "visible_on_screen_notifier_2d.h" + +#include "core/config/engine.h" +#include "gpu_particles_2d.h" +#include "scene/2d/animated_sprite_2d.h" +#include "scene/2d/physics_body_2d.h" +#include "scene/animation/animation_player.h" +#include "scene/main/window.h" +#include "scene/scene_string_names.h" + +#ifdef TOOLS_ENABLED +Rect2 VisibleOnScreenNotifier2D::_edit_get_rect() const { + return rect; +} + +bool VisibleOnScreenNotifier2D::_edit_use_rect() const { + return true; +} +#endif + +void VisibleOnScreenNotifier2D::_visibility_enter() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; + } + + on_screen = true; + emit_signal(SceneStringNames::get_singleton()->screen_entered); + _screen_enter(); +} +void VisibleOnScreenNotifier2D::_visibility_exit() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; + } + + on_screen = false; + emit_signal(SceneStringNames::get_singleton()->screen_exited); + _screen_exit(); +} + +void VisibleOnScreenNotifier2D::set_rect(const Rect2 &p_rect) { + rect = p_rect; + if (is_inside_tree()) { + RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); + } +} + +Rect2 VisibleOnScreenNotifier2D::get_rect() const { + return rect; +} + +void VisibleOnScreenNotifier2D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + //get_world_2d()-> + on_screen = false; + RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), true, rect, callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier2D::_visibility_exit)); + } break; + case NOTIFICATION_DRAW: { + if (Engine::get_singleton()->is_editor_hint()) { + draw_rect(rect, Color(1, 0.5, 1, 0.2)); + } + } break; + case NOTIFICATION_EXIT_TREE: { + on_screen = false; + RS::get_singleton()->canvas_item_set_visibility_notifier(get_canvas_item(), false, Rect2(), Callable(), Callable()); + } break; + } +} + +bool VisibleOnScreenNotifier2D::is_on_screen() const { + return on_screen; +} + +void VisibleOnScreenNotifier2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_rect", "rect"), &VisibleOnScreenNotifier2D::set_rect); + ClassDB::bind_method(D_METHOD("get_rect"), &VisibleOnScreenNotifier2D::get_rect); + ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibleOnScreenNotifier2D::is_on_screen); + + ADD_PROPERTY(PropertyInfo(Variant::RECT2, "rect"), "set_rect", "get_rect"); + + ADD_SIGNAL(MethodInfo("screen_entered")); + ADD_SIGNAL(MethodInfo("screen_exited")); +} + +VisibleOnScreenNotifier2D::VisibleOnScreenNotifier2D() { + rect = Rect2(-10, -10, 20, 20); +} + +////////////////////////////////////// + +void VisibleOnScreenEnabler2D::_screen_enter() { + _update_enable_mode(true); +} + +void VisibleOnScreenEnabler2D::_screen_exit() { + _update_enable_mode(false); +} + +void VisibleOnScreenEnabler2D::set_enable_mode(EnableMode p_mode) { + enable_mode = p_mode; + if (is_inside_tree()) { + _update_enable_mode(is_on_screen()); + } +} +VisibleOnScreenEnabler2D::EnableMode VisibleOnScreenEnabler2D::get_enable_mode() { + return enable_mode; +} + +void VisibleOnScreenEnabler2D::set_enable_node_path(NodePath p_path) { + if (enable_node_path == p_path) { + return; + } + enable_node_path = p_path; + if (is_inside_tree()) { + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + _update_enable_mode(is_on_screen()); + } + } +} +NodePath VisibleOnScreenEnabler2D::get_enable_node_path() { + return enable_node_path; +} + +void VisibleOnScreenEnabler2D::_update_enable_mode(bool p_enable) { + Node *node = static_cast<Node *>(ObjectDB::get_instance(node_id)); + if (node) { + if (p_enable) { + switch (enable_mode) { + case ENABLE_MODE_INHERIT: { + node->set_process_mode(PROCESS_MODE_INHERIT); + } break; + case ENABLE_MODE_ALWAYS: { + node->set_process_mode(PROCESS_MODE_ALWAYS); + } break; + case ENABLE_MODE_WHEN_PAUSED: { + node->set_process_mode(PROCESS_MODE_WHEN_PAUSED); + } break; + } + } else { + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } +} +void VisibleOnScreenEnabler2D::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE) { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } + + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + node_id = ObjectID(); + } +} + +void VisibleOnScreenEnabler2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibleOnScreenEnabler2D::set_enable_mode); + ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibleOnScreenEnabler2D::get_enable_mode); + + ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibleOnScreenEnabler2D::set_enable_node_path); + ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler2D::get_enable_node_path); + + ADD_GROUP("Enabling", "enable_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path"); + + BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT); + BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS); + BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED); +} + +VisibleOnScreenEnabler2D::VisibleOnScreenEnabler2D() { +} diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visible_on_screen_notifier_2d.h index 7f4a5bc193..9c236a138f 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visible_on_screen_notifier_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* visibility_notifier_2d.h */ +/* visible_on_screen_notifier_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,25 +28,25 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VISIBILITY_NOTIFIER_2D_H -#define VISIBILITY_NOTIFIER_2D_H +#ifndef VISIBLE_ON_SCREEN_NOTIFIER_2D_H +#define VISIBLE_ON_SCREEN_NOTIFIER_2D_H #include "scene/2d/node_2d.h" class Viewport; -class VisibilityNotifier2D : public Node2D { - GDCLASS(VisibilityNotifier2D, Node2D); +class VisibleOnScreenNotifier2D : public Node2D { + GDCLASS(VisibleOnScreenNotifier2D, Node2D); Set<Viewport *> viewports; Rect2 rect; -protected: - friend struct SpatialIndexer2D; - - void _enter_viewport(Viewport *p_viewport); - void _exit_viewport(Viewport *p_viewport); +private: + bool on_screen = false; + void _visibility_enter(); + void _visibility_exit(); +protected: virtual void _screen_enter() {} virtual void _screen_exit() {} @@ -64,49 +64,42 @@ public: bool is_on_screen() const; - VisibilityNotifier2D(); + VisibleOnScreenNotifier2D(); }; -class VisibilityEnabler2D : public VisibilityNotifier2D { - GDCLASS(VisibilityEnabler2D, VisibilityNotifier2D); +class VisibleOnScreenEnabler2D : public VisibleOnScreenNotifier2D { + GDCLASS(VisibleOnScreenEnabler2D, VisibleOnScreenNotifier2D); public: - enum Enabler { - ENABLER_PAUSE_ANIMATIONS, - ENABLER_FREEZE_BODIES, - ENABLER_PAUSE_PARTICLES, - ENABLER_PARENT_PROCESS, - ENABLER_PARENT_PHYSICS_PROCESS, - ENABLER_PAUSE_ANIMATED_SPRITES, - ENABLER_MAX + enum EnableMode { + ENABLE_MODE_INHERIT, + ENABLE_MODE_ALWAYS, + ENABLE_MODE_WHEN_PAUSED, }; protected: + ObjectID node_id; virtual void _screen_enter() override; virtual void _screen_exit() override; - bool visible = false; - - void _find_nodes(Node *p_node); - - Map<Node *, Variant> nodes; - void _node_removed(Node *p_node); - bool enabler[ENABLER_MAX]; - - void _change_node_state(Node *p_node, bool p_enabled); + EnableMode enable_mode = ENABLE_MODE_INHERIT; + NodePath enable_node_path = NodePath(".."); void _notification(int p_what); static void _bind_methods(); + void _update_enable_mode(bool p_enable); + public: - void set_enabler(Enabler p_enabler, bool p_enable); - bool is_enabler_enabled(Enabler p_enabler) const; + void set_enable_mode(EnableMode p_mode); + EnableMode get_enable_mode(); - TypedArray<String> get_configuration_warnings() const override; + void set_enable_node_path(NodePath p_path); + NodePath get_enable_node_path(); - VisibilityEnabler2D(); + VisibleOnScreenEnabler2D(); }; -VARIANT_ENUM_CAST(VisibilityEnabler2D::Enabler); +VARIANT_ENUM_CAST(VisibleOnScreenEnabler2D::EnableMode); #endif // VISIBILITY_NOTIFIER_2D_H diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp deleted file mode 100644 index 7e7bc27cc2..0000000000 --- a/scene/2d/y_sort.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* y_sort.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "y_sort.h" - -void YSort::set_sort_enabled(bool p_enabled) { - sort_enabled = p_enabled; - RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), sort_enabled); -} - -bool YSort::is_sort_enabled() const { - return sort_enabled; -} - -void YSort::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_sort_enabled", "enabled"), &YSort::set_sort_enabled); - ClassDB::bind_method(D_METHOD("is_sort_enabled"), &YSort::is_sort_enabled); - - ADD_GROUP("Sort", "sort_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sort_enabled"), "set_sort_enabled", "is_sort_enabled"); -} - -YSort::YSort() { - RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), true); -} diff --git a/scene/3d/SCsub b/scene/3d/SCsub index ce69e8aa19..40bdaee47d 100644 --- a/scene/3d/SCsub +++ b/scene/3d/SCsub @@ -4,6 +4,5 @@ Import("env") if env["disable_3d"]: env.add_source_files(env.scene_sources, "node_3d.cpp") - env.add_source_files(env.scene_sources, "skeleton_3d.cpp") else: env.add_source_files(env.scene_sources, "*.cpp") diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index 44708cddff..cd64a813dd 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -601,7 +601,7 @@ void Area3D::_bind_methods() { ADD_GROUP("Physics Overrides", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001,or_greater,exp"), "set_gravity_distance_scale", "get_gravity_distance_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity", PROPERTY_HINT_RANGE, "-32,32,0.001,or_lesser,or_greater"), "set_gravity", "get_gravity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index cad4330c17..ba559b4ecb 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -404,10 +404,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { break; } - List<Camera3D *> cameras; - world_3d->get_camera_list(&cameras); - - for (List<Camera3D *>::Element *E = cameras.front(); E; E = E->next()) { + for (const Set<Camera3D *>::Element *E = world_3d->get_cameras().front(); E; E = E->next()) { Camera3D *camera = E->get(); Viewport *vp = camera->get_viewport(); if (!vp->is_audio_listener()) { @@ -970,13 +967,13 @@ void AudioStreamPlayer3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); ADD_GROUP("Emission Angle", "emission_angle"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emission_angle_enabled"), "set_emission_angle_enabled", "is_emission_angle_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1"), "set_emission_angle", "get_emission_angle"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_degrees", PROPERTY_HINT_RANGE, "0.1,90,0.1,degrees"), "set_emission_angle", "get_emission_angle"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_angle_filter_attenuation_db", PROPERTY_HINT_RANGE, "-80,0,0.1"), "set_emission_angle_filter_attenuation_db", "get_emission_angle_filter_attenuation_db"); ADD_GROUP("Attenuation Filter", "attenuation_filter_"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "attenuation_filter_cutoff_hz", PROPERTY_HINT_RANGE, "1,20500,1"), "set_attenuation_filter_cutoff_hz", "get_attenuation_filter_cutoff_hz"); @@ -1000,7 +997,7 @@ void AudioStreamPlayer3D::_bind_methods() { } AudioStreamPlayer3D::AudioStreamPlayer3D() { - velocity_tracker.instance(); + velocity_tracker.instantiate(); AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed)); set_disable_scale(true); } diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 041da4f6ff..1ed8c0b4eb 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -93,10 +93,6 @@ void Camera3D::_update_camera() { } get_viewport()->_camera_transform_changed_notify(); - - if (get_world_3d().is_valid()) { - get_world_3d()->_update_camera(this); - } } void Camera3D::_notification(int p_what) { @@ -150,8 +146,8 @@ void Camera3D::_notification(int p_what) { } } -Transform Camera3D::get_camera_transform() const { - Transform tr = get_global_transform().orthonormalized(); +Transform3D Camera3D::get_camera_transform() const { + Transform3D tr = get_global_transform().orthonormalized(); tr.origin += tr.basis.get_axis(1) * v_offset; tr.origin += tr.basis.get_axis(0) * h_offset; return tr; @@ -318,7 +314,7 @@ Vector3 Camera3D::project_ray_origin(const Point2 &p_pos) const { }; bool Camera3D::is_position_behind(const Vector3 &p_pos) const { - Transform t = get_global_transform(); + Transform3D t = get_global_transform(); Vector3 eyedir = -t.basis.get_axis(2).normalized(); return eyedir.dot(p_pos - t.origin) < near; } @@ -337,7 +333,7 @@ Vector<Vector3> Camera3D::get_near_plane_points() const { } Vector3 endpoints[8]; - cm.get_endpoints(Transform(), endpoints); + cm.get_endpoints(Transform3D(), endpoints); Vector<Vector3> points; points.push_back(Vector3()); @@ -500,6 +496,7 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_doppler_tracking", "mode"), &Camera3D::set_doppler_tracking); ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera3D::get_doppler_tracking); ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum); + ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum); ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera); ClassDB::bind_method(D_METHOD("set_cull_mask_bit", "layer", "enable"), &Camera3D::set_cull_mask_bit); @@ -516,11 +513,11 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking"); ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal,Frustum"), "set_projection", "get_projection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1,degrees"), "set_fov", "get_fov"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,10,0.001,or_greater"), "set_near", "get_near"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4000,0.01,or_greater"), "set_far", "get_far"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater,exp"), "set_near", "get_near"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_RANGE, "0.01,4000,0.01,or_greater,exp"), "set_far", "get_far"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); @@ -623,6 +620,16 @@ Vector<Plane> Camera3D::get_frustum() const { return cm.get_projection_planes(get_camera_transform()); } +bool Camera3D::is_position_in_frustum(const Vector3 &p_position) const { + Vector<Plane> frustum = get_frustum(); + for (int i = 0; i < frustum.size(); i++) { + if (frustum[i].is_point_over(p_position)) { + return false; + } + } + return true; +} + void Camera3D::set_v_offset(float p_offset) { v_offset = p_offset; _update_camera(); @@ -654,7 +661,7 @@ Camera3D::Camera3D() { set_perspective(75.0, 0.05, 4000.0); RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); //active=false; - velocity_tracker.instance(); + velocity_tracker.instantiate(); set_notify_transform(true); set_disable_scale(true); } @@ -686,8 +693,8 @@ ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() con return process_callback; } -Transform ClippedCamera3D::get_camera_transform() const { - Transform t = Camera3D::get_camera_transform(); +Transform3D ClippedCamera3D::get_camera_transform() const { + Transform3D t = Camera3D::get_camera_transform(); t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset; return t; } @@ -735,7 +742,7 @@ void ClippedCamera3D::_notification(int p_what) { } } - Transform xf = get_global_transform(); + Transform3D xf = get_global_transform(); xf.origin = ray_from; xf.orthonormalize(); diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index cea61e4db8..c6efc8f9a9 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -134,7 +134,7 @@ public: void set_near(float p_near); void set_frustum_offset(Vector2 p_offset); - virtual Transform get_camera_transform() const; + virtual Transform3D get_camera_transform() const; virtual Vector3 project_ray_normal(const Point2 &p_pos) const; virtual Vector3 project_ray_origin(const Point2 &p_pos) const; @@ -153,6 +153,7 @@ public: bool get_cull_mask_bit(int p_layer) const; virtual Vector<Plane> get_frustum() const; + bool is_position_in_frustum(const Vector3 &p_position) const; void set_environment(const Ref<Environment> &p_environment); Ref<Environment> get_environment() const; @@ -207,7 +208,7 @@ private: protected: void _notification(int p_what); static void _bind_methods(); - virtual Transform get_camera_transform() const override; + virtual Transform3D get_camera_transform() const override; public: void set_clip_to_areas(bool p_clip); diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index cba769a8f8..40e3f7c764 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -32,7 +32,6 @@ #include "core/config/engine.h" #include "scene/scene_string_names.h" -#include "servers/physics_server_3d.h" void CollisionObject3D::_notification(int p_what) { switch (p_what) { @@ -59,15 +58,22 @@ void CollisionObject3D::_notification(int p_what) { PhysicsServer3D::get_singleton()->body_set_state(rid, PhysicsServer3D::BODY_STATE_TRANSFORM, get_global_transform()); } - RID space = get_world_3d()->get_space(); - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, space); - } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, space); + bool disabled = !is_enabled(); + + if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { + _apply_disabled(); + } + + if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { + RID space = get_world_3d()->get_space(); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, space); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, space); + } } _update_pickable(); - //get space } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -78,19 +84,34 @@ void CollisionObject3D::_notification(int p_what) { } _on_transform_changed(); - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); - } break; + case NOTIFICATION_EXIT_WORLD: { - if (area) { - PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); - } else { - PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + bool disabled = !is_enabled(); + + if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) { + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } + } + + if (disabled && (disable_mode != DISABLE_MODE_REMOVE)) { + _apply_enabled(); } + } break; + case NOTIFICATION_DISABLED: { + _apply_disabled(); + } break; + + case NOTIFICATION_ENABLED: { + _apply_enabled(); } break; } } @@ -153,6 +174,79 @@ bool CollisionObject3D::get_collision_mask_bit(int p_bit) const { return get_collision_mask() & (1 << p_bit); } +void CollisionObject3D::set_disable_mode(DisableMode p_mode) { + if (disable_mode == p_mode) { + return; + } + + bool disabled = is_inside_tree() && !is_enabled(); + + if (disabled) { + // Cancel previous disable mode. + _apply_enabled(); + } + + disable_mode = p_mode; + + if (disabled) { + // Apply new disable mode. + _apply_disabled(); + } +} + +CollisionObject3D::DisableMode CollisionObject3D::get_disable_mode() const { + return disable_mode; +} + +void CollisionObject3D::_apply_disabled() { + switch (disable_mode) { + case DISABLE_MODE_REMOVE: { + if (is_inside_tree()) { + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, RID()); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, RID()); + } + } + } break; + + case DISABLE_MODE_MAKE_STATIC: { + if (!area && (body_mode != PhysicsServer3D::BODY_MODE_STATIC)) { + PhysicsServer3D::get_singleton()->body_set_mode(rid, PhysicsServer3D::BODY_MODE_STATIC); + } + } break; + + case DISABLE_MODE_KEEP_ACTIVE: { + // Nothing to do. + } break; + } +} + +void CollisionObject3D::_apply_enabled() { + switch (disable_mode) { + case DISABLE_MODE_REMOVE: { + if (is_inside_tree()) { + RID space = get_world_3d()->get_space(); + if (area) { + PhysicsServer3D::get_singleton()->area_set_space(rid, space); + } else { + PhysicsServer3D::get_singleton()->body_set_space(rid, space); + } + } + } break; + + case DISABLE_MODE_MAKE_STATIC: { + if (!area && (body_mode != PhysicsServer3D::BODY_MODE_STATIC)) { + PhysicsServer3D::get_singleton()->body_set_mode(rid, body_mode); + } + } break; + + case DISABLE_MODE_KEEP_ACTIVE: { + // Nothing to do. + } break; + } +} + void CollisionObject3D::_input_event(Node *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { if (get_script_instance()) { get_script_instance()->call(SceneStringNames::get_singleton()->_input_event, p_camera, p_input_event, p_pos, p_normal, p_shape); @@ -174,6 +268,22 @@ void CollisionObject3D::_mouse_exit() { emit_signal(SceneStringNames::get_singleton()->mouse_exited); } +void CollisionObject3D::set_body_mode(PhysicsServer3D::BodyMode p_mode) { + ERR_FAIL_COND(area); + + if (body_mode == p_mode) { + return; + } + + body_mode = p_mode; + + if (is_inside_tree() && !is_enabled() && (disable_mode == DISABLE_MODE_MAKE_STATIC)) { + return; + } + + PhysicsServer3D::get_singleton()->body_set_mode(rid, p_mode); +} + void CollisionObject3D::_update_pickable() { if (!is_inside_tree()) { return; @@ -305,6 +415,8 @@ void CollisionObject3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collision_layer_bit", "bit"), &CollisionObject3D::get_collision_layer_bit); ClassDB::bind_method(D_METHOD("set_collision_mask_bit", "bit", "value"), &CollisionObject3D::set_collision_mask_bit); ClassDB::bind_method(D_METHOD("get_collision_mask_bit", "bit"), &CollisionObject3D::get_collision_mask_bit); + ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &CollisionObject3D::set_disable_mode); + ClassDB::bind_method(D_METHOD("get_disable_mode"), &CollisionObject3D::get_disable_mode); ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &CollisionObject3D::set_ray_pickable); ClassDB::bind_method(D_METHOD("is_ray_pickable"), &CollisionObject3D::is_ray_pickable); ClassDB::bind_method(D_METHOD("set_capture_input_on_drag", "enable"), &CollisionObject3D::set_capture_input_on_drag); @@ -326,12 +438,14 @@ void CollisionObject3D::_bind_methods() { ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes); ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner); - BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); + BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx"))); - ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); + ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx"))); ADD_SIGNAL(MethodInfo("mouse_entered")); ADD_SIGNAL(MethodInfo("mouse_exited")); + ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,MakeStatic,KeepActive"), "set_disable_mode", "get_disable_mode"); + ADD_GROUP("Collision", "collision_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); @@ -339,6 +453,10 @@ void CollisionObject3D::_bind_methods() { ADD_GROUP("Input", "input_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_ray_pickable"), "set_ray_pickable", "is_ray_pickable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "input_capture_on_drag"), "set_capture_input_on_drag", "get_capture_input_on_drag"); + + BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE); + BIND_ENUM_CONSTANT(DISABLE_MODE_MAKE_STATIC); + BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); } uint32_t CollisionObject3D::create_shape_owner(Object *p_owner) { @@ -406,7 +524,7 @@ Array CollisionObject3D::_get_shape_owners() { return ret; } -void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform) { +void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform) { ERR_FAIL_COND(!shapes.has(p_owner)); ShapeData &sd = shapes[p_owner]; @@ -421,9 +539,8 @@ void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transf _update_shape_data(p_owner); } - -Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const { - ERR_FAIL_COND_V(!shapes.has(p_owner), Transform()); +Transform3D CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const { + ERR_FAIL_COND_V(!shapes.has(p_owner), Transform3D()); return shapes[p_owner].xform; } @@ -541,8 +658,8 @@ CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) { PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id()); } else { PhysicsServer3D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id()); + PhysicsServer3D::get_singleton()->body_set_mode(rid, body_mode); } - //set_transform_notify(true); } void CollisionObject3D::set_capture_input_on_drag(bool p_capture) { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 7ff3c5efde..a3a890db75 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -33,10 +33,19 @@ #include "scene/3d/node_3d.h" #include "scene/resources/shape_3d.h" +#include "servers/physics_server_3d.h" class CollisionObject3D : public Node3D { GDCLASS(CollisionObject3D, Node3D); +public: + enum DisableMode { + DISABLE_MODE_REMOVE, + DISABLE_MODE_MAKE_STATIC, + DISABLE_MODE_KEEP_ACTIVE, + }; + +private: uint32_t collision_layer = 1; uint32_t collision_mask = 1; @@ -44,9 +53,13 @@ class CollisionObject3D : public Node3D { RID rid; + DisableMode disable_mode = DISABLE_MODE_REMOVE; + + PhysicsServer3D::BodyMode body_mode = PhysicsServer3D::BODY_MODE_STATIC; + struct ShapeData { Object *owner = nullptr; - Transform xform; + Transform3D xform; struct ShapeBase { RID debug_shape; Ref<Shape3D> shape; @@ -66,7 +79,7 @@ class CollisionObject3D : public Node3D { Set<uint32_t> debug_shapes_to_update; int debug_shapes_count = 0; - Transform debug_shape_old_transform; + Transform3D debug_shape_old_transform; void _update_pickable(); @@ -76,6 +89,9 @@ class CollisionObject3D : public Node3D { void _update_debug_shapes(); void _clear_debug_shapes(); + void _apply_disabled(); + void _apply_enabled(); + protected: CollisionObject3D(RID p_rid, bool p_area); @@ -89,6 +105,8 @@ protected: virtual void _mouse_enter(); virtual void _mouse_exit(); + void set_body_mode(PhysicsServer3D::BodyMode p_mode); + public: void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; @@ -102,13 +120,16 @@ public: void set_collision_mask_bit(int p_bit, bool p_value); bool get_collision_mask_bit(int p_bit) const; + void set_disable_mode(DisableMode p_mode); + DisableMode get_disable_mode() const; + uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); void get_shape_owners(List<uint32_t> *r_owners); Array _get_shape_owners(); - void shape_owner_set_transform(uint32_t p_owner, const Transform &p_transform); - Transform shape_owner_get_transform(uint32_t p_owner) const; + void shape_owner_set_transform(uint32_t p_owner, const Transform3D &p_transform); + Transform3D shape_owner_get_transform(uint32_t p_owner) const; Object *shape_owner_get_owner(uint32_t p_owner) const; void shape_owner_set_disabled(uint32_t p_owner, bool p_disabled); @@ -138,4 +159,6 @@ public: ~CollisionObject3D(); }; +VARIANT_ENUM_CAST(CollisionObject3D::DisableMode); + #endif // COLLISION_OBJECT__H diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index ac715b22b2..8a4f8b639b 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -171,7 +171,7 @@ TypedArray<String> CollisionPolygon3D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.")); + warnings.push_back(TTR("CollisionPolygon3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape.")); } if (polygon.is_empty()) { diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 70d9cebb83..be3fde8013 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -124,7 +124,7 @@ TypedArray<String> CollisionShape3D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, KinematicBody3D, etc. to give them a shape.")); + warnings.push_back(TTR("CollisionShape3D only serves to provide a collision shape to a CollisionObject3D derived node. Please only use it as a child of Area3D, StaticBody3D, RigidBody3D, CharacterBody3D, etc. to give them a shape.")); } if (!shape.is_valid()) { diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index aa29728c73..6dc865ec0e 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -435,27 +435,27 @@ Vector3 CPUParticles3D::get_gravity() const { void CPUParticles3D::_validate_property(PropertyInfo &property) const { if (property.name == "color" && color_ramp.is_valid()) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_normals" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -574,7 +574,7 @@ void CPUParticles3D::_particles_process(float p_delta) { } } - Transform emission_xform; + Transform3D emission_xform; Basis velocity_xform; if (!local_coords) { emission_xform = get_global_transform(); @@ -693,7 +693,7 @@ void CPUParticles3D::_particles_process(float p_delta) { p.custom[0] = Math::deg2rad(base_angle); //angle p.custom[1] = 0.0; //phase p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation offset (0-1) - p.transform = Transform(); + p.transform = Transform3D(); p.time = 0; p.lifetime = lifetime * (1.0 - Math::randf() * lifetime_randomness); p.base_color = Color(1, 1, 1, 1); @@ -1030,7 +1030,7 @@ void CPUParticles3D::_update_particle_data_buffer() { for (int i = 0; i < pc; i++) { int idx = order ? order[i] : i; - Transform t = r[idx].transform; + Transform3D t = r[idx].transform; if (!local_coords) { t = inv_emission_transform * t; @@ -1139,7 +1139,7 @@ void CPUParticles3D::_notification(int p_what) { float *ptr = w; for (int i = 0; i < pc; i++) { - Transform t = inv_emission_transform * r[i].transform; + Transform3D t = inv_emission_transform * r[i].transform; if (r[i].active) { ptr[0] = t.basis.elements[0][0]; @@ -1273,11 +1273,11 @@ void CPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("restart"), &CPUParticles3D::restart); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,exp"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); @@ -1390,7 +1390,7 @@ void CPUParticles3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_param_curve", "get_param_curve", PARAM_ANGLE); ADD_GROUP("Scale", ""); diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index c073c93c47..b35e659757 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -83,7 +83,7 @@ private: bool emitting = false; struct Particle { - Transform transform; + Transform3D transform; Color color; float custom[4] = {}; Vector3 velocity; @@ -141,7 +141,7 @@ private: int fixed_fps = 0; bool fractional_delta = true; - Transform inv_emission_transform; + Transform3D inv_emission_transform; SafeFlag can_update; diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index 7d6abe458a..5af7b8ca07 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -45,6 +45,7 @@ void Decal::set_texture(DecalTexture p_type, const Ref<Texture2D> &p_texture) { textures[p_type] = p_texture; RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); RS::get_singleton()->decal_set_texture(decal, RS::DecalTexture(p_type), texture_rid); + update_configuration_warnings(); } Ref<Texture2D> Decal::get_texture(DecalTexture p_type) const { @@ -137,6 +138,7 @@ float Decal::get_distance_fade_length() const { void Decal::set_cull_mask(uint32_t p_layers) { cull_mask = p_layers; RS::get_singleton()->decal_set_cull_mask(decal, cull_mask); + update_configuration_warnings(); } uint32_t Decal::get_cull_mask() const { @@ -160,6 +162,27 @@ void Decal::_validate_property(PropertyInfo &property) const { } } +TypedArray<String> Decal::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + if (textures[TEXTURE_ALBEDO].is_null() && textures[TEXTURE_NORMAL].is_null() && textures[TEXTURE_ORM].is_null() && textures[TEXTURE_EMISSION].is_null()) { + warnings.push_back(TTR("The decal has no textures loaded into any of its texture properties, and will therefore not be visible.")); + } + + if ((textures[TEXTURE_NORMAL].is_valid() || textures[TEXTURE_ORM].is_valid()) && textures[TEXTURE_ALBEDO].is_null()) { + warnings.push_back(TTR("The decal has a Normal and/or ORM texture, but no Albedo texture is set.\nAn Albedo texture with an alpha channel is required to blend the normal/ORM maps onto the underlying surface.\nIf you don't want the Albedo texture to be visible, set Albedo Mix to 0.")); + } + + if (cull_mask == 0) { + // NOTE: This warning will not be emitted if none of the 20 checkboxes + // exposed in the editor are checked. This is because there are + // currently 12 unexposed layers in the editor inspector. + warnings.push_back(TTR("The decal's Cull Mask has no bits enabled, which means the decal will not paint objects on any layer.\nTo resolve this, enable at least one bit in the Cull Mask property.")); + } + + return warnings; +} + void Decal::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extents", "extents"), &Decal::set_extents); ClassDB::bind_method(D_METHOD("get_extents"), &Decal::get_extents); @@ -207,7 +230,9 @@ void Decal::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "emission_energy", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "albedo_mix", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_albedo_mix", "get_albedo_mix"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_fade", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_normal_fade", "get_normal_fade"); + // A Normal Fade of 1.0 causes the decal to be invisible even if fully perpendicular to a surface. + // Due to this, limit Normal Fade to 0.999. + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_fade", PROPERTY_HINT_RANGE, "0,0.999,0.001"), "set_normal_fade", "get_normal_fade"); ADD_GROUP("Vertical Fade", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "upper_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_upper_fade", "get_upper_fade"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lower_fade", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_lower_fade", "get_lower_fade"); diff --git a/scene/3d/decal.h b/scene/3d/decal.h index ce19e76de1..31a6315213 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -67,6 +67,8 @@ protected: void _validate_property(PropertyInfo &property) const override; public: + virtual TypedArray<String> get_configuration_warnings() const override; + void set_extents(const Vector3 &p_extents); Vector3 get_extents() const; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 83181064c3..f78027e6c7 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -385,13 +385,13 @@ void GPUParticles3D::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("draw_pass_")) { int index = property.name.get_slicec('_', 2).to_int() - 1; if (index >= draw_passes.size()) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } } } -void GPUParticles3D::emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { +void GPUParticles3D::emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { RS::get_singleton()->particles_emit(particles, p_transform, p_velocity, p_color, p_custom, p_emit_flags); } @@ -458,7 +458,7 @@ void GPUParticles3D::_notification(int p_what) { } void GPUParticles3D::_skinning_changed() { - Vector<Transform> xforms; + Vector<Transform3D> xforms; if (skin.is_valid()) { xforms.resize(skin->get_bind_count()); for (int i = 0; i < skin->get_bind_count(); i++) { @@ -562,12 +562,12 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter"); ADD_GROUP("Time", ""); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater,exp"), "set_lifetime", "get_lifetime"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01,exp"), "set_pre_process_time", "get_pre_process_time"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "0,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio"); diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index 1b354b0d2a..7b21cf03f1 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -171,7 +171,7 @@ public: EMIT_FLAG_CUSTOM = RS::PARTICLES_EMIT_FLAG_CUSTOM }; - void emit_particle(const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); + void emit_particle(const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); AABB capture_aabb() const; GPUParticles3D(); diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 2d59461ff0..c1e71b9565 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -131,7 +131,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node, if (mesh.is_valid()) { AABB aabb = mesh->get_aabb(); - Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform(); + Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform(); if (p_aabb.intersects(xf.xform(aabb))) { PlotMesh pm; @@ -147,7 +147,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node, if (s->is_visible_in_tree()) { Array meshes = p_at_node->call("get_meshes"); for (int i = 0; i < meshes.size(); i += 2) { - Transform mxf = meshes[i]; + Transform3D mxf = meshes[i]; Ref<Mesh> mesh = meshes[i + 1]; if (!mesh.is_valid()) { continue; @@ -155,7 +155,7 @@ void GPUParticlesCollisionSDF::_find_meshes(const AABB &p_aabb, Node *p_at_node, AABB aabb = mesh->get_aabb(); - Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf); + Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf); if (p_aabb.intersects(xf.xform(aabb))) { PlotMesh pm; @@ -495,7 +495,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() { _compute_sdf(¶ms); Ref<Image> ret; - ret.instance(); + ret.instantiate(); ret->create(sdf_size.x, sdf_size.y * sdf_size.z, false, Image::FORMAT_RF, data); ret->convert(Image::FORMAT_RH); //convert to half, save space ret->set_meta("depth", sdf_size.z); //hack, make sure to add to the docs of this function @@ -598,14 +598,14 @@ void GPUParticlesCollisionHeightField::_notification(int p_what) { if (follow_camera_mode && get_viewport()) { Camera3D *cam = get_viewport()->get_camera(); if (cam) { - Transform xform = get_global_transform(); + Transform3D xform = get_global_transform(); Vector3 x_axis = xform.basis.get_axis(Vector3::AXIS_X).normalized(); Vector3 z_axis = xform.basis.get_axis(Vector3::AXIS_Z).normalized(); float x_len = xform.basis.get_scale().x; float z_len = xform.basis.get_scale().z; Vector3 cam_pos = cam->get_global_transform().origin; - Transform new_xform = xform; + Transform3D new_xform = xform; while (x_axis.dot(cam_pos - new_xform.origin) > x_len) { new_xform.origin += x_axis * x_len; diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h index 81c33663f3..c55463378d 100644 --- a/scene/3d/gpu_particles_collision_3d.h +++ b/scene/3d/gpu_particles_collision_3d.h @@ -119,7 +119,7 @@ private: struct PlotMesh { Ref<Mesh> mesh; - Transform local_xform; + Transform3D local_xform; }; void _find_meshes(const AABB &p_aabb, Node *p_at_node, List<PlotMesh> &plot_meshes); diff --git a/scene/3d/immediate_geometry_3d.cpp b/scene/3d/immediate_geometry_3d.cpp deleted file mode 100644 index d64babaa9d..0000000000 --- a/scene/3d/immediate_geometry_3d.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/*************************************************************************/ -/* immediate_geometry_3d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "immediate_geometry_3d.h" - -void ImmediateGeometry3D::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture) { - RS::get_singleton()->immediate_begin(im, (RS::PrimitiveType)p_primitive, p_texture.is_valid() ? p_texture->get_rid() : RID()); - if (p_texture.is_valid()) { - cached_textures.push_back(p_texture); - } -} - -void ImmediateGeometry3D::set_normal(const Vector3 &p_normal) { - RS::get_singleton()->immediate_normal(im, p_normal); -} - -void ImmediateGeometry3D::set_tangent(const Plane &p_tangent) { - RS::get_singleton()->immediate_tangent(im, p_tangent); -} - -void ImmediateGeometry3D::set_color(const Color &p_color) { - RS::get_singleton()->immediate_color(im, p_color); -} - -void ImmediateGeometry3D::set_uv(const Vector2 &p_uv) { - RS::get_singleton()->immediate_uv(im, p_uv); -} - -void ImmediateGeometry3D::set_uv2(const Vector2 &p_uv2) { - RS::get_singleton()->immediate_uv2(im, p_uv2); -} - -void ImmediateGeometry3D::add_vertex(const Vector3 &p_vertex) { - RS::get_singleton()->immediate_vertex(im, p_vertex); - if (empty) { - aabb.position = p_vertex; - aabb.size = Vector3(); - empty = false; - } else { - aabb.expand_to(p_vertex); - } -} - -void ImmediateGeometry3D::end() { - RS::get_singleton()->immediate_end(im); -} - -void ImmediateGeometry3D::clear() { - RS::get_singleton()->immediate_clear(im); - empty = true; - cached_textures.clear(); -} - -AABB ImmediateGeometry3D::get_aabb() const { - return aabb; -} - -Vector<Face3> ImmediateGeometry3D::get_faces(uint32_t p_usage_flags) const { - return Vector<Face3>(); -} - -void ImmediateGeometry3D::add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv) { - const double lat_step = Math_TAU / p_lats; - const double lon_step = Math_TAU / p_lons; - - for (int i = 1; i <= p_lats; i++) { - double lat0 = lat_step * (i - 1) - Math_TAU / 4; - double z0 = Math::sin(lat0); - double zr0 = Math::cos(lat0); - - double lat1 = lat_step * i - Math_TAU / 4; - double z1 = Math::sin(lat1); - double zr1 = Math::cos(lat1); - - for (int j = p_lons; j >= 1; j--) { - double lng0 = lon_step * (j - 1); - double x0 = Math::cos(lng0); - double y0 = Math::sin(lng0); - - double lng1 = lon_step * j; - double x1 = Math::cos(lng1); - double y1 = Math::sin(lng1); - - Vector3 v[4] = { - Vector3(x1 * zr0, z0, y1 * zr0), - Vector3(x1 * zr1, z1, y1 * zr1), - Vector3(x0 * zr1, z1, y0 * zr1), - Vector3(x0 * zr0, z0, y0 * zr0) - }; - -#define ADD_POINT(m_idx) \ - if (p_add_uv) { \ - set_uv(Vector2(Math::atan2(v[m_idx].x, v[m_idx].z) / Math_PI * 0.5 + 0.5, v[m_idx].y * 0.5 + 0.5)); \ - set_tangent(Plane(Vector3(-v[m_idx].z, v[m_idx].y, v[m_idx].x), 1)); \ - } \ - set_normal(v[m_idx]); \ - add_vertex(v[m_idx] * p_radius); - - ADD_POINT(0); - ADD_POINT(1); - ADD_POINT(2); - - ADD_POINT(2); - ADD_POINT(3); - ADD_POINT(0); - } - } -} - -void ImmediateGeometry3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("begin", "primitive", "texture"), &ImmediateGeometry3D::begin, DEFVAL(Ref<Texture2D>())); - ClassDB::bind_method(D_METHOD("set_normal", "normal"), &ImmediateGeometry3D::set_normal); - ClassDB::bind_method(D_METHOD("set_tangent", "tangent"), &ImmediateGeometry3D::set_tangent); - ClassDB::bind_method(D_METHOD("set_color", "color"), &ImmediateGeometry3D::set_color); - ClassDB::bind_method(D_METHOD("set_uv", "uv"), &ImmediateGeometry3D::set_uv); - ClassDB::bind_method(D_METHOD("set_uv2", "uv"), &ImmediateGeometry3D::set_uv2); - ClassDB::bind_method(D_METHOD("add_vertex", "position"), &ImmediateGeometry3D::add_vertex); - ClassDB::bind_method(D_METHOD("add_sphere", "lats", "lons", "radius", "add_uv"), &ImmediateGeometry3D::add_sphere, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("end"), &ImmediateGeometry3D::end); - ClassDB::bind_method(D_METHOD("clear"), &ImmediateGeometry3D::clear); -} - -ImmediateGeometry3D::ImmediateGeometry3D() { - im = RenderingServer::get_singleton()->immediate_create(); - set_base(im); -} - -ImmediateGeometry3D::~ImmediateGeometry3D() { - RenderingServer::get_singleton()->free(im); -} diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index d45749d36b..8478821ba1 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -209,19 +209,19 @@ void Light3D::_validate_property(PropertyInfo &property) const { } if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_specular") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_projector") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (get_light_type() != RS::LIGHT_DIRECTIONAL && property.name == "light_angular_distance") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -353,7 +353,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) { } Light3D::Light3D() { - ERR_PRINT("Light3D should not be instanced directly; use the DirectionalLight3D, OmniLight3D or SpotLight3D subtypes instead."); + ERR_PRINT("Light3D should not be instantiated directly; use the DirectionalLight3D, OmniLight3D or SpotLight3D subtypes instead."); } Light3D::~Light3D() { @@ -375,15 +375,6 @@ DirectionalLight3D::ShadowMode DirectionalLight3D::get_shadow_mode() const { return shadow_mode; } -void DirectionalLight3D::set_shadow_depth_range(ShadowDepthRange p_range) { - shadow_depth_range = p_range; - RS::get_singleton()->light_directional_set_shadow_depth_range_mode(light, RS::LightDirectionalShadowDepthRangeMode(p_range)); -} - -DirectionalLight3D::ShadowDepthRange DirectionalLight3D::get_shadow_depth_range() const { - return shadow_depth_range; -} - void DirectionalLight3D::set_blend_splits(bool p_enable) { blend_splits = p_enable; RS::get_singleton()->light_directional_set_blend_splits(light, p_enable); @@ -406,9 +397,6 @@ void DirectionalLight3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight3D::set_shadow_mode); ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight3D::get_shadow_mode); - ClassDB::bind_method(D_METHOD("set_shadow_depth_range", "mode"), &DirectionalLight3D::set_shadow_depth_range); - ClassDB::bind_method(D_METHOD("get_shadow_depth_range"), &DirectionalLight3D::get_shadow_depth_range); - ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight3D::set_blend_splits); ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight3D::is_blend_splits_enabled); @@ -422,18 +410,14 @@ void DirectionalLight3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_EXP_RANGE, "0,1024,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,8192,0.1,or_greater,exp"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "directional_shadow_pancake_size", PROPERTY_HINT_RANGE, "0,1024,0.1,or_greater,exp"), "set_param", "get_param", PARAM_SHADOW_PANCAKE_SIZE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_in_sky_only"), "set_sky_only", "is_sky_only"); BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL); BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS); BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS); - - BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_STABLE); - BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_OPTIMIZED); } DirectionalLight3D::DirectionalLight3D() : @@ -444,7 +428,6 @@ DirectionalLight3D::DirectionalLight3D() : // Leave normal bias untouched as it doesn't benefit DirectionalLight3D as much as OmniLight3D. set_param(PARAM_SHADOW_BIAS, 0.05); set_shadow_mode(SHADOW_PARALLEL_4_SPLITS); - set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE); blend_splits = false; } @@ -472,7 +455,7 @@ void OmniLight3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_shadow_mode"), &OmniLight3D::get_shadow_mode); ADD_GROUP("Omni", "omni_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_range", PROPERTY_HINT_RANGE, "0,4096,0.1,or_greater,exp"), "set_param", "get_param", PARAM_RANGE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode"); @@ -504,8 +487,8 @@ TypedArray<String> SpotLight3D::get_configuration_warnings() const { void SpotLight3D::_bind_methods() { ADD_GROUP("Spot", "spot_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_range", PROPERTY_HINT_RANGE, "0,4096,0.1,or_greater,exp"), "set_param", "get_param", PARAM_RANGE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1,degrees"), "set_param", "get_param", PARAM_SPOT_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION); } diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index e145b08b74..d0308a3025 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -149,15 +149,9 @@ public: SHADOW_PARALLEL_4_SPLITS, }; - enum ShadowDepthRange { - SHADOW_DEPTH_RANGE_STABLE = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE, - SHADOW_DEPTH_RANGE_OPTIMIZED = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED, - }; - private: bool blend_splits; ShadowMode shadow_mode; - ShadowDepthRange shadow_depth_range; bool sky_only = false; protected: @@ -167,9 +161,6 @@ public: void set_shadow_mode(ShadowMode p_mode); ShadowMode get_shadow_mode() const; - void set_shadow_depth_range(ShadowDepthRange p_range); - ShadowDepthRange get_shadow_depth_range() const; - void set_blend_splits(bool p_enable); bool is_blend_splits_enabled() const; @@ -180,7 +171,6 @@ public: }; VARIANT_ENUM_CAST(DirectionalLight3D::ShadowMode) -VARIANT_ENUM_CAST(DirectionalLight3D::ShadowDepthRange) class OmniLight3D : public Light3D { GDCLASS(OmniLight3D, Light3D); diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/lightmap_gi.cpp index ef648a126e..66e3535fc4 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* baked_lightmap.cpp */ +/* lightmap_gi.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,19 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "baked_lightmap.h" +#include "lightmap_gi.h" #include "core/io/config_file.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "core/io/resource_saver.h" #include "core/math/camera_matrix.h" #include "core/math/delaunay_3d.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/templates/sort_array.h" #include "lightmap_probe.h" -void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) { +void LightmapGIData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale, int p_slice_index, int32_t p_sub_instance) { User user; user.path = p_path; user.uv_scale = p_uv_scale; @@ -49,35 +49,35 @@ void BakedLightmapData::add_user(const NodePath &p_path, const Rect2 &p_uv_scale users.push_back(user); } -int BakedLightmapData::get_user_count() const { +int LightmapGIData::get_user_count() const { return users.size(); } -NodePath BakedLightmapData::get_user_path(int p_user) const { +NodePath LightmapGIData::get_user_path(int p_user) const { ERR_FAIL_INDEX_V(p_user, users.size(), NodePath()); return users[p_user].path; } -int32_t BakedLightmapData::get_user_sub_instance(int p_user) const { +int32_t LightmapGIData::get_user_sub_instance(int p_user) const { ERR_FAIL_INDEX_V(p_user, users.size(), -1); return users[p_user].sub_instance; } -Rect2 BakedLightmapData::get_user_lightmap_uv_scale(int p_user) const { +Rect2 LightmapGIData::get_user_lightmap_uv_scale(int p_user) const { ERR_FAIL_INDEX_V(p_user, users.size(), Rect2()); return users[p_user].uv_scale; } -int BakedLightmapData::get_user_lightmap_slice_index(int p_user) const { +int LightmapGIData::get_user_lightmap_slice_index(int p_user) const { ERR_FAIL_INDEX_V(p_user, users.size(), -1); return users[p_user].slice_index; } -void BakedLightmapData::clear_users() { +void LightmapGIData::clear_users() { users.clear(); } -void BakedLightmapData::_set_user_data(const Array &p_data) { +void LightmapGIData::_set_user_data(const Array &p_data) { ERR_FAIL_COND(p_data.size() <= 0); ERR_FAIL_COND((p_data.size() % 4) != 0); @@ -86,7 +86,7 @@ void BakedLightmapData::_set_user_data(const Array &p_data) { } } -Array BakedLightmapData::_get_user_data() const { +Array LightmapGIData::_get_user_data() const { Array ret; for (int i = 0; i < users.size(); i++) { ret.push_back(users[i].path); @@ -97,33 +97,33 @@ Array BakedLightmapData::_get_user_data() const { return ret; } -RID BakedLightmapData::get_rid() const { +RID LightmapGIData::get_rid() const { return lightmap; } -void BakedLightmapData::clear() { +void LightmapGIData::clear() { users.clear(); } -void BakedLightmapData::set_light_texture(const Ref<TextureLayered> &p_light_texture) { +void LightmapGIData::set_light_texture(const Ref<TextureLayered> &p_light_texture) { light_texture = p_light_texture; RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics); } -Ref<TextureLayered> BakedLightmapData::get_light_texture() const { +Ref<TextureLayered> LightmapGIData::get_light_texture() const { return light_texture; } -void BakedLightmapData::set_uses_spherical_harmonics(bool p_enable) { +void LightmapGIData::set_uses_spherical_harmonics(bool p_enable) { uses_spherical_harmonics = p_enable; RS::get_singleton()->lightmap_set_textures(lightmap, light_texture.is_valid() ? light_texture->get_rid() : RID(), uses_spherical_harmonics); } -bool BakedLightmapData::is_using_spherical_harmonics() const { +bool LightmapGIData::is_using_spherical_harmonics() const { return uses_spherical_harmonics; } -void BakedLightmapData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +void LightmapGIData::set_capture_data(const AABB &p_bounds, bool p_interior, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { if (p_points.size()) { int pc = p_points.size(); ERR_FAIL_COND(pc * 9 != p_point_sh.size()); @@ -141,31 +141,31 @@ void BakedLightmapData::set_capture_data(const AABB &p_bounds, bool p_interior, bounds = p_bounds; } -PackedVector3Array BakedLightmapData::get_capture_points() const { +PackedVector3Array LightmapGIData::get_capture_points() const { return RS::get_singleton()->lightmap_get_probe_capture_points(lightmap); } -PackedColorArray BakedLightmapData::get_capture_sh() const { +PackedColorArray LightmapGIData::get_capture_sh() const { return RS::get_singleton()->lightmap_get_probe_capture_sh(lightmap); } -PackedInt32Array BakedLightmapData::get_capture_tetrahedra() const { +PackedInt32Array LightmapGIData::get_capture_tetrahedra() const { return RS::get_singleton()->lightmap_get_probe_capture_tetrahedra(lightmap); } -PackedInt32Array BakedLightmapData::get_capture_bsp_tree() const { +PackedInt32Array LightmapGIData::get_capture_bsp_tree() const { return RS::get_singleton()->lightmap_get_probe_capture_bsp_tree(lightmap); } -AABB BakedLightmapData::get_capture_bounds() const { +AABB LightmapGIData::get_capture_bounds() const { return bounds; } -bool BakedLightmapData::is_interior() const { +bool LightmapGIData::is_interior() const { return interior; } -void BakedLightmapData::_set_probe_data(const Dictionary &p_data) { +void LightmapGIData::_set_probe_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bounds")); ERR_FAIL_COND(!p_data.has("points")); ERR_FAIL_COND(!p_data.has("tetrahedra")); @@ -175,7 +175,7 @@ void BakedLightmapData::_set_probe_data(const Dictionary &p_data) { set_capture_data(p_data["bounds"], p_data["interior"], p_data["points"], p_data["sh"], p_data["tetrahedra"], p_data["bsp"]); } -Dictionary BakedLightmapData::_get_probe_data() const { +Dictionary LightmapGIData::_get_probe_data() const { Dictionary d; d["bounds"] = get_capture_bounds(); d["points"] = get_capture_points(); @@ -186,23 +186,23 @@ Dictionary BakedLightmapData::_get_probe_data() const { return d; } -void BakedLightmapData::_bind_methods() { - ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &BakedLightmapData::_set_user_data); - ClassDB::bind_method(D_METHOD("_get_user_data"), &BakedLightmapData::_get_user_data); +void LightmapGIData::_bind_methods() { + ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &LightmapGIData::_set_user_data); + ClassDB::bind_method(D_METHOD("_get_user_data"), &LightmapGIData::_get_user_data); - ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &BakedLightmapData::set_light_texture); - ClassDB::bind_method(D_METHOD("get_light_texture"), &BakedLightmapData::get_light_texture); + ClassDB::bind_method(D_METHOD("set_light_texture", "light_texture"), &LightmapGIData::set_light_texture); + ClassDB::bind_method(D_METHOD("get_light_texture"), &LightmapGIData::get_light_texture); - ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &BakedLightmapData::set_uses_spherical_harmonics); - ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &BakedLightmapData::is_using_spherical_harmonics); + ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &LightmapGIData::set_uses_spherical_harmonics); + ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &LightmapGIData::is_using_spherical_harmonics); - ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &BakedLightmapData::add_user); - ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count); - ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path); - ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users); + ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &LightmapGIData::add_user); + ClassDB::bind_method(D_METHOD("get_user_count"), &LightmapGIData::get_user_count); + ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &LightmapGIData::get_user_path); + ClassDB::bind_method(D_METHOD("clear_users"), &LightmapGIData::clear_users); - ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &BakedLightmapData::_set_probe_data); - ClassDB::bind_method(D_METHOD("_get_probe_data"), &BakedLightmapData::_get_probe_data); + ClassDB::bind_method(D_METHOD("_set_probe_data", "data"), &LightmapGIData::_set_probe_data); + ClassDB::bind_method(D_METHOD("_get_probe_data"), &LightmapGIData::_get_probe_data); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_texture", PROPERTY_HINT_RESOURCE_TYPE, "TextureLayered"), "set_light_texture", "get_light_texture"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uses_spherical_harmonics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_uses_spherical_harmonics", "is_using_spherical_harmonics"); @@ -210,17 +210,17 @@ void BakedLightmapData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "probe_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_probe_data", "_get_probe_data"); } -BakedLightmapData::BakedLightmapData() { +LightmapGIData::LightmapGIData() { lightmap = RS::get_singleton()->lightmap_create(); } -BakedLightmapData::~BakedLightmapData() { +LightmapGIData::~LightmapGIData() { RS::get_singleton()->free(lightmap); } /////////////////////////// -void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) { +void LightmapGI::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> &meshes, Vector<LightsFound> &lights, Vector<Vector3> &probes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) { Ref<Mesh> mesh = mi->get_mesh(); @@ -273,7 +273,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> if (!mi && s) { Array bmeshes = p_at_node->call("get_bake_bmeshes"); if (bmeshes.size() && (bmeshes.size() & 1) == 0) { - Transform xf = get_global_transform().affine_inverse() * s->get_global_transform(); + Transform3D xf = get_global_transform().affine_inverse() * s->get_global_transform(); for (int i = 0; i < bmeshes.size(); i += 2) { Ref<Mesh> mesh = bmeshes[i]; if (!mesh.is_valid()) { @@ -282,7 +282,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> MeshesFound mf; - Transform mesh_xf = bmeshes[i + 1]; + Transform3D mesh_xf = bmeshes[i + 1]; mf.xform = xf * mesh_xf; mf.node_path = get_path_to(s); mf.subindex = i / 2; @@ -306,7 +306,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> LightmapProbe *probe = Object::cast_to<LightmapProbe>(p_at_node); if (probe) { - Transform xf = get_global_transform().affine_inverse() * probe->get_global_transform(); + Transform3D xf = get_global_transform().affine_inverse() * probe->get_global_transform(); probes.push_back(xf.origin); } @@ -320,7 +320,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, Vector<MeshesFound> } } -int BakedLightmap::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const { +int LightmapGI::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const { int over = 0; int under = 0; int coplanar = 0; @@ -348,7 +348,7 @@ int BakedLightmap::_bsp_get_simplex_side(const Vector<Vector3> &p_points, const //#define DEBUG_BSP -int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) { +int32_t LightmapGI::_compute_bsp_tree(const Vector<Vector3> &p_points, const LocalVector<Plane> &p_planes, LocalVector<int32_t> &planes_tested, const LocalVector<BSPSimplex> &p_simplices, const LocalVector<int32_t> &p_simplex_indices, LocalVector<BSPNode> &bsp_nodes) { //if we reach here, it means there is more than one simplex int32_t node_index = (int32_t)bsp_nodes.size(); bsp_nodes.push_back(BSPNode()); @@ -533,7 +533,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const return node_index; } -bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) { +bool LightmapGI::_lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh) { BakeStepUD *bsud = (BakeStepUD *)ud; bool ret = false; if (bsud->func) { @@ -542,7 +542,7 @@ bool BakedLightmap::_lightmap_bake_step_function(float p_completion, const Strin return ret; } -void BakedLightmap::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) { +void LightmapGI::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_cell_size, const Vector3 *p_triangle) { for (int i = 0; i < 8; i++) { Vector3i pos = p_cell->offset; uint32_t half_size = p_cell->size / 2; @@ -578,7 +578,7 @@ void BakedLightmap::_plot_triangle_into_octree(GenProbesOctree *p_cell, float p_ } } -void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) { +void LightmapGI::_gen_new_positions_from_octree(const GenProbesOctree *p_cell, float p_cell_size, const Vector<Vector3> &probe_positions, LocalVector<Vector3> &new_probe_positions, HashMap<Vector3i, bool, Vector3iHash> &positions_used, const AABB &p_bounds) { for (int i = 0; i < 8; i++) { Vector3i pos = p_cell->offset; if (i & 1) { @@ -618,7 +618,7 @@ void BakedLightmap::_gen_new_positions_from_octree(const GenProbesOctree *p_cell } } -BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) { +LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_path, Lightmapper::BakeStepFunc p_bake_step, void *p_bake_userdata) { if (p_image_data_path == "") { if (get_light_data().is_null()) { return BAKE_ERROR_NO_SAVE_PATH; @@ -717,7 +717,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d w_albedo[i + 3] = 255; } - md.albedo_on_uv2.instance(); + md.albedo_on_uv2.instantiate(); md.albedo_on_uv2->create(lightmap_size.width, lightmap_size.height, false, Image::FORMAT_RGBA8, albedom); } @@ -887,7 +887,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d } for (int i = 0; i < lights_found.size(); i++) { Light3D *light = lights_found[i].light; - Transform xf = lights_found[i].xform; + Transform3D xf = lights_found[i].xform; if (Object::cast_to<DirectionalLight3D>(light)) { DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light); @@ -940,7 +940,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d } break; case ENVIRONMENT_MODE_CUSTOM_COLOR: { - environment_image.instance(); + environment_image.instantiate(); environment_image->create(128, 64, false, Image::FORMAT_RGBAF); Color c = environment_custom_color; c.r *= environment_custom_energy; @@ -972,7 +972,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d } //we assume they are all the same, so let's create a large one for saving Ref<Image> large_image; - large_image.instance(); + large_image.instantiate(); large_image->create(images[0]->get_width(), images[0]->get_height() * images.size(), false, images[0]->get_format()); @@ -984,7 +984,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d Ref<ConfigFile> config; - config.instance(); + config.instantiate(); if (FileAccess::exists(base_path + ".import")) { config->load(base_path + ".import"); } @@ -1011,13 +1011,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d /* POSTBAKE: Save Light Data */ - Ref<BakedLightmapData> data; + Ref<LightmapGIData> data; if (get_light_data().is_valid()) { data = get_light_data(); - set_light_data(Ref<BakedLightmapData>()); //clear + set_light_data(Ref<LightmapGIData>()); //clear data->clear(); } else { - data.instance(); + data.instantiate(); } data->set_light_texture(texture); @@ -1183,7 +1183,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d return BAKE_ERROR_OK; } -void BakedLightmap::_notification(int p_what) { +void LightmapGI::_notification(int p_what) { if (p_what == NOTIFICATION_POST_ENTER_TREE) { if (light_data.is_valid()) { _assign_lightmaps(); @@ -1197,7 +1197,7 @@ void BakedLightmap::_notification(int p_what) { } } -void BakedLightmap::_assign_lightmaps() { +void LightmapGI::_assign_lightmaps() { ERR_FAIL_COND(!light_data.is_valid()); for (int i = 0; i < light_data->get_user_count(); i++) { @@ -1216,7 +1216,7 @@ void BakedLightmap::_assign_lightmaps() { } } -void BakedLightmap::_clear_lightmaps() { +void LightmapGI::_clear_lightmaps() { ERR_FAIL_COND(!light_data.is_valid()); for (int i = 0; i < light_data->get_user_count(); i++) { Node *node = get_node(light_data->get_user_path(i)); @@ -1234,7 +1234,7 @@ void BakedLightmap::_clear_lightmaps() { } } -void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) { +void LightmapGI::set_light_data(const Ref<LightmapGIData> &p_data) { if (light_data.is_valid()) { if (is_inside_tree()) { _clear_lightmaps(); @@ -1253,171 +1253,171 @@ void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) { update_gizmo(); } -Ref<BakedLightmapData> BakedLightmap::get_light_data() const { +Ref<LightmapGIData> LightmapGI::get_light_data() const { return light_data; } -void BakedLightmap::set_bake_quality(BakeQuality p_quality) { +void LightmapGI::set_bake_quality(BakeQuality p_quality) { bake_quality = p_quality; } -BakedLightmap::BakeQuality BakedLightmap::get_bake_quality() const { +LightmapGI::BakeQuality LightmapGI::get_bake_quality() const { return bake_quality; } -AABB BakedLightmap::get_aabb() const { +AABB LightmapGI::get_aabb() const { return AABB(); } -Vector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> LightmapGI::get_faces(uint32_t p_usage_flags) const { return Vector<Face3>(); } -void BakedLightmap::set_use_denoiser(bool p_enable) { +void LightmapGI::set_use_denoiser(bool p_enable) { use_denoiser = p_enable; } -bool BakedLightmap::is_using_denoiser() const { +bool LightmapGI::is_using_denoiser() const { return use_denoiser; } -void BakedLightmap::set_directional(bool p_enable) { +void LightmapGI::set_directional(bool p_enable) { directional = p_enable; } -bool BakedLightmap::is_directional() const { +bool LightmapGI::is_directional() const { return directional; } -void BakedLightmap::set_interior(bool p_enable) { +void LightmapGI::set_interior(bool p_enable) { interior = p_enable; } -bool BakedLightmap::is_interior() const { +bool LightmapGI::is_interior() const { return interior; } -void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) { +void LightmapGI::set_environment_mode(EnvironmentMode p_mode) { environment_mode = p_mode; notify_property_list_changed(); } -BakedLightmap::EnvironmentMode BakedLightmap::get_environment_mode() const { +LightmapGI::EnvironmentMode LightmapGI::get_environment_mode() const { return environment_mode; } -void BakedLightmap::set_environment_custom_sky(const Ref<Sky> &p_sky) { +void LightmapGI::set_environment_custom_sky(const Ref<Sky> &p_sky) { environment_custom_sky = p_sky; } -Ref<Sky> BakedLightmap::get_environment_custom_sky() const { +Ref<Sky> LightmapGI::get_environment_custom_sky() const { return environment_custom_sky; } -void BakedLightmap::set_environment_custom_color(const Color &p_color) { +void LightmapGI::set_environment_custom_color(const Color &p_color) { environment_custom_color = p_color; } -Color BakedLightmap::get_environment_custom_color() const { +Color LightmapGI::get_environment_custom_color() const { return environment_custom_color; } -void BakedLightmap::set_environment_custom_energy(float p_energy) { +void LightmapGI::set_environment_custom_energy(float p_energy) { environment_custom_energy = p_energy; } -float BakedLightmap::get_environment_custom_energy() const { +float LightmapGI::get_environment_custom_energy() const { return environment_custom_energy; } -void BakedLightmap::set_bounces(int p_bounces) { +void LightmapGI::set_bounces(int p_bounces) { ERR_FAIL_COND(p_bounces < 0 || p_bounces > 16); bounces = p_bounces; } -int BakedLightmap::get_bounces() const { +int LightmapGI::get_bounces() const { return bounces; } -void BakedLightmap::set_bias(float p_bias) { +void LightmapGI::set_bias(float p_bias) { ERR_FAIL_COND(p_bias < 0.00001); bias = p_bias; } -float BakedLightmap::get_bias() const { +float LightmapGI::get_bias() const { return bias; } -void BakedLightmap::set_max_texture_size(int p_size) { +void LightmapGI::set_max_texture_size(int p_size) { ERR_FAIL_COND(p_size < 2048); max_texture_size = p_size; } -int BakedLightmap::get_max_texture_size() const { +int LightmapGI::get_max_texture_size() const { return max_texture_size; } -void BakedLightmap::set_generate_probes(GenerateProbes p_generate_probes) { +void LightmapGI::set_generate_probes(GenerateProbes p_generate_probes) { gen_probes = p_generate_probes; } -BakedLightmap::GenerateProbes BakedLightmap::get_generate_probes() const { +LightmapGI::GenerateProbes LightmapGI::get_generate_probes() const { return gen_probes; } -void BakedLightmap::_validate_property(PropertyInfo &property) const { +void LightmapGI::_validate_property(PropertyInfo &property) const { if (property.name == "environment_custom_sky" && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "environment_custom_color" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "environment_custom_energy" && environment_mode != ENVIRONMENT_MODE_CUSTOM_COLOR && environment_mode != ENVIRONMENT_MODE_CUSTOM_SKY) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } -void BakedLightmap::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data); - ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data); +void LightmapGI::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_light_data", "data"), &LightmapGI::set_light_data); + ClassDB::bind_method(D_METHOD("get_light_data"), &LightmapGI::get_light_data); - ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality); - ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality); + ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &LightmapGI::set_bake_quality); + ClassDB::bind_method(D_METHOD("get_bake_quality"), &LightmapGI::get_bake_quality); - ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &BakedLightmap::set_bounces); - ClassDB::bind_method(D_METHOD("get_bounces"), &BakedLightmap::get_bounces); + ClassDB::bind_method(D_METHOD("set_bounces", "bounces"), &LightmapGI::set_bounces); + ClassDB::bind_method(D_METHOD("get_bounces"), &LightmapGI::get_bounces); - ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &BakedLightmap::set_generate_probes); - ClassDB::bind_method(D_METHOD("get_generate_probes"), &BakedLightmap::get_generate_probes); + ClassDB::bind_method(D_METHOD("set_generate_probes", "subdivision"), &LightmapGI::set_generate_probes); + ClassDB::bind_method(D_METHOD("get_generate_probes"), &LightmapGI::get_generate_probes); - ClassDB::bind_method(D_METHOD("set_bias", "bias"), &BakedLightmap::set_bias); - ClassDB::bind_method(D_METHOD("get_bias"), &BakedLightmap::get_bias); + ClassDB::bind_method(D_METHOD("set_bias", "bias"), &LightmapGI::set_bias); + ClassDB::bind_method(D_METHOD("get_bias"), &LightmapGI::get_bias); - ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &BakedLightmap::set_environment_mode); - ClassDB::bind_method(D_METHOD("get_environment_mode"), &BakedLightmap::get_environment_mode); + ClassDB::bind_method(D_METHOD("set_environment_mode", "mode"), &LightmapGI::set_environment_mode); + ClassDB::bind_method(D_METHOD("get_environment_mode"), &LightmapGI::get_environment_mode); - ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &BakedLightmap::set_environment_custom_sky); - ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &BakedLightmap::get_environment_custom_sky); + ClassDB::bind_method(D_METHOD("set_environment_custom_sky", "sky"), &LightmapGI::set_environment_custom_sky); + ClassDB::bind_method(D_METHOD("get_environment_custom_sky"), &LightmapGI::get_environment_custom_sky); - ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &BakedLightmap::set_environment_custom_color); - ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &BakedLightmap::get_environment_custom_color); + ClassDB::bind_method(D_METHOD("set_environment_custom_color", "color"), &LightmapGI::set_environment_custom_color); + ClassDB::bind_method(D_METHOD("get_environment_custom_color"), &LightmapGI::get_environment_custom_color); - ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &BakedLightmap::set_environment_custom_energy); - ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &BakedLightmap::get_environment_custom_energy); + ClassDB::bind_method(D_METHOD("set_environment_custom_energy", "energy"), &LightmapGI::set_environment_custom_energy); + ClassDB::bind_method(D_METHOD("get_environment_custom_energy"), &LightmapGI::get_environment_custom_energy); - ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &BakedLightmap::set_max_texture_size); - ClassDB::bind_method(D_METHOD("get_max_texture_size"), &BakedLightmap::get_max_texture_size); + ClassDB::bind_method(D_METHOD("set_max_texture_size", "max_texture_size"), &LightmapGI::set_max_texture_size); + ClassDB::bind_method(D_METHOD("get_max_texture_size"), &LightmapGI::get_max_texture_size); - ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &BakedLightmap::set_use_denoiser); - ClassDB::bind_method(D_METHOD("is_using_denoiser"), &BakedLightmap::is_using_denoiser); + ClassDB::bind_method(D_METHOD("set_use_denoiser", "use_denoiser"), &LightmapGI::set_use_denoiser); + ClassDB::bind_method(D_METHOD("is_using_denoiser"), &LightmapGI::is_using_denoiser); - ClassDB::bind_method(D_METHOD("set_interior", "enable"), &BakedLightmap::set_interior); - ClassDB::bind_method(D_METHOD("is_interior"), &BakedLightmap::is_interior); + ClassDB::bind_method(D_METHOD("set_interior", "enable"), &LightmapGI::set_interior); + ClassDB::bind_method(D_METHOD("is_interior"), &LightmapGI::is_interior); - ClassDB::bind_method(D_METHOD("set_directional", "directional"), &BakedLightmap::set_directional); - ClassDB::bind_method(D_METHOD("is_directional"), &BakedLightmap::is_directional); + ClassDB::bind_method(D_METHOD("set_directional", "directional"), &LightmapGI::set_directional); + ClassDB::bind_method(D_METHOD("is_directional"), &LightmapGI::is_directional); - // ClassDB::bind_method(D_METHOD("bake", "from_node"), &BakedLightmap::bake, DEFVAL(Variant())); + // ClassDB::bind_method(D_METHOD("bake", "from_node"), &LightmapGI::bake, DEFVAL(Variant())); ADD_GROUP("Tweaks", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "quality", PROPERTY_HINT_ENUM, "Low,Medium,High,Ultra"), "set_bake_quality", "get_bake_quality"); @@ -1435,7 +1435,7 @@ void BakedLightmap::_bind_methods() { ADD_GROUP("Gen Probes", "generate_probes_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "generate_probes_subdiv", PROPERTY_HINT_ENUM, "Disabled,4,8,16,32"), "set_generate_probes", "get_generate_probes"); ADD_GROUP("Data", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedLightmapData"), "set_light_data", "get_light_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "LightmapGIData"), "set_light_data", "get_light_data"); BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW); BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM); @@ -1462,5 +1462,5 @@ void BakedLightmap::_bind_methods() { BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_CUSTOM_COLOR); } -BakedLightmap::BakedLightmap() { +LightmapGI::LightmapGI() { } diff --git a/scene/3d/baked_lightmap.h b/scene/3d/lightmap_gi.h index e2d89ab2d0..8a54512383 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/lightmap_gi.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* baked_lightmap.h */ +/* lightmap_gi.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BAKED_LIGHTMAP_H -#define BAKED_LIGHTMAP_H +#ifndef LIGHTMAP_GI_H +#define LIGHTMAP_GI_H #include "core/templates/local_vector.h" #include "scene/3d/light_3d.h" @@ -39,8 +39,8 @@ #include "scene/3d/visual_instance_3d.h" #include "scene/resources/sky.h" -class BakedLightmapData : public Resource { - GDCLASS(BakedLightmapData, Resource); +class LightmapGIData : public Resource { + GDCLASS(LightmapGIData, Resource); RES_BASE_EXTENSION("lmbake") Ref<TextureLayered> light_texture; @@ -95,12 +95,12 @@ public: void clear(); virtual RID get_rid() const override; - BakedLightmapData(); - ~BakedLightmapData(); + LightmapGIData(); + ~LightmapGIData(); }; -class BakedLightmap : public VisualInstance3D { - GDCLASS(BakedLightmap, VisualInstance3D); +class LightmapGI : public VisualInstance3D { + GDCLASS(LightmapGI, VisualInstance3D); public: enum BakeQuality { @@ -149,15 +149,15 @@ private: bool directional = false; GenerateProbes gen_probes = GENERATE_PROBES_DISABLED; - Ref<BakedLightmapData> light_data; + Ref<LightmapGIData> light_data; struct LightsFound { - Transform xform; + Transform3D xform; Light3D *light = nullptr; }; struct MeshesFound { - Transform xform; + Transform3D xform; NodePath node_path; int32_t subindex = 0; Ref<Mesh> mesh; @@ -230,8 +230,8 @@ protected: void _notification(int p_what); public: - void set_light_data(const Ref<BakedLightmapData> &p_data); - Ref<BakedLightmapData> get_light_data() const; + void set_light_data(const Ref<LightmapGIData> &p_data); + Ref<LightmapGIData> get_light_data() const; void set_bake_quality(BakeQuality p_quality); BakeQuality get_bake_quality() const; @@ -273,12 +273,12 @@ public: Vector<Face3> get_faces(uint32_t p_usage_flags) const override; BakeError bake(Node *p_from_node, String p_image_data_path = "", Lightmapper::BakeStepFunc p_bake_step = nullptr, void *p_bake_userdata = nullptr); - BakedLightmap(); + LightmapGI(); }; -VARIANT_ENUM_CAST(BakedLightmap::BakeQuality); -VARIANT_ENUM_CAST(BakedLightmap::GenerateProbes); -VARIANT_ENUM_CAST(BakedLightmap::BakeError); -VARIANT_ENUM_CAST(BakedLightmap::EnvironmentMode); +VARIANT_ENUM_CAST(LightmapGI::BakeQuality); +VARIANT_ENUM_CAST(LightmapGI::GenerateProbes); +VARIANT_ENUM_CAST(LightmapGI::BakeError); +VARIANT_ENUM_CAST(LightmapGI::EnvironmentMode); #endif // BAKED_LIGHTMAP_H diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index f63515f666..3a6a88d435 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -44,8 +44,8 @@ #endif -class LightmapDenoiser : public Reference { - GDCLASS(LightmapDenoiser, Reference) +class LightmapDenoiser : public RefCounted { + GDCLASS(LightmapDenoiser, RefCounted) protected: static LightmapDenoiser *(*create_function)(); @@ -54,8 +54,8 @@ public: static Ref<LightmapDenoiser> create(); }; -class LightmapRaycaster : public Reference { - GDCLASS(LightmapRaycaster, Reference) +class LightmapRaycaster : public RefCounted { + GDCLASS(LightmapRaycaster, RefCounted) protected: static LightmapRaycaster *(*create_function)(); @@ -121,8 +121,8 @@ public: static Ref<LightmapRaycaster> create(); }; -class Lightmapper : public Reference { - GDCLASS(Lightmapper, Reference) +class Lightmapper : public RefCounted { + GDCLASS(Lightmapper, RefCounted) public: enum GenerateProbes { GENERATE_PROBES_DISABLED, diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp index 9842f152d7..636be083ab 100644 --- a/scene/3d/listener_3d.cpp +++ b/scene/3d/listener_3d.cpp @@ -105,7 +105,7 @@ void Listener3D::_notification(int p_what) { } } -Transform Listener3D::get_listener_transform() const { +Transform3D Listener3D::get_listener_transform() const { return get_global_transform().orthonormalized(); } diff --git a/scene/3d/listener_3d.h b/scene/3d/listener_3d.h index 85657a8e53..bcc66f167c 100644 --- a/scene/3d/listener_3d.h +++ b/scene/3d/listener_3d.h @@ -65,7 +65,7 @@ public: void clear_current(); bool is_current() const; - virtual Transform get_listener_transform() const; + virtual Transform3D get_listener_transform() const; void set_visible_layers(uint32_t p_layers); uint32_t get_visible_layers() const; diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index c495f68890..28ccbd3e68 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -100,7 +100,7 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { if (mesh.is_valid()) { for (int i = 0; i < mesh->get_surface_count(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_material_override/" + itos(i), PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE)); } } } @@ -241,12 +241,12 @@ void MeshInstance3D::create_trimesh_collision() { } } -Node *MeshInstance3D::create_convex_collision_node() { +Node *MeshInstance3D::create_convex_collision_node(bool p_clean, bool p_simplify) { if (mesh.is_null()) { return nullptr; } - Ref<Shape3D> shape = mesh->create_convex_shape(); + Ref<Shape3D> shape = mesh->create_convex_shape(p_clean, p_simplify); if (shape.is_null()) { return nullptr; } @@ -258,8 +258,8 @@ Node *MeshInstance3D::create_convex_collision_node() { return static_body; } -void MeshInstance3D::create_convex_collision() { - StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_convex_collision_node()); +void MeshInstance3D::create_convex_collision(bool p_clean, bool p_simplify) { + StaticBody3D *static_body = Object::cast_to<StaticBody3D>(create_convex_collision_node(p_clean, p_simplify)); ERR_FAIL_COND(!static_body); static_body->set_name(String(get_name()) + "_col"); @@ -405,14 +405,14 @@ void MeshInstance3D::create_debug_tangents() { if (lines.size()) { Ref<StandardMaterial3D> sm; - sm.instance(); + sm.instantiate(); sm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); sm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); sm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); Ref<ArrayMesh> am; - am.instance(); + am.instantiate(); Array a; a.resize(Mesh::ARRAY_MAX); a[Mesh::ARRAY_VERTEX] = lines; @@ -451,7 +451,7 @@ void MeshInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("create_trimesh_collision"), &MeshInstance3D::create_trimesh_collision); ClassDB::set_method_flags("MeshInstance3D", "create_trimesh_collision", METHOD_FLAGS_DEFAULT); - ClassDB::bind_method(D_METHOD("create_convex_collision"), &MeshInstance3D::create_convex_collision); + ClassDB::bind_method(D_METHOD("create_convex_collision", "clean", "simplify"), &MeshInstance3D::create_convex_collision, DEFVAL(true), DEFVAL(false)); ClassDB::set_method_flags("MeshInstance3D", "create_convex_collision", METHOD_FLAGS_DEFAULT); ClassDB::bind_method(D_METHOD("create_multiple_convex_collisions"), &MeshInstance3D::create_multiple_convex_collisions); ClassDB::set_method_flags("MeshInstance3D", "create_multiple_convex_collisions", METHOD_FLAGS_DEFAULT); diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index 9dea5804e0..e2d20d0a90 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -83,8 +83,8 @@ public: Node *create_trimesh_collision_node(); void create_trimesh_collision(); - Node *create_convex_collision_node(); - void create_convex_collision(); + Node *create_convex_collision_node(bool p_clean = true, bool p_simplify = false); + void create_convex_collision(bool p_clean = true, bool p_simplify = false); Node *create_multiple_convex_collisions_node(); void create_multiple_convex_collisions(); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index ba0f8cc870..d6c6ec75b4 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -32,6 +32,7 @@ #include "core/config/engine.h" #include "core/object/message_queue.h" +#include "scene/3d/visual_instance_3d.h" #include "scene/main/scene_tree.h" #include "scene/main/window.h" #include "scene/scene_string_names.h" @@ -148,6 +149,7 @@ void Node3D::_notification(int p_what) { _notify_dirty(); notification(NOTIFICATION_ENTER_WORLD); + _update_visibility_parent(true); } break; case NOTIFICATION_EXIT_TREE: { @@ -161,6 +163,7 @@ void Node3D::_notification(int p_what) { data.parent = nullptr; data.C = nullptr; data.top_level_active = false; + _update_visibility_parent(true); } break; case NOTIFICATION_ENTER_WORLD: { data.inside_world = true; @@ -223,7 +226,7 @@ void Node3D::_notification(int p_what) { } } -void Node3D::set_transform(const Transform &p_transform) { +void Node3D::set_transform(const Transform3D &p_transform) { data.local_transform = p_transform; data.dirty |= DIRTY_VECTORS; _propagate_transform_changed(this); @@ -232,8 +235,8 @@ void Node3D::set_transform(const Transform &p_transform) { } } -void Node3D::set_global_transform(const Transform &p_transform) { - Transform xform = +void Node3D::set_global_transform(const Transform3D &p_transform) { + Transform3D xform = (data.parent && !data.top_level_active) ? data.parent->get_global_transform().affine_inverse() * p_transform : p_transform; @@ -241,16 +244,15 @@ void Node3D::set_global_transform(const Transform &p_transform) { set_transform(xform); } -Transform Node3D::get_transform() const { +Transform3D Node3D::get_transform() const { if (data.dirty & DIRTY_LOCAL) { _update_local_transform(); } return data.local_transform; } - -Transform Node3D::get_global_transform() const { - ERR_FAIL_COND_V(!is_inside_tree(), Transform()); +Transform3D Node3D::get_global_transform() const { + ERR_FAIL_COND_V(!is_inside_tree(), Transform3D()); if (data.dirty & DIRTY_GLOBAL) { if (data.dirty & DIRTY_LOCAL) { @@ -274,25 +276,28 @@ Transform Node3D::get_global_transform() const { } #ifdef TOOLS_ENABLED -Transform Node3D::get_global_gizmo_transform() const { +Transform3D Node3D::get_global_gizmo_transform() const { return get_global_transform(); } -Transform Node3D::get_local_gizmo_transform() const { +Transform3D Node3D::get_local_gizmo_transform() const { return get_transform(); } #endif -Node3D *Node3D::get_parent_spatial() const { - return data.parent; +Node3D *Node3D::get_parent_node_3d() const { + if (data.top_level) { + return nullptr; + } + + return Object::cast_to<Node3D>(get_parent()); } -Transform Node3D::get_relative_transform(const Node *p_parent) const { - if (p_parent == this) { - return Transform(); - } +Transform3D Node3D::get_relative_transform(const Node *p_parent) const { + if (p_parent == this) + return Transform3D(); - ERR_FAIL_COND_V(!data.parent, Transform()); + ERR_FAIL_COND_V(!data.parent, Transform3D()); if (p_parent == data.parent) { return get_transform(); @@ -301,8 +306,8 @@ Transform Node3D::get_relative_transform(const Node *p_parent) const { } } -void Node3D::set_translation(const Vector3 &p_translation) { - data.local_transform.origin = p_translation; +void Node3D::set_position(const Vector3 &p_position) { + data.local_transform.origin = p_position; _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -323,10 +328,6 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) { } } -void Node3D::set_rotation_degrees(const Vector3 &p_euler_deg) { - set_rotation(p_euler_deg * (Math_PI / 180.0)); -} - void Node3D::set_scale(const Vector3 &p_scale) { if (data.dirty & DIRTY_VECTORS) { data.rotation = data.local_transform.basis.get_rotation(); @@ -341,7 +342,7 @@ void Node3D::set_scale(const Vector3 &p_scale) { } } -Vector3 Node3D::get_translation() const { +Vector3 Node3D::get_position() const { return data.local_transform.origin; } @@ -356,10 +357,6 @@ Vector3 Node3D::get_rotation() const { return data.rotation; } -Vector3 Node3D::get_rotation_degrees() const { - return get_rotation() * (180.0 / Math_PI); -} - Vector3 Node3D::get_scale() const { if (data.dirty & DIRTY_VECTORS) { data.scale = data.local_transform.basis.get_scale(); @@ -557,87 +554,87 @@ bool Node3D::is_visible() const { } void Node3D::rotate_object_local(const Vector3 &p_axis, float p_angle) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.rotate_local(p_axis, p_angle); set_transform(t); } void Node3D::rotate(const Vector3 &p_axis, float p_angle) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.rotate(p_axis, p_angle); set_transform(t); } void Node3D::rotate_x(float p_angle) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.rotate(Vector3(1, 0, 0), p_angle); set_transform(t); } void Node3D::rotate_y(float p_angle) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.rotate(Vector3(0, 1, 0), p_angle); set_transform(t); } void Node3D::rotate_z(float p_angle) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.rotate(Vector3(0, 0, 1), p_angle); set_transform(t); } void Node3D::translate(const Vector3 &p_offset) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.translate(p_offset); set_transform(t); } void Node3D::translate_object_local(const Vector3 &p_offset) { - Transform t = get_transform(); + Transform3D t = get_transform(); - Transform s; + Transform3D s; s.translate(p_offset); set_transform(t * s); } void Node3D::scale(const Vector3 &p_ratio) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.scale(p_ratio); set_transform(t); } void Node3D::scale_object_local(const Vector3 &p_scale) { - Transform t = get_transform(); + Transform3D t = get_transform(); t.basis.scale_local(p_scale); set_transform(t); } void Node3D::global_rotate(const Vector3 &p_axis, float p_angle) { - Transform t = get_global_transform(); + Transform3D t = get_global_transform(); t.basis.rotate(p_axis, p_angle); set_global_transform(t); } void Node3D::global_scale(const Vector3 &p_scale) { - Transform t = get_global_transform(); + Transform3D t = get_global_transform(); t.basis.scale(p_scale); set_global_transform(t); } void Node3D::global_translate(const Vector3 &p_offset) { - Transform t = get_global_transform(); + Transform3D t = get_global_transform(); t.origin += p_offset; set_global_transform(t); } void Node3D::orthonormalize() { - Transform t = get_transform(); + Transform3D t = get_transform(); t.orthonormalize(); set_transform(t); } void Node3D::set_identity() { - set_transform(Transform()); + set_transform(Transform3D()); } void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) { @@ -649,7 +646,7 @@ void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target ERR_FAIL_COND_MSG(p_pos == p_target, "Node origin and target are in the same position, look_at() failed."); ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos) == Vector3(), "Up vector and direction between node origin and target are aligned, look_at() failed."); - Transform lookat; + Transform3D lookat; lookat.origin = p_pos; Vector3 original_scale(get_scale()); @@ -692,20 +689,63 @@ void Node3D::force_update_transform() { notification(NOTIFICATION_TRANSFORM_CHANGED); } +void Node3D::_update_visibility_parent(bool p_update_root) { + RID new_parent; + + if (!visibility_parent_path.is_empty()) { + if (!p_update_root) { + return; + } + Node *parent = get_node_or_null(visibility_parent_path); + ERR_FAIL_COND_MSG(!parent, "Can't find visibility parent node at path: " + visibility_parent_path); + ERR_FAIL_COND_MSG(parent == this, "The visibility parent can't be the same node."); + GeometryInstance3D *gi = Object::cast_to<GeometryInstance3D>(parent); + ERR_FAIL_COND_MSG(!gi, "The visibility parent node must be a GeometryInstance3D, at path: " + visibility_parent_path); + new_parent = gi ? gi->get_instance() : RID(); + } else if (data.parent) { + new_parent = data.parent->data.visibility_parent; + } + + if (new_parent == data.visibility_parent) { + return; + } + + data.visibility_parent = new_parent; + + VisualInstance3D *vi = Object::cast_to<VisualInstance3D>(this); + if (vi) { + RS::get_singleton()->instance_set_visibility_parent(vi->get_instance(), data.visibility_parent); + } + + for (List<Node3D *>::Element *E = data.children.front(); E; E = E->next()) { + Node3D *c = E->get(); + c->_update_visibility_parent(false); + } +} + +void Node3D::set_visibility_parent(const NodePath &p_path) { + visibility_parent_path = p_path; + if (is_inside_tree()) { + _update_visibility_parent(true); + } +} + +NodePath Node3D::get_visibility_parent() const { + return visibility_parent_path; +} + void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform", "local"), &Node3D::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &Node3D::get_transform); - ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Node3D::set_translation); - ClassDB::bind_method(D_METHOD("get_translation"), &Node3D::get_translation); + ClassDB::bind_method(D_METHOD("set_position", "position"), &Node3D::set_position); + ClassDB::bind_method(D_METHOD("get_position"), &Node3D::get_position); ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Node3D::set_rotation); ClassDB::bind_method(D_METHOD("get_rotation"), &Node3D::get_rotation); - ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Node3D::set_rotation_degrees); - ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Node3D::get_rotation_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Node3D::set_scale); ClassDB::bind_method(D_METHOD("get_scale"), &Node3D::get_scale); ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Node3D::set_global_transform); ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform); - ClassDB::bind_method(D_METHOD("get_parent_spatial"), &Node3D::get_parent_spatial); + ClassDB::bind_method(D_METHOD("get_parent_node_3d"), &Node3D::get_parent_node_3d); ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification); ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &Node3D::set_as_top_level); ClassDB::bind_method(D_METHOD("is_set_as_top_level"), &Node3D::is_set_as_top_level); @@ -715,6 +755,9 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("force_update_transform"), &Node3D::force_update_transform); + ClassDB::bind_method(D_METHOD("set_visibility_parent", "path"), &Node3D::set_visibility_parent); + ClassDB::bind_method(D_METHOD("get_visibility_parent"), &Node3D::get_visibility_parent); + ClassDB::bind_method(D_METHOD("_update_gizmo"), &Node3D::_update_gizmo); ClassDB::bind_method(D_METHOD("update_gizmo"), &Node3D::update_gizmo); @@ -758,19 +801,19 @@ void Node3D::_bind_methods() { BIND_CONSTANT(NOTIFICATION_EXIT_WORLD); BIND_CONSTANT(NOTIFICATION_VISIBILITY_CHANGED); - //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ; + //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM3D,"transform/global",PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR ), "set_global_transform", "get_global_transform") ; ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_translation", "get_translation"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_NONE, "", 0), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); ADD_GROUP("Matrix", ""); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, ""), "set_transform", "get_transform"); ADD_GROUP("Visibility", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", 0), "set_gizmo", "get_gizmo"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "Node3DGizmo", PROPERTY_USAGE_NONE), "set_gizmo", "get_gizmo"); ADD_SIGNAL(MethodInfo("visibility_changed")); } diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index a62c7b31a8..fe6324c796 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -34,8 +34,8 @@ #include "scene/main/node.h" #include "scene/main/scene_tree.h" -class Node3DGizmo : public Reference { - GDCLASS(Node3DGizmo, Reference); +class Node3DGizmo : public RefCounted { + GDCLASS(Node3DGizmo, RefCounted); public: virtual void create() = 0; @@ -62,8 +62,8 @@ class Node3D : public Node { mutable SelfList<Node> xform_change; struct Data { - mutable Transform global_transform; - mutable Transform local_transform; + mutable Transform3D global_transform; + mutable Transform3D local_transform; mutable Vector3 rotation; mutable Vector3 scale = Vector3(1, 1, 1); @@ -75,6 +75,8 @@ class Node3D : public Node { bool top_level = false; bool inside_world = false; + RID visibility_parent; + int children_lock = 0; Node3D *parent = nullptr; List<Node3D *> children; @@ -95,12 +97,17 @@ class Node3D : public Node { } data; + NodePath visibility_parent_path; + void _update_gizmo(); void _notify_dirty(); void _propagate_transform_changed(Node3D *p_origin); void _propagate_visibility_changed(); + void _propagate_visibility_parent(); + void _update_visibility_parent(bool p_update_root); + protected: _FORCE_INLINE_ void set_ignore_transform_notification(bool p_ignore) { data.ignore_notification = p_ignore; } @@ -118,29 +125,27 @@ public: NOTIFICATION_LOCAL_TRANSFORM_CHANGED = 44, }; - Node3D *get_parent_spatial() const; + Node3D *get_parent_node_3d() const; Ref<World3D> get_world_3d() const; - void set_translation(const Vector3 &p_translation); + void set_position(const Vector3 &p_position); void set_rotation(const Vector3 &p_euler_rad); - void set_rotation_degrees(const Vector3 &p_euler_deg); void set_scale(const Vector3 &p_scale); - Vector3 get_translation() const; + Vector3 get_position() const; Vector3 get_rotation() const; - Vector3 get_rotation_degrees() const; Vector3 get_scale() const; - void set_transform(const Transform &p_transform); - void set_global_transform(const Transform &p_transform); + void set_transform(const Transform3D &p_transform); + void set_global_transform(const Transform3D &p_transform); - Transform get_transform() const; - Transform get_global_transform() const; + Transform3D get_transform() const; + Transform3D get_global_transform() const; #ifdef TOOLS_ENABLED - virtual Transform get_global_gizmo_transform() const; - virtual Transform get_local_gizmo_transform() const; + virtual Transform3D get_global_gizmo_transform() const; + virtual Transform3D get_local_gizmo_transform() const; #endif void set_as_top_level(bool p_enabled); @@ -156,7 +161,7 @@ public: _FORCE_INLINE_ bool is_inside_world() const { return data.inside_world; } - Transform get_relative_transform(const Node *p_parent) const; + Transform3D get_relative_transform(const Node *p_parent) const; void rotate(const Vector3 &p_axis, float p_angle); void rotate_x(float p_angle); @@ -196,6 +201,9 @@ public: void force_update_transform(); + void set_visibility_parent(const NodePath &p_path); + NodePath get_visibility_parent() const; + Node3D(); }; diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp index d3a256db34..7b736e689c 100644 --- a/scene/3d/occluder_instance_3d.cpp +++ b/scene/3d/occluder_instance_3d.cpp @@ -114,7 +114,7 @@ Ref<ArrayMesh> Occluder3D::get_debug_mesh() const { arrays[Mesh::ARRAY_VERTEX] = vertices; arrays[Mesh::ARRAY_INDEX] = indices; - debug_mesh.instance(); + debug_mesh.instantiate(); debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays); return debug_mesh; } @@ -174,10 +174,12 @@ void OccluderInstance3D::set_occluder(const Ref<Occluder3D> &p_occluder) { } update_gizmo(); + update_configuration_warnings(); } void OccluderInstance3D::_occluder_changed() { update_gizmo(); + update_configuration_warnings(); } Ref<Occluder3D> OccluderInstance3D::get_occluder() const { @@ -186,6 +188,7 @@ Ref<Occluder3D> OccluderInstance3D::get_occluder() const { void OccluderInstance3D::set_bake_mask(uint32_t p_mask) { bake_mask = p_mask; + update_configuration_warnings(); } uint32_t OccluderInstance3D::get_bake_mask() const { @@ -233,7 +236,7 @@ void OccluderInstance3D::_bake_node(Node *p_node, PackedVector3Array &r_vertices } if (valid) { - Transform global_to_local = get_global_transform().affine_inverse() * mi->get_global_transform(); + Transform3D global_to_local = get_global_transform().affine_inverse() * mi->get_global_transform(); for (int i = 0; i < mesh->get_surface_count(); i++) { if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { @@ -303,7 +306,7 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String if (get_occluder().is_valid()) { occ = get_occluder(); } else { - occ.instance(); + occ.instantiate(); occ->set_path(p_occluder_path); } @@ -314,6 +317,31 @@ OccluderInstance3D::BakeError OccluderInstance3D::bake(Node *p_from_node, String return BAKE_ERROR_OK; } +TypedArray<String> OccluderInstance3D::get_configuration_warnings() const { + TypedArray<String> warnings = Node::get_configuration_warnings(); + + if (!bool(GLOBAL_GET("rendering/occlusion_culling/use_occlusion_culling"))) { + warnings.push_back(TTR("Occlusion culling is disabled in the Project Settings, which means occlusion culling won't be performed in the root viewport.\nTo resolve this, open the Project Settings and enable Rendering > Occlusion Culling > Use Occlusion Culling.")); + } + + if (bake_mask == 0) { + // NOTE: This warning will not be emitted if none of the 20 checkboxes + // exposed in the editor are checked. This is because there are + // currently 12 unexposed layers in the editor inspector. + warnings.push_back(TTR("The Bake Mask has no bits enabled, which means baking will not produce any occluder meshes for this OccluderInstance3D.\nTo resolve this, enable at least one bit in the Bake Mask property.")); + } + + if (occluder.is_null()) { + warnings.push_back(TTR("No occluder mesh is defined in the Occluder property, so no occlusion culling will be performed using this OccluderInstance3D.\nTo resolve this, select the OccluderInstance3D then use the Bake Occluders button at the top of the 3D editor viewport.")); + } else if (occluder->get_vertices().size() < 3) { + // Using the "New Occluder" dropdown button won't result in a correct occluder, + // so warn the user about this. + warnings.push_back(TTR("The occluder mesh has less than 3 vertices, so no occlusion culling will be performed using this OccluderInstance3D.\nTo generate a proper occluder mesh, select the OccluderInstance3D then use the Bake Occluders button at the top of the 3D editor viewport.")); + } + + return warnings; +} + void OccluderInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bake_mask", "mask"), &OccluderInstance3D::set_bake_mask); ClassDB::bind_method(D_METHOD("get_bake_mask"), &OccluderInstance3D::get_bake_mask); diff --git a/scene/3d/occluder_instance_3d.h b/scene/3d/occluder_instance_3d.h index 4bb468274d..d382cd090e 100644 --- a/scene/3d/occluder_instance_3d.h +++ b/scene/3d/occluder_instance_3d.h @@ -82,6 +82,8 @@ protected: static void _bind_methods(); public: + virtual TypedArray<String> get_configuration_warnings() const override; + enum BakeError { BAKE_ERROR_OK, BAKE_ERROR_NO_SAVE_PATH, diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 4ec4ee6207..de115b35e3 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -108,7 +108,7 @@ void PathFollow3D::_update_transform(bool p_update_xyz_rot) { } Vector3 pos = c->interpolate_baked(offset, cubic); - Transform t = get_transform(); + Transform3D t = get_transform(); // Vector3 pos_offset = Vector3(h_offset, v_offset, 0); not used in all cases // will be replaced by "Vector3(h_offset, v_offset, 0)" where it was formerly used diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index e895d18604..e7482d35e7 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -43,16 +43,35 @@ #include "editor/plugins/node_3d_editor_plugin.h" #endif -Vector3 PhysicsBody3D::get_linear_velocity() const { - return Vector3(); +void PhysicsBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only", "safe_margin"), &PhysicsBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false), DEFVAL(0.001)); + ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "collision", "safe_margin"), &PhysicsBody3D::test_move, DEFVAL(true), DEFVAL(true), DEFVAL(Variant()), DEFVAL(0.001)); + + ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicsBody3D::set_axis_lock); + ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicsBody3D::get_axis_lock); + + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions); + ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with); + ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with); + + ADD_GROUP("Axis Lock", "axis_lock_"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); } -Vector3 PhysicsBody3D::get_angular_velocity() const { - return Vector3(); +PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : + CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { + set_body_mode(p_mode); } -real_t PhysicsBody3D::get_inverse_mass() const { - return 0; +PhysicsBody3D::~PhysicsBody3D() { + if (motion_cache.is_valid()) { + motion_cache->owner = nullptr; + } } TypedArray<PhysicsBody3D> PhysicsBody3D::get_collision_exceptions() { @@ -83,11 +102,108 @@ void PhysicsBody3D::remove_collision_exception_with(Node *p_node) { PhysicsServer3D::get_singleton()->body_remove_collision_exception(get_rid(), collision_object->get_rid()); } -void PhysicsBody3D::_bind_methods() {} +Ref<KinematicCollision3D> PhysicsBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only, real_t p_margin) { + PhysicsServer3D::MotionResult result; + if (move_and_collide(p_motion, p_infinite_inertia, result, p_margin, p_exclude_raycast_shapes, p_test_only)) { + if (motion_cache.is_null()) { + motion_cache.instantiate(); + motion_cache->owner = this; + } -PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : - CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode); + motion_cache->result = result; + + return motion_cache; + } + + return Ref<KinematicCollision3D>(); +} + +bool PhysicsBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes, bool p_test_only, bool p_cancel_sliding) { + Transform3D gt = get_global_transform(); + bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, p_margin, &r_result, p_exclude_raycast_shapes); + + // Restore direction of motion to be along original motion, + // in order to avoid sliding due to recovery, + // but only if collision depth is low enough to avoid tunneling. + real_t motion_length = p_motion.length(); + if (motion_length > CMP_EPSILON) { + real_t precision = CMP_EPSILON; + + if (colliding && p_cancel_sliding) { + // Can't just use margin as a threshold because collision depth is calculated on unsafe motion, + // so even in normal resting cases the depth can be a bit more than the margin. + precision += motion_length * (r_result.collision_unsafe_fraction - r_result.collision_safe_fraction); + + if (r_result.collision_depth > (real_t)p_margin + precision) { + p_cancel_sliding = false; + } + } + + if (p_cancel_sliding) { + // Check depth of recovery. + Vector3 motion_normal = p_motion / motion_length; + real_t dot = r_result.motion.dot(motion_normal); + Vector3 recovery = r_result.motion - motion_normal * dot; + real_t recovery_length = recovery.length(); + // Fixes cases where canceling slide causes the motion to go too deep into the ground, + // Becauses we're only taking rest information into account and not general recovery. + if (recovery_length < (real_t)p_margin + precision) { + // Apply adjustment to motion. + r_result.motion = motion_normal * dot; + r_result.remainder = p_motion - r_result.motion; + } + } + } + + for (int i = 0; i < 3; i++) { + if (locked_axis & (1 << i)) { + r_result.motion[i] = 0; + } + } + + if (!p_test_only) { + gt.origin += r_result.motion; + set_global_transform(gt); + } + + return colliding; +} + +bool PhysicsBody3D::test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, const Ref<KinematicCollision3D> &r_collision, real_t p_margin) { + ERR_FAIL_COND_V(!is_inside_tree(), false); + + PhysicsServer3D::MotionResult *r = nullptr; + if (r_collision.is_valid()) { + // Needs const_cast because method bindings don't support non-const Ref. + r = const_cast<PhysicsServer3D::MotionResult *>(&r_collision->result); + } + + return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, p_margin, r, p_exclude_raycast_shapes); +} + +void PhysicsBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { + if (p_lock) { + locked_axis |= p_axis; + } else { + locked_axis &= (~p_axis); + } + PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); +} + +bool PhysicsBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { + return (locked_axis & p_axis); +} + +Vector3 PhysicsBody3D::get_linear_velocity() const { + return Vector3(); +} + +Vector3 PhysicsBody3D::get_angular_velocity() const { + return Vector3(); +} + +real_t PhysicsBody3D::get_inverse_mass() const { + return 0; } void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) { @@ -109,14 +225,44 @@ Ref<PhysicsMaterial> StaticBody3D::get_physics_material_override() const { return physics_material_override; } +void StaticBody3D::set_kinematic_motion_enabled(bool p_enabled) { + if (p_enabled == kinematic_motion) { + return; + } + + kinematic_motion = p_enabled; + + if (kinematic_motion) { + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); + } else { + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); + } + + _update_kinematic_motion(); +} + +bool StaticBody3D::is_kinematic_motion_enabled() const { + return kinematic_motion; +} + void StaticBody3D::set_constant_linear_velocity(const Vector3 &p_vel) { constant_linear_velocity = p_vel; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); + + if (kinematic_motion) { + _update_kinematic_motion(); + } else { + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY, constant_linear_velocity); + } } void StaticBody3D::set_constant_angular_velocity(const Vector3 &p_vel) { constant_angular_velocity = p_vel; - PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); + + if (kinematic_motion) { + _update_kinematic_motion(); + } else { + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY, constant_angular_velocity); + } } Vector3 StaticBody3D::get_constant_linear_velocity() const { @@ -127,30 +273,83 @@ Vector3 StaticBody3D::get_constant_angular_velocity() const { return constant_angular_velocity; } +Vector3 StaticBody3D::get_linear_velocity() const { + return linear_velocity; +} + +Vector3 StaticBody3D::get_angular_velocity() const { + return angular_velocity; +} + +void StaticBody3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + ERR_FAIL_COND(!kinematic_motion); + + real_t delta_time = get_physics_process_delta_time(); + + Transform3D new_transform = get_global_transform(); + new_transform.origin += constant_linear_velocity * delta_time; + + real_t ang_vel = constant_angular_velocity.length(); + if (!Math::is_zero_approx(ang_vel)) { + Vector3 ang_vel_axis = constant_angular_velocity / ang_vel; + Basis rot(ang_vel_axis, ang_vel * delta_time); + new_transform.basis = rot * new_transform.basis; + new_transform.orthonormalize(); + } + + PhysicsServer3D::get_singleton()->body_set_state(get_rid(), PhysicsServer3D::BODY_STATE_TRANSFORM, new_transform); + + // Propagate transform change to node. + set_ignore_transform_notification(true); + set_global_transform(new_transform); + set_ignore_transform_notification(false); + _on_transform_changed(); + } break; + } +} + void StaticBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity); ClassDB::bind_method(D_METHOD("set_constant_angular_velocity", "vel"), &StaticBody3D::set_constant_angular_velocity); ClassDB::bind_method(D_METHOD("get_constant_linear_velocity"), &StaticBody3D::get_constant_linear_velocity); ClassDB::bind_method(D_METHOD("get_constant_angular_velocity"), &StaticBody3D::get_constant_angular_velocity); + ClassDB::bind_method(D_METHOD("set_kinematic_motion_enabled", "enabled"), &StaticBody3D::set_kinematic_motion_enabled); + ClassDB::bind_method(D_METHOD("is_kinematic_motion_enabled"), &StaticBody3D::is_kinematic_motion_enabled); + ClassDB::bind_method(D_METHOD("set_physics_material_override", "physics_material_override"), &StaticBody3D::set_physics_material_override); ClassDB::bind_method(D_METHOD("get_physics_material_override"), &StaticBody3D::get_physics_material_override); - ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &PhysicsBody3D::get_collision_exceptions); - ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &PhysicsBody3D::add_collision_exception_with); - ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &PhysicsBody3D::remove_collision_exception_with); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_linear_velocity"), "set_constant_linear_velocity", "get_constant_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_angular_velocity"), "set_constant_angular_velocity", "get_constant_angular_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "kinematic_motion"), "set_kinematic_motion_enabled", "is_kinematic_motion_enabled"); +} + +void StaticBody3D::_direct_state_changed(Object *p_state) { +#ifdef DEBUG_ENABLED + PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state); + ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument"); +#else + PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it +#endif + + linear_velocity = state->get_linear_velocity(); + angular_velocity = state->get_angular_velocity(); } StaticBody3D::StaticBody3D() : PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { } -StaticBody3D::~StaticBody3D() {} - void StaticBody3D::_reload_physics_characteristics() { if (physics_material_override.is_null()) { PhysicsServer3D::get_singleton()->body_set_param(get_rid(), PhysicsServer3D::BODY_PARAM_BOUNCE, 0); @@ -161,6 +360,27 @@ void StaticBody3D::_reload_physics_characteristics() { } } +void StaticBody3D::_update_kinematic_motion() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return; + } +#endif + + if (kinematic_motion) { + PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &StaticBody3D::_direct_state_changed)); + + if (!constant_angular_velocity.is_equal_approx(Vector3()) || !constant_linear_velocity.is_equal_approx(Vector3())) { + set_physics_process_internal(true); + return; + } + } else { + PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable()); + } + + set_physics_process_internal(false); +} + void RigidBody3D::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = Object::cast_to<Node>(obj); @@ -380,37 +600,36 @@ void RigidBody3D::_direct_state_changed(Object *p_state) { void RigidBody3D::_notification(int p_what) { #ifdef TOOLS_ENABLED - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - set_notify_local_transform(true); //used for warnings and only in editor - } - } + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + set_notify_local_transform(true); //used for warnings and only in editor + } + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - } + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; } - #endif } void RigidBody3D::set_mode(Mode p_mode) { mode = p_mode; switch (p_mode) { - case MODE_RIGID: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID); + case MODE_DYNAMIC: { + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); } break; case MODE_STATIC: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); - + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); } break; - case MODE_CHARACTER: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_CHARACTER); - + case MODE_DYNAMIC_LOCKED: { + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED); } break; case MODE_KINEMATIC: { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); } break; } update_configuration_warnings(); @@ -627,14 +846,6 @@ bool RigidBody3D::is_contact_monitor_enabled() const { return contact_monitor != nullptr; } -void RigidBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); -} - -bool RigidBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); -} - Array RigidBody3D::get_colliding_bodies() const { ERR_FAIL_COND_V(!contact_monitor, Array()); @@ -654,12 +865,12 @@ Array RigidBody3D::get_colliding_bodies() const { } TypedArray<String> RigidBody3D::get_configuration_warnings() const { - Transform t = get_transform(); + Transform3D t = get_transform(); TypedArray<String> warnings = Node::get_configuration_warnings(); - if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { - warnings.push_back(TTR("Size changes to RigidBody3D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); + if ((get_mode() == MODE_DYNAMIC || get_mode() == MODE_DYNAMIC_LOCKED) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { + warnings.push_back(TTR("Size changes to RigidBody3D (in dynamic modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } return warnings; @@ -720,15 +931,12 @@ void RigidBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody3D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody3D::is_able_to_sleep); - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &RigidBody3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &RigidBody3D::get_axis_lock); - ClassDB::bind_method(D_METHOD("get_colliding_bodies"), &RigidBody3D::get_colliding_bodies); BIND_VMETHOD(MethodInfo("_integrate_forces", PropertyInfo(Variant::OBJECT, "state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectBodyState3D"))); - ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Dynamic,Static,DynamicLocked,Kinematic"), "set_mode", "get_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "physics_material_override", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsMaterial"), "set_physics_material_override", "get_physics_material_override"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-128,128,0.01"), "set_gravity_scale", "get_gravity_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "custom_integrator"), "set_use_custom_integrator", "is_using_custom_integrator"); @@ -737,13 +945,6 @@ void RigidBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "contact_monitor"), "set_contact_monitor", "is_contact_monitor_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleeping", "is_sleeping"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); ADD_GROUP("Linear", "linear_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); @@ -757,14 +958,14 @@ void RigidBody3D::_bind_methods() { ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("sleeping_state_changed")); - BIND_ENUM_CONSTANT(MODE_RIGID); + BIND_ENUM_CONSTANT(MODE_DYNAMIC); BIND_ENUM_CONSTANT(MODE_STATIC); - BIND_ENUM_CONSTANT(MODE_CHARACTER); + BIND_ENUM_CONSTANT(MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(MODE_KINEMATIC); } RigidBody3D::RigidBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) { + PhysicsBody3D(PhysicsServer3D::BODY_MODE_DYNAMIC) { PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &RigidBody3D::_direct_state_changed)); } @@ -784,233 +985,146 @@ void RigidBody3D::_reload_physics_characteristics() { } } -////////////////////////////////////////////////////// -////////////////////////// - -Ref<KinematicCollision3D> KinematicBody3D::_move(const Vector3 &p_motion, bool p_infinite_inertia, bool p_exclude_raycast_shapes, bool p_test_only) { - Collision col; - if (move_and_collide(p_motion, p_infinite_inertia, col, p_exclude_raycast_shapes, p_test_only)) { - if (motion_cache.is_null()) { - motion_cache.instance(); - motion_cache->owner = this; - } - - motion_cache->collision = col; - - return motion_cache; - } - - return Ref<KinematicCollision3D>(); -} - -Vector3 KinematicBody3D::get_linear_velocity() const { - return linear_velocity; -} - -Vector3 KinematicBody3D::get_angular_velocity() const { - return angular_velocity; -} - -bool KinematicBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes, bool p_test_only) { - Transform gt = get_global_transform(); - PhysicsServer3D::MotionResult result; - bool colliding = PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result, p_exclude_raycast_shapes); - - if (colliding) { - r_collision.collider_metadata = result.collider_metadata; - r_collision.collider_shape = result.collider_shape; - r_collision.collider_vel = result.collider_velocity; - r_collision.collision = result.collision_point; - r_collision.normal = result.collision_normal; - r_collision.collider = result.collider_id; - r_collision.collider_rid = result.collider; - r_collision.travel = result.motion; - r_collision.remainder = result.remainder; - r_collision.local_shape = result.collision_local_shape; - } - - for (int i = 0; i < 3; i++) { - if (locked_axis & (1 << i)) { - result.motion[i] = 0; - } - } - - if (!p_test_only) { - gt.origin += result.motion; - set_global_transform(gt); - } - - return colliding; -} +/////////////////////////////////////// //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { - Vector3 body_velocity = p_linear_velocity; - Vector3 body_velocity_normal = body_velocity.normalized(); - Vector3 up_direction = p_up_direction.normalized(); +void CharacterBody3D::move_and_slide() { + Vector3 body_velocity_normal = linear_velocity.normalized(); + + bool was_on_floor = on_floor; for (int i = 0; i < 3; i++) { if (locked_axis & (1 << i)) { - body_velocity[i] = 0; + linear_velocity[i] = 0.0; } } // Hack in order to work with calling from _process as well as from _physics_process; calling from thread is risky - Vector3 motion = (floor_velocity + body_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); + Vector3 motion = (floor_velocity + linear_velocity) * (Engine::get_singleton()->is_in_physics_frame() ? get_physics_process_delta_time() : get_process_delta_time()); on_floor = false; on_floor_body = RID(); on_ceiling = false; on_wall = false; - colliders.clear(); + motion_results.clear(); floor_normal = Vector3(); floor_velocity = Vector3(); - while (p_max_slides) { - Collision collision; + // No sliding on first attempt to keep motion stable when possible. + bool sliding_enabled = false; + for (int iteration = 0; iteration < max_slides; ++iteration) { + PhysicsServer3D::MotionResult result; bool found_collision = false; for (int i = 0; i < 2; ++i) { bool collided; if (i == 0) { //collide - collided = move_and_collide(motion, p_infinite_inertia, collision); + collided = move_and_collide(motion, infinite_inertia, result, margin, true, false, !sliding_enabled); if (!collided) { motion = Vector3(); //clear because no collision happened and motion completed } } else { //separate raycasts (if any) - collided = separate_raycast_shapes(p_infinite_inertia, collision); + collided = separate_raycast_shapes(result); if (collided) { - collision.remainder = motion; //keep - collision.travel = Vector3(); + result.remainder = motion; //keep + result.motion = Vector3(); } } if (collided) { found_collision = true; - colliders.push_back(collision); - motion = collision.remainder; + motion_results.push_back(result); if (up_direction == Vector3()) { //all is a wall on_wall = true; } else { - if (Math::acos(collision.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor + if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //floor on_floor = true; - floor_normal = collision.normal; - on_floor_body = collision.collider_rid; - floor_velocity = collision.collider_vel; - - if (p_stop_on_slope) { - if ((body_velocity_normal + up_direction).length() < 0.01 && collision.travel.length() < 1) { - Transform gt = get_global_transform(); - gt.origin -= collision.travel.slide(up_direction); + floor_normal = result.collision_normal; + on_floor_body = result.collider; + floor_velocity = result.collider_velocity; + + if (stop_on_slope) { + if ((body_velocity_normal + up_direction).length() < 0.01) { + Transform3D gt = get_global_transform(); + gt.origin -= result.motion.slide(up_direction); set_global_transform(gt); - return Vector3(); + linear_velocity = Vector3(); + return; } } - } else if (Math::acos(collision.normal.dot(-up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling + } else if (Math::acos(result.collision_normal.dot(-up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { //ceiling on_ceiling = true; } else { on_wall = true; } } - motion = motion.slide(collision.normal); - body_velocity = body_velocity.slide(collision.normal); + if (sliding_enabled || !on_floor) { + motion = result.remainder.slide(result.collision_normal); + linear_velocity = linear_velocity.slide(result.collision_normal); - for (int j = 0; j < 3; j++) { - if (locked_axis & (1 << j)) { - body_velocity[j] = 0; + for (int j = 0; j < 3; j++) { + if (locked_axis & (1 << j)) { + linear_velocity[j] = 0.0; + } } + } else { + motion = result.remainder; } } + + sliding_enabled = true; } if (!found_collision || motion == Vector3()) { break; } - - --p_max_slides; } - return body_velocity; -} - -Vector3 KinematicBody3D::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { - Vector3 up_direction = p_up_direction.normalized(); - bool was_on_floor = on_floor; - - Vector3 ret = move_and_slide(p_linear_velocity, up_direction, p_stop_on_slope, p_max_slides, p_floor_max_angle, p_infinite_inertia); - if (!was_on_floor || p_snap == Vector3()) { - return ret; + if (!was_on_floor || snap == Vector3()) { + return; } - Collision col; - Transform gt = get_global_transform(); - - if (move_and_collide(p_snap, p_infinite_inertia, col, false, true)) { + // Apply snap. + Transform3D gt = get_global_transform(); + PhysicsServer3D::MotionResult result; + if (move_and_collide(snap, infinite_inertia, result, margin, false, true)) { bool apply = true; if (up_direction != Vector3()) { - if (Math::acos(col.normal.dot(up_direction)) <= p_floor_max_angle + FLOOR_ANGLE_THRESHOLD) { + if (Math::acos(result.collision_normal.dot(up_direction)) <= floor_max_angle + FLOOR_ANGLE_THRESHOLD) { on_floor = true; - floor_normal = col.normal; - on_floor_body = col.collider_rid; - floor_velocity = col.collider_vel; - if (p_stop_on_slope) { + floor_normal = result.collision_normal; + on_floor_body = result.collider; + floor_velocity = result.collider_velocity; + if (stop_on_slope) { // move and collide may stray the object a bit because of pre un-stucking, // so only ensure that motion happens on floor direction in this case. - col.travel = col.travel.project(up_direction); + result.motion = result.motion.project(up_direction); } } else { apply = false; //snapped with floor direction, but did not snap to a floor, do not snap. } } if (apply) { - gt.origin += col.travel; + gt.origin += result.motion; set_global_transform(gt); } } - - return ret; -} - -bool KinematicBody3D::is_on_floor() const { - return on_floor; -} - -bool KinematicBody3D::is_on_wall() const { - return on_wall; } -bool KinematicBody3D::is_on_ceiling() const { - return on_ceiling; -} - -Vector3 KinematicBody3D::get_floor_normal() const { - return floor_normal; -} - -Vector3 KinematicBody3D::get_floor_velocity() const { - return floor_velocity; -} - -bool KinematicBody3D::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) { - ERR_FAIL_COND_V(!is_inside_tree(), false); - - return PhysicsServer3D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia); -} - -bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision) { +bool CharacterBody3D::separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result) { PhysicsServer3D::SeparationResult sep_res[8]; //max 8 rays - Transform gt = get_global_transform(); + Transform3D gt = get_global_transform(); Vector3 recover; - int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); + int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, infinite_inertia, recover, sep_res, 8, margin); int deepest = -1; real_t deepest_depth; for (int i = 0; i < hits; i++) { @@ -1024,15 +1138,15 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision set_global_transform(gt); if (deepest != -1) { - r_collision.collider = sep_res[deepest].collider_id; - r_collision.collider_metadata = sep_res[deepest].collider_metadata; - r_collision.collider_shape = sep_res[deepest].collider_shape; - r_collision.collider_vel = sep_res[deepest].collider_velocity; - r_collision.collision = sep_res[deepest].collision_point; - r_collision.normal = sep_res[deepest].collision_normal; - r_collision.local_shape = sep_res[deepest].collision_local_shape; - r_collision.travel = recover; - r_collision.remainder = Vector3(); + r_result.collider_id = sep_res[deepest].collider_id; + r_result.collider_metadata = sep_res[deepest].collider_metadata; + r_result.collider_shape = sep_res[deepest].collider_shape; + r_result.collider_velocity = sep_res[deepest].collider_velocity; + r_result.collision_point = sep_res[deepest].collision_point; + r_result.collision_normal = sep_res[deepest].collision_normal; + r_result.collision_local_shape = sep_res[deepest].collision_local_shape; + r_result.motion = recover; + r_result.remainder = Vector3(); return true; } else { @@ -1040,117 +1154,173 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision } } -void KinematicBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - if (p_lock) { - locked_axis |= p_axis; - } else { - locked_axis &= (~p_axis); - } - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); +void CharacterBody3D::set_safe_margin(real_t p_margin) { + margin = p_margin; +} + +real_t CharacterBody3D::get_safe_margin() const { + return margin; } -bool KinematicBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); +Vector3 CharacterBody3D::get_linear_velocity() const { + return linear_velocity; } -void KinematicBody3D::set_safe_margin(real_t p_margin) { - margin = p_margin; - PhysicsServer3D::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin); +void CharacterBody3D::set_linear_velocity(const Vector3 &p_velocity) { + linear_velocity = p_velocity; } -real_t KinematicBody3D::get_safe_margin() const { - return margin; +bool CharacterBody3D::is_on_floor() const { + return on_floor; +} + +bool CharacterBody3D::is_on_wall() const { + return on_wall; +} + +bool CharacterBody3D::is_on_ceiling() const { + return on_ceiling; +} + +Vector3 CharacterBody3D::get_floor_normal() const { + return floor_normal; } -int KinematicBody3D::get_slide_count() const { - return colliders.size(); +Vector3 CharacterBody3D::get_floor_velocity() const { + return floor_velocity; } -KinematicBody3D::Collision KinematicBody3D::get_slide_collision(int p_bounce) const { - ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Collision()); - return colliders[p_bounce]; +int CharacterBody3D::get_slide_count() const { + return motion_results.size(); } -Ref<KinematicCollision3D> KinematicBody3D::_get_slide_collision(int p_bounce) { - ERR_FAIL_INDEX_V(p_bounce, colliders.size(), Ref<KinematicCollision3D>()); +PhysicsServer3D::MotionResult CharacterBody3D::get_slide_collision(int p_bounce) const { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), PhysicsServer3D::MotionResult()); + return motion_results[p_bounce]; +} + +Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) { + ERR_FAIL_INDEX_V(p_bounce, motion_results.size(), Ref<KinematicCollision3D>()); if (p_bounce >= slide_colliders.size()) { slide_colliders.resize(p_bounce + 1); } if (slide_colliders[p_bounce].is_null()) { - slide_colliders.write[p_bounce].instance(); + slide_colliders.write[p_bounce].instantiate(); slide_colliders.write[p_bounce]->owner = this; } - slide_colliders.write[p_bounce]->collision = colliders[p_bounce]; + slide_colliders.write[p_bounce]->result = motion_results[p_bounce]; return slide_colliders[p_bounce]; } -void KinematicBody3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - // Reset move_and_slide() data. - on_floor = false; - on_floor_body = RID(); - on_ceiling = false; - on_wall = false; - colliders.clear(); - floor_velocity = Vector3(); - } +bool CharacterBody3D::is_stop_on_slope_enabled() const { + return stop_on_slope; } -void KinematicBody3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); - - ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody3D::test_move, DEFVAL(true)); +void CharacterBody3D::set_stop_on_slope_enabled(bool p_enabled) { + stop_on_slope = p_enabled; +} - ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody3D::is_on_floor); - ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody3D::is_on_ceiling); - ClassDB::bind_method(D_METHOD("is_on_wall"), &KinematicBody3D::is_on_wall); - ClassDB::bind_method(D_METHOD("get_floor_normal"), &KinematicBody3D::get_floor_normal); - ClassDB::bind_method(D_METHOD("get_floor_velocity"), &KinematicBody3D::get_floor_velocity); +bool CharacterBody3D::is_infinite_inertia_enabled() const { + return infinite_inertia; +} +void CharacterBody3D::set_infinite_inertia_enabled(bool p_enabled) { + infinite_inertia = p_enabled; +} - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &KinematicBody3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &KinematicBody3D::get_axis_lock); +int CharacterBody3D::get_max_slides() const { + return max_slides; +} - ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &KinematicBody3D::set_safe_margin); - ClassDB::bind_method(D_METHOD("get_safe_margin"), &KinematicBody3D::get_safe_margin); +void CharacterBody3D::set_max_slides(int p_max_slides) { + ERR_FAIL_COND(p_max_slides > 0); + max_slides = p_max_slides; +} - ClassDB::bind_method(D_METHOD("get_slide_count"), &KinematicBody3D::get_slide_count); - ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &KinematicBody3D::_get_slide_collision); +real_t CharacterBody3D::get_floor_max_angle() const { + return floor_max_angle; +} - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_motion_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); +void CharacterBody3D::set_floor_max_angle(real_t p_radians) { + floor_max_angle = p_radians; +} - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); +const Vector3 &CharacterBody3D::get_snap() const { + return snap; } -void KinematicBody3D::_direct_state_changed(Object *p_state) { -#ifdef DEBUG_ENABLED - PhysicsDirectBodyState3D *state = Object::cast_to<PhysicsDirectBodyState3D>(p_state); - ERR_FAIL_NULL_MSG(state, "Method '_direct_state_changed' must receive a valid PhysicsDirectBodyState3D object as argument"); -#else - PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; //trust it -#endif +void CharacterBody3D::set_snap(const Vector3 &p_snap) { + snap = p_snap; +} - linear_velocity = state->get_linear_velocity(); - angular_velocity = state->get_angular_velocity(); +const Vector3 &CharacterBody3D::get_up_direction() const { + return up_direction; } -KinematicBody3D::KinematicBody3D() : - PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { - set_safe_margin(0.001); - PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &KinematicBody3D::_direct_state_changed)); +void CharacterBody3D::set_up_direction(const Vector3 &p_up_direction) { + up_direction = p_up_direction.normalized(); } -KinematicBody3D::~KinematicBody3D() { - if (motion_cache.is_valid()) { - motion_cache->owner = nullptr; +void CharacterBody3D::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + // Reset move_and_slide() data. + on_floor = false; + on_floor_body = RID(); + on_ceiling = false; + on_wall = false; + motion_results.clear(); + floor_velocity = Vector3(); + } break; } +} + +void CharacterBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("move_and_slide"), &CharacterBody3D::move_and_slide); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "linear_velocity"), &CharacterBody3D::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &CharacterBody3D::get_linear_velocity); + + ClassDB::bind_method(D_METHOD("set_safe_margin", "pixels"), &CharacterBody3D::set_safe_margin); + ClassDB::bind_method(D_METHOD("get_safe_margin"), &CharacterBody3D::get_safe_margin); + ClassDB::bind_method(D_METHOD("is_stop_on_slope_enabled"), &CharacterBody3D::is_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("set_stop_on_slope_enabled", "enabled"), &CharacterBody3D::set_stop_on_slope_enabled); + ClassDB::bind_method(D_METHOD("is_infinite_inertia_enabled"), &CharacterBody3D::is_infinite_inertia_enabled); + ClassDB::bind_method(D_METHOD("set_infinite_inertia_enabled", "enabled"), &CharacterBody3D::set_infinite_inertia_enabled); + ClassDB::bind_method(D_METHOD("get_max_slides"), &CharacterBody3D::get_max_slides); + ClassDB::bind_method(D_METHOD("set_max_slides", "max_slides"), &CharacterBody3D::set_max_slides); + ClassDB::bind_method(D_METHOD("get_floor_max_angle"), &CharacterBody3D::get_floor_max_angle); + ClassDB::bind_method(D_METHOD("set_floor_max_angle", "radians"), &CharacterBody3D::set_floor_max_angle); + ClassDB::bind_method(D_METHOD("get_snap"), &CharacterBody3D::get_snap); + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &CharacterBody3D::set_snap); + ClassDB::bind_method(D_METHOD("get_up_direction"), &CharacterBody3D::get_up_direction); + ClassDB::bind_method(D_METHOD("set_up_direction", "up_direction"), &CharacterBody3D::set_up_direction); + + ClassDB::bind_method(D_METHOD("is_on_floor"), &CharacterBody3D::is_on_floor); + ClassDB::bind_method(D_METHOD("is_on_ceiling"), &CharacterBody3D::is_on_ceiling); + ClassDB::bind_method(D_METHOD("is_on_wall"), &CharacterBody3D::is_on_wall); + ClassDB::bind_method(D_METHOD("get_floor_normal"), &CharacterBody3D::get_floor_normal); + ClassDB::bind_method(D_METHOD("get_floor_velocity"), &CharacterBody3D::get_floor_velocity); + + ClassDB::bind_method(D_METHOD("get_slide_count"), &CharacterBody3D::get_slide_count); + ClassDB::bind_method(D_METHOD("get_slide_collision", "slide_idx"), &CharacterBody3D::_get_slide_collision); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stop_on_slope"), "set_stop_on_slope_enabled", "is_stop_on_slope_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "infinite_inertia"), "set_infinite_inertia_enabled", "is_infinite_inertia_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_slides"), "set_max_slides", "get_max_slides"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "floor_max_angle", PROPERTY_HINT_RANGE, "0,180,0.1,radians"), "set_floor_max_angle", "get_floor_max_angle"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "snap"), "set_snap", "get_snap"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_direction"), "set_up_direction", "get_up_direction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision/safe_margin", PROPERTY_HINT_RANGE, "0.001,256,0.001"), "set_safe_margin", "get_safe_margin"); +} +CharacterBody3D::CharacterBody3D() : + PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { +} + +CharacterBody3D::~CharacterBody3D() { for (int i = 0; i < slide_colliders.size(); i++) { if (slide_colliders[i].is_valid()) { slide_colliders.write[i]->owner = nullptr; @@ -1161,39 +1331,43 @@ KinematicBody3D::~KinematicBody3D() { /////////////////////////////////////// Vector3 KinematicCollision3D::get_position() const { - return collision.collision; + return result.collision_point; } Vector3 KinematicCollision3D::get_normal() const { - return collision.normal; + return result.collision_normal; } Vector3 KinematicCollision3D::get_travel() const { - return collision.travel; + return result.motion; } Vector3 KinematicCollision3D::get_remainder() const { - return collision.remainder; + return result.remainder; } Object *KinematicCollision3D::get_local_shape() const { if (!owner) { return nullptr; } - uint32_t ownerid = owner->shape_find_owner(collision.local_shape); + uint32_t ownerid = owner->shape_find_owner(result.collision_local_shape); return owner->shape_owner_get_owner(ownerid); } Object *KinematicCollision3D::get_collider() const { - if (collision.collider.is_valid()) { - return ObjectDB::get_instance(collision.collider); + if (result.collider_id.is_valid()) { + return ObjectDB::get_instance(result.collider_id); } return nullptr; } ObjectID KinematicCollision3D::get_collider_id() const { - return collision.collider; + return result.collider_id; +} + +RID KinematicCollision3D::get_collider_rid() const { + return result.collider; } Object *KinematicCollision3D::get_collider_shape() const { @@ -1201,7 +1375,7 @@ Object *KinematicCollision3D::get_collider_shape() const { if (collider) { CollisionObject3D *obj2d = Object::cast_to<CollisionObject3D>(collider); if (obj2d) { - uint32_t ownerid = obj2d->shape_find_owner(collision.collider_shape); + uint32_t ownerid = obj2d->shape_find_owner(result.collider_shape); return obj2d->shape_owner_get_owner(ownerid); } } @@ -1210,11 +1384,11 @@ Object *KinematicCollision3D::get_collider_shape() const { } int KinematicCollision3D::get_collider_shape_index() const { - return collision.collider_shape; + return result.collider_shape; } Vector3 KinematicCollision3D::get_collider_velocity() const { - return collision.collider_vel; + return result.collider_velocity; } Variant KinematicCollision3D::get_collider_metadata() const { @@ -1229,6 +1403,7 @@ void KinematicCollision3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_local_shape"), &KinematicCollision3D::get_local_shape); ClassDB::bind_method(D_METHOD("get_collider"), &KinematicCollision3D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_id"), &KinematicCollision3D::get_collider_id); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &KinematicCollision3D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider_shape"), &KinematicCollision3D::get_collider_shape); ClassDB::bind_method(D_METHOD("get_collider_shape_index"), &KinematicCollision3D::get_collider_shape_index); ClassDB::bind_method(D_METHOD("get_collider_velocity"), &KinematicCollision3D::get_collider_velocity); @@ -1241,18 +1416,13 @@ void KinematicCollision3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "local_shape"), "", "get_local_shape"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id"), "", "get_collider_id"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider_shape"), "", "get_collider_shape"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape_index"), "", "get_collider_shape_index"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity"); ADD_PROPERTY(PropertyInfo(Variant::NIL, "collider_metadata", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "", "get_collider_metadata"); } -KinematicCollision3D::KinematicCollision3D() { - collision.collider_shape = 0; - collision.local_shape = 0; - owner = nullptr; -} - /////////////////////////////////////// bool PhysicalBone3D::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) { @@ -1954,7 +2124,8 @@ void PhysicalBone3D::_notification(int p_what) { _reload_joint(); } break; - case NOTIFICATION_EXIT_TREE: + + case NOTIFICATION_EXIT_TREE: { if (parent_skeleton) { if (-1 != bone_id) { parent_skeleton->unbind_physical_bone_from_bone(bone_id); @@ -1964,12 +2135,13 @@ void PhysicalBone3D::_notification(int p_what) { } parent_skeleton = nullptr; PhysicsServer3D::get_singleton()->joint_clear(joint); - break; - case NOTIFICATION_TRANSFORM_CHANGED: + } break; + + case NOTIFICATION_TRANSFORM_CHANGED: { if (Engine::get_singleton()->is_editor_hint()) { update_offset(); } - break; + } break; } } @@ -1989,7 +2161,7 @@ void PhysicalBone3D::_direct_state_changed(Object *p_state) { state = (PhysicsDirectBodyState3D *)p_state; //trust it #endif - Transform global_transform(state->get_transform()); + Transform3D global_transform(state->get_transform()); set_ignore_transform_notification(true); set_global_transform(global_transform); @@ -2015,8 +2187,6 @@ void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone3D::get_joint_offset); ClassDB::bind_method(D_METHOD("set_joint_rotation", "euler"), &PhysicalBone3D::set_joint_rotation); ClassDB::bind_method(D_METHOD("get_joint_rotation"), &PhysicalBone3D::get_joint_rotation); - ClassDB::bind_method(D_METHOD("set_joint_rotation_degrees", "euler_degrees"), &PhysicalBone3D::set_joint_rotation_degrees); - ClassDB::bind_method(D_METHOD("get_joint_rotation_degrees"), &PhysicalBone3D::get_joint_rotation_degrees); ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone3D::set_body_offset); ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone3D::get_body_offset); @@ -2048,18 +2218,14 @@ void PhysicalBone3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &PhysicalBone3D::set_can_sleep); ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &PhysicalBone3D::is_able_to_sleep); - ClassDB::bind_method(D_METHOD("set_axis_lock", "axis", "lock"), &PhysicalBone3D::set_axis_lock); - ClassDB::bind_method(D_METHOD("get_axis_lock", "axis"), &PhysicalBone3D::get_axis_lock); - ADD_GROUP("Joint", "joint_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation_degrees", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_joint_rotation_degrees", "get_joint_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_NONE, "", 0), "set_joint_rotation", "get_joint_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "joint_offset"), "set_joint_offset", "get_joint_offset"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "joint_rotation", PROPERTY_HINT_RANGE, "-360,360,0.01,or_lesser,or_greater,radians"), "set_joint_rotation", "get_joint_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "body_offset"), "set_body_offset", "get_body_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass", PROPERTY_HINT_RANGE, "0.01,65535,0.01,exp"), "set_mass", "get_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale"); @@ -2067,14 +2233,6 @@ void PhysicalBone3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "can_sleep"), "set_can_sleep", "is_able_to_sleep"); - ADD_GROUP("Axis Lock", "axis_lock_"); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_linear_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_LINEAR_Z); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_x"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_X); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_y"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Y); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "axis_lock_angular_z"), "set_axis_lock", "get_axis_lock", PhysicsServer3D::BODY_AXIS_ANGULAR_Z); - BIND_ENUM_CONSTANT(JOINT_TYPE_NONE); BIND_ENUM_CONSTANT(JOINT_TYPE_PIN); BIND_ENUM_CONSTANT(JOINT_TYPE_CONE); @@ -2124,8 +2282,8 @@ void PhysicalBone3D::_reload_joint() { return; } - Transform joint_transf = get_global_transform() * joint_offset; - Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf; + Transform3D joint_transf = get_global_transform() * joint_offset; + Transform3D local_a = body_a->get_global_transform().affine_inverse() * joint_transf; local_a.orthonormalize(); switch (get_joint_type()) { @@ -2218,11 +2376,11 @@ void PhysicalBone3D::_set_gizmo_move_joint(bool p_move_joint) { } #ifdef TOOLS_ENABLED -Transform PhysicalBone3D::get_global_gizmo_transform() const { +Transform3D PhysicalBone3D::get_global_gizmo_transform() const { return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform(); } -Transform PhysicalBone3D::get_local_gizmo_transform() const { +Transform3D PhysicalBone3D::get_local_gizmo_transform() const { return gizmo_move_joint ? get_transform() * joint_offset : get_transform(); } #endif @@ -2278,13 +2436,13 @@ PhysicalBone3D::JointType PhysicalBone3D::get_joint_type() const { return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE; } -void PhysicalBone3D::set_joint_offset(const Transform &p_offset) { +void PhysicalBone3D::set_joint_offset(const Transform3D &p_offset) { joint_offset = p_offset; _update_joint_offset(); } -const Transform &PhysicalBone3D::get_joint_offset() const { +const Transform3D &PhysicalBone3D::get_joint_offset() const { return joint_offset; } @@ -2298,19 +2456,11 @@ Vector3 PhysicalBone3D::get_joint_rotation() const { return joint_offset.basis.get_rotation(); } -void PhysicalBone3D::set_joint_rotation_degrees(const Vector3 &p_euler_deg) { - set_joint_rotation(p_euler_deg * (Math_PI / 180.0)); -} - -Vector3 PhysicalBone3D::get_joint_rotation_degrees() const { - return get_joint_rotation() * (180.0 / Math_PI); -} - -const Transform &PhysicalBone3D::get_body_offset() const { +const Transform3D &PhysicalBone3D::get_body_offset() const { return body_offset; } -void PhysicalBone3D::set_body_offset(const Transform &p_offset) { +void PhysicalBone3D::set_body_offset(const Transform3D &p_offset) { body_offset = p_offset; body_offset_inverse = body_offset.affine_inverse(); @@ -2416,14 +2566,6 @@ bool PhysicalBone3D::is_able_to_sleep() const { return can_sleep; } -void PhysicalBone3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock) { - PhysicsServer3D::get_singleton()->body_set_axis_lock(get_rid(), p_axis, p_lock); -} - -bool PhysicalBone3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { - return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); -} - PhysicalBone3D::PhysicalBone3D() : PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { joint = PhysicsServer3D::get_singleton()->joint_create(); @@ -2463,7 +2605,7 @@ void PhysicalBone3D::update_bone_id() { void PhysicalBone3D::update_offset() { #ifdef TOOLS_ENABLED if (parent_skeleton) { - Transform bone_transform(parent_skeleton->get_global_transform()); + Transform3D bone_transform(parent_skeleton->get_global_transform()); if (-1 != bone_id) { bone_transform *= parent_skeleton->get_bone_global_pose(bone_id); } @@ -2483,7 +2625,7 @@ void PhysicalBone3D::_start_physics_simulation() { return; } reset_to_rest_position(); - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_RIGID); + set_body_mode(PhysicsServer3D::BODY_MODE_DYNAMIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), callable_mp(this, &PhysicalBone3D::_direct_state_changed)); @@ -2496,17 +2638,17 @@ void PhysicalBone3D::_stop_physics_simulation() { return; } if (parent_skeleton->get_animate_physical_bones()) { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_KINEMATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_KINEMATIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); } else { - PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), PhysicsServer3D::BODY_MODE_STATIC); + set_body_mode(PhysicsServer3D::BODY_MODE_STATIC); PhysicsServer3D::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer3D::get_singleton()->body_set_collision_mask(get_rid(), 0); } if (_internal_simulate_physics) { PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), Callable()); - parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform3D(), 0.0, false); set_as_top_level(false); _internal_simulate_physics = false; } diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 818ff97730..9d45ce3799 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -37,6 +37,8 @@ #include "servers/physics_server_3d.h" #include "skeleton_3d.h" +class KinematicCollision3D; + class PhysicsBody3D : public CollisionObject3D { GDCLASS(PhysicsBody3D, CollisionObject3D); @@ -44,7 +46,19 @@ protected: static void _bind_methods(); PhysicsBody3D(PhysicsServer3D::BodyMode p_mode); + Ref<KinematicCollision3D> motion_cache; + + uint16_t locked_axis = 0; + + Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false, real_t p_margin = 0.001); + public: + bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, PhysicsServer3D::MotionResult &r_result, real_t p_margin, bool p_exclude_raycast_shapes = true, bool p_test_only = false, bool p_cancel_sliding = true); + bool test_move(const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, const Ref<KinematicCollision3D> &r_collision = Ref<KinematicCollision3D>(), real_t p_margin = 0.001); + + void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); + bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; + virtual Vector3 get_linear_velocity() const; virtual Vector3 get_angular_velocity() const; virtual real_t get_inverse_mass() const; @@ -53,7 +67,7 @@ public: void add_collision_exception_with(Node *p_node); //must be physicsbody void remove_collision_exception_with(Node *p_node); - PhysicsBody3D(); + virtual ~PhysicsBody3D(); }; class StaticBody3D : public PhysicsBody3D { @@ -62,11 +76,19 @@ class StaticBody3D : public PhysicsBody3D { Vector3 constant_linear_velocity; Vector3 constant_angular_velocity; + Vector3 linear_velocity; + Vector3 angular_velocity; + Ref<PhysicsMaterial> physics_material_override; + bool kinematic_motion = false; + protected: + void _notification(int p_what); static void _bind_methods(); + void _direct_state_changed(Object *p_state); + public: void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); Ref<PhysicsMaterial> get_physics_material_override() const; @@ -77,11 +99,18 @@ public: Vector3 get_constant_linear_velocity() const; Vector3 get_constant_angular_velocity() const; + virtual Vector3 get_linear_velocity() const override; + virtual Vector3 get_angular_velocity() const override; + StaticBody3D(); - ~StaticBody3D(); private: void _reload_physics_characteristics(); + + void _update_kinematic_motion(); + + void set_kinematic_motion_enabled(bool p_enabled); + bool is_kinematic_motion_enabled() const; }; class RigidBody3D : public PhysicsBody3D { @@ -89,16 +118,16 @@ class RigidBody3D : public PhysicsBody3D { public: enum Mode { - MODE_RIGID, + MODE_DYNAMIC, MODE_STATIC, - MODE_CHARACTER, + MODE_DYNAMIC_LOCKED, MODE_KINEMATIC, }; protected: bool can_sleep = true; PhysicsDirectBodyState3D *state = nullptr; - Mode mode = MODE_RIGID; + Mode mode = MODE_DYNAMIC; real_t mass = 1.0; Ref<PhysicsMaterial> physics_material_override; @@ -212,9 +241,6 @@ public: void set_use_continuous_collision_detection(bool p_enable); bool is_using_continuous_collision_detection() const; - void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); - bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; - Array get_colliding_bodies() const; void add_central_force(const Vector3 &p_force); @@ -238,30 +264,20 @@ VARIANT_ENUM_CAST(RigidBody3D::Mode); class KinematicCollision3D; -class KinematicBody3D : public PhysicsBody3D { - GDCLASS(KinematicBody3D, PhysicsBody3D); - -public: - struct Collision { - Vector3 collision; - Vector3 normal; - Vector3 collider_vel; - ObjectID collider; - RID collider_rid; - int collider_shape = 0; - Variant collider_metadata; - Vector3 remainder; - Vector3 travel; - int local_shape = 0; - }; +class CharacterBody3D : public PhysicsBody3D { + GDCLASS(CharacterBody3D, PhysicsBody3D); private: - Vector3 linear_velocity; - Vector3 angular_velocity; + real_t margin = 0.001; - uint16_t locked_axis = 0; + bool stop_on_slope = false; + bool infinite_inertia = true; + int max_slides = 4; + real_t floor_max_angle = Math::deg2rad((real_t)45.0); + Vector3 snap; + Vector3 up_direction = Vector3(0.0, 1.0, 0.0); - real_t margin; + Vector3 linear_velocity; Vector3 floor_normal; Vector3 floor_velocity; @@ -269,38 +285,44 @@ private: bool on_floor = false; bool on_ceiling = false; bool on_wall = false; - Vector<Collision> colliders; + Vector<PhysicsServer3D::MotionResult> motion_results; Vector<Ref<KinematicCollision3D>> slide_colliders; - Ref<KinematicCollision3D> motion_cache; - - _FORCE_INLINE_ bool _ignores_mode(PhysicsServer3D::BodyMode) const; - Ref<KinematicCollision3D> _move(const Vector3 &p_motion, bool p_infinite_inertia = true, bool p_exclude_raycast_shapes = true, bool p_test_only = false); Ref<KinematicCollision3D> _get_slide_collision(int p_bounce); -protected: - void _notification(int p_what); - static void _bind_methods(); + bool separate_raycast_shapes(PhysicsServer3D::MotionResult &r_result); - virtual void _direct_state_changed(Object *p_state); + void set_safe_margin(real_t p_margin); + real_t get_safe_margin() const; -public: - virtual Vector3 get_linear_velocity() const override; - virtual Vector3 get_angular_velocity() const override; + bool is_stop_on_slope_enabled() const; + void set_stop_on_slope_enabled(bool p_enabled); - bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision, bool p_exclude_raycast_shapes = true, bool p_test_only = false); - bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia); + bool is_infinite_inertia_enabled() const; + void set_infinite_inertia_enabled(bool p_enabled); - bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision); + int get_max_slides() const; + void set_max_slides(int p_max_slides); - void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); - bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; + real_t get_floor_max_angle() const; + void set_floor_max_angle(real_t p_radians); - void set_safe_margin(real_t p_margin); - real_t get_safe_margin() const; + const Vector3 &get_snap() const; + void set_snap(const Vector3 &p_snap); + + const Vector3 &get_up_direction() const; + void set_up_direction(const Vector3 &p_up_direction); + +protected: + void _notification(int p_what); + static void _bind_methods(); + +public: + void move_and_slide(); + + virtual Vector3 get_linear_velocity() const override; + void set_linear_velocity(const Vector3 &p_velocity); - Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); - Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; @@ -308,18 +330,19 @@ public: Vector3 get_floor_velocity() const; int get_slide_count() const; - Collision get_slide_collision(int p_bounce) const; + PhysicsServer3D::MotionResult get_slide_collision(int p_bounce) const; - KinematicBody3D(); - ~KinematicBody3D(); + CharacterBody3D(); + ~CharacterBody3D(); }; -class KinematicCollision3D : public Reference { - GDCLASS(KinematicCollision3D, Reference); +class KinematicCollision3D : public RefCounted { + GDCLASS(KinematicCollision3D, RefCounted); - KinematicBody3D *owner; - friend class KinematicBody3D; - KinematicBody3D::Collision collision; + PhysicsBody3D *owner = nullptr; + friend class PhysicsBody3D; + friend class CharacterBody3D; + PhysicsServer3D::MotionResult result; protected: static void _bind_methods(); @@ -332,12 +355,11 @@ public: Object *get_local_shape() const; Object *get_collider() const; ObjectID get_collider_id() const; + RID get_collider_rid() const; Object *get_collider_shape() const; int get_collider_shape_index() const; Vector3 get_collider_velocity() const; Variant get_collider_metadata() const; - - KinematicCollision3D(); }; class PhysicalBone3D : public PhysicsBody3D { @@ -467,12 +489,12 @@ private: #endif JointData *joint_data = nullptr; - Transform joint_offset; + Transform3D joint_offset; RID joint; Skeleton3D *parent_skeleton = nullptr; - Transform body_offset; - Transform body_offset_inverse; + Transform3D body_offset; + Transform3D body_offset_inverse; bool simulate_physics = false; bool _internal_simulate_physics = false; int bone_id = -1; @@ -508,8 +530,8 @@ public: public: #ifdef TOOLS_ENABLED - virtual Transform get_global_gizmo_transform() const override; - virtual Transform get_local_gizmo_transform() const override; + virtual Transform3D get_global_gizmo_transform() const override; + virtual Transform3D get_local_gizmo_transform() const override; #endif const JointData *get_joint_data() const; @@ -520,17 +542,14 @@ public: void set_joint_type(JointType p_joint_type); JointType get_joint_type() const; - void set_joint_offset(const Transform &p_offset); - const Transform &get_joint_offset() const; + void set_joint_offset(const Transform3D &p_offset); + const Transform3D &get_joint_offset() const; void set_joint_rotation(const Vector3 &p_euler_rad); Vector3 get_joint_rotation() const; - void set_joint_rotation_degrees(const Vector3 &p_euler_deg); - Vector3 get_joint_rotation_degrees() const; - - void set_body_offset(const Transform &p_offset); - const Transform &get_body_offset() const; + void set_body_offset(const Transform3D &p_offset); + const Transform3D &get_body_offset() const; void set_simulate_physics(bool p_simulate); bool get_simulate_physics(); @@ -560,9 +579,6 @@ public: void set_can_sleep(bool p_active); bool is_able_to_sleep() const; - void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); - bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; - void apply_central_impulse(const Vector3 &p_impulse); void apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position = Vector3()); diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp index 3d58d1c10e..01f10c171f 100644 --- a/scene/3d/physics_joint_3d.cpp +++ b/scene/3d/physics_joint_3d.cpp @@ -372,15 +372,15 @@ bool HingeJoint3D::get_flag(Flag p_flag) const { } void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform gt = get_global_transform(); - Transform ainv = body_a->get_global_transform().affine_inverse(); + Transform3D gt = get_global_transform(); + Transform3D ainv = body_a->get_global_transform().affine_inverse(); - Transform local_a = ainv * gt; + Transform3D local_a = ainv * gt; local_a.orthonormalize(); - Transform local_b = gt; + Transform3D local_b = gt; if (body_b) { - Transform binv = body_b->get_global_transform().affine_inverse(); + Transform3D binv = body_b->get_global_transform().affine_inverse(); local_b = binv * gt; } @@ -506,15 +506,15 @@ real_t SliderJoint3D::get_param(Param p_param) const { } void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform gt = get_global_transform(); - Transform ainv = body_a->get_global_transform().affine_inverse(); + Transform3D gt = get_global_transform(); + Transform3D ainv = body_a->get_global_transform().affine_inverse(); - Transform local_a = ainv * gt; + Transform3D local_a = ainv * gt; local_a.orthonormalize(); - Transform local_b = gt; + Transform3D local_b = gt; if (body_b) { - Transform binv = body_b->get_global_transform().affine_inverse(); + Transform3D binv = body_b->get_global_transform().affine_inverse(); local_b = binv * gt; } @@ -611,18 +611,18 @@ real_t ConeTwistJoint3D::get_param(Param p_param) const { } void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform gt = get_global_transform(); + Transform3D gt = get_global_transform(); //Vector3 cone_twistpos = gt.origin; //Vector3 cone_twistdir = gt.basis.get_axis(2); - Transform ainv = body_a->get_global_transform().affine_inverse(); + Transform3D ainv = body_a->get_global_transform().affine_inverse(); - Transform local_a = ainv * gt; + Transform3D local_a = ainv * gt; local_a.orthonormalize(); - Transform local_b = gt; + Transform3D local_b = gt; if (body_b) { - Transform binv = body_b->get_global_transform().affine_inverse(); + Transform3D binv = body_b->get_global_transform().affine_inverse(); local_b = binv * gt; } @@ -936,18 +936,18 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const { } void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { - Transform gt = get_global_transform(); + Transform3D gt = get_global_transform(); //Vector3 cone_twistpos = gt.origin; //Vector3 cone_twistdir = gt.basis.get_axis(2); - Transform ainv = body_a->get_global_transform().affine_inverse(); + Transform3D ainv = body_a->get_global_transform().affine_inverse(); - Transform local_a = ainv * gt; + Transform3D local_a = ainv * gt; local_a.orthonormalize(); - Transform local_b = gt; + Transform3D local_b = gt; if (body_b) { - Transform binv = body_b->get_global_transform().affine_inverse(); + Transform3D binv = body_b->get_global_transform().affine_inverse(); local_b = binv * gt; } diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index 475f8c07fd..dfab3d4a17 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -205,7 +205,7 @@ void RayCast3D::_update_raycast_state() { PhysicsDirectSpaceState3D *dss = PhysicsServer3D::get_singleton()->space_get_direct_state(w3d->get_space()); ERR_FAIL_COND(!dss); - Transform gt = get_global_transform(); + Transform3D gt = get_global_transform(); Vector3 to = target_position; if (to == Vector3()) { @@ -419,6 +419,8 @@ void RayCast3D::_update_debug_shape_material(bool p_check_collision) { debug_material = material; material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + // Use double-sided rendering so that the RayCast can be seen if the camera is inside. + material->set_cull_mode(BaseMaterial3D::CULL_DISABLED); material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA); } diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index 7762156b4a..c289fc4fd7 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -232,7 +232,7 @@ void ReflectionProbe::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once (Fast),Always (Slow)"), "set_update_mode", "get_update_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1,or_greater,exp"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset"), "set_origin_offset", "get_origin_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled"); diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index 15c2da3ae0..4bf20c89c5 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -55,7 +55,7 @@ private: RID probe; float intensity = 1.0; float max_distance = 0.0; - Vector3 extents = Vector3(1, 1, 1); + Vector3 extents = Vector3(10, 10, 10); Vector3 origin_offset = Vector3(0, 0, 0); bool box_projection = false; bool enable_shadows = false; diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 29a407905b..d5fb1fa6ab 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -34,7 +34,7 @@ void RemoteTransform3D::_update_cache() { cache = ObjectID(); if (has_node(remote_node)) { Node *node = get_node(remote_node); - if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) { + if (!node || this == node || node->is_ancestor_of(this) || this->is_ancestor_of(node)) { return; } @@ -65,7 +65,7 @@ void RemoteTransform3D::_update_remote() { if (update_remote_position && update_remote_rotation && update_remote_scale) { n->set_global_transform(get_global_transform()); } else { - Transform our_trans = get_global_transform(); + Transform3D our_trans = get_global_transform(); if (update_remote_rotation) { n->set_rotation(our_trans.basis.get_rotation()); @@ -76,7 +76,7 @@ void RemoteTransform3D::_update_remote() { } if (update_remote_position) { - Transform n_trans = n->get_global_transform(); + Transform3D n_trans = n->get_global_transform(); n_trans.set_origin(our_trans.get_origin()); n->set_global_transform(n_trans); @@ -87,7 +87,7 @@ void RemoteTransform3D::_update_remote() { if (update_remote_position && update_remote_rotation && update_remote_scale) { n->set_transform(get_transform()); } else { - Transform our_trans = get_transform(); + Transform3D our_trans = get_transform(); if (update_remote_rotation) { n->set_rotation(our_trans.basis.get_rotation()); @@ -98,7 +98,7 @@ void RemoteTransform3D::_update_remote() { } if (update_remote_position) { - Transform n_trans = n->get_transform(); + Transform3D n_trans = n->get_transform(); n_trans.set_origin(our_trans.get_origin()); n->set_transform(n_trans); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 82927df5f1..fa3b16935c 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -135,9 +135,9 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const { String prep = "bones/" + itos(i) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, prep + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } } @@ -211,7 +211,7 @@ void Skeleton3D::_notification(int p_what) { if (b.disable_rest) { if (b.enabled) { - Transform pose = b.pose; + Transform3D pose = b.pose; if (b.custom_pose_enable) { pose = b.custom_pose * pose; } @@ -227,14 +227,14 @@ void Skeleton3D::_notification(int p_what) { b.pose_global = bonesptr[b.parent].pose_global; b.pose_global_no_override = bonesptr[b.parent].pose_global; } else { - b.pose_global = Transform(); - b.pose_global_no_override = Transform(); + b.pose_global = Transform3D(); + b.pose_global_no_override = Transform3D(); } } } else { if (b.enabled) { - Transform pose = b.pose; + Transform3D pose = b.pose; if (b.custom_pose_enable) { pose = b.custom_pose * pose; } @@ -337,7 +337,6 @@ void Skeleton3D::_notification(int p_what) { } break; -#ifndef _3D_DISABLED case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { // This is active only if the skeleton animates the physical bones // and the state of the bone is not active. @@ -356,7 +355,6 @@ void Skeleton3D::_notification(int p_what) { set_physics_process_internal(true); } } break; -#endif } } @@ -368,7 +366,7 @@ void Skeleton3D::clear_bones_global_pose_override() { _make_dirty(); } -void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) { +void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, float p_amount, bool p_persistent) { ERR_FAIL_INDEX(p_bone, bones.size()); bones.write[p_bone].global_pose_override_amount = p_amount; bones.write[p_bone].global_pose_override = p_pose; @@ -376,16 +374,16 @@ void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform &p_po _make_dirty(); } -Transform Skeleton3D::get_bone_global_pose(int p_bone) const { - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); +Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const { + ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D()); if (dirty) { const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); } return bones[p_bone].pose_global; } -Transform Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); +Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { + ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D()); if (dirty) { const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); } @@ -496,15 +494,14 @@ int Skeleton3D::get_bone_parent(int p_bone) const { return bones[p_bone].parent; } -void Skeleton3D::set_bone_rest(int p_bone, const Transform &p_rest) { +void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) { ERR_FAIL_INDEX(p_bone, bones.size()); bones.write[p_bone].rest = p_rest; _make_dirty(); } - -Transform Skeleton3D::get_bone_rest(int p_bone) const { - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); +Transform3D Skeleton3D::get_bone_rest(int p_bone) const { + ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D()); return bones[p_bone].rest; } @@ -563,7 +560,7 @@ void Skeleton3D::clear_bones() { // posing api -void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) { +void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) { ERR_FAIL_INDEX(p_bone, bones.size()); bones.write[p_bone].pose = p_pose; @@ -571,24 +568,23 @@ void Skeleton3D::set_bone_pose(int p_bone, const Transform &p_pose) { _make_dirty(); } } - -Transform Skeleton3D::get_bone_pose(int p_bone) const { - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); +Transform3D Skeleton3D::get_bone_pose(int p_bone) const { + ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D()); return bones[p_bone].pose; } -void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) { +void Skeleton3D::set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose) { ERR_FAIL_INDEX(p_bone, bones.size()); //ERR_FAIL_COND( !is_inside_scene() ); - bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform()); + bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform3D()); bones.write[p_bone].custom_pose = p_custom_pose; _make_dirty(); } -Transform Skeleton3D::get_bone_custom_pose(int p_bone) const { - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); +Transform3D Skeleton3D::get_bone_custom_pose(int p_bone) const { + ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform3D()); return bones[p_bone].custom_pose; } @@ -623,8 +619,6 @@ void Skeleton3D::localize_rests() { } } -#ifndef _3D_DISABLED - void Skeleton3D::set_animate_physical_bones(bool p_animate) { animate_physical_bones = p_animate; @@ -785,8 +779,6 @@ void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) { _physical_bones_add_remove_collision_exception(false, this, p_exception); } -#endif // _3D_DISABLED - void Skeleton3D::_skin_changed() { _make_dirty(); } @@ -805,7 +797,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { //when skeletons did not support skins. It is also used by gizmo //to display the skeleton. - skin.instance(); + skin.instantiate(); skin->set_bind_count(bones.size()); _update_process_order(); //just in case @@ -834,7 +826,7 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>()); Ref<SkinReference> skin_ref; - skin_ref.instance(); + skin_ref.instantiate(); skin_ref->skeleton_node = this; skin_ref->bind_count = 0; @@ -852,11 +844,11 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { } // helper functions -Transform Skeleton3D::bone_transform_to_world_transform(Transform p_bone_transform) { +Transform3D Skeleton3D::bone_transform_to_world_transform(Transform3D p_bone_transform) { return get_global_transform() * p_bone_transform; } -Transform Skeleton3D::world_transform_to_bone_transform(Transform p_world_transform) { +Transform3D Skeleton3D::world_transform_to_bone_transform(Transform3D p_world_transform) { return get_global_transform().affine_inverse() * p_world_transform; } @@ -900,8 +892,6 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("bone_transform_to_world_transform", "bone_transform"), &Skeleton3D::bone_transform_to_world_transform); ClassDB::bind_method(D_METHOD("world_transform_to_bone_transform", "world_transform"), &Skeleton3D::world_transform_to_bone_transform); -#ifndef _3D_DISABLED - ClassDB::bind_method(D_METHOD("set_animate_physical_bones"), &Skeleton3D::set_animate_physical_bones); ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones); @@ -911,7 +901,6 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones"); -#endif // _3D_DISABLED #ifdef TOOLS_ENABLED ADD_SIGNAL(MethodInfo("pose_updated")); diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index 299a4b6a02..2f6e416c8c 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -35,16 +35,13 @@ #include "scene/3d/node_3d.h" #include "scene/resources/skin.h" -#ifndef _3D_DISABLED typedef int BoneId; class PhysicalBone3D; -#endif // _3D_DISABLED - class Skeleton3D; -class SkinReference : public Reference { - GDCLASS(SkinReference, Reference) +class SkinReference : public RefCounted { + GDCLASS(SkinReference, RefCounted) friend class Skeleton3D; Skeleton3D *skeleton_node; @@ -79,23 +76,21 @@ private: int sort_index = 0; //used for re-sorting process order bool disable_rest = false; - Transform rest; + Transform3D rest; - Transform pose; - Transform pose_global; - Transform pose_global_no_override; + Transform3D pose; + Transform3D pose_global; + Transform3D pose_global_no_override; bool custom_pose_enable = false; - Transform custom_pose; + Transform3D custom_pose; float global_pose_override_amount = 0.0; bool global_pose_override_reset = false; - Transform global_pose_override; + Transform3D global_pose_override; -#ifndef _3D_DISABLED PhysicalBone3D *physical_bone = nullptr; PhysicalBone3D *cache_parent_physical_bone = nullptr; -#endif // _3D_DISABLED List<ObjectID> nodes_bound; }; @@ -146,13 +141,13 @@ public: int get_bone_count() const; - void set_bone_rest(int p_bone, const Transform &p_rest); - Transform get_bone_rest(int p_bone) const; - Transform get_bone_global_pose(int p_bone) const; - Transform get_bone_global_pose_no_override(int p_bone) const; + void set_bone_rest(int p_bone, const Transform3D &p_rest); + Transform3D get_bone_rest(int p_bone) const; + Transform3D get_bone_global_pose(int p_bone) const; + Transform3D get_bone_global_pose_no_override(int p_bone) const; void clear_bones_global_pose_override(); - void set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent = false); + void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, float p_amount, bool p_persistent = false); void set_bone_enabled(int p_bone, bool p_enabled); bool is_bone_enabled(int p_bone) const; @@ -165,11 +160,11 @@ public: // posing api - void set_bone_pose(int p_bone, const Transform &p_pose); - Transform get_bone_pose(int p_bone) const; + void set_bone_pose(int p_bone, const Transform3D &p_pose); + Transform3D get_bone_pose(int p_bone) const; - void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose); - Transform get_bone_custom_pose(int p_bone) const; + void set_bone_custom_pose(int p_bone, const Transform3D &p_custom_pose); + Transform3D get_bone_custom_pose(int p_bone) const; void localize_rests(); // used for loaders and tools int get_process_order(int p_idx); @@ -178,10 +173,9 @@ public: Ref<SkinReference> register_skin(const Ref<Skin> &p_skin); // Helper functions - Transform bone_transform_to_world_transform(Transform p_transform); - Transform world_transform_to_bone_transform(Transform p_transform); + Transform3D bone_transform_to_world_transform(Transform3D p_transform); + Transform3D world_transform_to_bone_transform(Transform3D p_transform); -#ifndef _3D_DISABLED // Physical bone API void set_animate_physical_bones(bool p_animate); @@ -203,7 +197,6 @@ public: void physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones); void physical_bones_add_collision_exception(RID p_exception); void physical_bones_remove_collision_exception(RID p_exception); -#endif // _3D_DISABLED public: Skeleton3D(); diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 294e313300..1005d51e63 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -212,7 +212,7 @@ void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_ } } -FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform) { +FabrikInverseKinematic::Task *FabrikInverseKinematic::create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform3D &goal_transform) { FabrikInverseKinematic::EndEffector ee; ee.tip_bone = tip_bone; @@ -236,17 +236,17 @@ void FabrikInverseKinematic::free_task(Task *p_task) { } } -void FabrikInverseKinematic::set_goal(Task *p_task, const Transform &p_goal) { +void FabrikInverseKinematic::set_goal(Task *p_task, const Transform3D &p_goal) { p_task->goal_global_transform = p_goal; } -void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta) { +void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta) { if (blending_delta >= 0.99f) { // Update the end_effector (local transform) without blending p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform; } else { // End effector in local transform - const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose_no_override(p_task->end_effectors[0].tip_bone)); + const Transform3D end_effector_pose(p_task->skeleton->get_bone_global_pose_no_override(p_task->end_effectors[0].tip_bone)); // Update the end_effector (local transform) by blending with current pose p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta); @@ -273,7 +273,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove // Update the initial root transform so its synced with any animation changes _update_chain(p_task->skeleton, &p_task->chain.chain_root); - p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform(), 0.0, false); + p_task->skeleton->set_bone_global_pose_override(p_task->chain.chain_root.bone, Transform3D(), 0.0, false); Vector3 origin_pos = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone).origin; make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta); @@ -287,7 +287,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove // Assign new bone position. ChainItem *ci(&p_task->chain.chain_root); while (ci) { - Transform new_bone_pose(ci->initial_transform); + Transform3D new_bone_pose(ci->initial_transform); new_bone_pose.origin = ci->current_pos; if (!ci->children.is_empty()) { @@ -397,7 +397,7 @@ void SkeletonIK3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "root_bone"), "set_root_bone", "get_root_bone"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "tip_bone"), "set_tip_bone", "get_tip_bone"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "interpolation", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_interpolation", "get_interpolation"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "target"), "set_target_transform", "get_target_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "target"), "set_target_transform", "get_target_transform"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_tip_basis"), "set_override_tip_basis", "is_override_tip_basis"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_magnet"), "set_use_magnet", "is_using_magnet"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "magnet"), "set_magnet_position", "get_magnet_position"); @@ -461,12 +461,12 @@ real_t SkeletonIK3D::get_interpolation() const { return interpolation; } -void SkeletonIK3D::set_target_transform(const Transform &p_target) { +void SkeletonIK3D::set_target_transform(const Transform3D &p_target) { target = p_target; reload_goal(); } -const Transform &SkeletonIK3D::get_target_transform() const { +const Transform3D &SkeletonIK3D::get_target_transform() const { return target; } @@ -537,7 +537,7 @@ void SkeletonIK3D::stop() { } } -Transform SkeletonIK3D::_get_target_transform() { +Transform3D SkeletonIK3D::_get_target_transform() { if (!target_node_override && !target_node_path_override.is_empty()) { target_node_override = Object::cast_to<Node3D>(get_node(target_node_path_override)); } diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h index 9b5ae240f6..81dfe675c3 100644 --- a/scene/3d/skeleton_ik_3d.h +++ b/scene/3d/skeleton_ik_3d.h @@ -37,13 +37,13 @@ * @author AndreaCatania */ -#include "core/math/transform.h" +#include "core/math/transform_3d.h" #include "scene/3d/skeleton_3d.h" class FabrikInverseKinematic { struct EndEffector { BoneId tip_bone; - Transform goal_transform; + Transform3D goal_transform; }; struct ChainItem { @@ -55,7 +55,7 @@ class FabrikInverseKinematic { real_t length = 0.0; /// Positions relative to root bone - Transform initial_transform; + Transform3D initial_transform; Vector3 current_pos; // Direction from this bone to child Vector3 current_ori; @@ -97,7 +97,7 @@ public: BoneId root_bone = -1; Vector<EndEffector> end_effectors; - Transform goal_global_transform; + Transform3D goal_global_transform; Task() {} }; @@ -112,11 +112,11 @@ private: static void solve_simple_forwards(Chain &r_chain, bool p_solve_magnet, Vector3 p_origin_pos); public: - static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform &goal_transform); + static Task *create_simple_task(Skeleton3D *p_sk, BoneId root_bone, BoneId tip_bone, const Transform3D &goal_transform); static void free_task(Task *p_task); // The goal of chain should be always in local space - static void set_goal(Task *p_task, const Transform &p_goal); - static void make_goal(Task *p_task, const Transform &p_inverse_transf, real_t blending_delta); + static void set_goal(Task *p_task, const Transform3D &p_goal); + static void make_goal(Task *p_task, const Transform3D &p_inverse_transf, real_t blending_delta); static void solve(Task *p_task, real_t blending_delta, bool override_tip_basis, bool p_use_magnet, const Vector3 &p_magnet_position); static void _update_chain(const Skeleton3D *p_skeleton, ChainItem *p_chain_item); @@ -128,7 +128,7 @@ class SkeletonIK3D : public Node { StringName root_bone; StringName tip_bone; real_t interpolation = 1.0; - Transform target; + Transform3D target; NodePath target_node_path_override; bool override_tip_basis = true; bool use_magnet = false; @@ -161,8 +161,8 @@ public: void set_interpolation(real_t p_interpolation); real_t get_interpolation() const; - void set_target_transform(const Transform &p_target); - const Transform &get_target_transform() const; + void set_target_transform(const Transform3D &p_target); + const Transform3D &get_target_transform() const; void set_target_node(const NodePath &p_node); NodePath get_target_node(); @@ -190,7 +190,7 @@ public: void stop(); private: - Transform _get_target_transform(); + Transform3D _get_target_transform(); void reload_chain(); void reload_goal(); void _solve_chain(); diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index dc4deb0570..efd8a2b50c 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -81,7 +81,7 @@ void SoftBodyRenderingServerHandler::close() { } void SoftBodyRenderingServerHandler::commit_changes() { - RS::get_singleton()->mesh_surface_update_region(mesh, surface, 0, buffer); + RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer); } void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) { @@ -266,12 +266,13 @@ void SoftBody3D::_notification(int p_what) { PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space); prepare_physics_server(); } break; + case NOTIFICATION_READY: { if (!parent_collision_ignore.is_empty()) { add_collision_exception_with(get_node(parent_collision_ignore)); } - } break; + case NOTIFICATION_TRANSFORM_CHANGED: { if (Engine::get_singleton()->is_editor_hint()) { _reset_points_offsets(); @@ -283,29 +284,38 @@ void SoftBody3D::_notification(int p_what) { set_notify_transform(false); // Required to be top level with Transform at center of world in order to modify RenderingServer only to support custom Transform set_as_top_level(true); - set_transform(Transform()); + set_transform(Transform3D()); set_notify_transform(true); - } break; + case NOTIFICATION_VISIBILITY_CHANGED: { _update_pickable(); - } break; + case NOTIFICATION_EXIT_WORLD: { PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID()); - } break; - } -#ifdef TOOLS_ENABLED + case NOTIFICATION_DISABLED: { + if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } + } break; - if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) { - if (Engine::get_singleton()->is_editor_hint()) { - update_configuration_warnings(); - } - } + case NOTIFICATION_ENABLED: { + if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } + } break; +#ifdef TOOLS_ENABLED + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (Engine::get_singleton()->is_editor_hint()) { + update_configuration_warnings(); + } + } break; #endif + } } void SoftBody3D::_bind_methods() { @@ -326,6 +336,9 @@ void SoftBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore); ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore); + ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftBody3D::set_disable_mode); + ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftBody3D::get_disable_mode); + ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions); ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with); ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with); @@ -364,6 +377,11 @@ void SoftBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable"); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,KeepActive"), "set_disable_mode", "get_disable_mode"); + + BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE); + BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE); } TypedArray<String> SoftBody3D::get_configuration_warnings() const { @@ -373,7 +391,7 @@ TypedArray<String> SoftBody3D::get_configuration_warnings() const { warnings.push_back(TTR("This body will be ignored until you set a mesh.")); } - Transform t = get_transform(); + Transform3D t = get_transform(); if ((ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) { warnings.push_back(TTR("Size changes to SoftBody3D will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.")); } @@ -408,7 +426,7 @@ void SoftBody3D::_draw_soft_mesh() { /// Necessary in order to render the mesh correctly (Soft body nodes are in global space) simulation_started = true; call_deferred("set_as_top_level", true); - call_deferred("set_transform", Transform()); + call_deferred("set_transform", Transform3D()); } _update_physics_server(); @@ -421,6 +439,7 @@ void SoftBody3D::_draw_soft_mesh() { } void SoftBody3D::prepare_physics_server() { +#ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { if (get_mesh().is_valid()) { PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); @@ -430,8 +449,9 @@ void SoftBody3D::prepare_physics_server() { return; } +#endif - if (get_mesh().is_valid()) { + if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) { become_mesh_owner(); PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh)); @@ -465,7 +485,7 @@ void SoftBody3D::become_mesh_owner() { surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; Ref<ArrayMesh> soft_mesh; - soft_mesh.instance(); + soft_mesh.instantiate(); soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format); soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); @@ -527,6 +547,28 @@ bool SoftBody3D::get_collision_layer_bit(int p_bit) const { return get_collision_layer() & (1 << p_bit); } +void SoftBody3D::set_disable_mode(DisableMode p_mode) { + if (disable_mode == p_mode) { + return; + } + + bool inside_tree = is_inside_tree(); + + if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } + + disable_mode = p_mode; + + if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) { + prepare_physics_server(); + } +} + +SoftBody3D::DisableMode SoftBody3D::get_disable_mode() const { + return disable_mode; +} + void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) { parent_collision_ignore = p_parent_collision_ignore; } diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index 0d0d39d48f..81aa0c10c6 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -67,6 +67,11 @@ class SoftBody3D : public MeshInstance3D { GDCLASS(SoftBody3D, MeshInstance3D); public: + enum DisableMode { + DISABLE_MODE_REMOVE, + DISABLE_MODE_KEEP_ACTIVE, + }; + struct PinnedPoint { int point_index = -1; NodePath spatial_attachment_path; @@ -83,6 +88,8 @@ private: RID physics_rid; + DisableMode disable_mode = DISABLE_MODE_REMOVE; + bool mesh_owner = false; uint32_t collision_mask = 1; uint32_t collision_layer = 1; @@ -137,6 +144,9 @@ public: void set_collision_layer_bit(int p_bit, bool p_value); bool get_collision_layer_bit(int p_bit) const; + void set_disable_mode(DisableMode p_mode); + DisableMode get_disable_mode() const; + void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore); const NodePath &get_parent_collision_ignore() const; @@ -192,4 +202,6 @@ private: int _has_pinned_point(int p_point_index) const; }; +VARIANT_ENUM_CAST(SoftBody3D::DisableMode); + #endif // SOFT_PHYSICS_BODY_H diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp index 9518b47696..1911e14d54 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/spring_arm_3d.cpp @@ -153,7 +153,7 @@ void SpringArm3D::process_spring() { } current_spring_length = spring_length * motion_delta; - Transform childs_transform; + Transform3D childs_transform; childs_transform.origin = get_global_transform().origin + cast_direction * (spring_length * motion_delta); for (int i = get_child_count() - 1; 0 <= i; --i) { diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index be474e82e0..13f8002721 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -164,6 +164,8 @@ void SpriteBase3D::_im_update() { _draw(); pending_update = false; + + //texture->draw_rect_region(ci,dst_rect,src_rect,modulate); } void SpriteBase3D::_queue_update() { @@ -204,6 +206,7 @@ Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const { float pixel_size = get_pixel_size(); Vector2 vertices[4] = { + (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, (final_rect.position + final_rect.size) * pixel_size, (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, @@ -313,6 +316,9 @@ void SpriteBase3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect); ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh); + ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update); + ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h"); @@ -343,21 +349,89 @@ SpriteBase3D::SpriteBase3D() { flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED; } - immediate = RenderingServer::get_singleton()->immediate_create(); - set_base(immediate); + material = RenderingServer::get_singleton()->material_create(); + // Set defaults for material, names need to match up those in StandardMaterial3D + RS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1)); + RS::get_singleton()->material_set_param(material, "specular", 0.5); + RS::get_singleton()->material_set_param(material, "metallic", 0.0); + RS::get_singleton()->material_set_param(material, "roughness", 1.0); + RS::get_singleton()->material_set_param(material, "uv1_offset", Vector3(0, 0, 0)); + RS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1)); + RS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0)); + RS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1)); + RS::get_singleton()->material_set_param(material, "alpha_scissor_threshold", 0.98); + + mesh = RenderingServer::get_singleton()->mesh_create(); + + PackedVector3Array mesh_vertices; + PackedVector3Array mesh_normals; + PackedFloat32Array mesh_tangents; + PackedColorArray mesh_colors; + PackedVector2Array mesh_uvs; + PackedInt32Array indices; + + mesh_vertices.resize(4); + mesh_normals.resize(4); + mesh_tangents.resize(16); + mesh_colors.resize(4); + mesh_uvs.resize(4); + + // create basic mesh and store format information + for (int i = 0; i < 4; i++) { + mesh_normals.write[i] = Vector3(0.0, 0.0, 0.0); + mesh_tangents.write[i * 4 + 0] = 0.0; + mesh_tangents.write[i * 4 + 1] = 0.0; + mesh_tangents.write[i * 4 + 2] = 0.0; + mesh_tangents.write[i * 4 + 3] = 0.0; + mesh_colors.write[i] = Color(1.0, 1.0, 1.0, 1.0); + mesh_uvs.write[i] = Vector2(0.0, 0.0); + mesh_vertices.write[i] = Vector3(0.0, 0.0, 0.0); + } + + indices.resize(6); + indices.write[0] = 0; + indices.write[1] = 1; + indices.write[2] = 2; + indices.write[3] = 0; + indices.write[4] = 2; + indices.write[5] = 3; + + Array mesh_array; + mesh_array.resize(RS::ARRAY_MAX); + mesh_array[RS::ARRAY_VERTEX] = mesh_vertices; + mesh_array[RS::ARRAY_NORMAL] = mesh_normals; + mesh_array[RS::ARRAY_TANGENT] = mesh_tangents; + mesh_array[RS::ARRAY_COLOR] = mesh_colors; + mesh_array[RS::ARRAY_TEX_UV] = mesh_uvs; + mesh_array[RS::ARRAY_INDEX] = indices; + + RS::SurfaceData sd; + RS::get_singleton()->mesh_create_surface_data_from_arrays(&sd, RS::PRIMITIVE_TRIANGLES, mesh_array); + + mesh_surface_format = sd.format; + vertex_buffer = sd.vertex_data; + attribute_buffer = sd.attribute_data; + + sd.material = material; + + RS::get_singleton()->mesh_surface_make_offsets_from_format(sd.format, sd.vertex_count, sd.index_count, mesh_surface_offsets, vertex_stride, attrib_stride, skin_stride); + RS::get_singleton()->mesh_add_surface(mesh, sd); + set_base(mesh); } SpriteBase3D::~SpriteBase3D() { - RenderingServer::get_singleton()->free(immediate); + RenderingServer::get_singleton()->free(mesh); + RenderingServer::get_singleton()->free(material); } /////////////////////////////////////////// void Sprite3D::_draw() { - RID immediate = get_immediate(); - - RS::get_singleton()->immediate_clear(immediate); + if (get_base() != get_mesh()) { + set_base(get_mesh()); + } if (!texture.is_valid()) { + set_base(RID()); return; } Vector2 tsize = texture->get_size(); @@ -366,7 +440,7 @@ void Sprite3D::_draw() { } Rect2 base_rect; - if (region_enabled) { + if (region) { base_rect = region_rect; } else { base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); @@ -399,6 +473,7 @@ void Sprite3D::_draw() { float pixel_size = get_pixel_size(); Vector2 vertices[4] = { + (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, (final_rect.position + final_rect.size) * pixel_size, (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, @@ -426,6 +501,7 @@ void Sprite3D::_draw() { SWAP(uvs[0], uvs[1]); SWAP(uvs[2], uvs[3]); } + if (is_flipped_v()) { SWAP(uvs[0], uvs[3]); SWAP(uvs[1], uvs[2]); @@ -442,11 +518,6 @@ void Sprite3D::_draw() { tangent = Plane(1, 0, 0, 1); } - RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y); - RS::get_singleton()->immediate_set_material(immediate, mat); - - RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_TRIANGLES, texture->get_rid()); - int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); @@ -466,31 +537,80 @@ void Sprite3D::_draw() { AABB aabb; - for (int i = 0; i < 6; i++) { - static const int index[6] = { 0, 1, 2, 0, 2, 3 }; + // Everything except position and UV is compressed + uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); + uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); + + uint32_t v_normal; + { + Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + + v_normal = value; + } + uint32_t v_tangent; + { + Plane t = tangent; + uint32_t value = 0; + value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + if (t.d > 0) { + value |= 3 << 30; + } + v_tangent = value; + } - RS::get_singleton()->immediate_normal(immediate, normal); - RS::get_singleton()->immediate_tangent(immediate, tangent); - RS::get_singleton()->immediate_color(immediate, color); - RS::get_singleton()->immediate_uv(immediate, uvs[index[i]]); + uint8_t v_color[4] = { + uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0)) + }; + for (int i = 0; i < 4; i++) { Vector3 vtx; - vtx[x_axis] = vertices[index[i]][0]; - vtx[y_axis] = vertices[index[i]][1]; - RS::get_singleton()->immediate_vertex(immediate, vtx); + vtx[x_axis] = vertices[i][0]; + vtx[y_axis] = vertices[i][1]; if (i == 0) { aabb.position = vtx; aabb.size = Vector3(); } else { aabb.expand_to(vtx); } + + float v_uv[2] = { uvs[i].x, uvs[i].y }; + memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8); + + float v_vertex[3] = { vtx.x, vtx.y, vtx.z }; + + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3); + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); + memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4); } + + RID mesh = get_mesh(); + RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer); + RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer); + + RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb); set_aabb(aabb); - RS::get_singleton()->immediate_end(immediate); -} -void Sprite3D::_texture_changed() { - _queue_update(); + RID shader_rid; + StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, &shader_rid); + if (last_shader != shader_rid) { + RS::get_singleton()->material_set_shader(get_material(), shader_rid); + last_shader = shader_rid; + } + if (last_texture != texture->get_rid()) { + RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid()); + last_texture = texture->get_rid(); + } } void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) { @@ -498,11 +618,11 @@ void Sprite3D::set_texture(const Ref<Texture2D> &p_texture) { return; } if (texture.is_valid()) { - texture->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed)); + texture->disconnect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update")); } texture = p_texture; if (texture.is_valid()) { - texture->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Sprite3D::_texture_changed)); + texture->connect(CoreStringNames::get_singleton()->changed, Callable(this, "_queue_update")); } _queue_update(); } @@ -511,24 +631,23 @@ Ref<Texture2D> Sprite3D::get_texture() const { return texture; } -void Sprite3D::set_region_enabled(bool p_region_enabled) { - if (p_region_enabled == region_enabled) { +void Sprite3D::set_region_enabled(bool p_region) { + if (p_region == region) { return; } - region_enabled = p_region_enabled; + region = p_region; _queue_update(); - notify_property_list_changed(); } bool Sprite3D::is_region_enabled() const { - return region_enabled; + return region; } void Sprite3D::set_region_rect(const Rect2 &p_region_rect) { bool changed = region_rect != p_region_rect; region_rect = p_region_rect; - if (region_enabled && changed) { + if (region && changed) { _queue_update(); } } @@ -595,7 +714,7 @@ Rect2 Sprite3D::get_item_rect() const { Size2i s; - if (region_enabled) { + if (region) { s = region_rect.size; } else { s = texture->get_size(); @@ -624,10 +743,6 @@ void Sprite3D::_validate_property(PropertyInfo &property) const { if (property.name == "frame_coords") { property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } - - if (!region_enabled && property.name == "region_rect") { - property.usage = PROPERTY_USAGE_NOEDITOR; - } } void Sprite3D::_bind_methods() { @@ -652,12 +767,12 @@ void Sprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite3D::set_hframes); ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture"); ADD_GROUP("Animation", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); ADD_GROUP("Region", "region_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); @@ -666,17 +781,14 @@ void Sprite3D::_bind_methods() { } Sprite3D::Sprite3D() { - region_enabled = false; - frame = 0; - vframes = 1; - hframes = 1; } //////////////////////////////////////// void AnimatedSprite3D::_draw() { - RID immediate = get_immediate(); - RS::get_singleton()->immediate_clear(immediate); + if (get_base() != get_mesh()) { + set_base(get_mesh()); + } if (frames.is_null()) { return; @@ -692,7 +804,8 @@ void AnimatedSprite3D::_draw() { Ref<Texture2D> texture = frames->get_frame(animation, frame); if (!texture.is_valid()) { - return; //no texture no life + set_base(RID()); + return; //no texuture no life } Vector2 tsize = texture->get_size(); if (tsize.x == 0 || tsize.y == 0) { @@ -727,6 +840,7 @@ void AnimatedSprite3D::_draw() { float pixel_size = get_pixel_size(); Vector2 vertices[4] = { + (final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size, (final_rect.position + final_rect.size) * pixel_size, (final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size, @@ -770,12 +884,6 @@ void AnimatedSprite3D::_draw() { tangent = Plane(1, 0, 0, -1); } - RID mat = StandardMaterial3D::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y); - - RS::get_singleton()->immediate_set_material(immediate, mat); - - RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_TRIANGLES, texture->get_rid()); - int x_axis = ((axis + 1) % 3); int y_axis = ((axis + 2) % 3); @@ -795,30 +903,79 @@ void AnimatedSprite3D::_draw() { AABB aabb; - for (int i = 0; i < 6; i++) { - static const int indices[6] = { - 0, 1, 2, - 0, 2, 3 - }; + // Everything except position and UV is compressed + uint8_t *vertex_write_buffer = vertex_buffer.ptrw(); + uint8_t *attribute_write_buffer = attribute_buffer.ptrw(); + + uint32_t v_normal; + { + Vector3 n = normal * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + + v_normal = value; + } + uint32_t v_tangent; + { + Plane t = tangent; + uint32_t value = 0; + value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + if (t.d > 0) { + value |= 3 << 30; + } + v_tangent = value; + } - RS::get_singleton()->immediate_normal(immediate, normal); - RS::get_singleton()->immediate_tangent(immediate, tangent); - RS::get_singleton()->immediate_color(immediate, color); - RS::get_singleton()->immediate_uv(immediate, uvs[indices[i]]); + uint8_t v_color[4] = { + uint8_t(CLAMP(color.r * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.g * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.b * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(color.a * 255.0, 0.0, 255.0)) + }; + for (int i = 0; i < 4; i++) { Vector3 vtx; - vtx[x_axis] = vertices[indices[i]][0]; - vtx[y_axis] = vertices[indices[i]][1]; - RS::get_singleton()->immediate_vertex(immediate, vtx); + vtx[x_axis] = vertices[i][0]; + vtx[y_axis] = vertices[i][1]; if (i == 0) { aabb.position = vtx; aabb.size = Vector3(); } else { aabb.expand_to(vtx); } + + float v_uv[2] = { uvs[i].x, uvs[i].y }; + memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_TEX_UV]], v_uv, 8); + + float v_vertex[3] = { vtx.x, vtx.y, vtx.z }; + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3); + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_NORMAL]], &v_normal, 4); + memcpy(&vertex_write_buffer[i * vertex_stride + mesh_surface_offsets[RS::ARRAY_TANGENT]], &v_tangent, 4); + memcpy(&attribute_write_buffer[i * attrib_stride + mesh_surface_offsets[RS::ARRAY_COLOR]], v_color, 4); } + + RID mesh = get_mesh(); + RS::get_singleton()->mesh_surface_update_vertex_region(mesh, 0, 0, vertex_buffer); + RS::get_singleton()->mesh_surface_update_attribute_region(mesh, 0, 0, attribute_buffer); + + RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb); set_aabb(aabb); - RS::get_singleton()->immediate_end(immediate); + + RID shader_rid; + StandardMaterial3D::get_material_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == StandardMaterial3D::BILLBOARD_ENABLED, get_billboard_mode() == StandardMaterial3D::BILLBOARD_FIXED_Y, &shader_rid); + if (last_shader != shader_rid) { + RS::get_singleton()->material_set_shader(get_material(), shader_rid); + last_shader = shader_rid; + } + if (last_texture != texture->get_rid()) { + RS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid()); + last_texture = texture->get_rid(); + } } void AnimatedSprite3D::_validate_property(PropertyInfo &property) const { @@ -912,11 +1069,11 @@ void AnimatedSprite3D::_notification(int p_what) { void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { if (frames.is_valid()) { - frames->disconnect("changed", callable_mp(this, &AnimatedSprite3D::_res_changed)); + frames->disconnect("changed", Callable(this, "_res_changed")); } frames = p_frames; if (frames.is_valid()) { - frames->connect("changed", callable_mp(this, &AnimatedSprite3D::_res_changed)); + frames->connect("changed", Callable(this, "_res_changed")); } if (!frames.is_valid()) { @@ -942,9 +1099,8 @@ void AnimatedSprite3D::set_frame(int p_frame) { if (frames->has_animation(animation)) { int limit = frames->get_frame_count(animation); - if (p_frame >= limit) { + if (p_frame >= limit) p_frame = limit - 1; - } } if (p_frame < 0) { @@ -958,7 +1114,6 @@ void AnimatedSprite3D::set_frame(int p_frame) { frame = p_frame; _reset_timeout(); _queue_update(); - emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -1059,8 +1214,7 @@ StringName AnimatedSprite3D::get_animation() const { } TypedArray<String> AnimatedSprite3D::get_configuration_warnings() const { - TypedArray<String> warnings = Node::get_configuration_warnings(); - + TypedArray<String> warnings = SpriteBase3D::get_configuration_warnings(); if (frames.is_null()) { warnings.push_back(TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.")); } @@ -1085,11 +1239,13 @@ void AnimatedSprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame); ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame); + ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed); + ADD_SIGNAL(MethodInfo("frame_changed")); ADD_SIGNAL(MethodInfo("animation_finished")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation"); ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing"); } diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index e3dd117804..404ef57e6a 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -31,8 +31,8 @@ #ifndef SPRITE_3D_H #define SPRITE_3D_H +#include "scene/2d/animated_sprite_2d.h" #include "scene/3d/visual_instance_3d.h" -#include "scene/resources/sprite_frames.h" class SpriteBase3D : public GeometryInstance3D { GDCLASS(SpriteBase3D, GeometryInstance3D); @@ -75,9 +75,10 @@ private: float pixel_size = 0.01; AABB aabb; - RID immediate; + RID mesh; + RID material; - bool flags[FLAG_MAX]; + bool flags[FLAG_MAX] = {}; AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED; StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED; bool pending_update = false; @@ -91,7 +92,17 @@ protected: static void _bind_methods(); virtual void _draw() = 0; _FORCE_INLINE_ void set_aabb(const AABB &p_aabb) { aabb = p_aabb; } - _FORCE_INLINE_ RID &get_immediate() { return immediate; } + _FORCE_INLINE_ RID &get_mesh() { return mesh; } + _FORCE_INLINE_ RID &get_material() { return material; } + + uint32_t mesh_surface_offsets[RS::ARRAY_MAX]; + PackedByteArray vertex_buffer; + PackedByteArray attribute_buffer; + uint32_t vertex_stride; + uint32_t attrib_stride; + uint32_t skin_stride; + uint32_t mesh_surface_format; + void _queue_update(); public: @@ -107,7 +118,7 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; - void set_region_enabled(bool p_region_enabled); + void set_region_enabled(bool p_region); bool is_region_enabled() const; void set_region_rect(const Rect2 &p_region_rect); @@ -147,15 +158,16 @@ class Sprite3D : public SpriteBase3D { GDCLASS(Sprite3D, SpriteBase3D); Ref<Texture2D> texture; - bool region_enabled; + bool region = false; Rect2 region_rect; - int frame; + int frame = 0; - int vframes; - int hframes; + int vframes = 1; + int hframes = 1; - void _texture_changed(); + RID last_shader; + RID last_texture; protected: virtual void _draw() override; @@ -167,7 +179,7 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - void set_region_enabled(bool p_region_enabled); + void set_region_enabled(bool p_region); bool is_region_enabled() const; void set_region_rect(const Rect2 &p_region_rect); @@ -199,14 +211,9 @@ class AnimatedSprite3D : public SpriteBase3D { StringName animation = "default"; int frame = 0; - bool centered = true; - - float timeout = 0.0; - - bool hflip = true; - bool vflip = true; + bool centered = false; - Color modulate; + float timeout = 0; void _res_changed(); @@ -214,6 +221,9 @@ class AnimatedSprite3D : public SpriteBase3D { void _set_playing(bool p_playing); bool _is_playing() const; + RID last_shader; + RID last_texture; + protected: virtual void _draw() override; static void _bind_methods(); @@ -236,10 +246,11 @@ public: virtual Rect2 get_item_rect() const override; - TypedArray<String> get_configuration_warnings() const override; + virtual TypedArray<String> get_configuration_warnings() const override; AnimatedSprite3D(); }; VARIANT_ENUM_CAST(SpriteBase3D::DrawFlags); VARIANT_ENUM_CAST(SpriteBase3D::AlphaCutMode); + #endif // SPRITE_3D_H diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index 9493f686c4..b0e37b81a5 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -79,26 +79,29 @@ public: }; void VehicleWheel3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); - if (!cb) { - return; - } - body = cb; - local_xform = get_transform(); - cb->wheels.push_back(this); - - m_chassisConnectionPointCS = get_transform().origin; - m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); - m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); - } - if (p_what == NOTIFICATION_EXIT_TREE) { - VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); - if (!cb) { - return; - } - cb->wheels.erase(this); - body = nullptr; + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); + if (!cb) { + return; + } + body = cb; + local_xform = get_transform(); + cb->wheels.push_back(this); + + m_chassisConnectionPointCS = get_transform().origin; + m_wheelDirectionCS = -get_transform().basis.get_axis(Vector3::AXIS_Y).normalized(); + m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); + } break; + + case NOTIFICATION_EXIT_TREE: { + VehicleBody3D *cb = Object::cast_to<VehicleBody3D>(get_parent()); + if (!cb) { + return; + } + cb->wheels.erase(this); + body = nullptr; + } break; } } @@ -346,7 +349,7 @@ VehicleWheel3D::VehicleWheel3D() { void VehicleBody3D::_update_wheel_transform(VehicleWheel3D &wheel, PhysicsDirectBodyState3D *s) { wheel.m_raycastInfo.m_isInContact = false; - Transform chassisTrans = s->get_transform(); + Transform3D chassisTrans = s->get_transform(); /* if (interpolatedTransform && (getRigidBody()->getMotionState())) { getRigidBody()->getMotionState()->getWorldTransform(chassisTrans); @@ -784,7 +787,7 @@ void VehicleBody3D::_update_friction(PhysicsDirectBodyState3D *s) { Vector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; #if defined ROLLING_INFLUENCE_FIX // fix. It only worked if car's up was along Y - VT. - Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform().getBasis().getColumn(m_indexUpAxis); + Vector3 vChassisWorldUp = s->get_transform().basis.transposed()[1]; //getRigidBody()->getCenterOfMassTransform3D().getBasis().getColumn(m_indexUpAxis); rel_pos -= vChassisWorldUp * (vChassisWorldUp.dot(rel_pos) * (1.f - wheelInfo.m_rollInfluence)); #else rel_pos[1] *= wheelInfo.m_rollInfluence; //? @@ -841,7 +844,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) { Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos); if (wheel.m_raycastInfo.m_isInContact) { - const Transform &chassisWorldTransform = state->get_transform(); + const Transform3D &chassisWorldTransform = state->get_transform(); Vector3 fwd( chassisWorldTransform.basis[0][Vector3::AXIS_Z], diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h index 646071a363..2c10205ea3 100644 --- a/scene/3d/vehicle_body_3d.h +++ b/scene/3d/vehicle_body_3d.h @@ -40,8 +40,8 @@ class VehicleWheel3D : public Node3D { friend class VehicleBody3D; - Transform m_worldTransform; - Transform local_xform; + Transform3D m_worldTransform; + Transform3D local_xform; bool engine_traction = false; bool steers = false; diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h index e971f4755a..827c3f5bd8 100644 --- a/scene/3d/velocity_tracker_3d.h +++ b/scene/3d/velocity_tracker_3d.h @@ -33,8 +33,8 @@ #include "scene/3d/node_3d.h" -class VelocityTracker3D : public Reference { - GDCLASS(VelocityTracker3D, Reference); +class VelocityTracker3D : public RefCounted { + GDCLASS(VelocityTracker3D, RefCounted); struct PositionHistory { uint64_t frame = 0; diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp deleted file mode 100644 index 471838b9d1..0000000000 --- a/scene/3d/visibility_notifier_3d.cpp +++ /dev/null @@ -1,253 +0,0 @@ -/*************************************************************************/ -/* visibility_notifier_3d.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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. */ -/*************************************************************************/ - -#include "visibility_notifier_3d.h" - -#include "core/config/engine.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/physics_body_3d.h" -#include "scene/animation/animation_player.h" -#include "scene/scene_string_names.h" - -void VisibilityNotifier3D::_enter_camera(Camera3D *p_camera) { - ERR_FAIL_COND(cameras.has(p_camera)); - cameras.insert(p_camera); - if (cameras.size() == 1) { - emit_signal(SceneStringNames::get_singleton()->screen_entered); - _screen_enter(); - } - - emit_signal(SceneStringNames::get_singleton()->camera_entered, p_camera); -} - -void VisibilityNotifier3D::_exit_camera(Camera3D *p_camera) { - ERR_FAIL_COND(!cameras.has(p_camera)); - cameras.erase(p_camera); - - emit_signal(SceneStringNames::get_singleton()->camera_exited, p_camera); - if (cameras.size() == 0) { - emit_signal(SceneStringNames::get_singleton()->screen_exited); - - _screen_exit(); - } -} - -void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) { - if (aabb == p_aabb) { - return; - } - aabb = p_aabb; - - if (is_inside_world()) { - get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb)); - } - - update_gizmo(); -} - -AABB VisibilityNotifier3D::get_aabb() const { - return aabb; -} - -void VisibilityNotifier3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_WORLD: { - world = get_world_3d(); - ERR_FAIL_COND(!world.is_valid()); - world->_register_notifier(this, get_global_transform().xform(aabb)); - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - world->_update_notifier(this, get_global_transform().xform(aabb)); - } break; - case NOTIFICATION_EXIT_WORLD: { - ERR_FAIL_COND(!world.is_valid()); - world->_remove_notifier(this); - } break; - } -} - -bool VisibilityNotifier3D::is_on_screen() const { - return cameras.size() != 0; -} - -void VisibilityNotifier3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibilityNotifier3D::set_aabb); - ClassDB::bind_method(D_METHOD("get_aabb"), &VisibilityNotifier3D::get_aabb); - ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibilityNotifier3D::is_on_screen); - - ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb"); - - ADD_SIGNAL(MethodInfo("camera_entered", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"))); - ADD_SIGNAL(MethodInfo("camera_exited", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Camera3D"))); - ADD_SIGNAL(MethodInfo("screen_entered")); - ADD_SIGNAL(MethodInfo("screen_exited")); -} - -VisibilityNotifier3D::VisibilityNotifier3D() { - set_notify_transform(true); -} - -////////////////////////////////////// - -void VisibilityEnabler3D::_screen_enter() { - for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), true); - } - - visible = true; -} - -void VisibilityEnabler3D::_screen_exit() { - for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) { - _change_node_state(E->key(), false); - } - - visible = false; -} - -void VisibilityEnabler3D::_find_nodes(Node *p_node) { - bool add = false; - Variant meta; - - { - RigidBody3D *rb = Object::cast_to<RigidBody3D>(p_node); - if (rb && ((rb->get_mode() == RigidBody3D::MODE_CHARACTER || rb->get_mode() == RigidBody3D::MODE_RIGID))) { - add = true; - meta = rb->get_mode(); - } - } - - { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); - if (ap) { - add = true; - } - } - - if (add) { - p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed), varray(p_node), CONNECT_ONESHOT); - nodes[p_node] = meta; - _change_node_state(p_node, false); - } - - for (int i = 0; i < p_node->get_child_count(); i++) { - Node *c = p_node->get_child(i); - if (c->get_filename() != String()) { - continue; //skip, instance - } - - _find_nodes(c); - } -} - -void VisibilityEnabler3D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - - Node *from = this; - //find where current scene starts - while (from->get_parent() && from->get_filename() == String()) { - from = from->get_parent(); - } - - _find_nodes(from); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - if (Engine::get_singleton()->is_editor_hint()) { - return; - } - - for (Map<Node *, Variant>::Element *E = nodes.front(); E; E = E->next()) { - if (!visible) { - _change_node_state(E->key(), true); - } - E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &VisibilityEnabler3D::_node_removed)); - } - - nodes.clear(); - } -} - -void VisibilityEnabler3D::_change_node_state(Node *p_node, bool p_enabled) { - ERR_FAIL_COND(!nodes.has(p_node)); - - if (enabler[ENABLER_FREEZE_BODIES]) { - RigidBody3D *rb = Object::cast_to<RigidBody3D>(p_node); - if (rb) { - rb->set_sleeping(!p_enabled); - } - } - - if (enabler[ENABLER_PAUSE_ANIMATIONS]) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node); - - if (ap) { - ap->set_active(p_enabled); - } - } -} - -void VisibilityEnabler3D::_node_removed(Node *p_node) { - if (!visible) { - _change_node_state(p_node, true); - } - nodes.erase(p_node); -} - -void VisibilityEnabler3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_enabler", "enabler", "enabled"), &VisibilityEnabler3D::set_enabler); - ClassDB::bind_method(D_METHOD("is_enabler_enabled", "enabler"), &VisibilityEnabler3D::is_enabler_enabled); - - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "pause_animations"), "set_enabler", "is_enabler_enabled", ENABLER_PAUSE_ANIMATIONS); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "freeze_bodies"), "set_enabler", "is_enabler_enabled", ENABLER_FREEZE_BODIES); - - BIND_ENUM_CONSTANT(ENABLER_PAUSE_ANIMATIONS); - BIND_ENUM_CONSTANT(ENABLER_FREEZE_BODIES); - BIND_ENUM_CONSTANT(ENABLER_MAX); -} - -void VisibilityEnabler3D::set_enabler(Enabler p_enabler, bool p_enable) { - ERR_FAIL_INDEX(p_enabler, ENABLER_MAX); - enabler[p_enabler] = p_enable; -} - -bool VisibilityEnabler3D::is_enabler_enabled(Enabler p_enabler) const { - ERR_FAIL_INDEX_V(p_enabler, ENABLER_MAX, false); - return enabler[p_enabler]; -} - -VisibilityEnabler3D::VisibilityEnabler3D() { - for (int i = 0; i < ENABLER_MAX; i++) { - enabler[i] = true; - } -} diff --git a/scene/3d/visible_on_screen_notifier_3d.cpp b/scene/3d/visible_on_screen_notifier_3d.cpp new file mode 100644 index 0000000000..682bcec449 --- /dev/null +++ b/scene/3d/visible_on_screen_notifier_3d.cpp @@ -0,0 +1,203 @@ +/*************************************************************************/ +/* visible_on_screen_notifier_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "visible_on_screen_notifier_3d.h" + +#include "core/config/engine.h" +#include "scene/3d/camera_3d.h" +#include "scene/3d/physics_body_3d.h" +#include "scene/animation/animation_player.h" +#include "scene/scene_string_names.h" + +void VisibleOnScreenNotifier3D::_visibility_enter() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; + } + + on_screen = true; + emit_signal(SceneStringNames::get_singleton()->screen_entered); + _screen_enter(); +} +void VisibleOnScreenNotifier3D::_visibility_exit() { + if (!is_inside_tree() || Engine::get_singleton()->is_editor_hint()) { + return; + } + + on_screen = false; + emit_signal(SceneStringNames::get_singleton()->screen_exited); + _screen_exit(); +} + +void VisibleOnScreenNotifier3D::set_aabb(const AABB &p_aabb) { + if (aabb == p_aabb) { + return; + } + aabb = p_aabb; + + RS::get_singleton()->visibility_notifier_set_aabb(get_base(), aabb); + + update_gizmo(); +} + +AABB VisibleOnScreenNotifier3D::get_aabb() const { + return aabb; +} + +bool VisibleOnScreenNotifier3D::is_on_screen() const { + return on_screen; +} + +void VisibleOnScreenNotifier3D::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_EXIT_TREE) { + on_screen = false; + } +} + +void VisibleOnScreenNotifier3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_aabb", "rect"), &VisibleOnScreenNotifier3D::set_aabb); + ClassDB::bind_method(D_METHOD("is_on_screen"), &VisibleOnScreenNotifier3D::is_on_screen); + + ADD_PROPERTY(PropertyInfo(Variant::AABB, "aabb"), "set_aabb", "get_aabb"); + + ADD_SIGNAL(MethodInfo("screen_entered")); + ADD_SIGNAL(MethodInfo("screen_exited")); +} + +Vector<Face3> VisibleOnScreenNotifier3D::get_faces(uint32_t p_usage_flags) const { + return Vector<Face3>(); +} + +VisibleOnScreenNotifier3D::VisibleOnScreenNotifier3D() { + RID notifier = RS::get_singleton()->visibility_notifier_create(); + RS::get_singleton()->visibility_notifier_set_aabb(notifier, aabb); + RS::get_singleton()->visibility_notifier_set_callbacks(notifier, callable_mp(this, &VisibleOnScreenNotifier3D::_visibility_enter), callable_mp(this, &VisibleOnScreenNotifier3D::_visibility_exit)); + set_base(notifier); +} +VisibleOnScreenNotifier3D::~VisibleOnScreenNotifier3D() { + RID base = get_base(); + set_base(RID()); + RS::get_singleton()->free(base); +} + +////////////////////////////////////// + +void VisibleOnScreenEnabler3D::_screen_enter() { + _update_enable_mode(true); +} + +void VisibleOnScreenEnabler3D::_screen_exit() { + _update_enable_mode(false); +} + +void VisibleOnScreenEnabler3D::set_enable_mode(EnableMode p_mode) { + enable_mode = p_mode; + if (is_inside_tree()) { + _update_enable_mode(is_on_screen()); + } +} +VisibleOnScreenEnabler3D::EnableMode VisibleOnScreenEnabler3D::get_enable_mode() { + return enable_mode; +} + +void VisibleOnScreenEnabler3D::set_enable_node_path(NodePath p_path) { + if (enable_node_path == p_path) { + return; + } + enable_node_path = p_path; + if (is_inside_tree()) { + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + _update_enable_mode(is_on_screen()); + } + } +} +NodePath VisibleOnScreenEnabler3D::get_enable_node_path() { + return enable_node_path; +} + +void VisibleOnScreenEnabler3D::_update_enable_mode(bool p_enable) { + Node *node = static_cast<Node *>(ObjectDB::get_instance(node_id)); + if (node) { + if (p_enable) { + switch (enable_mode) { + case ENABLE_MODE_INHERIT: { + node->set_process_mode(PROCESS_MODE_INHERIT); + } break; + case ENABLE_MODE_ALWAYS: { + node->set_process_mode(PROCESS_MODE_ALWAYS); + } break; + case ENABLE_MODE_WHEN_PAUSED: { + node->set_process_mode(PROCESS_MODE_WHEN_PAUSED); + } break; + } + } else { + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } +} +void VisibleOnScreenEnabler3D::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE) { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } + + node_id = ObjectID(); + Node *node = get_node(enable_node_path); + if (node) { + node_id = node->get_instance_id(); + node->set_process_mode(PROCESS_MODE_DISABLED); + } + } + + if (p_what == NOTIFICATION_EXIT_TREE) { + node_id = ObjectID(); + } +} + +void VisibleOnScreenEnabler3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_enable_mode", "mode"), &VisibleOnScreenEnabler3D::set_enable_mode); + ClassDB::bind_method(D_METHOD("get_enable_mode"), &VisibleOnScreenEnabler3D::get_enable_mode); + + ClassDB::bind_method(D_METHOD("set_enable_node_path", "path"), &VisibleOnScreenEnabler3D::set_enable_node_path); + ClassDB::bind_method(D_METHOD("get_enable_node_path"), &VisibleOnScreenEnabler3D::get_enable_node_path); + + ADD_GROUP("Enabling", "enable_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "enable_mode", PROPERTY_HINT_ENUM, "Inherit,Always,WhenPaused"), "set_enable_mode", "get_enable_mode"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "enable_node_path"), "set_enable_node_path", "get_enable_node_path"); + + BIND_ENUM_CONSTANT(ENABLE_MODE_INHERIT); + BIND_ENUM_CONSTANT(ENABLE_MODE_ALWAYS); + BIND_ENUM_CONSTANT(ENABLE_MODE_WHEN_PAUSED); +} + +VisibleOnScreenEnabler3D::VisibleOnScreenEnabler3D() { +} diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visible_on_screen_notifier_3d.h index 9f7705067f..fb7137c4f0 100644 --- a/scene/3d/visibility_notifier_3d.h +++ b/scene/3d/visible_on_screen_notifier_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* visibility_notifier_3d.h */ +/* visible_on_screen_notifier_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,74 +28,74 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VISIBILITY_NOTIFIER_H -#define VISIBILITY_NOTIFIER_H +#ifndef VISIBLE_ON_SCREEN_NOTIFIER_3D_H +#define VISIBLE_ON_SCREEN_NOTIFIER_3D_H -#include "scene/3d/node_3d.h" +#include "scene/3d/visual_instance_3d.h" class World3D; class Camera3D; -class VisibilityNotifier3D : public Node3D { - GDCLASS(VisibilityNotifier3D, Node3D); - - Ref<World3D> world; - Set<Camera3D *> cameras; +class VisibleOnScreenNotifier3D : public VisualInstance3D { + GDCLASS(VisibleOnScreenNotifier3D, VisualInstance3D); AABB aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); +private: + bool on_screen = false; + void _visibility_enter(); + void _visibility_exit(); + protected: virtual void _screen_enter() {} virtual void _screen_exit() {} void _notification(int p_what); static void _bind_methods(); - friend struct SpatialIndexer; - - void _enter_camera(Camera3D *p_camera); - void _exit_camera(Camera3D *p_camera); public: void set_aabb(const AABB &p_aabb); - AABB get_aabb() const; + virtual AABB get_aabb() const override; bool is_on_screen() const; - VisibilityNotifier3D(); + virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; + + VisibleOnScreenNotifier3D(); + ~VisibleOnScreenNotifier3D(); }; -class VisibilityEnabler3D : public VisibilityNotifier3D { - GDCLASS(VisibilityEnabler3D, VisibilityNotifier3D); +class VisibleOnScreenEnabler3D : public VisibleOnScreenNotifier3D { + GDCLASS(VisibleOnScreenEnabler3D, VisibleOnScreenNotifier3D); public: - enum Enabler { - ENABLER_PAUSE_ANIMATIONS, - ENABLER_FREEZE_BODIES, - ENABLER_MAX + enum EnableMode { + ENABLE_MODE_INHERIT, + ENABLE_MODE_ALWAYS, + ENABLE_MODE_WHEN_PAUSED, }; protected: + ObjectID node_id; virtual void _screen_enter() override; virtual void _screen_exit() override; - bool visible = false; - - void _find_nodes(Node *p_node); - - Map<Node *, Variant> nodes; - void _node_removed(Node *p_node); - bool enabler[ENABLER_MAX]; - - void _change_node_state(Node *p_node, bool p_enabled); + EnableMode enable_mode = ENABLE_MODE_INHERIT; + NodePath enable_node_path = NodePath(".."); void _notification(int p_what); static void _bind_methods(); + void _update_enable_mode(bool p_enable); + public: - void set_enabler(Enabler p_enabler, bool p_enable); - bool is_enabler_enabled(Enabler p_enabler) const; + void set_enable_mode(EnableMode p_mode); + EnableMode get_enable_mode(); + + void set_enable_node_path(NodePath p_path); + NodePath get_enable_node_path(); - VisibilityEnabler3D(); + VisibleOnScreenEnabler3D(); }; -VARIANT_ENUM_CAST(VisibilityEnabler3D::Enabler); +VARIANT_ENUM_CAST(VisibleOnScreenEnabler3D::EnableMode); #endif // VISIBILITY_NOTIFIER_H diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index d81b09b86c..bd47af8100 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -61,7 +61,7 @@ void VisualInstance3D::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - Transform gt = get_global_transform(); + Transform3D gt = get_global_transform(); RenderingServer::get_singleton()->instance_set_transform(instance, gt); } break; case NOTIFICATION_EXIT_WORLD: { @@ -150,40 +150,40 @@ Ref<Material> GeometryInstance3D::get_material_override() const { return material_override; } -void GeometryInstance3D::set_lod_min_distance(float p_dist) { - lod_min_distance = p_dist; - RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis); +void GeometryInstance3D::set_visibility_range_begin(float p_dist) { + visibility_range_begin = p_dist; + RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin); } -float GeometryInstance3D::get_lod_min_distance() const { - return lod_min_distance; +float GeometryInstance3D::get_visibility_range_begin() const { + return visibility_range_begin; } -void GeometryInstance3D::set_lod_max_distance(float p_dist) { - lod_max_distance = p_dist; - RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis); +void GeometryInstance3D::set_visibility_range_end(float p_dist) { + visibility_range_end = p_dist; + RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin); } -float GeometryInstance3D::get_lod_max_distance() const { - return lod_max_distance; +float GeometryInstance3D::get_visibility_range_end() const { + return visibility_range_end; } -void GeometryInstance3D::set_lod_min_hysteresis(float p_dist) { - lod_min_hysteresis = p_dist; - RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis); +void GeometryInstance3D::set_visibility_range_begin_margin(float p_dist) { + visibility_range_begin_margin = p_dist; + RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin); } -float GeometryInstance3D::get_lod_min_hysteresis() const { - return lod_min_hysteresis; +float GeometryInstance3D::get_visibility_range_begin_margin() const { + return visibility_range_begin_margin; } -void GeometryInstance3D::set_lod_max_hysteresis(float p_dist) { - lod_max_hysteresis = p_dist; - RS::get_singleton()->instance_geometry_set_draw_range(get_instance(), lod_min_distance, lod_max_distance, lod_min_hysteresis, lod_max_hysteresis); +void GeometryInstance3D::set_visibility_range_end_margin(float p_dist) { + visibility_range_end_margin = p_dist; + RS::get_singleton()->instance_geometry_set_visibility_range(get_instance(), visibility_range_begin, visibility_range_end, visibility_range_begin_margin, visibility_range_end_margin); } -float GeometryInstance3D::get_lod_max_hysteresis() const { - return lod_max_hysteresis; +float GeometryInstance3D::get_visibility_range_end_margin() const { + return visibility_range_end_margin; } void GeometryInstance3D::_notification(int p_what) { @@ -246,9 +246,9 @@ void GeometryInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { has_def_value = true; } if (instance_uniforms.has(pi.name)) { - pi.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | (has_def_value ? (PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED) : 0); + pi.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | (has_def_value ? (PROPERTY_USAGE_CHECKABLE | PROPERTY_USAGE_CHECKED) : PROPERTY_USAGE_NONE); } else { - pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : 0); //do not save if not changed + pi.usage = PROPERTY_USAGE_EDITOR | (has_def_value ? PROPERTY_USAGE_CHECKABLE : PROPERTY_USAGE_NONE); //do not save if not changed } pi.name = "shader_params/" + pi.name; @@ -293,7 +293,12 @@ void GeometryInstance3D::set_shader_instance_uniform(const StringName &p_uniform instance_uniforms.erase(p_value); } else { instance_uniforms[p_uniform] = p_value; - RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value); + if (p_value.get_type() == Variant::OBJECT) { + RID tex_id = p_value; + RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, tex_id); + } else { + RS::get_singleton()->instance_geometry_set_shader_parameter(get_instance(), p_uniform, p_value); + } } } @@ -357,17 +362,17 @@ void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias); ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias); - ClassDB::bind_method(D_METHOD("set_lod_max_hysteresis", "mode"), &GeometryInstance3D::set_lod_max_hysteresis); - ClassDB::bind_method(D_METHOD("get_lod_max_hysteresis"), &GeometryInstance3D::get_lod_max_hysteresis); + ClassDB::bind_method(D_METHOD("set_visibility_range_end_margin", "distance"), &GeometryInstance3D::set_visibility_range_end_margin); + ClassDB::bind_method(D_METHOD("get_visibility_range_end_margin"), &GeometryInstance3D::get_visibility_range_end_margin); - ClassDB::bind_method(D_METHOD("set_lod_max_distance", "mode"), &GeometryInstance3D::set_lod_max_distance); - ClassDB::bind_method(D_METHOD("get_lod_max_distance"), &GeometryInstance3D::get_lod_max_distance); + ClassDB::bind_method(D_METHOD("set_visibility_range_end", "distance"), &GeometryInstance3D::set_visibility_range_end); + ClassDB::bind_method(D_METHOD("get_visibility_range_end"), &GeometryInstance3D::get_visibility_range_end); - ClassDB::bind_method(D_METHOD("set_lod_min_hysteresis", "mode"), &GeometryInstance3D::set_lod_min_hysteresis); - ClassDB::bind_method(D_METHOD("get_lod_min_hysteresis"), &GeometryInstance3D::get_lod_min_hysteresis); + ClassDB::bind_method(D_METHOD("set_visibility_range_begin_margin", "distance"), &GeometryInstance3D::set_visibility_range_begin_margin); + ClassDB::bind_method(D_METHOD("get_visibility_range_begin_margin"), &GeometryInstance3D::get_visibility_range_begin_margin); - ClassDB::bind_method(D_METHOD("set_lod_min_distance", "mode"), &GeometryInstance3D::set_lod_min_distance); - ClassDB::bind_method(D_METHOD("get_lod_min_distance"), &GeometryInstance3D::get_lod_min_distance); + ClassDB::bind_method(D_METHOD("set_visibility_range_begin", "distance"), &GeometryInstance3D::set_visibility_range_begin); + ClassDB::bind_method(D_METHOD("get_visibility_range_begin"), &GeometryInstance3D::get_visibility_range_begin); ClassDB::bind_method(D_METHOD("set_shader_instance_uniform", "uniform", "value"), &GeometryInstance3D::set_shader_instance_uniform); ClassDB::bind_method(D_METHOD("get_shader_instance_uniform", "uniform"), &GeometryInstance3D::get_shader_instance_uniform); @@ -389,7 +394,7 @@ void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_aabb"), &GeometryInstance3D::get_aabb); ADD_GROUP("Geometry", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE), "set_material_override", "get_material_override"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_bias", PROPERTY_HINT_RANGE, "0.001,128,0.001"), "set_lod_bias", "get_lod_bias"); @@ -398,11 +403,11 @@ void GeometryInstance3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_mode", PROPERTY_HINT_ENUM, "Disabled,Baked,Dynamic"), "set_gi_mode", "get_gi_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "gi_lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale"); - ADD_GROUP("LOD", "lod_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_distance", "get_lod_min_distance"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_min_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_min_hysteresis", "get_lod_min_hysteresis"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_distance", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_distance", "get_lod_max_distance"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_max_hysteresis", PROPERTY_HINT_RANGE, "0,32768,0.01"), "set_lod_max_hysteresis", "get_lod_max_hysteresis"); + ADD_GROUP("Visibility Range", "visibility_range_"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin", "get_visibility_range_begin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_begin_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_begin_margin", "get_visibility_range_begin_margin"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end", "get_visibility_range_end"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visibility_range_end_margin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01"), "set_visibility_range_end_margin", "get_visibility_range_end_margin"); //ADD_SIGNAL( MethodInfo("visibility_changed")); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 68d29ef81e..2d5699859b 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -107,10 +107,13 @@ public: private: ShadowCastingSetting shadow_casting_setting = SHADOW_CASTING_SETTING_ON; Ref<Material> material_override; - float lod_min_distance = 0.0; - float lod_max_distance = 0.0; - float lod_min_hysteresis = 0.0; - float lod_max_hysteresis = 0.0; + + float visibility_range_begin = 0.0; + float visibility_range_end = 0.0; + float visibility_range_begin_margin = 0.0; + float visibility_range_end_margin = 0.0; + + Vector<NodePath> visibility_range_children; float lod_bias = 1.0; @@ -136,17 +139,20 @@ public: void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting); ShadowCastingSetting get_cast_shadows_setting() const; - void set_lod_min_distance(float p_dist); - float get_lod_min_distance() const; + void set_visibility_range_begin(float p_dist); + float get_visibility_range_begin() const; + + void set_visibility_range_end(float p_dist); + float get_visibility_range_end() const; - void set_lod_max_distance(float p_dist); - float get_lod_max_distance() const; + void set_visibility_range_begin_margin(float p_dist); + float get_visibility_range_begin_margin() const; - void set_lod_min_hysteresis(float p_dist); - float get_lod_min_hysteresis() const; + void set_visibility_range_end_margin(float p_dist); + float get_visibility_range_end_margin() const; - void set_lod_max_hysteresis(float p_dist); - float get_lod_max_hysteresis() const; + void set_visibility_range_parent(const Node *p_parent); + void clear_visibility_range_parent(); void set_material_override(const Ref<Material> &p_material); Ref<Material> get_material_override() const; diff --git a/scene/3d/gi_probe.cpp b/scene/3d/voxel_gi.cpp index 6505fb1ee8..3da59ac4c0 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/voxel_gi.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gi_probe.cpp */ +/* voxel_gi.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "gi_probe.h" +#include "voxel_gi.h" #include "core/os/os.h" #include "mesh_instance_3d.h" #include "voxelizer.h" -void GIProbeData::_set_data(const Dictionary &p_data) { +void VoxelGIData::_set_data(const Dictionary &p_data) { ERR_FAIL_COND(!p_data.has("bounds")); ERR_FAIL_COND(!p_data.has("octree_size")); ERR_FAIL_COND(!p_data.has("octree_cells")); @@ -55,19 +55,19 @@ void GIProbeData::_set_data(const Dictionary &p_data) { } else if (p_data.has("octree_df_png")) { Vector<uint8_t> octree_df_png = p_data["octree_df_png"]; Ref<Image> img; - img.instance(); + img.instantiate(); Error err = img->load_png_from_buffer(octree_df_png); ERR_FAIL_COND(err != OK); ERR_FAIL_COND(img->get_format() != Image::FORMAT_L8); octree_df = img->get_data(); } Vector<int> octree_levels = p_data["level_counts"]; - Transform to_cell_xform = p_data["to_cell_xform"]; + Transform3D to_cell_xform = p_data["to_cell_xform"]; allocate(to_cell_xform, bounds, octree_size, octree_cells, octree_data, octree_df, octree_levels); } -Dictionary GIProbeData::_get_data() const { +Dictionary VoxelGIData::_get_data() const { Dictionary d; d["bounds"] = get_bounds(); Vector3i otsize = get_octree_size(); @@ -76,7 +76,7 @@ Dictionary GIProbeData::_get_data() const { d["octree_data"] = get_data_cells(); if (otsize != Vector3i()) { Ref<Image> img; - img.instance(); + img.instantiate(); img->create(otsize.x * otsize.y, otsize.z, false, Image::FORMAT_L8, get_distance_field()); Vector<uint8_t> df_png = img->save_png_to_buffer(); ERR_FAIL_COND_V(df_png.size() == 0, Dictionary()); @@ -90,186 +90,141 @@ Dictionary GIProbeData::_get_data() const { return d; } -void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { - RS::get_singleton()->gi_probe_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts); +void VoxelGIData::allocate(const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { + RS::get_singleton()->voxel_gi_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts); bounds = p_aabb; to_cell_xform = p_to_cell_xform; octree_size = p_octree_size; } -AABB GIProbeData::get_bounds() const { +AABB VoxelGIData::get_bounds() const { return bounds; } -Vector3 GIProbeData::get_octree_size() const { +Vector3 VoxelGIData::get_octree_size() const { return octree_size; } -Vector<uint8_t> GIProbeData::get_octree_cells() const { - return RS::get_singleton()->gi_probe_get_octree_cells(probe); +Vector<uint8_t> VoxelGIData::get_octree_cells() const { + return RS::get_singleton()->voxel_gi_get_octree_cells(probe); } -Vector<uint8_t> GIProbeData::get_data_cells() const { - return RS::get_singleton()->gi_probe_get_data_cells(probe); +Vector<uint8_t> VoxelGIData::get_data_cells() const { + return RS::get_singleton()->voxel_gi_get_data_cells(probe); } -Vector<uint8_t> GIProbeData::get_distance_field() const { - return RS::get_singleton()->gi_probe_get_distance_field(probe); +Vector<uint8_t> VoxelGIData::get_distance_field() const { + return RS::get_singleton()->voxel_gi_get_distance_field(probe); } -Vector<int> GIProbeData::get_level_counts() const { - return RS::get_singleton()->gi_probe_get_level_counts(probe); +Vector<int> VoxelGIData::get_level_counts() const { + return RS::get_singleton()->voxel_gi_get_level_counts(probe); } -Transform GIProbeData::get_to_cell_xform() const { +Transform3D VoxelGIData::get_to_cell_xform() const { return to_cell_xform; } -void GIProbeData::set_dynamic_range(float p_range) { - RS::get_singleton()->gi_probe_set_dynamic_range(probe, p_range); +void VoxelGIData::set_dynamic_range(float p_range) { + RS::get_singleton()->voxel_gi_set_dynamic_range(probe, p_range); dynamic_range = p_range; } -float GIProbeData::get_dynamic_range() const { +float VoxelGIData::get_dynamic_range() const { return dynamic_range; } -void GIProbeData::set_propagation(float p_propagation) { - RS::get_singleton()->gi_probe_set_propagation(probe, p_propagation); +void VoxelGIData::set_propagation(float p_propagation) { + RS::get_singleton()->voxel_gi_set_propagation(probe, p_propagation); propagation = p_propagation; } -float GIProbeData::get_propagation() const { +float VoxelGIData::get_propagation() const { return propagation; } -void GIProbeData::set_anisotropy_strength(float p_anisotropy_strength) { - RS::get_singleton()->gi_probe_set_anisotropy_strength(probe, p_anisotropy_strength); - anisotropy_strength = p_anisotropy_strength; -} - -float GIProbeData::get_anisotropy_strength() const { - return anisotropy_strength; -} - -void GIProbeData::set_energy(float p_energy) { - RS::get_singleton()->gi_probe_set_energy(probe, p_energy); +void VoxelGIData::set_energy(float p_energy) { + RS::get_singleton()->voxel_gi_set_energy(probe, p_energy); energy = p_energy; } -float GIProbeData::get_energy() const { +float VoxelGIData::get_energy() const { return energy; } -void GIProbeData::set_ao(float p_ao) { - RS::get_singleton()->gi_probe_set_ao(probe, p_ao); - ao = p_ao; -} - -float GIProbeData::get_ao() const { - return ao; -} - -void GIProbeData::set_ao_size(float p_ao_size) { - RS::get_singleton()->gi_probe_set_ao_size(probe, p_ao_size); - ao_size = p_ao_size; -} - -float GIProbeData::get_ao_size() const { - return ao_size; -} - -void GIProbeData::set_bias(float p_bias) { - RS::get_singleton()->gi_probe_set_bias(probe, p_bias); +void VoxelGIData::set_bias(float p_bias) { + RS::get_singleton()->voxel_gi_set_bias(probe, p_bias); bias = p_bias; } -float GIProbeData::get_bias() const { +float VoxelGIData::get_bias() const { return bias; } -void GIProbeData::set_normal_bias(float p_normal_bias) { - RS::get_singleton()->gi_probe_set_normal_bias(probe, p_normal_bias); +void VoxelGIData::set_normal_bias(float p_normal_bias) { + RS::get_singleton()->voxel_gi_set_normal_bias(probe, p_normal_bias); normal_bias = p_normal_bias; } -float GIProbeData::get_normal_bias() const { +float VoxelGIData::get_normal_bias() const { return normal_bias; } -void GIProbeData::set_interior(bool p_enable) { - RS::get_singleton()->gi_probe_set_interior(probe, p_enable); +void VoxelGIData::set_interior(bool p_enable) { + RS::get_singleton()->voxel_gi_set_interior(probe, p_enable); interior = p_enable; } -bool GIProbeData::is_interior() const { +bool VoxelGIData::is_interior() const { return interior; } -void GIProbeData::set_use_two_bounces(bool p_enable) { - RS::get_singleton()->gi_probe_set_use_two_bounces(probe, p_enable); +void VoxelGIData::set_use_two_bounces(bool p_enable) { + RS::get_singleton()->voxel_gi_set_use_two_bounces(probe, p_enable); use_two_bounces = p_enable; } -bool GIProbeData::is_using_two_bounces() const { +bool VoxelGIData::is_using_two_bounces() const { return use_two_bounces; } -RID GIProbeData::get_rid() const { +RID VoxelGIData::get_rid() const { return probe; } -void GIProbeData::_validate_property(PropertyInfo &property) const { - if (property.name == "anisotropy_strength") { - bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/gi_probes/anisotropic"); - if (!anisotropy_enabled) { - property.usage = PROPERTY_USAGE_NOEDITOR; - } - } -} - -void GIProbeData::_bind_methods() { - ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &GIProbeData::allocate); - - ClassDB::bind_method(D_METHOD("get_bounds"), &GIProbeData::get_bounds); - ClassDB::bind_method(D_METHOD("get_octree_size"), &GIProbeData::get_octree_size); - ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &GIProbeData::get_to_cell_xform); - ClassDB::bind_method(D_METHOD("get_octree_cells"), &GIProbeData::get_octree_cells); - ClassDB::bind_method(D_METHOD("get_data_cells"), &GIProbeData::get_data_cells); - ClassDB::bind_method(D_METHOD("get_level_counts"), &GIProbeData::get_level_counts); - - ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &GIProbeData::set_dynamic_range); - ClassDB::bind_method(D_METHOD("get_dynamic_range"), &GIProbeData::get_dynamic_range); - - ClassDB::bind_method(D_METHOD("set_energy", "energy"), &GIProbeData::set_energy); - ClassDB::bind_method(D_METHOD("get_energy"), &GIProbeData::get_energy); +void VoxelGIData::_bind_methods() { + ClassDB::bind_method(D_METHOD("allocate", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &VoxelGIData::allocate); - ClassDB::bind_method(D_METHOD("set_bias", "bias"), &GIProbeData::set_bias); - ClassDB::bind_method(D_METHOD("get_bias"), &GIProbeData::get_bias); + ClassDB::bind_method(D_METHOD("get_bounds"), &VoxelGIData::get_bounds); + ClassDB::bind_method(D_METHOD("get_octree_size"), &VoxelGIData::get_octree_size); + ClassDB::bind_method(D_METHOD("get_to_cell_xform"), &VoxelGIData::get_to_cell_xform); + ClassDB::bind_method(D_METHOD("get_octree_cells"), &VoxelGIData::get_octree_cells); + ClassDB::bind_method(D_METHOD("get_data_cells"), &VoxelGIData::get_data_cells); + ClassDB::bind_method(D_METHOD("get_level_counts"), &VoxelGIData::get_level_counts); - ClassDB::bind_method(D_METHOD("set_normal_bias", "bias"), &GIProbeData::set_normal_bias); - ClassDB::bind_method(D_METHOD("get_normal_bias"), &GIProbeData::get_normal_bias); + ClassDB::bind_method(D_METHOD("set_dynamic_range", "dynamic_range"), &VoxelGIData::set_dynamic_range); + ClassDB::bind_method(D_METHOD("get_dynamic_range"), &VoxelGIData::get_dynamic_range); - ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &GIProbeData::set_propagation); - ClassDB::bind_method(D_METHOD("get_propagation"), &GIProbeData::get_propagation); + ClassDB::bind_method(D_METHOD("set_energy", "energy"), &VoxelGIData::set_energy); + ClassDB::bind_method(D_METHOD("get_energy"), &VoxelGIData::get_energy); - ClassDB::bind_method(D_METHOD("set_anisotropy_strength", "strength"), &GIProbeData::set_anisotropy_strength); - ClassDB::bind_method(D_METHOD("get_anisotropy_strength"), &GIProbeData::get_anisotropy_strength); + ClassDB::bind_method(D_METHOD("set_bias", "bias"), &VoxelGIData::set_bias); + ClassDB::bind_method(D_METHOD("get_bias"), &VoxelGIData::get_bias); - ClassDB::bind_method(D_METHOD("set_ao", "ao"), &GIProbeData::set_ao); - ClassDB::bind_method(D_METHOD("get_ao"), &GIProbeData::get_ao); + ClassDB::bind_method(D_METHOD("set_normal_bias", "bias"), &VoxelGIData::set_normal_bias); + ClassDB::bind_method(D_METHOD("get_normal_bias"), &VoxelGIData::get_normal_bias); - ClassDB::bind_method(D_METHOD("set_ao_size", "strength"), &GIProbeData::set_ao_size); - ClassDB::bind_method(D_METHOD("get_ao_size"), &GIProbeData::get_ao_size); + ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &VoxelGIData::set_propagation); + ClassDB::bind_method(D_METHOD("get_propagation"), &VoxelGIData::get_propagation); - ClassDB::bind_method(D_METHOD("set_interior", "interior"), &GIProbeData::set_interior); - ClassDB::bind_method(D_METHOD("is_interior"), &GIProbeData::is_interior); + ClassDB::bind_method(D_METHOD("set_interior", "interior"), &VoxelGIData::set_interior); + ClassDB::bind_method(D_METHOD("is_interior"), &VoxelGIData::is_interior); - ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &GIProbeData::set_use_two_bounces); - ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &GIProbeData::is_using_two_bounces); + ClassDB::bind_method(D_METHOD("set_use_two_bounces", "enable"), &VoxelGIData::set_use_two_bounces); + ClassDB::bind_method(D_METHOD("is_using_two_bounces"), &VoxelGIData::is_using_two_bounces); - ClassDB::bind_method(D_METHOD("_set_data", "data"), &GIProbeData::_set_data); - ClassDB::bind_method(D_METHOD("_get_data"), &GIProbeData::_get_data); + ClassDB::bind_method(D_METHOD("_set_data", "data"), &VoxelGIData::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &VoxelGIData::_get_data); ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); @@ -278,25 +233,22 @@ void GIProbeData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_bias", "get_bias"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "normal_bias", PROPERTY_HINT_RANGE, "0,8,0.01"), "set_normal_bias", "get_normal_bias"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "anisotropy_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_anisotropy_strength", "get_anisotropy_strength"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao", "get_ao"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ao_size", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ao_size", "get_ao_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_two_bounces"), "set_use_two_bounces", "is_using_two_bounces"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior"); } -GIProbeData::GIProbeData() { - probe = RS::get_singleton()->gi_probe_create(); +VoxelGIData::VoxelGIData() { + probe = RS::get_singleton()->voxel_gi_create(); } -GIProbeData::~GIProbeData() { +VoxelGIData::~VoxelGIData() { RS::get_singleton()->free(probe); } ////////////////////// ////////////////////// -void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) { +void VoxelGI::set_probe_data(const Ref<VoxelGIData> &p_data) { if (p_data.is_valid()) { RS::get_singleton()->instance_set_base(get_instance(), p_data->get_rid()); } else { @@ -306,37 +258,37 @@ void GIProbe::set_probe_data(const Ref<GIProbeData> &p_data) { probe_data = p_data; } -Ref<GIProbeData> GIProbe::get_probe_data() const { +Ref<VoxelGIData> VoxelGI::get_probe_data() const { return probe_data; } -void GIProbe::set_subdiv(Subdiv p_subdiv) { +void VoxelGI::set_subdiv(Subdiv p_subdiv) { ERR_FAIL_INDEX(p_subdiv, SUBDIV_MAX); subdiv = p_subdiv; update_gizmo(); } -GIProbe::Subdiv GIProbe::get_subdiv() const { +VoxelGI::Subdiv VoxelGI::get_subdiv() const { return subdiv; } -void GIProbe::set_extents(const Vector3 &p_extents) { +void VoxelGI::set_extents(const Vector3 &p_extents) { extents = p_extents; update_gizmo(); } -Vector3 GIProbe::get_extents() const { +Vector3 VoxelGI::get_extents() const { return extents; } -void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { +void VoxelGI::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_at_node); if (mi && mi->get_gi_mode() == GeometryInstance3D::GI_MODE_BAKED && mi->is_visible_in_tree()) { Ref<Mesh> mesh = mi->get_mesh(); if (mesh.is_valid()) { AABB aabb = mesh->get_aabb(); - Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform(); + Transform3D xf = get_global_transform().affine_inverse() * mi->get_global_transform(); if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) { PlotMesh pm; @@ -356,7 +308,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { if (s->is_visible_in_tree()) { Array meshes = p_at_node->call("get_meshes"); for (int i = 0; i < meshes.size(); i += 2) { - Transform mxf = meshes[i]; + Transform3D mxf = meshes[i]; Ref<Mesh> mesh = meshes[i + 1]; if (!mesh.is_valid()) { continue; @@ -364,7 +316,7 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { AABB aabb = mesh->get_aabb(); - Transform xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf); + Transform3D xf = get_global_transform().affine_inverse() * (s->get_global_transform() * mxf); if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) { PlotMesh pm; @@ -382,11 +334,11 @@ void GIProbe::_find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes) { } } -GIProbe::BakeBeginFunc GIProbe::bake_begin_function = nullptr; -GIProbe::BakeStepFunc GIProbe::bake_step_function = nullptr; -GIProbe::BakeEndFunc GIProbe::bake_end_function = nullptr; +VoxelGI::BakeBeginFunc VoxelGI::bake_begin_function = nullptr; +VoxelGI::BakeStepFunc VoxelGI::bake_step_function = nullptr; +VoxelGI::BakeEndFunc VoxelGI::bake_end_function = nullptr; -Vector3i GIProbe::get_estimated_cell_size() const { +Vector3i VoxelGI::get_estimated_cell_size() const { static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; int cell_subdiv = subdiv_value[subdiv]; int axis_cell_size[3]; @@ -412,7 +364,7 @@ Vector3i GIProbe::get_estimated_cell_size() const { return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]); } -void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { +void VoxelGI::bake(Node *p_from_node, bool p_create_visual_debug) { static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; p_from_node = p_from_node ? p_from_node : get_parent(); @@ -464,10 +416,10 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { #endif } else { - Ref<GIProbeData> probe_data = get_probe_data(); + Ref<VoxelGIData> probe_data = get_probe_data(); if (probe_data.is_null()) { - probe_data.instance(); + probe_data.instantiate(); } if (bake_step_function) { @@ -476,7 +428,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { Vector<uint8_t> df = baker.get_sdf_3d_image(); - probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_giprobe_octree_size(), baker.get_giprobe_octree_cells(), baker.get_giprobe_data_cells(), df, baker.get_giprobe_level_cell_count()); + probe_data->allocate(baker.get_to_cell_space_xform(), AABB(-extents, extents * 2.0), baker.get_voxel_gi_octree_size(), baker.get_voxel_gi_octree_cells(), baker.get_voxel_gi_data_cells(), df, baker.get_voxel_gi_level_cell_count()); set_probe_data(probe_data); #ifdef TOOLS_ENABLED @@ -491,46 +443,46 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { notify_property_list_changed(); //bake property may have changed } -void GIProbe::_debug_bake() { +void VoxelGI::_debug_bake() { bake(nullptr, true); } -AABB GIProbe::get_aabb() const { +AABB VoxelGI::get_aabb() const { return AABB(-extents, extents * 2); } -Vector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const { +Vector<Face3> VoxelGI::get_faces(uint32_t p_usage_flags) const { return Vector<Face3>(); } -TypedArray<String> GIProbe::get_configuration_warnings() const { +TypedArray<String> VoxelGI::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); if (RenderingServer::get_singleton()->is_low_end()) { - warnings.push_back(TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead.")); + warnings.push_back(TTR("VoxelGIs are not supported by the GLES2 video driver.\nUse a LightmapGI instead.")); } else if (probe_data.is_null()) { - warnings.push_back(TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI.")); + warnings.push_back(TTR("No VoxelGI data set, so this node is disabled. Bake static objects to enable GI.")); } return warnings; } -void GIProbe::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &GIProbe::set_probe_data); - ClassDB::bind_method(D_METHOD("get_probe_data"), &GIProbe::get_probe_data); +void VoxelGI::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_probe_data", "data"), &VoxelGI::set_probe_data); + ClassDB::bind_method(D_METHOD("get_probe_data"), &VoxelGI::get_probe_data); - ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &GIProbe::set_subdiv); - ClassDB::bind_method(D_METHOD("get_subdiv"), &GIProbe::get_subdiv); + ClassDB::bind_method(D_METHOD("set_subdiv", "subdiv"), &VoxelGI::set_subdiv); + ClassDB::bind_method(D_METHOD("get_subdiv"), &VoxelGI::get_subdiv); - ClassDB::bind_method(D_METHOD("set_extents", "extents"), &GIProbe::set_extents); - ClassDB::bind_method(D_METHOD("get_extents"), &GIProbe::get_extents); + ClassDB::bind_method(D_METHOD("set_extents", "extents"), &VoxelGI::set_extents); + ClassDB::bind_method(D_METHOD("get_extents"), &VoxelGI::get_extents); - ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &GIProbe::bake, DEFVAL(Variant()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("debug_bake"), &GIProbe::_debug_bake); + ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &VoxelGI::bake, DEFVAL(Variant()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("debug_bake"), &VoxelGI::_debug_bake); ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdiv", PROPERTY_HINT_ENUM, "64,128,256,512"), "set_subdiv", "get_subdiv"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "VoxelGIData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data"); BIND_ENUM_CONSTANT(SUBDIV_64); BIND_ENUM_CONSTANT(SUBDIV_128); @@ -539,11 +491,11 @@ void GIProbe::_bind_methods() { BIND_ENUM_CONSTANT(SUBDIV_MAX); } -GIProbe::GIProbe() { - gi_probe = RS::get_singleton()->gi_probe_create(); +VoxelGI::VoxelGI() { + voxel_gi = RS::get_singleton()->voxel_gi_create(); set_disable_scale(true); } -GIProbe::~GIProbe() { - RS::get_singleton()->free(gi_probe); +VoxelGI::~VoxelGI() { + RS::get_singleton()->free(voxel_gi); } diff --git a/scene/3d/gi_probe.h b/scene/3d/voxel_gi.h index dac7dd3e17..434d209421 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/voxel_gi.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* gi_probe.h */ +/* voxel_gi.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,21 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef GIPROBE_H -#define GIPROBE_H +#ifndef VOXEL_GI_H +#define VOXEL_GI_H #include "multimesh_instance_3d.h" #include "scene/3d/visual_instance_3d.h" -class GIProbeData : public Resource { - GDCLASS(GIProbeData, Resource); +class VoxelGIData : public Resource { + GDCLASS(VoxelGIData, Resource); RID probe; void _set_data(const Dictionary &p_data); Dictionary _get_data() const; - Transform to_cell_xform; + Transform3D to_cell_xform; AABB bounds; Vector3 octree_size; @@ -51,25 +51,21 @@ class GIProbeData : public Resource { float bias = 1.5; float normal_bias = 0.0; float propagation = 0.7; - float anisotropy_strength = 0.5; - float ao = 0.0; - float ao_size = 0.5; bool interior = false; bool use_two_bounces = false; protected: static void _bind_methods(); - void _validate_property(PropertyInfo &property) const override; public: - void allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); + void allocate(const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); AABB get_bounds() const; Vector3 get_octree_size() const; Vector<uint8_t> get_octree_cells() const; Vector<uint8_t> get_data_cells() const; Vector<uint8_t> get_distance_field() const; Vector<int> get_level_counts() const; - Transform get_to_cell_xform() const; + Transform3D get_to_cell_xform() const; void set_dynamic_range(float p_range); float get_dynamic_range() const; @@ -77,15 +73,6 @@ public: void set_propagation(float p_propagation); float get_propagation() const; - void set_anisotropy_strength(float p_anisotropy_strength); - float get_anisotropy_strength() const; - - void set_ao(float p_ao); - float get_ao() const; - - void set_ao_size(float p_ao_size); - float get_ao_size() const; - void set_energy(float p_energy); float get_energy() const; @@ -103,12 +90,12 @@ public: virtual RID get_rid() const override; - GIProbeData(); - ~GIProbeData(); + VoxelGIData(); + ~VoxelGIData(); }; -class GIProbe : public VisualInstance3D { - GDCLASS(GIProbe, VisualInstance3D); +class VoxelGI : public VisualInstance3D { + GDCLASS(VoxelGI, VisualInstance3D); public: enum Subdiv { @@ -125,9 +112,9 @@ public: typedef void (*BakeEndFunc)(); private: - Ref<GIProbeData> probe_data; + Ref<VoxelGIData> probe_data; - RID gi_probe; + RID voxel_gi; Subdiv subdiv = SUBDIV_128; Vector3 extents = Vector3(10, 10, 10); @@ -136,7 +123,7 @@ private: Ref<Material> override_material; Vector<Ref<Material>> instance_materials; Ref<Mesh> mesh; - Transform local_xform; + Transform3D local_xform; }; void _find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes); @@ -150,8 +137,8 @@ public: static BakeStepFunc bake_step_function; static BakeEndFunc bake_end_function; - void set_probe_data(const Ref<GIProbeData> &p_data); - Ref<GIProbeData> get_probe_data() const; + void set_probe_data(const Ref<VoxelGIData> &p_data); + Ref<VoxelGIData> get_probe_data() const; void set_subdiv(Subdiv p_subdiv); Subdiv get_subdiv() const; @@ -167,10 +154,10 @@ public: TypedArray<String> get_configuration_warnings() const override; - GIProbe(); - ~GIProbe(); + VoxelGI(); + ~VoxelGI(); }; -VARIANT_ENUM_CAST(GIProbe::Subdiv) +VARIANT_ENUM_CAST(VoxelGI::Subdiv) -#endif // GIPROBE_H +#endif // VOXEL_GI_H diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index 1b9ce0201f..12f055c01d 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -378,7 +378,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material return mc; } -void Voxelizer::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) { +void Voxelizer::plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material) { for (int i = 0; i < p_mesh->get_surface_count(); i++) { if (p_mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) { continue; //only triangles @@ -647,11 +647,11 @@ void Voxelizer::begin_bake(int p_subdiv, const AABB &p_bounds) { po2_bounds.size[i] = po2_bounds.size[longest_axis]; } - Transform to_bounds; + Transform3D to_bounds; to_bounds.basis.scale(Vector3(po2_bounds.size[longest_axis], po2_bounds.size[longest_axis], po2_bounds.size[longest_axis])); to_bounds.origin = po2_bounds.position; - Transform to_grid; + Transform3D to_grid; to_grid.basis.scale(Vector3(axis_cell_size[longest_axis], axis_cell_size[longest_axis], axis_cell_size[longest_axis])); to_cell_space = to_grid * to_bounds.affine_inverse(); @@ -668,19 +668,19 @@ void Voxelizer::end_bake() { //create the data for visual server -int Voxelizer::get_gi_probe_octree_depth() const { +int Voxelizer::get_voxel_gi_octree_depth() const { return cell_subdiv; } -Vector3i Voxelizer::get_giprobe_octree_size() const { +Vector3i Voxelizer::get_voxel_gi_octree_size() const { return Vector3i(axis_cell_size[0], axis_cell_size[1], axis_cell_size[2]); } -int Voxelizer::get_giprobe_cell_count() const { +int Voxelizer::get_voxel_gi_cell_count() const { return bake_cells.size(); } -Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const { +Vector<uint8_t> Voxelizer::get_voxel_gi_octree_cells() const { Vector<uint8_t> data; data.resize((8 * 4) * bake_cells.size()); //8 uint32t values { @@ -700,7 +700,7 @@ Vector<uint8_t> Voxelizer::get_giprobe_octree_cells() const { return data; } -Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const { +Vector<uint8_t> Voxelizer::get_voxel_gi_data_cells() const { Vector<uint8_t> data; data.resize((4 * 4) * bake_cells.size()); //8 uint32t values { @@ -755,7 +755,7 @@ Vector<uint8_t> Voxelizer::get_giprobe_data_cells() const { return data; } -Vector<int> Voxelizer::get_giprobe_level_cell_count() const { +Vector<int> Voxelizer::get_voxel_gi_level_cell_count() const { uint32_t cell_count = bake_cells.size(); const Cell *cells = bake_cells.ptr(); Vector<int> level_count; @@ -819,7 +819,7 @@ static void edt(float *f, int stride, int n) { #undef square Vector<uint8_t> Voxelizer::get_sdf_3d_image() const { - Vector3i octree_size = get_giprobe_octree_size(); + Vector3i octree_size = get_voxel_gi_octree_size(); uint32_t float_count = octree_size.x * octree_size.y * octree_size.z; float *work_memory = memnew_arr(float, float_count); @@ -891,7 +891,7 @@ Vector<uint8_t> Voxelizer::get_sdf_3d_image() const { void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx) { if (p_level == cell_subdiv - 1) { Vector3 center = p_aabb.position + p_aabb.size * 0.5; - Transform xform; + Transform3D xform; xform.origin = center; xform.basis.scale(p_aabb.size * 0.5); p_multimesh->set_instance_transform(idx, xform); @@ -931,14 +931,14 @@ void Voxelizer::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<Mult Ref<MultiMesh> Voxelizer::create_debug_multimesh() { Ref<MultiMesh> mm; - mm.instance(); + mm.instantiate(); mm->set_transform_format(MultiMesh::TRANSFORM_3D); mm->set_use_colors(true); mm->set_instance_count(leaf_voxel_count); Ref<ArrayMesh> mesh; - mesh.instance(); + mesh.instantiate(); { Array arr; @@ -985,7 +985,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() { { Ref<StandardMaterial3D> fsm; - fsm.instance(); + fsm.instantiate(); fsm->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true); fsm->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); fsm->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); @@ -1002,7 +1002,7 @@ Ref<MultiMesh> Voxelizer::create_debug_multimesh() { return mm; } -Transform Voxelizer::get_to_cell_space_xform() const { +Transform3D Voxelizer::get_to_cell_space_xform() const { return to_cell_space; } diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 87f949e7db..e500d2d4c3 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -93,7 +93,7 @@ private: AABB po2_bounds; int axis_cell_size[3] = {}; - Transform to_cell_space; + Transform3D to_cell_space; int color_scan_cell_width = 4; int bake_texture_size = 128; @@ -114,20 +114,20 @@ private: public: void begin_bake(int p_subdiv, const AABB &p_bounds); - void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material); + void plot_mesh(const Transform3D &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material>> &p_materials, const Ref<Material> &p_override_material); void end_bake(); - int get_gi_probe_octree_depth() const; - Vector3i get_giprobe_octree_size() const; - int get_giprobe_cell_count() const; - Vector<uint8_t> get_giprobe_octree_cells() const; - Vector<uint8_t> get_giprobe_data_cells() const; - Vector<int> get_giprobe_level_cell_count() const; + int get_voxel_gi_octree_depth() const; + Vector3i get_voxel_gi_octree_size() const; + int get_voxel_gi_cell_count() const; + Vector<uint8_t> get_voxel_gi_octree_cells() const; + Vector<uint8_t> get_voxel_gi_data_cells() const; + Vector<int> get_voxel_gi_level_cell_count() const; Vector<uint8_t> get_sdf_3d_image() const; Ref<MultiMesh> create_debug_multimesh(); - Transform get_to_cell_space_xform() const; + Transform3D get_to_cell_space_xform() const; Voxelizer(); }; diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 829ecc5ec2..352bef072f 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -145,7 +145,7 @@ TypedArray<String> WorldEnvironment::get_configuration_warnings() const { } if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) { - warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).")); + warnings.push_back(TTR("Only one WorldEnvironment is allowed per scene (or set of instantiated scenes).")); } return warnings; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index b5037f9be7..a91e712b0b 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -86,7 +86,8 @@ Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const { Vector2 cpos = get_viewport()->get_camera_coords(p_pos); Vector3 ray; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); + // Just use the first view, if multiple views are supported this function has no good result + CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far()); Vector2 screen_he = cm.get_viewport_half_extents(); ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_near()).normalized(); @@ -108,7 +109,8 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const { Size2 viewport_size = get_viewport()->get_visible_rect().size; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); + // Just use the first view, if multiple views are supported this function has no good result + CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far()); Plane p(get_camera_transform().xform_inv(p_pos), 1.0); @@ -137,7 +139,8 @@ Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) con Size2 viewport_size = get_viewport()->get_visible_rect().size; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); + // Just use the first view, if multiple views are supported this function has no good result + CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far()); Vector2 vp_he = cm.get_viewport_half_extents(); @@ -165,7 +168,8 @@ Vector<Plane> XRCamera3D::get_frustum() const { ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>()); Size2 viewport_size = get_viewport()->get_visible_rect().size; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); + // TODO Just use the first view for now, this is mostly for debugging so we may look into using our combined projection here. + CameraMatrix cm = xr_interface->get_projection_for_view(0, viewport_size.aspect(), get_near(), get_far()); return cm.get_projection_planes(get_camera_transform()); }; @@ -200,7 +204,7 @@ void XRController3D::_notification(int p_what) { // check button states for (int i = 0; i < 16; i++) { bool was_pressed = (button_states & mask) == mask; - bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, i); + bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)i); if (!was_pressed && is_pressed) { emit_signal("button_pressed", i); @@ -300,7 +304,7 @@ bool XRController3D::is_button_pressed(int p_button) const { return false; }; - return Input::get_singleton()->is_joy_button_pressed(joy_id, p_button); + return Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)p_button); }; float XRController3D::get_joystick_axis(int p_axis) const { @@ -309,7 +313,7 @@ float XRController3D::get_joystick_axis(int p_axis) const { return 0.0; }; - return Input::get_singleton()->get_joy_axis(joy_id, p_axis); + return Input::get_singleton()->get_joy_axis(joy_id, (JoyAxis)p_axis); }; real_t XRController3D::get_rumble() const { @@ -397,7 +401,7 @@ void XRAnchor3D::_notification(int p_what) { is_active = false; } else { is_active = true; - Transform transform; + Transform3D transform; // we'll need our world_scale real_t world_scale = xr_server->get_world_scale(); @@ -493,7 +497,7 @@ TypedArray<String> XRAnchor3D::get_configuration_warnings() const { }; Plane XRAnchor3D::get_plane() const { - Vector3 location = get_translation(); + Vector3 location = get_position(); Basis orientation = get_transform().basis; Plane plane(location, orientation.get_axis(1).normalized()); @@ -516,6 +520,11 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const { } } + bool xr_enabled = GLOBAL_GET("rendering/xr/enabled"); + if (!xr_enabled) { + warnings.push_back(TTR("XR is not enabled in rendering project settings. Stereoscopic output is not supported unless this is enabled.")); + } + return warnings; }; @@ -571,7 +580,7 @@ void XROrigin3D::_notification(int p_what) { Ref<XRInterface> xr_interface = xr_server->get_primary_interface(); if (xr_interface.is_valid() && tracked_camera != nullptr) { // get our positioning transform for our headset - Transform t = xr_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform()); + Transform3D t = xr_interface->get_camera_transform(); // now apply this to our camera tracked_camera->set_transform(t); diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index 15f562242f..3818c7edd1 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -47,7 +47,7 @@ void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const String left = property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); if (idx >= blend_points_used) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } AnimationRootNode::_validate_property(property); diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 9c4bc107dd..935ec457aa 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -34,8 +34,8 @@ void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const { r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position)); - r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", 0)); + r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const { @@ -556,13 +556,13 @@ String AnimationNodeBlendSpace2D::get_caption() const { void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const { if (auto_triangles && property.name == "triangles") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("blend_point_")) { String left = property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); if (idx >= blend_points_used) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } AnimationRootNode::_validate_property(property); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 79a1dc1ac0..6a988042b5 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -43,7 +43,7 @@ StringName AnimationNodeAnimation::get_animation() const { Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr; void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const { - r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", 0)); + r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { @@ -130,10 +130,10 @@ AnimationNodeAnimation::AnimationNodeAnimation() { void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const { r_list->push_back(PropertyInfo(Variant::BOOL, active)); - r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", 0)); + r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const { @@ -607,10 +607,10 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con } r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims)); - r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", 0)); - r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", 0)); + r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const { @@ -752,7 +752,7 @@ void AnimationNodeTransition::_validate_property(PropertyInfo &property) const { if (n != "count") { int idx = n.to_int(); if (idx >= enabled_inputs) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -1164,7 +1164,7 @@ void AnimationNodeBlendTree::_bind_methods() { AnimationNodeBlendTree::AnimationNodeBlendTree() { Ref<AnimationNodeOutput> output; - output.instance(); + output.instantiate(); Node n; n.node = output; n.position = Vector2(300, 150); diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index 689acdd57b..b8980fd56b 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -80,10 +80,11 @@ void AnimationCache::_update_cache() { Ref<Resource> res; - if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM) { + if (animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D) { +#ifndef _3D_DISABLED if (np.get_subname_count() > 1) { path_cache.push_back(Path()); - ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM, "Transform tracks can't have a subpath '" + np + "'."); + ERR_CONTINUE_MSG(animation->track_get_type(i) == Animation::TYPE_TRANSFORM3D, "Transform tracks can't have a subpath '" + np + "'."); } Node3D *sp = Object::cast_to<Node3D>(node); @@ -113,8 +114,8 @@ void AnimationCache::_update_cache() { path.skeleton = sk; } - path.spatial = sp; - + path.node_3d = sp; +#endif // _3D_DISABLED } else { if (np.get_subname_count() > 0) { RES res2; @@ -167,7 +168,7 @@ void AnimationCache::_update_cache() { cache_valid = true; } -void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform) { +void AnimationCache::set_track_transform(int p_idx, const Transform3D &p_transform) { if (cache_dirty) { _update_cache(); } @@ -179,14 +180,16 @@ void AnimationCache::set_track_transform(int p_idx, const Transform &p_transform return; } +#ifndef _3D_DISABLED ERR_FAIL_COND(!p.node); - ERR_FAIL_COND(!p.spatial); + ERR_FAIL_COND(!p.node_3d); if (p.skeleton) { p.skeleton->set_bone_pose(p.bone_idx, p_transform); } else { - p.spatial->set_transform(p_transform); + p.node_3d->set_transform(p_transform); } +#endif // _3D_DISABLED } void AnimationCache::set_track_value(int p_idx, const Variant &p_value) { @@ -231,11 +234,11 @@ void AnimationCache::set_all(float p_time, float p_delta) { int tc = animation->get_track_count(); for (int i = 0; i < tc; i++) { switch (animation->track_get_type(i)) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { Vector3 loc, scale; - Quat rot; + Quaternion rot; animation->transform_track_interpolate(i, p_time, &loc, &rot, &scale); - Transform tr(Basis(rot), loc); + Transform3D tr(Basis(rot), loc); tr.basis.scale(scale); set_track_transform(i, tr); diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h index 07c9d09ae0..c856e644f7 100644 --- a/scene/animation/animation_cache.h +++ b/scene/animation/animation_cache.h @@ -40,9 +40,11 @@ class AnimationCache : public Object { struct Path { RES resource; Object *object = nullptr; - Skeleton3D *skeleton = nullptr; // haxor +#ifndef _3D_DISABLED + Skeleton3D *skeleton = nullptr; + Node3D *node_3d = nullptr; +#endif // _3D_DISABLED Node *node = nullptr; - Node3D *spatial = nullptr; int bone_idx = -1; Vector<StringName> subpath; @@ -67,7 +69,7 @@ protected: static void _bind_methods(); public: - void set_track_transform(int p_idx, const Transform &p_transform); + void set_track_transform(int p_idx, const Transform3D &p_transform); void set_track_value(int p_idx, const Variant &p_value); void call_track(int p_idx, const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 65918a2989..f494f5c163 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -496,7 +496,7 @@ void AnimationNodeStateMachinePlayback::_bind_methods() { } AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() { - set_local_to_scene(true); //only one per instanced scene + set_local_to_scene(true); //only one per instantiated scene } /////////////////////////////////////////////////////// @@ -520,7 +520,7 @@ void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) c Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const { if (p_parameter == playback) { Ref<AnimationNodeStateMachinePlayback> p; - p.instance(); + p.instantiate(); return p; } else { return false; //advance condition diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 0c1798a876..6154eef3cf 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -252,6 +252,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov ObjectID id = resource.is_valid() ? resource->get_instance_id() : child->get_instance_id(); int bone_idx = -1; +#ifndef _3D_DISABLED if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton3D>(child)) { Skeleton3D *sk = Object::cast_to<Skeleton3D>(child); bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0)); @@ -259,6 +260,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov continue; } } +#endif // _3D_DISABLED { if (!child->is_connected("tree_exiting", callable_mp(this, &AnimationPlayer::_node_removed))) { @@ -279,11 +281,12 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov p_anim->node_cache[i]->node = child; p_anim->node_cache[i]->resource = resource; p_anim->node_cache[i]->node_2d = Object::cast_to<Node2D>(child); - if (a->track_get_type(i) == Animation::TYPE_TRANSFORM) { +#ifndef _3D_DISABLED + if (a->track_get_type(i) == Animation::TYPE_TRANSFORM3D) { // special cases and caches for transform tracks - // cache spatial - p_anim->node_cache[i]->spatial = Object::cast_to<Node3D>(child); + // cache node_3d + p_anim->node_cache[i]->node_3d = Object::cast_to<Node3D>(child); // cache skeleton p_anim->node_cache[i]->skeleton = Object::cast_to<Skeleton3D>(child); if (p_anim->node_cache[i]->skeleton) { @@ -294,7 +297,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov if (p_anim->node_cache[i]->bone_idx < 0) { // broken track (nonexistent bone) p_anim->node_cache[i]->skeleton = nullptr; - p_anim->node_cache[i]->spatial = nullptr; + p_anim->node_cache[i]->node_3d = nullptr; ERR_CONTINUE(p_anim->node_cache[i]->bone_idx < 0); } } else { @@ -303,6 +306,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov } } } +#endif // _3D_DISABLED if (a->track_get_type(i) == Animation::TYPE_VALUE) { if (!p_anim->node_cache[i]->property_anim.has(a->track_get_path(i).get_concatenated_subnames())) { @@ -366,13 +370,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float } switch (a->track_get_type(i)) { - case Animation::TYPE_TRANSFORM: { - if (!nc->spatial) { + case Animation::TYPE_TRANSFORM3D: { +#ifndef _3D_DISABLED + if (!nc->node_3d) { continue; } Vector3 loc; - Quat rot; + Quaternion rot; Vector3 scale; Error err = a->transform_track_interpolate(i, p_time, &loc, &rot, &scale); @@ -395,7 +400,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float nc->rot_accum = nc->rot_accum.slerp(rot, p_interp); nc->scale_accum = nc->scale_accum.lerp(scale, p_interp); } - +#endif // _3D_DISABLED } break; case Animation::TYPE_VALUE: { if (!nc->node) { @@ -508,7 +513,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float } #endif - static_cast<Node2D *>(pa->object)->set_rotation(Math::deg2rad((double)value)); + static_cast<Node2D *>(pa->object)->set_rotation((double)value); } break; case SP_NODE2D_SCALE: { #ifdef DEBUG_ENABLED @@ -838,20 +843,21 @@ void AnimationPlayer::_animation_process2(float p_delta, bool p_started) { void AnimationPlayer::_animation_update_transforms() { { - Transform t; + Transform3D t; for (int i = 0; i < cache_update_size; i++) { TrackNodeCache *nc = cache_update[i]; ERR_CONTINUE(nc->accum_pass != accum_pass); t.origin = nc->loc_accum; - t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum); + t.basis.set_quaternion_scale(nc->rot_accum, nc->scale_accum); +#ifndef _3D_DISABLED if (nc->skeleton && nc->bone_idx >= 0) { nc->skeleton->set_bone_pose(nc->bone_idx, t); - - } else if (nc->spatial) { - nc->spatial->set_transform(t); + } else if (nc->node_3d) { + nc->node_3d->set_transform(t); } +#endif // _3D_DISABLED } } @@ -1505,7 +1511,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o _ensure_node_caches(playback.current.from, p_root_override); - backup.instance(); + backup.instantiate(); for (int i = 0; i < playback.current.from->node_cache.size(); i++) { TrackNodeCache *nc = playback.current.from->node_cache[i]; if (!nc) { @@ -1523,11 +1529,11 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o entry.value = nc->skeleton->get_bone_pose(nc->bone_idx); backup->entries.push_back(entry); } else { - if (nc->spatial) { + if (nc->node_3d) { AnimatedValuesBackup::Entry entry; - entry.object = nc->spatial; + entry.object = nc->node_3d; entry.subpath.push_back("transform"); - entry.value = nc->spatial->get_transform(); + entry.value = nc->node_3d->get_transform(); entry.bone_idx = -1; backup->entries.push_back(entry); } else { @@ -1651,16 +1657,16 @@ void AnimationPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "current_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ANIMATE_AS_TRIGGER), "set_current_animation", "get_current_animation"); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "assigned_animation", PROPERTY_HINT_NONE, "", 0), "set_assigned_animation", "get_assigned_animation"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "assigned_animation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_assigned_animation", "get_assigned_animation"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "autoplay", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_autoplay", "get_autoplay"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_on_save", PROPERTY_HINT_NONE, ""), "set_reset_on_save_enabled", "is_reset_on_save_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_length", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_length"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_current_animation_length"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_current_animation_position"); ADD_GROUP("Playback Options", "playback_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); ADD_PROPERTY(PropertyInfo(Variant::INT, "method_call_mode", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_method_call_mode", "get_method_call_mode"); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 2a1821c215..7cd9de1fa1 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -37,8 +37,8 @@ #include "scene/resources/animation.h" #ifdef TOOLS_ENABLED -class AnimatedValuesBackup : public Reference { - GDCLASS(AnimatedValuesBackup, Reference); +class AnimatedValuesBackup : public RefCounted { + GDCLASS(AnimatedValuesBackup, RefCounted); struct Entry { Object *object = nullptr; @@ -93,14 +93,16 @@ private: uint32_t id = 0; RES resource; Node *node = nullptr; - Node3D *spatial = nullptr; Node2D *node_2d = nullptr; +#ifndef _3D_DISABLED + Node3D *node_3d = nullptr; Skeleton3D *skeleton = nullptr; +#endif // _3D_DISABLED int bone_idx = -1; // accumulated transforms Vector3 loc_accum; - Quat rot_accum; + Quaternion rot_accum; Vector3 scale_accum; uint64_t accum_pass = 0; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 2ad871ba61..1e07f83d09 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -37,7 +37,7 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { if (get_script_instance()) { - Array parameters = get_script_instance()->call("get_parameter_list"); + Array parameters = get_script_instance()->call("_get_parameter_list"); for (int i = 0; i < parameters.size(); i++) { Dictionary d = parameters[i]; ERR_CONTINUE(d.is_empty()); @@ -48,7 +48,7 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const { if (get_script_instance()) { - return get_script_instance()->call("get_parameter_default_value", p_parameter); + return get_script_instance()->call("_get_parameter_default_value", p_parameter); } return Variant(); } @@ -73,7 +73,7 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const { void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { if (get_script_instance()) { - Dictionary cn = get_script_instance()->call("get_child_nodes"); + Dictionary cn = get_script_instance()->call("_get_child_nodes"); List<Variant> keys; cn.get_key_list(&keys); for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { @@ -299,7 +299,7 @@ String AnimationNode::get_input_name(int p_input) { String AnimationNode::get_caption() const { if (get_script_instance()) { - return get_script_instance()->call("get_caption"); + return get_script_instance()->call("_get_caption"); } return "Node"; @@ -330,7 +330,7 @@ void AnimationNode::remove_input(int p_index) { float AnimationNode::process(float p_time, bool p_seek) { if (get_script_instance()) { - return get_script_instance()->call("process", p_time, p_seek); + return get_script_instance()->call("_process", p_time, p_seek); } return 0; @@ -357,6 +357,10 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const { } bool AnimationNode::has_filter() const { + if (get_script_instance()) { + return get_script_instance()->call("_has_filter"); + } + return false; } @@ -381,13 +385,13 @@ void AnimationNode::_set_filters(const Array &p_filters) { void AnimationNode::_validate_property(PropertyInfo &property) const { if (!has_filter() && (property.name == "filter_enabled" || property.name == "filters")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) { if (get_script_instance()) { - return get_script_instance()->call("get_child_by_name", p_name); + return get_script_instance()->call("_get_child_by_name", p_name); } return Ref<AnimationNode>(); } @@ -418,17 +422,17 @@ void AnimationNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters"); - BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "get_child_nodes")); - BIND_VMETHOD(MethodInfo(Variant::ARRAY, "get_parameter_list")); - BIND_VMETHOD(MethodInfo(Variant::OBJECT, "get_child_by_name", PropertyInfo(Variant::STRING, "name"))); + BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_child_nodes")); + BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_parameter_list")); + BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_get_child_by_name", PropertyInfo(Variant::STRING, "name"))); { - MethodInfo mi = MethodInfo(Variant::NIL, "get_parameter_default_value", PropertyInfo(Variant::STRING_NAME, "name")); + MethodInfo mi = MethodInfo(Variant::NIL, "_get_parameter_default_value", PropertyInfo(Variant::STRING_NAME, "name")); mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT; BIND_VMETHOD(mi); } - BIND_VMETHOD(MethodInfo("process", PropertyInfo(Variant::FLOAT, "time"), PropertyInfo(Variant::BOOL, "seek"))); - BIND_VMETHOD(MethodInfo(Variant::STRING, "get_caption")); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_filter")); + BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "time"), PropertyInfo(Variant::BOOL, "seek"))); + BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_caption")); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_filter")); ADD_SIGNAL(MethodInfo("removed_from_graph")); @@ -581,22 +585,23 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { track = track_value; } break; - case Animation::TYPE_TRANSFORM: { - Node3D *spatial = Object::cast_to<Node3D>(child); + case Animation::TYPE_TRANSFORM3D: { +#ifndef _3D_DISABLED + Node3D *node_3d = Object::cast_to<Node3D>(child); - if (!spatial) { - ERR_PRINT("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'"); + if (!node_3d) { + ERR_PRINT("AnimationTree: '" + String(E->get()) + "', transform track does not point to Node3D: '" + String(path) + "'"); continue; } TrackCacheTransform *track_xform = memnew(TrackCacheTransform); - track_xform->spatial = spatial; + track_xform->node_3d = node_3d; track_xform->skeleton = nullptr; track_xform->bone_idx = -1; - if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(spatial)) { - Skeleton3D *sk = Object::cast_to<Skeleton3D>(spatial); + if (path.get_subname_count() == 1 && Object::cast_to<Skeleton3D>(node_3d)) { + Skeleton3D *sk = Object::cast_to<Skeleton3D>(node_3d); track_xform->skeleton = sk; int bone_idx = sk->find_bone(path.get_subname(0)); if (bone_idx != -1) { @@ -604,11 +609,11 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { } } - track_xform->object = spatial; + track_xform->object = node_3d; track_xform->object_id = track_xform->object->get_instance_id(); track = track_xform; - +#endif // _3D_DISABLED } break; case Animation::TYPE_METHOD: { TrackCacheMethod *track_method = memnew(TrackCacheMethod); @@ -718,7 +723,7 @@ void AnimationTree::_process_graph(float p_delta) { //check all tracks, see if they need modification - root_motion_transform = Transform(); + root_motion_transform = Transform3D(); if (!root.is_valid()) { ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback."); @@ -844,14 +849,15 @@ void AnimationTree::_process_graph(float p_delta) { } switch (track->type) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { +#ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (track->root_motion) { if (t->process_pass != process_pass) { t->process_pass = process_pass; t->loc = Vector3(); - t->rot = Quat(); + t->rot = Quaternion(); t->rot_blend_accum = 0; t->scale = Vector3(1, 1, 1); } @@ -866,7 +872,7 @@ void AnimationTree::_process_graph(float p_delta) { } Vector3 loc[2]; - Quat rot[2]; + Quaternion rot[2]; Vector3 scale[2]; if (prev_time > time) { @@ -879,7 +885,7 @@ void AnimationTree::_process_graph(float p_delta) { t->loc += (loc[1] - loc[0]) * blend; t->scale += (scale[1] - scale[0]) * blend; - Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); + Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; @@ -894,14 +900,14 @@ void AnimationTree::_process_graph(float p_delta) { t->loc += (loc[1] - loc[0]) * blend; t->scale += (scale[1] - scale[0]) * blend; - Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); + Quaternion q = Quaternion().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } else { Vector3 loc; - Quat rot; + Quaternion rot; Vector3 scale; Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); @@ -930,7 +936,7 @@ void AnimationTree::_process_graph(float p_delta) { } t->scale = t->scale.lerp(scale, blend); } - +#endif // _3D_DISABLED } break; case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); @@ -1188,13 +1194,14 @@ void AnimationTree::_process_graph(float p_delta) { } switch (track->type) { - case Animation::TYPE_TRANSFORM: { + case Animation::TYPE_TRANSFORM3D: { +#ifndef _3D_DISABLED TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); - Transform xform; + Transform3D xform; xform.origin = t->loc; - xform.basis.set_quat_scale(t->rot, t->scale); + xform.basis.set_quaternion_scale(t->rot, t->scale); if (t->root_motion) { root_motion_transform = xform; @@ -1206,9 +1213,9 @@ void AnimationTree::_process_graph(float p_delta) { t->skeleton->set_bone_pose(t->bone_idx, xform); } else if (!t->skeleton) { - t->spatial->set_transform(xform); + t->node_3d->set_transform(xform); } - +#endif // _3D_DISABLED } break; case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); @@ -1311,7 +1318,7 @@ NodePath AnimationTree::get_root_motion_track() const { return root_motion_track; } -Transform AnimationTree::get_root_motion_transform() const { +Transform3D AnimationTree::get_root_motion_transform() const { return root_motion_transform; } diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 700ff1cb5b..60e0c7200a 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -184,16 +184,18 @@ private: }; struct TrackCacheTransform : public TrackCache { - Node3D *spatial = nullptr; +#ifndef _3D_DISABLED + Node3D *node_3d = nullptr; Skeleton3D *skeleton = nullptr; +#endif // _3D_DISABLED int bone_idx = -1; Vector3 loc; - Quat rot; + Quaternion rot; float rot_blend_accum = 0.0; Vector3 scale; TrackCacheTransform() { - type = Animation::TYPE_TRANSFORM; + type = Animation::TYPE_TRANSFORM3D; } }; @@ -257,7 +259,7 @@ private: bool started = true; NodePath root_motion_track; - Transform root_motion_transform; + Transform3D root_motion_transform; friend class AnimationNode; bool properties_dirty = true; @@ -308,7 +310,7 @@ public: void set_root_motion_track(const NodePath &p_track); NodePath get_root_motion_track() const; - Transform get_root_motion_transform() const; + Transform3D get_root_motion_transform() const; float get_connection_activity(const StringName &p_path, int p_connection) const; void advance(float p_time); diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index 9ee1f32581..770996820d 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -77,12 +77,12 @@ bool RootMotionView::get_zero_y() const { void RootMotionView::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - RS::get_singleton()->immediate_set_material(immediate, StandardMaterial3D::get_material_rid_for_2d(false, true, false, false, false)); + immediate_material = StandardMaterial3D::get_material_for_2d(false, true, false, false, false); first = true; } if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { - Transform transform; + Transform3D transform; if (has_node(path)) { Node *node = get_node(path); @@ -103,7 +103,7 @@ void RootMotionView::_notification(int p_what) { } } - if (!first && transform == Transform()) { + if (!first && transform == Transform3D()) { return; } @@ -119,11 +119,12 @@ void RootMotionView::_notification(int p_what) { } accumulated.origin.z = Math::fposmod(accumulated.origin.z, cell_size); - RS::get_singleton()->immediate_clear(immediate); + immediate->clear_surfaces(); int cells_in_radius = int((radius / cell_size) + 1.0); - RS::get_singleton()->immediate_begin(immediate, RS::PRIMITIVE_LINES); + immediate->surface_begin(Mesh::PRIMITIVE_LINES, immediate_material); + for (int i = -cells_in_radius; i < cells_in_radius; i++) { for (int j = -cells_in_radius; j < cells_in_radius; j++) { Vector3 from(i * cell_size, 0, j * cell_size); @@ -138,21 +139,21 @@ void RootMotionView::_notification(int p_what) { c_i.a *= MAX(0, 1.0 - from_i.length() / radius); c_j.a *= MAX(0, 1.0 - from_j.length() / radius); - RS::get_singleton()->immediate_color(immediate, c); - RS::get_singleton()->immediate_vertex(immediate, from); + immediate->surface_set_color(c); + immediate->surface_add_vertex(from); - RS::get_singleton()->immediate_color(immediate, c_i); - RS::get_singleton()->immediate_vertex(immediate, from_i); + immediate->surface_set_color(c_i); + immediate->surface_add_vertex(from_i); - RS::get_singleton()->immediate_color(immediate, c); - RS::get_singleton()->immediate_vertex(immediate, from); + immediate->surface_set_color(c); + immediate->surface_add_vertex(from); - RS::get_singleton()->immediate_color(immediate, c_j); - RS::get_singleton()->immediate_vertex(immediate, from_j); + immediate->surface_set_color(c_j); + immediate->surface_add_vertex(from_j); } } - RS::get_singleton()->immediate_end(immediate); + immediate->surface_end(); } } @@ -188,12 +189,13 @@ void RootMotionView::_bind_methods() { } RootMotionView::RootMotionView() { - set_process_internal(true); - immediate = RenderingServer::get_singleton()->immediate_create(); - set_base(immediate); + if (Engine::get_singleton()->is_editor_hint()) { + set_process_internal(true); + } + immediate.instantiate(); + set_base(immediate->get_rid()); } RootMotionView::~RootMotionView() { set_base(RID()); - RenderingServer::get_singleton()->free(immediate); } diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h index afcff6137f..55fd2d2b73 100644 --- a/scene/animation/root_motion_view.h +++ b/scene/animation/root_motion_view.h @@ -32,12 +32,12 @@ #define ROOT_MOTION_VIEW_H #include "scene/3d/visual_instance_3d.h" - +#include "scene/resources/immediate_mesh.h" class RootMotionView : public VisualInstance3D { GDCLASS(RootMotionView, VisualInstance3D); public: - RID immediate; + Ref<ImmediateMesh> immediate; NodePath path; float cell_size = 1.0; float radius = 10.0; @@ -46,7 +46,9 @@ public: bool first = true; bool zero_y = true; - Transform accumulated; + Ref<Material> immediate_material; + + Transform3D accumulated; private: void _notification(int p_what); diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 2030808724..7bf616e602 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -30,535 +30,407 @@ #include "tween.h" -void Tween::_add_pending_command(StringName p_key, const Variant &p_arg1, const Variant &p_arg2, const Variant &p_arg3, const Variant &p_arg4, const Variant &p_arg5, const Variant &p_arg6, const Variant &p_arg7, const Variant &p_arg8, const Variant &p_arg9, const Variant &p_arg10) { - // Add a new pending command and reference it - pending_commands.push_back(PendingCommand()); - PendingCommand &cmd = pending_commands.back()->get(); - - // Update the command with the target key - cmd.key = p_key; - - // Determine command argument count - int &count = cmd.args; - if (p_arg10.get_type() != Variant::NIL) { - count = 10; - } else if (p_arg9.get_type() != Variant::NIL) { - count = 9; - } else if (p_arg8.get_type() != Variant::NIL) { - count = 8; - } else if (p_arg7.get_type() != Variant::NIL) { - count = 7; - } else if (p_arg6.get_type() != Variant::NIL) { - count = 6; - } else if (p_arg5.get_type() != Variant::NIL) { - count = 5; - } else if (p_arg4.get_type() != Variant::NIL) { - count = 4; - } else if (p_arg3.get_type() != Variant::NIL) { - count = 3; - } else if (p_arg2.get_type() != Variant::NIL) { - count = 2; - } else if (p_arg1.get_type() != Variant::NIL) { - count = 1; - } else { - count = 0; - } +#include "scene/main/node.h" - // Add the specified arguments to the command - if (count > 0) { - cmd.arg[0] = p_arg1; - } - if (count > 1) { - cmd.arg[1] = p_arg2; - } - if (count > 2) { - cmd.arg[2] = p_arg3; - } - if (count > 3) { - cmd.arg[3] = p_arg4; - } - if (count > 4) { - cmd.arg[4] = p_arg5; - } - if (count > 5) { - cmd.arg[5] = p_arg6; - } - if (count > 6) { - cmd.arg[6] = p_arg7; - } - if (count > 7) { - cmd.arg[7] = p_arg8; - } - if (count > 8) { - cmd.arg[8] = p_arg9; +void Tweener::set_tween(Ref<Tween> p_tween) { + tween = p_tween; +} + +void Tweener::_bind_methods() { + ADD_SIGNAL(MethodInfo("finished")); +} + +void Tween::start_tweeners() { + if (tweeners.is_empty()) { + dead = true; + ERR_FAIL_MSG("Tween without commands, aborting."); } - if (count > 9) { - cmd.arg[9] = p_arg10; + + for (List<Ref<Tweener>>::Element *E = tweeners.write[current_step].front(); E; E = E->next()) { + E->get()->start(); } } -void Tween::_process_pending_commands() { - // For each pending command... - for (List<PendingCommand>::Element *E = pending_commands.front(); E; E = E->next()) { - // Get the command - PendingCommand &cmd = E->get(); - Callable::CallError err; - - // Grab all of the arguments for the command - Variant *arg[10] = { - &cmd.arg[0], - &cmd.arg[1], - &cmd.arg[2], - &cmd.arg[3], - &cmd.arg[4], - &cmd.arg[5], - &cmd.arg[6], - &cmd.arg[7], - &cmd.arg[8], - &cmd.arg[9], - }; - - // Execute the command (and retrieve any errors) - this->call(cmd.key, (const Variant **)arg, cmd.args, err); - } +Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration) { + ERR_FAIL_NULL_V(p_target, nullptr); + ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); - // Clear the pending commands - pending_commands.clear(); + Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration)); + append(tweener); + return tweener; } -bool Tween::_set(const StringName &p_name, const Variant &p_value) { - // Set the correct attribute based on the given name - String name = p_name; - if (name == "playback/speed" || name == "speed") { // Backwards compatibility - set_speed_scale(p_value); - return true; +Ref<IntervalTweener> Tween::tween_interval(float p_time) { + ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); - } else if (name == "playback/active") { - set_active(p_value); - return true; + Ref<IntervalTweener> tweener = memnew(IntervalTweener(p_time)); + append(tweener); + return tweener; +} - } else if (name == "playback/repeat") { - set_repeat(p_value); - return true; - } - return false; +Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) { + ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); + + Ref<CallbackTweener> tweener = memnew(CallbackTweener(p_callback)); + append(tweener); + return tweener; } -bool Tween::_get(const StringName &p_name, Variant &r_ret) const { - // Get the correct attribute based on the given name - String name = p_name; - if (name == "playback/speed") { // Backwards compatibility - r_ret = speed_scale; - return true; +Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float p_to, float p_duration) { + ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); - } else if (name == "playback/active") { - r_ret = is_active(); - return true; + Ref<MethodTweener> tweener = memnew(MethodTweener(p_callback, p_from, p_to, p_duration)); + append(tweener); + return tweener; +} - } else if (name == "playback/repeat") { - r_ret = is_repeat(); - return true; +Ref<Tween> Tween::append(Ref<Tweener> p_tweener) { + ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners."); + ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first."); + p_tweener->set_tween(this); + + if (parallel_enabled) { + current_step = MAX(current_step, 0); + } else { + current_step++; } - return false; -} - -void Tween::_get_property_list(List<PropertyInfo> *p_list) const { - // Add the property info for the Tween object - p_list->push_back(PropertyInfo(Variant::BOOL, "playback/active", PROPERTY_HINT_NONE, "")); - p_list->push_back(PropertyInfo(Variant::BOOL, "playback/repeat", PROPERTY_HINT_NONE, "")); - p_list->push_back(PropertyInfo(Variant::FLOAT, "playback/speed", PROPERTY_HINT_RANGE, "-64,64,0.01")); -} - -void Tween::_notification(int p_what) { - // What notification did we receive? - switch (p_what) { - case NOTIFICATION_ENTER_TREE: { - // Are we not already active? - if (!is_active()) { - // Make sure that a previous process state was not saved - // Only process if "processing" is set - set_physics_process_internal(false); - set_process_internal(false); - } - } break; + parallel_enabled = default_parallel; - case NOTIFICATION_READY: { - // Do nothing - } break; + tweeners.resize(current_step + 1); + tweeners.write[current_step].push_back(p_tweener); - case NOTIFICATION_INTERNAL_PROCESS: { - // Are we processing during physics time? - if (tween_process_mode == TWEEN_PROCESS_PHYSICS) { - // Do nothing since we aren't aligned with physics when we should be - break; - } + return this; +} - // Should we update? - if (is_active()) { - // Update the tweens - _tween_process(get_process_delta_time()); - } - } break; +void Tween::stop() { + started = false; + running = false; + dead = false; +} - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - // Are we processing during 'regular' time? - if (tween_process_mode == TWEEN_PROCESS_IDLE) { - // Do nothing since we would only process during idle time - break; - } +void Tween::pause() { + running = false; +} - // Should we update? - if (is_active()) { - // Update the tweens - _tween_process(get_physics_process_delta_time()); - } - } break; +void Tween::play() { + ERR_FAIL_COND_MSG(invalid, "Tween invalid, can't play."); + ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state."); + running = true; +} - case NOTIFICATION_EXIT_TREE: { - // We've left the tree. Stop all tweens - stop_all(); - } break; - } +void Tween::kill() { + running = false; // For the sake of is_running(). + dead = true; } -void Tween::_bind_methods() { - // Bind getters and setters - ClassDB::bind_method(D_METHOD("is_active"), &Tween::is_active); - ClassDB::bind_method(D_METHOD("set_active", "active"), &Tween::set_active); +bool Tween::is_running() { + return running; +} - ClassDB::bind_method(D_METHOD("is_repeat"), &Tween::is_repeat); - ClassDB::bind_method(D_METHOD("set_repeat", "repeat"), &Tween::set_repeat); +void Tween::set_valid(bool p_valid) { + invalid = !p_valid; +} - ClassDB::bind_method(D_METHOD("set_speed_scale", "speed"), &Tween::set_speed_scale); - ClassDB::bind_method(D_METHOD("get_speed_scale"), &Tween::get_speed_scale); - - ClassDB::bind_method(D_METHOD("set_tween_process_mode", "mode"), &Tween::set_tween_process_mode); - ClassDB::bind_method(D_METHOD("get_tween_process_mode"), &Tween::get_tween_process_mode); - - // Bind the various Tween control methods - ClassDB::bind_method(D_METHOD("start"), &Tween::start); - ClassDB::bind_method(D_METHOD("reset", "object", "key"), &Tween::reset, DEFVAL("")); - ClassDB::bind_method(D_METHOD("reset_all"), &Tween::reset_all); - ClassDB::bind_method(D_METHOD("stop", "object", "key"), &Tween::stop, DEFVAL("")); - ClassDB::bind_method(D_METHOD("stop_all"), &Tween::stop_all); - ClassDB::bind_method(D_METHOD("resume", "object", "key"), &Tween::resume, DEFVAL("")); - ClassDB::bind_method(D_METHOD("resume_all"), &Tween::resume_all); - ClassDB::bind_method(D_METHOD("remove", "object", "key"), &Tween::remove, DEFVAL("")); - ClassDB::bind_method(D_METHOD("_remove_by_uid", "uid"), &Tween::_remove_by_uid); - ClassDB::bind_method(D_METHOD("remove_all"), &Tween::remove_all); - ClassDB::bind_method(D_METHOD("seek", "time"), &Tween::seek); - ClassDB::bind_method(D_METHOD("tell"), &Tween::tell); - ClassDB::bind_method(D_METHOD("get_runtime"), &Tween::get_runtime); - - // Bind interpolation and follow methods - ClassDB::bind_method(D_METHOD("interpolate_property", "object", "property", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::interpolate_property, DEFVAL(TRANS_LINEAR), DEFVAL(EASE_IN_OUT), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("interpolate_method", "object", "method", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::interpolate_method, DEFVAL(TRANS_LINEAR), DEFVAL(EASE_IN_OUT), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("interpolate_callback", "object", "duration", "callback", "arg1", "arg2", "arg3", "arg4", "arg5"), &Tween::interpolate_callback, DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("interpolate_deferred_callback", "object", "duration", "callback", "arg1", "arg2", "arg3", "arg4", "arg5"), &Tween::interpolate_deferred_callback, DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("follow_property", "object", "property", "initial_val", "target", "target_property", "duration", "trans_type", "ease_type", "delay"), &Tween::follow_property, DEFVAL(TRANS_LINEAR), DEFVAL(EASE_IN_OUT), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("follow_method", "object", "method", "initial_val", "target", "target_method", "duration", "trans_type", "ease_type", "delay"), &Tween::follow_method, DEFVAL(TRANS_LINEAR), DEFVAL(EASE_IN_OUT), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("targeting_property", "object", "property", "initial", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::targeting_property, DEFVAL(TRANS_LINEAR), DEFVAL(EASE_IN_OUT), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("targeting_method", "object", "method", "initial", "initial_method", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::targeting_method, DEFVAL(TRANS_LINEAR), DEFVAL(EASE_IN_OUT), DEFVAL(0)); - - // Add the Tween signals - ADD_SIGNAL(MethodInfo("tween_started", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"))); - ADD_SIGNAL(MethodInfo("tween_step", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"), PropertyInfo(Variant::FLOAT, "elapsed"), PropertyInfo(Variant::OBJECT, "value"))); - ADD_SIGNAL(MethodInfo("tween_completed", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"))); - ADD_SIGNAL(MethodInfo("tween_all_completed")); - - // Add the properties and tie them to the getters and setters - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "repeat"), "set_repeat", "is_repeat"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_tween_process_mode", "get_tween_process_mode"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); - - // Bind Idle vs Physics process - BIND_ENUM_CONSTANT(TWEEN_PROCESS_PHYSICS); - BIND_ENUM_CONSTANT(TWEEN_PROCESS_IDLE); +bool Tween::is_valid() { + return invalid; +} - // Bind the Transition type constants - BIND_ENUM_CONSTANT(TRANS_LINEAR); - BIND_ENUM_CONSTANT(TRANS_SINE); - BIND_ENUM_CONSTANT(TRANS_QUINT); - BIND_ENUM_CONSTANT(TRANS_QUART); - BIND_ENUM_CONSTANT(TRANS_QUAD); - BIND_ENUM_CONSTANT(TRANS_EXPO); - BIND_ENUM_CONSTANT(TRANS_ELASTIC); - BIND_ENUM_CONSTANT(TRANS_CUBIC); - BIND_ENUM_CONSTANT(TRANS_CIRC); - BIND_ENUM_CONSTANT(TRANS_BOUNCE); - BIND_ENUM_CONSTANT(TRANS_BACK); +Ref<Tween> Tween::bind_node(Node *p_node) { + bound_node = p_node->get_instance_id(); + is_bound = true; + return this; +} - // Bind the easing constants - BIND_ENUM_CONSTANT(EASE_IN); - BIND_ENUM_CONSTANT(EASE_OUT); - BIND_ENUM_CONSTANT(EASE_IN_OUT); - BIND_ENUM_CONSTANT(EASE_OUT_IN); +Ref<Tween> Tween::set_process_mode(TweenProcessMode p_mode) { + process_mode = p_mode; + return this; } -Variant Tween::_get_initial_val(const InterpolateData &p_data) const { - // What type of data are we interpolating? - switch (p_data.type) { - case INTER_PROPERTY: - case INTER_METHOD: - case FOLLOW_PROPERTY: - case FOLLOW_METHOD: - // Simply use the given initial value - return p_data.initial_val; - - case TARGETING_PROPERTY: - case TARGETING_METHOD: { - // Get the object that is being targeted - Object *object = ObjectDB::get_instance(p_data.target_id); - ERR_FAIL_COND_V(object == nullptr, p_data.initial_val); - - // Are we targeting a property or a method? - Variant initial_val; - if (p_data.type == TARGETING_PROPERTY) { - // Get the property from the target object - bool valid = false; - initial_val = object->get_indexed(p_data.target_key, &valid); - ERR_FAIL_COND_V(!valid, p_data.initial_val); - } else { - // Call the method and get the initial value from it - Callable::CallError error; - initial_val = object->call(p_data.target_key[0], nullptr, 0, error); - ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, p_data.initial_val); - } - return initial_val; - } +Tween::TweenProcessMode Tween::get_process_mode() { + return process_mode; +} + +Ref<Tween> Tween::set_pause_mode(TweenPauseMode p_mode) { + pause_mode = p_mode; + return this; +} + +Tween::TweenPauseMode Tween::get_pause_mode() { + return pause_mode; +} + +Ref<Tween> Tween::set_parallel(bool p_parallel) { + default_parallel = p_parallel; + parallel_enabled = p_parallel; + return this; +} + +Ref<Tween> Tween::set_loops(int p_loops) { + loops = p_loops; + return this; +} + +Ref<Tween> Tween::set_speed_scale(float p_speed) { + speed_scale = p_speed; + return this; +} + +Ref<Tween> Tween::set_trans(TransitionType p_trans) { + default_transition = p_trans; + return this; +} - case INTER_CALLBACK: - // Callback does not have a special initial value - break; +Tween::TransitionType Tween::get_trans() { + return default_transition; +} + +Ref<Tween> Tween::set_ease(EaseType p_ease) { + default_ease = p_ease; + return this; +} + +Tween::EaseType Tween::get_ease() { + return default_ease; +} + +Ref<Tween> Tween::parallel() { + parallel_enabled = true; + return this; +} + +Ref<Tween> Tween::chain() { + parallel_enabled = false; + return this; +} + +bool Tween::custom_step(float p_delta) { + bool r = running; + running = true; + bool ret = step(p_delta); + running = running && r; // Running might turn false when Tween finished. + return ret; +} + +bool Tween::step(float p_delta) { + ERR_FAIL_COND_V_MSG(tweeners.is_empty(), false, "Tween started, but has no Tweeners."); + + if (dead) { + return false; } - // If we've made it here, just return the delta value as the initial value - return p_data.delta_val; -} - -Variant Tween::_get_final_val(const InterpolateData &p_data) const { - switch (p_data.type) { - case FOLLOW_PROPERTY: - case FOLLOW_METHOD: { - // Get the object that is being followed - Object *target = ObjectDB::get_instance(p_data.target_id); - ERR_FAIL_COND_V(target == nullptr, p_data.initial_val); - - // We want to figure out the final value - Variant final_val; - if (p_data.type == FOLLOW_PROPERTY) { - // Read the property as-is - bool valid = false; - final_val = target->get_indexed(p_data.target_key, &valid); - ERR_FAIL_COND_V(!valid, p_data.initial_val); - } else { - // We're looking at a method. Call the method on the target object - Callable::CallError error; - final_val = target->call(p_data.target_key[0], nullptr, 0, error); - ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, p_data.initial_val); - } - // If we're looking at an INT value, instead convert it to a FLOAT - // This is better for interpolation - if (final_val.get_type() == Variant::INT) { - final_val = final_val.operator real_t(); - } + if (!running) { + return true; + } - return final_val; - } - default: { - // If we're not following a final value/method, use the final value from the data - return p_data.final_val; + if (is_bound) { + Object *bound_instance = ObjectDB::get_instance(bound_node); + if (bound_instance) { + Node *bound_node = Object::cast_to<Node>(bound_instance); + // This can't by anything else than Node, so we can omit checking if casting succeeded. + if (!bound_node->is_inside_tree()) { + return true; + } + } else { + return false; } } -} -Variant &Tween::_get_delta_val(InterpolateData &p_data) { - // What kind of data are we interpolating? - switch (p_data.type) { - case INTER_PROPERTY: - case INTER_METHOD: - // Simply return the given delta value - return p_data.delta_val; - - case FOLLOW_PROPERTY: - case FOLLOW_METHOD: { - // We're following an object, so grab that instance - Object *target = ObjectDB::get_instance(p_data.target_id); - ERR_FAIL_COND_V(target == nullptr, p_data.initial_val); - - // We want to figure out the final value - Variant final_val; - if (p_data.type == FOLLOW_PROPERTY) { - // Read the property as-is - bool valid = false; - final_val = target->get_indexed(p_data.target_key, &valid); - ERR_FAIL_COND_V(!valid, p_data.initial_val); - } else { - // We're looking at a method. Call the method on the target object - Callable::CallError error; - final_val = target->call(p_data.target_key[0], nullptr, 0, error); - ERR_FAIL_COND_V(error.error != Callable::CallError::CALL_OK, p_data.initial_val); - } + if (!started) { + current_step = 0; + loops_done = 0; + start_tweeners(); + started = true; + } - // If we're looking at an INT value, instead convert it to a FLOAT - // This is better for interpolation - if (final_val.get_type() == Variant::INT) { - final_val = final_val.operator real_t(); - } + float rem_delta = p_delta * speed_scale; + bool step_active = false; - // Calculate the delta based on the initial value and the final value - _calc_delta_val(p_data.initial_val, final_val, p_data.delta_val); - return p_data.delta_val; + while (rem_delta > 0 && running) { + float step_delta = rem_delta; + step_active = false; + + for (List<Ref<Tweener>>::Element *E = tweeners.write[current_step].front(); E; E = E->next()) { + // Modified inside Tweener.step(). + float temp_delta = rem_delta; + // Turns to true if any Tweener returns true (i.e. is still not finished). + step_active = E->get()->step(temp_delta) || step_active; + step_delta = MIN(temp_delta, rem_delta); } - case TARGETING_PROPERTY: - case TARGETING_METHOD: { - // Grab the initial value from the data to calculate delta - Variant initial_val = _get_initial_val(p_data); + rem_delta = step_delta; - // If we're looking at an INT value, instead convert it to a FLOAT - // This is better for interpolation - if (initial_val.get_type() == Variant::INT) { - initial_val = initial_val.operator real_t(); - } + if (!step_active) { + emit_signal("step_finished", current_step); + current_step++; - // Calculate the delta based on the initial value and the final value - _calc_delta_val(initial_val, p_data.final_val, p_data.delta_val); - return p_data.delta_val; + if (current_step == tweeners.size()) { + loops_done++; + if (loops_done == loops) { + running = false; + dead = true; + emit_signal("finished"); + } else { + emit_signal("loop_finished", loops_done); + current_step = 0; + start_tweeners(); + } + } else { + start_tweeners(); + } } + } + + return true; +} - case INTER_CALLBACK: - // Callbacks have no special delta - break; +bool Tween::should_pause() { + if (is_bound && pause_mode == TWEEN_PAUSE_BOUND) { + Object *bound_instance = ObjectDB::get_instance(bound_node); + if (bound_instance) { + Node *bound_node = Object::cast_to<Node>(bound_instance); + return !bound_node->can_process(); + } } - // If we've made it here, use the initial value as the delta - return p_data.initial_val; + + return pause_mode != TWEEN_PAUSE_PROCESS; } -Variant Tween::_run_equation(InterpolateData &p_data) { - // Get the initial and delta values from the data - Variant initial_val = _get_initial_val(p_data); - Variant &delta_val = _get_delta_val(p_data); - Variant result; +Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, TransitionType p_trans, EaseType p_ease) { + ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant()); + ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant()); +// Helper macro to run equation on sub-elements of the value (e.g. x and y of Vector2). #define APPLY_EQUATION(element) \ - r.element = _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, i.element, d.element, p_data.duration); + r.element = run_equation(p_trans, p_ease, p_time, i.element, d.element, p_duration); - // What type of data are we interpolating? - switch (initial_val.get_type()) { - case Variant::BOOL: - // Run the boolean specific equation (checking if it is at least 0.5) - result = (_run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, initial_val, delta_val, p_data.duration)) >= 0.5; - break; + switch (p_initial_val.get_type()) { + case Variant::BOOL: { + return (run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration)) >= 0.5; + } - case Variant::INT: - // Run the integer specific equation - result = (int)_run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int)initial_val, (int)delta_val, p_data.duration); - break; + case Variant::INT: { + return (int)run_equation(p_trans, p_ease, p_time, (int)p_initial_val, (int)p_delta_val, p_duration); + } - case Variant::FLOAT: - // Run the FLOAT specific equation - result = _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (real_t)initial_val, (real_t)delta_val, p_data.duration); - break; + case Variant::FLOAT: { + return run_equation(p_trans, p_ease, p_time, (real_t)p_initial_val, (real_t)p_delta_val, p_duration); + } case Variant::VECTOR2: { - // Get vectors for initial and delta values - Vector2 i = initial_val; - Vector2 d = delta_val; + Vector2 i = p_initial_val; + Vector2 d = p_delta_val; Vector2 r; - // Execute the equation and mutate the r vector - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(x); APPLY_EQUATION(y); - result = r; - } break; + return r; + } + + case Variant::VECTOR2I: { + Vector2i i = p_initial_val; + Vector2i d = p_delta_val; + Vector2i r; + + APPLY_EQUATION(x); + APPLY_EQUATION(y); + return r; + } case Variant::RECT2: { - // Get the Rect2 for initial and delta value - Rect2 i = initial_val; - Rect2 d = delta_val; + Rect2 i = p_initial_val; + Rect2 d = p_delta_val; Rect2 r; - // Execute the equation for the position and size of Rect2 APPLY_EQUATION(position.x); APPLY_EQUATION(position.y); APPLY_EQUATION(size.x); APPLY_EQUATION(size.y); - result = r; - } break; + return r; + } + + case Variant::RECT2I: { + Rect2i i = p_initial_val; + Rect2i d = p_delta_val; + Rect2i r; + + APPLY_EQUATION(position.x); + APPLY_EQUATION(position.y); + APPLY_EQUATION(size.x); + APPLY_EQUATION(size.y); + return r; + } case Variant::VECTOR3: { - // Get vectors for initial and delta values - Vector3 i = initial_val; - Vector3 d = delta_val; + Vector3 i = p_initial_val; + Vector3 d = p_delta_val; Vector3 r; - // Execute the equation and mutate the r vector - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(x); APPLY_EQUATION(y); APPLY_EQUATION(z); - result = r; - } break; + return r; + } + + case Variant::VECTOR3I: { + Vector3i i = p_initial_val; + Vector3i d = p_delta_val; + Vector3i r; + + APPLY_EQUATION(x); + APPLY_EQUATION(y); + APPLY_EQUATION(z); + return r; + } case Variant::TRANSFORM2D: { - // Get the transforms for initial and delta values - Transform2D i = initial_val; - Transform2D d = delta_val; + Transform2D i = p_initial_val; + Transform2D d = p_delta_val; Transform2D r; - // Execute the equation on the transforms and mutate the r transform - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(elements[0][0]); APPLY_EQUATION(elements[0][1]); APPLY_EQUATION(elements[1][0]); APPLY_EQUATION(elements[1][1]); APPLY_EQUATION(elements[2][0]); APPLY_EQUATION(elements[2][1]); - result = r; - } break; + return r; + } - case Variant::QUAT: { - // Get the quaternian for the initial and delta values - Quat i = initial_val; - Quat d = delta_val; - Quat r; + case Variant::QUATERNION: { + Quaternion i = p_initial_val; + Quaternion d = p_delta_val; + Quaternion r; - // Execute the equation on the quaternian values and mutate the r quaternian - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(x); APPLY_EQUATION(y); APPLY_EQUATION(z); APPLY_EQUATION(w); - result = r; - } break; + return r; + } case Variant::AABB: { - // Get the AABB's for the initial and delta values - AABB i = initial_val; - AABB d = delta_val; + AABB i = p_initial_val; + AABB d = p_delta_val; AABB r; - // Execute the equation for the position and size of the AABB's and mutate the r AABB - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(position.x); APPLY_EQUATION(position.y); APPLY_EQUATION(position.z); APPLY_EQUATION(size.x); APPLY_EQUATION(size.y); APPLY_EQUATION(size.z); - result = r; - } break; + return r; + } case Variant::BASIS: { - // Get the basis for initial and delta values - Basis i = initial_val; - Basis d = delta_val; + Basis i = p_initial_val; + Basis d = p_delta_val; Basis r; - // Execute the equation on all the basis and mutate the r basis - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(elements[0][0]); APPLY_EQUATION(elements[0][1]); APPLY_EQUATION(elements[0][2]); @@ -568,17 +440,14 @@ Variant Tween::_run_equation(InterpolateData &p_data) { APPLY_EQUATION(elements[2][0]); APPLY_EQUATION(elements[2][1]); APPLY_EQUATION(elements[2][2]); - result = r; - } break; + return r; + } - case Variant::TRANSFORM: { - // Get the transforms for the initial and delta values - Transform i = initial_val; - Transform d = delta_val; - Transform r; + case Variant::TRANSFORM3D: { + Transform3D i = p_initial_val; + Transform3D d = p_delta_val; + Transform3D r; - // Execute the equation for each of the transforms and their origin and mutate the r transform - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(basis.elements[0][0]); APPLY_EQUATION(basis.elements[0][1]); APPLY_EQUATION(basis.elements[0][2]); @@ -591,634 +460,67 @@ Variant Tween::_run_equation(InterpolateData &p_data) { APPLY_EQUATION(origin.x); APPLY_EQUATION(origin.y); APPLY_EQUATION(origin.z); - result = r; - } break; + return r; + } case Variant::COLOR: { - // Get the Color for initial and delta value - Color i = initial_val; - Color d = delta_val; + Color i = p_initial_val; + Color d = p_delta_val; Color r; - // Apply the equation on the Color RGBA, and mutate the r color - // This uses the custom APPLY_EQUATION macro defined above APPLY_EQUATION(r); APPLY_EQUATION(g); APPLY_EQUATION(b); APPLY_EQUATION(a); - result = r; - } break; - - default: { - // If unknown, just return the initial value - result = initial_val; - } break; - }; -#undef APPLY_EQUATION - // Return the result that was computed - return result; -} - -bool Tween::_apply_tween_value(InterpolateData &p_data, Variant &value) { - // Get the object we want to apply the new value to - Object *object = ObjectDB::get_instance(p_data.id); - ERR_FAIL_COND_V(object == nullptr, false); - - // What kind of data are we mutating? - switch (p_data.type) { - case INTER_PROPERTY: - case FOLLOW_PROPERTY: - case TARGETING_PROPERTY: { - // Simply set the property on the object - bool valid = false; - object->set_indexed(p_data.key, value, &valid); - return valid; + return r; } - case INTER_METHOD: - case FOLLOW_METHOD: - case TARGETING_METHOD: { - // We want to call the method on the target object - Callable::CallError error; - - // Do we have a non-nil value passed in? - if (value.get_type() != Variant::NIL) { - // Pass it as an argument to the function call - Variant *arg[1] = { &value }; - object->call(p_data.key[0], (const Variant **)arg, 1, error); - } else { - // Don't pass any argument - object->call(p_data.key[0], nullptr, 0, error); - } - - // Did we get an error from the function call? - return error.error == Callable::CallError::CALL_OK; + default: { + return p_initial_val; } - - case INTER_CALLBACK: - // Nothing to apply for a callback - break; }; - // No issues found! - return true; -} - -void Tween::_tween_process(float p_delta) { - // Process all of the pending commands - _process_pending_commands(); - - // If the scale is 0, make no progress on the tweens - if (speed_scale == 0) { - return; - } - - // Update the delta and whether we are pending an update - p_delta *= speed_scale; - pending_update++; - - // Are we repeating the interpolations? - if (repeat) { - // For each interpolation... - bool repeats_finished = true; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the data from it - InterpolateData &data = E->get(); - - // Is not finished? - if (!data.finish) { - // We aren't finished yet, no need to check the rest - repeats_finished = false; - break; - } - } - - // If we are all finished, we can reset all of the tweens - if (repeats_finished) { - reset_all(); - } - } - - // Are all of the tweens complete? - int any_unfinished = 0; - - // For each tween we wish to interpolate... - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the data from it - InterpolateData &data = E->get(); - - // Is the data not active or already finished? No need to go any further - if (!data.active || data.finish) { - continue; - } - - // Track if we hit one that isn't finished yet - any_unfinished++; - - // Get the target object for this interpolation - Object *object = ObjectDB::get_instance(data.id); - if (object == nullptr) { - continue; - } - - // Are we still delaying this tween? - bool prev_delaying = data.elapsed <= data.delay; - data.elapsed += p_delta; - if (data.elapsed < data.delay) { - continue; - } else if (prev_delaying) { - // We can apply the tween's value to the data and emit that the tween has started - _apply_tween_value(data, data.initial_val); - emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false)); - } - - // Are we at the end of the tween? - if (data.elapsed > (data.delay + data.duration)) { - // Set the elapsed time to the end and mark this one as finished - data.elapsed = data.delay + data.duration; - data.finish = true; - } - - // Are we interpolating a callback? - if (data.type == INTER_CALLBACK) { - // Is the tween completed? - if (data.finish) { - // Are we calling this callback deferred or immediately? - if (data.call_deferred) { - // Run the deferred function callback, applying the correct number of arguments - switch (data.args) { - case 0: - object->call_deferred(data.key[0]); - break; - case 1: - object->call_deferred(data.key[0], data.arg[0]); - break; - case 2: - object->call_deferred(data.key[0], data.arg[0], data.arg[1]); - break; - case 3: - object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2]); - break; - case 4: - object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3]); - break; - case 5: - object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]); - break; - } - } else { - // Call the function directly with the arguments - Callable::CallError error; - Variant *arg[5] = { - &data.arg[0], - &data.arg[1], - &data.arg[2], - &data.arg[3], - &data.arg[4], - }; - object->call(data.key[0], (const Variant **)arg, data.args, error); - } - } - } else { - // We can apply the value directly - Variant result = _run_equation(data); - _apply_tween_value(data, result); - - // Emit that the tween has taken a step - emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result); - } - - // Is the tween now finished? - if (data.finish) { - // Set it to the final value directly - Variant final_val = _get_final_val(data); - _apply_tween_value(data, final_val); - - // Mark the tween as completed and emit the signal - data.elapsed = 0; - emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false)); - - // If we are not repeating the tween, remove it - if (!repeat) { - call_deferred("_remove_by_uid", data.uid); - any_unfinished--; - } - } - } - // One less update left to go - pending_update--; - - // If all tweens are completed, we no longer need to be active - if (any_unfinished == 0) { - set_active(false); - emit_signal("tween_all_completed"); - } -} - -void Tween::set_tween_process_mode(TweenProcessMode p_mode) { - tween_process_mode = p_mode; -} - -Tween::TweenProcessMode Tween::get_tween_process_mode() const { - return tween_process_mode; -} - -bool Tween::is_active() const { - return is_processing_internal() || is_physics_processing_internal(); -} - -void Tween::set_active(bool p_active) { - // Do nothing if it's the same active mode that we currently are - if (is_active() == p_active) { - return; - } - - // Depending on physics or idle, set processing - switch (tween_process_mode) { - case TWEEN_PROCESS_IDLE: - set_process_internal(p_active); - break; - case TWEEN_PROCESS_PHYSICS: - set_physics_process_internal(p_active); - break; - } -} - -bool Tween::is_repeat() const { - return repeat; -} - -void Tween::set_repeat(bool p_repeat) { - repeat = p_repeat; -} - -void Tween::set_speed_scale(float p_speed) { - speed_scale = p_speed; -} - -float Tween::get_speed_scale() const { - return speed_scale; -} - -void Tween::start() { - ERR_FAIL_COND_MSG(!is_inside_tree(), "Tween was not added to the SceneTree!"); - - // Are there any pending updates? - if (pending_update != 0) { - // Start the tweens after deferring - call_deferred("start"); - return; - } - - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - InterpolateData &data = E->get(); - data.active = true; - } - pending_update--; - - // We want to be activated - set_active(true); - - // Don't resume from current position if stop_all() function has been used - if (was_stopped) { - seek(0); - } - was_stopped = false; -} - -void Tween::reset(Object *p_object, StringName p_key) { - // Find all interpolations that use the same object and target string - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the target object - InterpolateData &data = E->get(); - Object *object = ObjectDB::get_instance(data.id); - if (object == nullptr) { - continue; - } - - // Do we have the correct object and key? - if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { - // Reset the tween to the initial state - data.elapsed = 0; - data.finish = false; - - // Also apply the initial state if there isn't a delay - if (data.delay == 0) { - _apply_tween_value(data, data.initial_val); - } - } - } - pending_update--; -} - -void Tween::reset_all() { - // Go through all interpolations - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the target data and set it back to the initial state - InterpolateData &data = E->get(); - data.elapsed = 0; - data.finish = false; - - // If there isn't a delay, apply the value to the object - if (data.delay == 0) { - _apply_tween_value(data, data.initial_val); - } - } - pending_update--; -} - -void Tween::stop(Object *p_object, StringName p_key) { - // Find the tween that has the given target object and string key - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the object the tween is targeting - InterpolateData &data = E->get(); - Object *object = ObjectDB::get_instance(data.id); - if (object == nullptr) { - continue; - } - - // Is this the correct object and does it have the given key? - if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { - // Disable the tween - data.active = false; - } - } - pending_update--; -} - -void Tween::stop_all() { - // We no longer need to be active since all tweens have been stopped - set_active(false); - was_stopped = true; - // For each interpolation... - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Simply set it inactive - InterpolateData &data = E->get(); - data.active = false; - } - pending_update--; -} - -void Tween::resume(Object *p_object, StringName p_key) { - // We need to be activated - // TODO: What if no tween is found?? - set_active(true); - - // Find the tween that uses the given target object and string key - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Grab the object - InterpolateData &data = E->get(); - Object *object = ObjectDB::get_instance(data.id); - if (object == nullptr) { - continue; - } - - // If the object and string key match, activate it - if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { - data.active = true; - } - } - pending_update--; -} - -void Tween::resume_all() { - // Set ourselves active so we can process tweens - // TODO: What if there are no tweens? We get set to active for no reason! - set_active(true); - - // For each interpolation... - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Simply grab it and set it to active - InterpolateData &data = E->get(); - data.active = true; - } - pending_update--; -} - -void Tween::remove(Object *p_object, StringName p_key) { - // If we are still updating, call this function again later - if (pending_update != 0) { - call_deferred("remove", p_object, p_key); - return; - } - - // For each interpolation... - List<List<InterpolateData>::Element *> for_removal; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the target object - InterpolateData &data = E->get(); - Object *object = ObjectDB::get_instance(data.id); - if (object == nullptr) { - continue; - } - - // If the target object and string key match, queue it for removal - if (object == p_object && (data.concatenated_key == p_key || p_key == "")) { - for_removal.push_back(E); - } - } - - // For each interpolation we wish to remove... - for (List<List<InterpolateData>::Element *>::Element *E = for_removal.front(); E; E = E->next()) { - // Erase it - interpolates.erase(E->get()); - } -} - -void Tween::_remove_by_uid(int uid) { - // If we are still updating, call this function again later - if (pending_update != 0) { - call_deferred("_remove_by_uid", uid); - return; - } - - // Find the interpolation that matches the given UID - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - if (uid == E->get().uid) { - // It matches, erase it and stop looking - E->erase(); - break; - } - } -} - -void Tween::_push_interpolate_data(InterpolateData &p_data) { - pending_update++; - - // Add the new interpolation - p_data.uid = ++uid; - interpolates.push_back(p_data); - - pending_update--; +#undef APPLY_EQUATION } -void Tween::remove_all() { - // If we are still updating, call this function again later - if (pending_update != 0) { - call_deferred("remove_all"); - return; - } - // We no longer need to be active - set_active(false); - - // Clear out all interpolations and reset the uid - interpolates.clear(); - uid = 0; -} - -void Tween::seek(real_t p_time) { - // Go through each interpolation... - pending_update++; - for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the target data - InterpolateData &data = E->get(); - - // Update the elapsed data to be set to the target time - data.elapsed = p_time; - - // Are we at the end? - if (data.elapsed < data.delay) { - // There is still time left to go - data.finish = false; - continue; - } else if (data.elapsed >= (data.delay + data.duration)) { - // We are past the end of it, set the elapsed time to the end and mark as finished - data.elapsed = (data.delay + data.duration); - data.finish = true; - } else { - // We are not finished with this interpolation yet - data.finish = false; +Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) { + switch (p_intial_val.get_type()) { + case Variant::BOOL: { + return (int)p_final_val - (int)p_intial_val; } - // If we are a callback, do nothing special - if (data.type == INTER_CALLBACK) { - continue; - } - - // Run the equation on the data and apply the value - Variant result = _run_equation(data); - _apply_tween_value(data, result); - } - pending_update--; -} - -real_t Tween::tell() const { - // We want to grab the position of the furthest along tween - pending_update++; - real_t pos = 0.0; - - // For each interpolation... - for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the data and figure out if its position is further along than the previous ones - const InterpolateData &data = E->get(); - if (data.elapsed > pos) { - // Save it if so - pos = data.elapsed; + case Variant::RECT2: { + Rect2 i = p_intial_val; + Rect2 f = p_final_val; + return Rect2(f.position - i.position, f.size - i.size); } - } - pending_update--; - return pos; -} -real_t Tween::get_runtime() const { - // If the tween isn't moving, it'll last forever - if (speed_scale == 0) { - return INFINITY; - } - - pending_update++; - - // For each interpolation... - real_t runtime = 0.0; - for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the tween data and see if it's runtime is greater than the previous tweens - const InterpolateData &data = E->get(); - real_t t = data.delay + data.duration; - if (t > runtime) { - // This is the longest running tween - runtime = t; + case Variant::RECT2I: { + Rect2i i = p_intial_val; + Rect2i f = p_final_val; + return Rect2i(f.position - i.position, f.size - i.size); } - } - pending_update--; - - // Adjust the runtime for the current speed scale - return runtime / speed_scale; -} - -bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final_val, Variant &p_delta_val) { - // Get the initial, final, and delta values - const Variant &initial_val = p_initial_val; - const Variant &final_val = p_final_val; - Variant &delta_val = p_delta_val; - - // What kind of data are we interpolating? - switch (initial_val.get_type()) { - case Variant::BOOL: - // We'll treat booleans just like integers - case Variant::INT: - // Compute the integer delta - delta_val = (int)final_val - (int)initial_val; - break; - - case Variant::FLOAT: - // Convert to FLOAT and find the delta - delta_val = (real_t)final_val - (real_t)initial_val; - break; - - case Variant::VECTOR2: - // Convert to Vectors and find the delta - delta_val = final_val.operator Vector2() - initial_val.operator Vector2(); - break; - - case Variant::RECT2: { - // Build a new Rect2 and use the new position and sizes to make a delta - Rect2 i = initial_val; - Rect2 f = final_val; - delta_val = Rect2(f.position - i.position, f.size - i.size); - } break; - - case Variant::VECTOR3: - // Convert to Vectors and find the delta - delta_val = final_val.operator Vector3() - initial_val.operator Vector3(); - break; case Variant::TRANSFORM2D: { - // Build a new transform which is the difference between the initial and final values - Transform2D i = initial_val; - Transform2D f = final_val; - Transform2D d = Transform2D(); - d[0][0] = f.elements[0][0] - i.elements[0][0]; - d[0][1] = f.elements[0][1] - i.elements[0][1]; - d[1][0] = f.elements[1][0] - i.elements[1][0]; - d[1][1] = f.elements[1][1] - i.elements[1][1]; - d[2][0] = f.elements[2][0] - i.elements[2][0]; - d[2][1] = f.elements[2][1] - i.elements[2][1]; - delta_val = d; - } break; - - case Variant::QUAT: - // Convert to quaternianls and find the delta - delta_val = final_val.operator Quat() - initial_val.operator Quat(); - break; + Transform2D i = p_intial_val; + Transform2D f = p_final_val; + return Transform2D(f.elements[0][0] - i.elements[0][0], + f.elements[0][1] - i.elements[0][1], + f.elements[1][0] - i.elements[1][0], + f.elements[1][1] - i.elements[1][1], + f.elements[2][0] - i.elements[2][0], + f.elements[2][1] - i.elements[2][1]); + } case Variant::AABB: { - // Build a new AABB and use the new position and sizes to make a delta - AABB i = initial_val; - AABB f = final_val; - delta_val = AABB(f.position - i.position, f.size - i.size); - } break; + AABB i = p_intial_val; + AABB f = p_final_val; + return AABB(f.position - i.position, f.size - i.size); + } case Variant::BASIS: { - // Build a new basis which is the delta between the initial and final values - Basis i = initial_val; - Basis f = final_val; - delta_val = Basis(f.elements[0][0] - i.elements[0][0], + Basis i = p_intial_val; + Basis f = p_final_val; + return Basis(f.elements[0][0] - i.elements[0][0], f.elements[0][1] - i.elements[0][1], f.elements[0][2] - i.elements[0][2], f.elements[1][0] - i.elements[1][0], @@ -1227,14 +529,12 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final f.elements[2][0] - i.elements[2][0], f.elements[2][1] - i.elements[2][1], f.elements[2][2] - i.elements[2][2]); - } break; - - case Variant::TRANSFORM: { - // Build a new transform which is the difference between the initial and final values - Transform i = initial_val; - Transform f = final_val; - Transform d; - d.set(f.basis.elements[0][0] - i.basis.elements[0][0], + } + + case Variant::TRANSFORM3D: { + Transform3D i = p_intial_val; + Transform3D f = p_final_val; + return Transform3D(f.basis.elements[0][0] - i.basis.elements[0][0], f.basis.elements[0][1] - i.basis.elements[0][1], f.basis.elements[0][2] - i.basis.elements[0][2], f.basis.elements[1][0] - i.basis.elements[1][0], @@ -1246,569 +546,342 @@ bool Tween::_calc_delta_val(const Variant &p_initial_val, const Variant &p_final f.origin.x - i.origin.x, f.origin.y - i.origin.y, f.origin.z - i.origin.z); - - delta_val = d; - } break; - - case Variant::COLOR: { - // Make a new color which is the difference between each the color's RGBA attributes - Color i = initial_val; - Color f = final_val; - delta_val = Color(f.r - i.r, f.g - i.g, f.b - i.b, f.a - i.a); - } break; + } default: { - static Variant::Type supported_types[] = { - Variant::BOOL, - Variant::INT, - Variant::FLOAT, - Variant::VECTOR2, - Variant::RECT2, - Variant::VECTOR3, - Variant::TRANSFORM2D, - Variant::QUAT, - Variant::AABB, - Variant::BASIS, - Variant::TRANSFORM, - Variant::COLOR, - }; - - int length = *(&supported_types + 1) - supported_types; - String error_msg = "Invalid parameter type. Supported types are: "; - for (int i = 0; i < length; i++) { - if (i != 0) { - error_msg += ", "; - } - error_msg += Variant::get_type_name(supported_types[i]); - } - error_msg += "."; - ERR_PRINT(error_msg); - return false; + return Variant::evaluate(Variant::OP_SUBTRACT, p_final_val, p_intial_val); } }; - return true; } -void Tween::_build_interpolation(InterpolateType p_interpolation_type, Object *p_object, NodePath *p_property, StringName *p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // TODO: Add initialization+implementation for remaining interpolation types - // TODO: Fix this method's organization to take advantage of the type - - // Make a new interpolation data - InterpolateData data; - data.active = true; - data.type = p_interpolation_type; - data.finish = false; - data.elapsed = 0; +void Tween::_bind_methods() { + ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property); + ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval); + ClassDB::bind_method(D_METHOD("tween_callback", "callback"), &Tween::tween_callback); + ClassDB::bind_method(D_METHOD("tween_method", "method", "from", "to", "duration"), &Tween::tween_method); + + ClassDB::bind_method(D_METHOD("custom_step", "delta"), &Tween::custom_step); + ClassDB::bind_method(D_METHOD("stop"), &Tween::stop); + ClassDB::bind_method(D_METHOD("pause"), &Tween::pause); + ClassDB::bind_method(D_METHOD("play"), &Tween::play); + ClassDB::bind_method(D_METHOD("kill"), &Tween::kill); + + ClassDB::bind_method(D_METHOD("is_running"), &Tween::is_running); + ClassDB::bind_method(D_METHOD("is_valid"), &Tween::is_valid); + ClassDB::bind_method(D_METHOD("bind_node", "node"), &Tween::bind_node); + ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Tween::set_process_mode); + ClassDB::bind_method(D_METHOD("set_pause_mode", "mode"), &Tween::set_pause_mode); + + ClassDB::bind_method(D_METHOD("set_parallel", "parallel"), &Tween::set_parallel, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_loops", "loops"), &Tween::set_loops, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("set_speed_scale", "speed"), &Tween::set_speed_scale); + ClassDB::bind_method(D_METHOD("set_trans", "trans"), &Tween::set_trans); + ClassDB::bind_method(D_METHOD("set_ease", "ease"), &Tween::set_ease); - // Validate and apply interpolation data + ClassDB::bind_method(D_METHOD("parallel"), &Tween::parallel); + ClassDB::bind_method(D_METHOD("chain"), &Tween::chain); - // Give it the object - ERR_FAIL_COND_MSG(p_object == nullptr, "Invalid object provided to Tween."); - data.id = p_object->get_instance_id(); + ClassDB::bind_method(D_METHOD("interpolate_value", "trans_type", "ease_type", "elapsed_time", "initial_value", "delta_value", "duration"), &Tween::interpolate_variant); - // Validate the initial and final values - ERR_FAIL_COND_MSG(p_initial_val.get_type() != p_final_val.get_type(), "Initial value type '" + Variant::get_type_name(p_initial_val.get_type()) + "' does not match final value type '" + Variant::get_type_name(p_final_val.get_type()) + "'."); - data.initial_val = p_initial_val; - data.final_val = p_final_val; + ADD_SIGNAL(MethodInfo("step_finished", PropertyInfo(Variant::INT, "idx"))); + ADD_SIGNAL(MethodInfo("loop_finished", PropertyInfo(Variant::INT, "loop_count"))); + ADD_SIGNAL(MethodInfo("finished")); - // Check the Duration - ERR_FAIL_COND_MSG(p_duration < 0, "Only non-negative duration values allowed in Tweens."); - data.duration = p_duration; + BIND_ENUM_CONSTANT(TWEEN_PROCESS_PHYSICS); + BIND_ENUM_CONSTANT(TWEEN_PROCESS_IDLE); - // Tween Delay - ERR_FAIL_COND_MSG(p_delay < 0, "Only non-negative delay values allowed in Tweens."); - data.delay = p_delay; + BIND_ENUM_CONSTANT(TWEEN_PAUSE_BOUND); + BIND_ENUM_CONSTANT(TWEEN_PAUSE_STOP); + BIND_ENUM_CONSTANT(TWEEN_PAUSE_PROCESS); - // Transition type - ERR_FAIL_COND_MSG(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, "Invalid transition type provided to Tween."); - data.trans_type = p_trans_type; + BIND_ENUM_CONSTANT(TRANS_LINEAR); + BIND_ENUM_CONSTANT(TRANS_SINE); + BIND_ENUM_CONSTANT(TRANS_QUINT); + BIND_ENUM_CONSTANT(TRANS_QUART); + BIND_ENUM_CONSTANT(TRANS_QUAD); + BIND_ENUM_CONSTANT(TRANS_EXPO); + BIND_ENUM_CONSTANT(TRANS_ELASTIC); + BIND_ENUM_CONSTANT(TRANS_CUBIC); + BIND_ENUM_CONSTANT(TRANS_CIRC); + BIND_ENUM_CONSTANT(TRANS_BOUNCE); + BIND_ENUM_CONSTANT(TRANS_BACK); - // Easing type - ERR_FAIL_COND_MSG(p_ease_type < 0 || p_ease_type >= EASE_COUNT, "Invalid easing type provided to Tween."); - data.ease_type = p_ease_type; + BIND_ENUM_CONSTANT(EASE_IN); + BIND_ENUM_CONSTANT(EASE_OUT); + BIND_ENUM_CONSTANT(EASE_IN_OUT); + BIND_ENUM_CONSTANT(EASE_OUT_IN); +} - // Is the property defined? - if (p_property) { - // Check that the object actually contains the given property - bool prop_valid = false; - p_object->get_indexed(p_property->get_subnames(), &prop_valid); - ERR_FAIL_COND_MSG(!prop_valid, "Tween target object has no property named: " + p_property->get_concatenated_subnames() + "."); +Ref<PropertyTweener> PropertyTweener::from(Variant p_value) { + initial_val = p_value; + do_continue = false; + return this; +} - data.key = p_property->get_subnames(); - data.concatenated_key = p_property->get_concatenated_subnames(); - } +Ref<PropertyTweener> PropertyTweener::from_current() { + do_continue = false; + return this; +} - // Is the method defined? - if (p_method) { - // Does the object even have the requested method? - ERR_FAIL_COND_MSG(!p_object->has_method(*p_method), "Tween target object has no method named: " + *p_method + "."); +Ref<PropertyTweener> PropertyTweener::as_relative() { + relative = true; + return this; +} - data.key.push_back(*p_method); - data.concatenated_key = *p_method; - } +Ref<PropertyTweener> PropertyTweener::set_trans(Tween::TransitionType p_trans) { + trans_type = p_trans; + return this; +} - // Is there not a valid delta? - if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) { - return; - } +Ref<PropertyTweener> PropertyTweener::set_ease(Tween::EaseType p_ease) { + ease_type = p_ease; + return this; +} - // Add this interpolation to the total - _push_interpolate_data(data); +Ref<PropertyTweener> PropertyTweener::set_delay(float p_delay) { + delay = p_delay; + return this; } -void Tween::interpolate_property(Object *p_object, NodePath p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // If we are busy updating, call this function again later - if (pending_update != 0) { - _add_pending_command("interpolate_property", p_object, p_property, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); +void PropertyTweener::start() { + elapsed_time = 0; + finished = false; + + Object *target_instance = ObjectDB::get_instance(target); + if (!target_instance) { + WARN_PRINT("Target object freed before starting, aborting Tweener."); return; } - // Check that the target object is valid - ERR_FAIL_COND_MSG(p_object == nullptr, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name())); - - // Get the property from the node path - p_property = p_property.get_as_property_path(); - - // If no initial value given, grab the initial value from the object - // TODO: Is this documented? This is very useful and removes a lot of clutter from tweens! - if (p_initial_val.get_type() == Variant::NIL) { - p_initial_val = p_object->get_indexed(p_property.get_subnames()); + if (do_continue) { + initial_val = target_instance->get_indexed(property); } - // Convert any integers into REALs as they are better for interpolation - if (p_initial_val.get_type() == Variant::INT) { - p_initial_val = p_initial_val.operator real_t(); - } - if (p_final_val.get_type() == Variant::INT) { - p_final_val = p_final_val.operator real_t(); + if (relative) { + final_val = Variant::evaluate(Variant::Operator::OP_ADD, initial_val, base_final_val); } - // Build the interpolation data - _build_interpolation(INTER_PROPERTY, p_object, &p_property, nullptr, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); + delta_val = tween->calculate_delta_value(initial_val, final_val); } -void Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // If we are busy updating, call this function again later - if (pending_update != 0) { - _add_pending_command("interpolate_method", p_object, p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); - return; +bool PropertyTweener::step(float &r_delta) { + if (finished) { + // This is needed in case there's a parallel Tweener with longer duration. + return false; } - // Check that the target object is valid - ERR_FAIL_COND_MSG(p_object == nullptr, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name())); - - // Convert any integers into REALs as they are better for interpolation - if (p_initial_val.get_type() == Variant::INT) { - p_initial_val = p_initial_val.operator real_t(); - } - if (p_final_val.get_type() == Variant::INT) { - p_final_val = p_final_val.operator real_t(); + Object *target_instance = ObjectDB::get_instance(target); + if (!target_instance) { + return false; } + elapsed_time += r_delta; - // Build the interpolation data - _build_interpolation(INTER_METHOD, p_object, nullptr, &p_method, p_initial_val, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); -} - -void Tween::interpolate_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE) { - // If we are already updating, call this function again later - if (pending_update != 0) { - _add_pending_command("interpolate_callback", p_object, p_duration, p_callback, p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); - return; + if (elapsed_time < delay) { + r_delta = 0; + return true; } - // Check that the target object is valid - ERR_FAIL_COND(p_object == nullptr); - - // Duration cannot be negative - ERR_FAIL_COND(p_duration < 0); - - // Check whether the object even has the callback - ERR_FAIL_COND_MSG(!p_object->has_method(p_callback), "Object has no callback named: " + p_callback + "."); - - // Build a new InterpolationData - InterpolateData data; - data.active = true; - data.type = INTER_CALLBACK; - data.finish = false; - data.call_deferred = false; - data.elapsed = 0; - - // Give the data it's configuration - data.id = p_object->get_instance_id(); - data.key.push_back(p_callback); - data.concatenated_key = p_callback; - data.duration = p_duration; - data.delay = 0; - - // Add arguments to the interpolation - int args = 0; - if (p_arg5.get_type() != Variant::NIL) { - args = 5; - } else if (p_arg4.get_type() != Variant::NIL) { - args = 4; - } else if (p_arg3.get_type() != Variant::NIL) { - args = 3; - } else if (p_arg2.get_type() != Variant::NIL) { - args = 2; - } else if (p_arg1.get_type() != Variant::NIL) { - args = 1; + float time = MIN(elapsed_time - delay, duration); + target_instance->set_indexed(property, tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type)); + + if (time < duration) { + r_delta = 0; + return true; } else { - args = 0; + finished = true; + r_delta = elapsed_time - delay - duration; + emit_signal("finished"); + return false; } - - data.args = args; - data.arg[0] = p_arg1; - data.arg[1] = p_arg2; - data.arg[2] = p_arg3; - data.arg[3] = p_arg4; - data.arg[4] = p_arg5; - - // Add the new interpolation - _push_interpolate_data(data); } -void Tween::interpolate_deferred_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE) { - // If we are already updating, call this function again later - if (pending_update != 0) { - _add_pending_command("interpolate_deferred_callback", p_object, p_duration, p_callback, p_arg1, p_arg2, p_arg3, p_arg4, p_arg5); - return; +void PropertyTweener::set_tween(Ref<Tween> p_tween) { + tween = p_tween; + if (trans_type == Tween::TRANS_MAX) { + trans_type = tween->get_trans(); } - - // Check that the target object is valid - ERR_FAIL_COND(p_object == nullptr); - - // No negative durations allowed - ERR_FAIL_COND(p_duration < 0); - - // Confirm the callback exists on the object - ERR_FAIL_COND_MSG(!p_object->has_method(p_callback), "Object has no callback named: " + p_callback + "."); - - // Create a new InterpolateData for the callback - InterpolateData data; - data.active = true; - data.type = INTER_CALLBACK; - data.finish = false; - data.call_deferred = true; - data.elapsed = 0; - - // Give the data it's configuration - data.id = p_object->get_instance_id(); - data.key.push_back(p_callback); - data.concatenated_key = p_callback; - data.duration = p_duration; - data.delay = 0; - - // Collect arguments for the callback - int args = 0; - if (p_arg5.get_type() != Variant::NIL) { - args = 5; - } else if (p_arg4.get_type() != Variant::NIL) { - args = 4; - } else if (p_arg3.get_type() != Variant::NIL) { - args = 3; - } else if (p_arg2.get_type() != Variant::NIL) { - args = 2; - } else if (p_arg1.get_type() != Variant::NIL) { - args = 1; - } else { - args = 0; + if (ease_type == Tween::EASE_MAX) { + ease_type = tween->get_ease(); } +} - data.args = args; - data.arg[0] = p_arg1; - data.arg[1] = p_arg2; - data.arg[2] = p_arg3; - data.arg[3] = p_arg4; - data.arg[4] = p_arg5; +void PropertyTweener::_bind_methods() { + ClassDB::bind_method(D_METHOD("from", "value"), &PropertyTweener::from); + ClassDB::bind_method(D_METHOD("from_current"), &PropertyTweener::from_current); + ClassDB::bind_method(D_METHOD("as_relative"), &PropertyTweener::as_relative); + ClassDB::bind_method(D_METHOD("set_trans", "trans"), &PropertyTweener::set_trans); + ClassDB::bind_method(D_METHOD("set_ease", "ease"), &PropertyTweener::set_ease); + ClassDB::bind_method(D_METHOD("set_delay", "delay"), &PropertyTweener::set_delay); +} - // Add the new interpolation - _push_interpolate_data(data); +PropertyTweener::PropertyTweener(Object *p_target, NodePath p_property, Variant p_to, float p_duration) { + target = p_target->get_instance_id(); + property = p_property.get_as_property_path().get_subnames(); + initial_val = p_target->get_indexed(property); + base_final_val = p_to; + final_val = base_final_val; + duration = p_duration; } -void Tween::follow_property(Object *p_object, NodePath p_property, Variant p_initial_val, Object *p_target, NodePath p_target_property, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // If we are already updating, call this function again later - if (pending_update != 0) { - _add_pending_command("follow_property", p_object, p_property, p_initial_val, p_target, p_target_property, p_duration, p_trans_type, p_ease_type, p_delay); - return; - } +PropertyTweener::PropertyTweener() { + ERR_FAIL_MSG("Can't create empty PropertyTweener. Use get_tree().tween_property() or tween_property() instead."); +} - // Get the two properties from their paths - p_property = p_property.get_as_property_path(); - p_target_property = p_target_property.get_as_property_path(); +void IntervalTweener::start() { + elapsed_time = 0; + finished = false; +} - // If no initial value is given, grab it from the source object - // TODO: Is this documented? It's really helpful for decluttering tweens - if (p_initial_val.get_type() == Variant::NIL) { - p_initial_val = p_object->get_indexed(p_property.get_subnames()); +bool IntervalTweener::step(float &r_delta) { + if (finished) { + return false; } - // Convert initial INT values to FLOAT as they are better for interpolation - if (p_initial_val.get_type() == Variant::INT) { - p_initial_val = p_initial_val.operator real_t(); + elapsed_time += r_delta; + + if (elapsed_time < duration) { + r_delta = 0; + return true; + } else { + finished = true; + r_delta = elapsed_time - duration; + emit_signal("finished"); + return false; } +} - // Confirm the source and target objects are valid - ERR_FAIL_COND(p_object == nullptr); - ERR_FAIL_COND(p_target == nullptr); +IntervalTweener::IntervalTweener(float p_time) { + duration = p_time; +} - // No negative durations - ERR_FAIL_COND(p_duration < 0); +IntervalTweener::IntervalTweener() { + ERR_FAIL_MSG("Can't create empty IntervalTweener. Use get_tree().tween_interval() instead."); +} - // Ensure transition and easing types are valid - ERR_FAIL_COND(p_trans_type < 0 || p_trans_type >= TRANS_COUNT); - ERR_FAIL_COND(p_ease_type < 0 || p_ease_type >= EASE_COUNT); +Ref<CallbackTweener> CallbackTweener::set_delay(float p_delay) { + delay = p_delay; + return this; +} - // No negative delays - ERR_FAIL_COND(p_delay < 0); +void CallbackTweener::start() { + elapsed_time = 0; + finished = false; +} - // Confirm the source and target objects have the desired properties - bool prop_valid = false; - p_object->get_indexed(p_property.get_subnames(), &prop_valid); - ERR_FAIL_COND(!prop_valid); +bool CallbackTweener::step(float &r_delta) { + if (finished) { + return false; + } - bool target_prop_valid = false; - Variant target_val = p_target->get_indexed(p_target_property.get_subnames(), &target_prop_valid); - ERR_FAIL_COND(!target_prop_valid); + elapsed_time += r_delta; + if (elapsed_time >= delay) { + Variant result; + Callable::CallError ce; + callback.call(nullptr, 0, result, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_FAIL_V_MSG(false, "Error calling method from CallbackTweener: " + Variant::get_call_error_text(this, callback.get_method(), nullptr, 0, ce)); + } - // Convert target INT to FLOAT since it is better for interpolation - if (target_val.get_type() == Variant::INT) { - target_val = target_val.operator real_t(); + finished = true; + r_delta = elapsed_time - delay; + emit_signal("finished"); + return false; } - // Verify that the target value and initial value are the same type - ERR_FAIL_COND(target_val.get_type() != p_initial_val.get_type()); - - // Create a new InterpolateData - InterpolateData data; - data.active = true; - data.type = FOLLOW_PROPERTY; - data.finish = false; - data.elapsed = 0; - - // Give the InterpolateData it's configuration - data.id = p_object->get_instance_id(); - data.key = p_property.get_subnames(); - data.concatenated_key = p_property.get_concatenated_subnames(); - data.initial_val = p_initial_val; - data.target_id = p_target->get_instance_id(); - data.target_key = p_target_property.get_subnames(); - data.duration = p_duration; - data.trans_type = p_trans_type; - data.ease_type = p_ease_type; - data.delay = p_delay; - - // Add the interpolation - _push_interpolate_data(data); -} - -void Tween::follow_method(Object *p_object, StringName p_method, Variant p_initial_val, Object *p_target, StringName p_target_method, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // If we are currently updating, call this function again later - if (pending_update != 0) { - _add_pending_command("follow_method", p_object, p_method, p_initial_val, p_target, p_target_method, p_duration, p_trans_type, p_ease_type, p_delay); - return; - } - // Convert initial INT values to FLOAT as they are better for interpolation - if (p_initial_val.get_type() == Variant::INT) { - p_initial_val = p_initial_val.operator real_t(); - } + r_delta = 0; + return true; +} - // Verify the source and target objects are valid - ERR_FAIL_COND(p_object == nullptr); - ERR_FAIL_COND(p_target == nullptr); +void CallbackTweener::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_delay", "delay"), &CallbackTweener::set_delay); +} - // No negative durations - ERR_FAIL_COND(p_duration < 0); +CallbackTweener::CallbackTweener(Callable p_callback) { + callback = p_callback; +} - // Ensure that the transition and ease types are valid - ERR_FAIL_COND(p_trans_type < 0 || p_trans_type >= TRANS_COUNT); - ERR_FAIL_COND(p_ease_type < 0 || p_ease_type >= EASE_COUNT); +CallbackTweener::CallbackTweener() { + ERR_FAIL_MSG("Can't create empty CallbackTweener. Use get_tree().tween_callback() instead."); +} - // No negative delays - ERR_FAIL_COND(p_delay < 0); +Ref<MethodTweener> MethodTweener::set_delay(float p_delay) { + delay = p_delay; + return this; +} - // Confirm both objects have the target methods - ERR_FAIL_COND_MSG(!p_object->has_method(p_method), "Object has no method named: " + p_method + "."); - ERR_FAIL_COND_MSG(!p_target->has_method(p_target_method), "Target has no method named: " + p_target_method + "."); +Ref<MethodTweener> MethodTweener::set_trans(Tween::TransitionType p_trans) { + trans_type = p_trans; + return this; +} - // Call the method to get the target value - Callable::CallError error; - Variant target_val = p_target->call(p_target_method, nullptr, 0, error); - ERR_FAIL_COND(error.error != Callable::CallError::CALL_OK); +Ref<MethodTweener> MethodTweener::set_ease(Tween::EaseType p_ease) { + ease_type = p_ease; + return this; +} - // Convert target INT values to FLOAT as they are better for interpolation - if (target_val.get_type() == Variant::INT) { - target_val = target_val.operator real_t(); - } - ERR_FAIL_COND(target_val.get_type() != p_initial_val.get_type()); - - // Make the new InterpolateData for the method follow - InterpolateData data; - data.active = true; - data.type = FOLLOW_METHOD; - data.finish = false; - data.elapsed = 0; - - // Give the data it's configuration - data.id = p_object->get_instance_id(); - data.key.push_back(p_method); - data.concatenated_key = p_method; - data.initial_val = p_initial_val; - data.target_id = p_target->get_instance_id(); - data.target_key.push_back(p_target_method); - data.duration = p_duration; - data.trans_type = p_trans_type; - data.ease_type = p_ease_type; - data.delay = p_delay; - - // Add the new interpolation - _push_interpolate_data(data); -} - -void Tween::targeting_property(Object *p_object, NodePath p_property, Object *p_initial, NodePath p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // If we are currently updating, call this function again later - if (pending_update != 0) { - _add_pending_command("targeting_property", p_object, p_property, p_initial, p_initial_property, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); - return; - } - // Grab the target property and the target property - p_property = p_property.get_as_property_path(); - p_initial_property = p_initial_property.get_as_property_path(); +void MethodTweener::start() { + elapsed_time = 0; + finished = false; +} - // Convert the initial INT values to FLOAT as they are better for Interpolation - if (p_final_val.get_type() == Variant::INT) { - p_final_val = p_final_val.operator real_t(); +bool MethodTweener::step(float &r_delta) { + if (finished) { + return false; } - // Verify both objects are valid - ERR_FAIL_COND(p_object == nullptr); - ERR_FAIL_COND(p_initial == nullptr); - - // No negative durations - ERR_FAIL_COND(p_duration < 0); - - // Ensure transition and easing types are valid - ERR_FAIL_COND(p_trans_type < 0 || p_trans_type >= TRANS_COUNT); - ERR_FAIL_COND(p_ease_type < 0 || p_ease_type >= EASE_COUNT); - - // No negative delays - ERR_FAIL_COND(p_delay < 0); - - // Ensure the initial and target properties exist on their objects - bool prop_valid = false; - p_object->get_indexed(p_property.get_subnames(), &prop_valid); - ERR_FAIL_COND(!prop_valid); + elapsed_time += r_delta; - bool initial_prop_valid = false; - Variant initial_val = p_initial->get_indexed(p_initial_property.get_subnames(), &initial_prop_valid); - ERR_FAIL_COND(!initial_prop_valid); - - // Convert the initial INT value to FLOAT as it is better for interpolation - if (initial_val.get_type() == Variant::INT) { - initial_val = initial_val.operator real_t(); - } - ERR_FAIL_COND(initial_val.get_type() != p_final_val.get_type()); - - // Build the InterpolateData object - InterpolateData data; - data.active = true; - data.type = TARGETING_PROPERTY; - data.finish = false; - data.elapsed = 0; - - // Give the data it's configuration - data.id = p_object->get_instance_id(); - data.key = p_property.get_subnames(); - data.concatenated_key = p_property.get_concatenated_subnames(); - data.target_id = p_initial->get_instance_id(); - data.target_key = p_initial_property.get_subnames(); - data.initial_val = initial_val; - data.final_val = p_final_val; - data.duration = p_duration; - data.trans_type = p_trans_type; - data.ease_type = p_ease_type; - data.delay = p_delay; - - // Ensure there is a valid delta - if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) { - return; + if (elapsed_time < delay) { + r_delta = 0; + return true; } - // Add the interpolation - _push_interpolate_data(data); -} + float time = MIN(elapsed_time - delay, duration); + Variant current_val = tween->interpolate_variant(initial_val, delta_val, time, duration, trans_type, ease_type); + const Variant **argptr = (const Variant **)alloca(sizeof(Variant *)); + argptr[0] = ¤t_val; -void Tween::targeting_method(Object *p_object, StringName p_method, Object *p_initial, StringName p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay) { - // If we are currently updating, call this function again later - if (pending_update != 0) { - _add_pending_command("targeting_method", p_object, p_method, p_initial, p_initial_method, p_final_val, p_duration, p_trans_type, p_ease_type, p_delay); - return; + Variant result; + Callable::CallError ce; + callback.call(argptr, 1, result, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_FAIL_V_MSG(false, "Error calling method from MethodTweener: " + Variant::get_call_error_text(this, callback.get_method(), argptr, 1, ce)); } - // Convert final INT values to FLOAT as they are better for interpolation - if (p_final_val.get_type() == Variant::INT) { - p_final_val = p_final_val.operator real_t(); + if (time < duration) { + r_delta = 0; + return true; + } else { + finished = true; + r_delta = elapsed_time - delay - duration; + emit_signal("finished"); + return false; } +} - // Make sure the given objects are valid - ERR_FAIL_COND(p_object == nullptr); - ERR_FAIL_COND(p_initial == nullptr); - - // No negative durations - ERR_FAIL_COND(p_duration < 0); - - // Ensure transition and easing types are valid - ERR_FAIL_COND(p_trans_type < 0 || p_trans_type >= TRANS_COUNT); - ERR_FAIL_COND(p_ease_type < 0 || p_ease_type >= EASE_COUNT); - - // No negative delays - ERR_FAIL_COND(p_delay < 0); - - // Make sure both objects have the given method - ERR_FAIL_COND_MSG(!p_object->has_method(p_method), "Object has no method named: " + p_method + "."); - ERR_FAIL_COND_MSG(!p_initial->has_method(p_initial_method), "Initial Object has no method named: " + p_initial_method + "."); - - // Call the method to get the initial value - Callable::CallError error; - Variant initial_val = p_initial->call(p_initial_method, nullptr, 0, error); - ERR_FAIL_COND(error.error != Callable::CallError::CALL_OK); - - // Convert initial INT values to FLOAT as they aer better for interpolation - if (initial_val.get_type() == Variant::INT) { - initial_val = initial_val.operator real_t(); +void MethodTweener::set_tween(Ref<Tween> p_tween) { + tween = p_tween; + if (trans_type == Tween::TRANS_MAX) { + trans_type = tween->get_trans(); } - ERR_FAIL_COND(initial_val.get_type() != p_final_val.get_type()); - - // Build the new InterpolateData object - InterpolateData data; - data.active = true; - data.type = TARGETING_METHOD; - data.finish = false; - data.elapsed = 0; - - // Configure the data - data.id = p_object->get_instance_id(); - data.key.push_back(p_method); - data.concatenated_key = p_method; - data.target_id = p_initial->get_instance_id(); - data.target_key.push_back(p_initial_method); - data.initial_val = initial_val; - data.final_val = p_final_val; - data.duration = p_duration; - data.trans_type = p_trans_type; - data.ease_type = p_ease_type; - data.delay = p_delay; - - // Ensure there is a valid delta - if (!_calc_delta_val(data.initial_val, data.final_val, data.delta_val)) { - return; + if (ease_type == Tween::EASE_MAX) { + ease_type = tween->get_ease(); } +} - // Add the interpolation - _push_interpolate_data(data); +void MethodTweener::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_delay", "delay"), &MethodTweener::set_delay); + ClassDB::bind_method(D_METHOD("set_trans", "trans"), &MethodTweener::set_trans); + ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease); } -Tween::Tween() { +MethodTweener::MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration) { + callback = p_callback; + initial_val = p_from; + delta_val = tween->calculate_delta_value(p_from, p_to); + duration = p_duration; } -Tween::~Tween() { +MethodTweener::MethodTweener() { + ERR_FAIL_MSG("Can't create empty MethodTweener. Use get_tree().tween_method() instead."); } diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 142c0c65e0..947cdb7c2d 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -31,10 +31,33 @@ #ifndef TWEEN_H #define TWEEN_H -#include "scene/main/node.h" +#include "core/object/ref_counted.h" -class Tween : public Node { - GDCLASS(Tween, Node); +class Tween; +class Node; + +class Tweener : public RefCounted { + GDCLASS(Tweener, RefCounted); + +public: + virtual void set_tween(Ref<Tween> p_tween); + virtual void start() = 0; + virtual bool step(float &r_delta) = 0; + +protected: + static void _bind_methods(); + Ref<Tween> tween; + float elapsed_time = 0; + bool finished = false; +}; + +class PropertyTweener; +class IntervalTweener; +class CallbackTweener; +class MethodTweener; + +class Tween : public RefCounted { + GDCLASS(Tween, RefCounted); public: enum TweenProcessMode { @@ -42,6 +65,12 @@ public: TWEEN_PROCESS_IDLE, }; + enum TweenPauseMode { + TWEEN_PAUSE_BOUND, + TWEEN_PAUSE_STOP, + TWEEN_PAUSE_PROCESS, + }; + enum TransitionType { TRANS_LINEAR, TRANS_SINE, @@ -54,8 +83,7 @@ public: TRANS_CIRC, TRANS_BOUNCE, TRANS_BACK, - - TRANS_COUNT, + TRANS_MAX }; enum EaseType { @@ -63,130 +91,187 @@ public: EASE_OUT, EASE_IN_OUT, EASE_OUT_IN, - - EASE_COUNT, + EASE_MAX }; private: - enum InterpolateType { - INTER_PROPERTY, - INTER_METHOD, - FOLLOW_PROPERTY, - FOLLOW_METHOD, - TARGETING_PROPERTY, - TARGETING_METHOD, - INTER_CALLBACK, - }; + TweenProcessMode process_mode = TweenProcessMode::TWEEN_PROCESS_IDLE; + TweenPauseMode pause_mode = TweenPauseMode::TWEEN_PAUSE_STOP; + TransitionType default_transition = TransitionType::TRANS_LINEAR; + EaseType default_ease = EaseType::EASE_IN_OUT; + ObjectID bound_node; - struct InterpolateData { - bool active = false; - InterpolateType type = INTER_CALLBACK; - bool finish = false; - bool call_deferred = false; - real_t elapsed = 0.0; - ObjectID id; - Vector<StringName> key; - StringName concatenated_key; - Variant initial_val; - Variant delta_val; - Variant final_val; - ObjectID target_id; - Vector<StringName> target_key; - real_t duration = 0.0; - TransitionType trans_type = TransitionType::TRANS_BACK; - EaseType ease_type = EaseType::EASE_COUNT; - real_t delay = 0.0; - int args = 0; - Variant arg[5]; - int uid = 0; - }; + Vector<List<Ref<Tweener>>> tweeners; + int current_step = -1; + int loops = 1; + int loops_done = 0; + float speed_scale = 1; - String autoplay; - TweenProcessMode tween_process_mode = TWEEN_PROCESS_IDLE; - bool repeat = false; - float speed_scale = 1.0; - mutable int pending_update = 0; - int uid = 0; - bool was_stopped = false; + bool is_bound = false; + bool started = false; + bool running = true; + bool dead = false; + bool invalid = true; + bool default_parallel = false; + bool parallel_enabled = false; - List<InterpolateData> interpolates; + typedef real_t (*interpolater)(real_t t, real_t b, real_t c, real_t d); + static interpolater interpolaters[TRANS_MAX][EASE_MAX]; - struct PendingCommand { - StringName key; - int args = 0; - Variant arg[10]; - }; - List<PendingCommand> pending_commands; + void start_tweeners(); - void _add_pending_command(StringName p_key, const Variant &p_arg1 = Variant(), const Variant &p_arg2 = Variant(), const Variant &p_arg3 = Variant(), const Variant &p_arg4 = Variant(), const Variant &p_arg5 = Variant(), const Variant &p_arg6 = Variant(), const Variant &p_arg7 = Variant(), const Variant &p_arg8 = Variant(), const Variant &p_arg9 = Variant(), const Variant &p_arg10 = Variant()); - void _process_pending_commands(); +protected: + static void _bind_methods(); - typedef real_t (*interpolater)(real_t t, real_t b, real_t c, real_t d); - static interpolater interpolaters[TRANS_COUNT][EASE_COUNT]; +public: + Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration); + Ref<IntervalTweener> tween_interval(float p_time); + Ref<CallbackTweener> tween_callback(Callable p_callback); + Ref<MethodTweener> tween_method(Callable p_callback, float p_from, float p_to, float p_duration); + Ref<Tween> append(Ref<Tweener> p_tweener); - real_t _run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d); - Variant &_get_delta_val(InterpolateData &p_data); - Variant _get_initial_val(const InterpolateData &p_data) const; - Variant _get_final_val(const InterpolateData &p_data) const; - Variant _run_equation(InterpolateData &p_data); - bool _calc_delta_val(const Variant &p_initial_val, const Variant &p_final_val, Variant &p_delta_val); - bool _apply_tween_value(InterpolateData &p_data, Variant &value); + bool custom_step(float p_delta); + void stop(); + void pause(); + void play(); + void kill(); - void _tween_process(float p_delta); - void _remove_by_uid(int uid); - void _push_interpolate_data(InterpolateData &p_data); - void _build_interpolation(InterpolateType p_interpolation_type, Object *p_object, NodePath *p_property, StringName *p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type, EaseType p_ease_type, real_t p_delay); + bool is_running(); + void set_valid(bool p_valid); + bool is_valid(); -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; - void _notification(int p_what); + Ref<Tween> bind_node(Node *p_node); + Ref<Tween> set_process_mode(TweenProcessMode p_mode); + TweenProcessMode get_process_mode(); + Ref<Tween> set_pause_mode(TweenPauseMode p_mode); + TweenPauseMode get_pause_mode(); - static void _bind_methods(); + Ref<Tween> set_parallel(bool p_parallel); + Ref<Tween> set_loops(int p_loops); + Ref<Tween> set_speed_scale(float p_speed); + Ref<Tween> set_trans(TransitionType p_trans); + TransitionType get_trans(); + Ref<Tween> set_ease(EaseType p_ease); + EaseType get_ease(); -public: - bool is_active() const; - void set_active(bool p_active); - - bool is_repeat() const; - void set_repeat(bool p_repeat); - - void set_tween_process_mode(TweenProcessMode p_mode); - TweenProcessMode get_tween_process_mode() const; - - void set_speed_scale(float p_speed); - float get_speed_scale() const; - - void start(); - void reset(Object *p_object, StringName p_key); - void reset_all(); - void stop(Object *p_object, StringName p_key); - void stop_all(); - void resume(Object *p_object, StringName p_key); - void resume_all(); - void remove(Object *p_object, StringName p_key); - void remove_all(); - - void seek(real_t p_time); - real_t tell() const; - real_t get_runtime() const; - - void interpolate_property(Object *p_object, NodePath p_property, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type = TRANS_LINEAR, EaseType p_ease_type = EASE_IN_OUT, real_t p_delay = 0); - void interpolate_method(Object *p_object, StringName p_method, Variant p_initial_val, Variant p_final_val, real_t p_duration, TransitionType p_trans_type = TRANS_LINEAR, EaseType p_ease_type = EASE_IN_OUT, real_t p_delay = 0); - void interpolate_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE); - void interpolate_deferred_callback(Object *p_object, real_t p_duration, String p_callback, VARIANT_ARG_DECLARE); - void follow_property(Object *p_object, NodePath p_property, Variant p_initial_val, Object *p_target, NodePath p_target_property, real_t p_duration, TransitionType p_trans_type = TRANS_LINEAR, EaseType p_ease_type = EASE_IN_OUT, real_t p_delay = 0); - void follow_method(Object *p_object, StringName p_method, Variant p_initial_val, Object *p_target, StringName p_target_method, real_t p_duration, TransitionType p_trans_type = TRANS_LINEAR, EaseType p_ease_type = EASE_IN_OUT, real_t p_delay = 0); - void targeting_property(Object *p_object, NodePath p_property, Object *p_initial, NodePath p_initial_property, Variant p_final_val, real_t p_duration, TransitionType p_trans_type = TRANS_LINEAR, EaseType p_ease_type = EASE_IN_OUT, real_t p_delay = 0); - void targeting_method(Object *p_object, StringName p_method, Object *p_initial, StringName p_initial_method, Variant p_final_val, real_t p_duration, TransitionType p_trans_type = TRANS_LINEAR, EaseType p_ease_type = EASE_IN_OUT, real_t p_delay = 0); - - Tween(); - ~Tween(); + Ref<Tween> parallel(); + Ref<Tween> chain(); + + real_t run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d); + Variant interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, Tween::TransitionType p_trans, Tween::EaseType p_ease); + Variant calculate_delta_value(Variant p_intial_val, Variant p_final_val); + + bool step(float p_delta); + bool should_pause(); + + Tween() {} }; +VARIANT_ENUM_CAST(Tween::TweenPauseMode); VARIANT_ENUM_CAST(Tween::TweenProcessMode); VARIANT_ENUM_CAST(Tween::TransitionType); VARIANT_ENUM_CAST(Tween::EaseType); +class PropertyTweener : public Tweener { + GDCLASS(PropertyTweener, Tweener); + +public: + Ref<PropertyTweener> from(Variant p_value); + Ref<PropertyTweener> from_current(); + Ref<PropertyTweener> as_relative(); + Ref<PropertyTweener> set_trans(Tween::TransitionType p_trans); + Ref<PropertyTweener> set_ease(Tween::EaseType p_ease); + Ref<PropertyTweener> set_delay(float p_delay); + + void set_tween(Ref<Tween> p_tween) override; + void start() override; + bool step(float &r_delta) override; + + PropertyTweener(Object *p_target, NodePath p_property, Variant p_to, float p_duration); + PropertyTweener(); + +protected: + static void _bind_methods(); + +private: + ObjectID target; + Vector<StringName> property; + Variant initial_val; + Variant base_final_val; + Variant final_val; + Variant delta_val; + + float duration = 0; + Tween::TransitionType trans_type = Tween::TRANS_MAX; // This is set inside set_tween(); + Tween::EaseType ease_type = Tween::EASE_MAX; + + float delay = 0; + bool do_continue = true; + bool relative = false; +}; + +class IntervalTweener : public Tweener { + GDCLASS(IntervalTweener, Tweener); + +public: + void start() override; + bool step(float &r_delta) override; + + IntervalTweener(float p_time); + IntervalTweener(); + +private: + float duration = 0; +}; + +class CallbackTweener : public Tweener { + GDCLASS(CallbackTweener, Tweener); + +public: + Ref<CallbackTweener> set_delay(float p_delay); + + void start() override; + bool step(float &r_delta) override; + + CallbackTweener(Callable p_callback); + CallbackTweener(); + +protected: + static void _bind_methods(); + +private: + Callable callback; + float delay = 0; +}; + +class MethodTweener : public Tweener { + GDCLASS(MethodTweener, Tweener); + +public: + Ref<MethodTweener> set_trans(Tween::TransitionType p_trans); + Ref<MethodTweener> set_ease(Tween::EaseType p_ease); + Ref<MethodTweener> set_delay(float p_delay); + + void set_tween(Ref<Tween> p_tween) override; + void start() override; + bool step(float &r_delta) override; + + MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration); + MethodTweener(); + +protected: + static void _bind_methods(); + +private: + float duration = 0; + float delay = 0; + Tween::TransitionType trans_type = Tween::TRANS_MAX; + Tween::EaseType ease_type = Tween::EASE_MAX; + + Ref<Tween> tween; + Variant initial_val; + Variant delta_val; + Callable callback; +}; + #endif diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index a1d4adcd41..1e121ab6e5 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -98,7 +98,7 @@ Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Arra } else if (p_msg == "override_camera_3D:transform") { ERR_FAIL_COND_V(p_args.size() < 5, ERR_INVALID_DATA); - Transform transform = p_args[0]; + Transform3D transform = p_args[0]; bool is_perspective = p_args[1]; float size_or_fov = p_args[2]; float near = p_args[3]; @@ -525,7 +525,7 @@ void LiveEditor::_node_set_func(int p_id, const StringName &p_prop, const Varian for (Set<Node *>::Element *F = E->get().front(); F; F = F->next()) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -569,7 +569,7 @@ void LiveEditor::_node_call_func(int p_id, const StringName &p_method, VARIANT_A for (Set<Node *>::Element *F = E->get().front(); F; F = F->next()) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -652,7 +652,7 @@ void LiveEditor::_create_node_func(const NodePath &p_parent, const String &p_typ for (Set<Node *>::Element *F = E->get().front(); F; F = F->next()) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -661,7 +661,7 @@ void LiveEditor::_create_node_func(const NodePath &p_parent, const String &p_typ } Node *n2 = n->get_node(p_parent); - Node *no = Object::cast_to<Node>(ClassDB::instance(p_type)); + Node *no = Object::cast_to<Node>(ClassDB::instantiate(p_type)); if (!no) { continue; } @@ -696,7 +696,7 @@ void LiveEditor::_instance_node_func(const NodePath &p_parent, const String &p_p for (Set<Node *>::Element *F = E->get().front(); F; F = F->next()) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -705,7 +705,7 @@ void LiveEditor::_instance_node_func(const NodePath &p_parent, const String &p_p } Node *n2 = n->get_node(p_parent); - Node *no = ps->instance(); + Node *no = ps->instantiate(); if (!no) { continue; } @@ -736,7 +736,7 @@ void LiveEditor::_remove_node_func(const NodePath &p_at) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -772,7 +772,7 @@ void LiveEditor::_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_kee Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -811,7 +811,7 @@ void LiveEditor::_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_a Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -862,7 +862,7 @@ void LiveEditor::_duplicate_node_func(const NodePath &p_at, const String &p_new_ for (Set<Node *>::Element *F = E->get().front(); F; F = F->next()) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } @@ -901,7 +901,7 @@ void LiveEditor::_reparent_node_func(const NodePath &p_at, const NodePath &p_new for (Set<Node *>::Element *F = E->get().front(); F; F = F->next()) { Node *n = F->get(); - if (base && !base->is_a_parent_of(n)) { + if (base && !base->is_ancestor_of(n)) { continue; } diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ac067aa001..c1ae0479f5 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -98,17 +98,14 @@ void BaseButton::_notification(int p_what) { } if (p_what == NOTIFICATION_FOCUS_ENTER) { - status.hovering = true; update(); } if (p_what == NOTIFICATION_FOCUS_EXIT) { if (status.press_attempt) { status.press_attempt = false; - status.hovering = false; update(); } else if (status.hovering) { - status.hovering = false; update(); } } @@ -175,10 +172,9 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) { status.hovering = false; } } - // pressed state should be correct with button_up signal - emit_signal("button_up"); status.press_attempt = false; status.pressing_inside = false; + emit_signal("button_up"); } update(); @@ -395,7 +391,7 @@ bool BaseButton::_is_focus_owner_in_shorcut_context() const { Control *vp_focus = get_focus_owner(); // If the context is valid and the viewport focus is valid, check if the context is the focus or is a parent of it. - return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_a_parent_of(vp_focus)); + return ctx_node && vp_focus && (ctx_node == vp_focus || ctx_node->is_ancestor_of(vp_focus)); } void BaseButton::_bind_methods() { diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index c0df5271b4..bcc273114b 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -49,9 +49,14 @@ Size2 Button::get_minimum_size() const { if (!_icon.is_null()) { minsize.height = MAX(minsize.height, _icon->get_height()); - minsize.width += _icon->get_width(); - if (xl_text != "") { - minsize.width += get_theme_constant("hseparation"); + + if (icon_align != ALIGN_CENTER) { + minsize.width += _icon->get_width(); + if (xl_text != "") { + minsize.width += get_theme_constant("hseparation"); + } + } else { + minsize.width = MAX(minsize.width, _icon->get_width()); } } } @@ -202,6 +207,21 @@ void Button::_notification(int p_what) { } Rect2 icon_region = Rect2(); + TextAlign icon_align_rtl_checked = icon_align; + TextAlign align_rtl_checked = align; + // Swap icon and text alignment sides if right-to-left layout is set. + if (rtl) { + if (icon_align == ALIGN_RIGHT) { + icon_align_rtl_checked = ALIGN_LEFT; + } else if (icon_align == ALIGN_LEFT) { + icon_align_rtl_checked = ALIGN_RIGHT; + } + if (align == ALIGN_RIGHT) { + align_rtl_checked = ALIGN_LEFT; + } else if (align == ALIGN_LEFT) { + align_rtl_checked = ALIGN_RIGHT; + } + } if (!_icon.is_null()) { int valign = size.height - style->get_minimum_size().y; if (is_disabled()) { @@ -209,20 +229,27 @@ void Button::_notification(int p_what) { } float icon_ofs_region = 0.0; - if (rtl) { - if (_internal_margin[SIDE_RIGHT] > 0) { - icon_ofs_region = _internal_margin[SIDE_RIGHT] + get_theme_constant("hseparation"); - } - } else { + Point2 style_offset; + Size2 icon_size = _icon->get_size(); + if (icon_align_rtl_checked == ALIGN_LEFT) { + style_offset.x = style->get_margin(SIDE_LEFT); if (_internal_margin[SIDE_LEFT] > 0) { icon_ofs_region = _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } + } else if (icon_align_rtl_checked == ALIGN_CENTER) { + style_offset.x = 0.0; + } else if (icon_align_rtl_checked == ALIGN_RIGHT) { + style_offset.x = -style->get_margin(SIDE_RIGHT); + if (_internal_margin[SIDE_RIGHT] > 0) { + icon_ofs_region = -_internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); + } } + style_offset.y = style->get_margin(SIDE_TOP); if (expand_icon) { Size2 _size = get_size() - style->get_offset() * 2; _size.width -= get_theme_constant("hseparation") + icon_ofs_region; - if (!clip_text) { + if (!clip_text && icon_align_rtl_checked != ALIGN_CENTER) { _size.width -= text_buf->get_size().width; } float icon_width = _icon->get_width() * _size.height / _icon->get_height(); @@ -233,21 +260,26 @@ void Button::_notification(int p_what) { icon_height = _icon->get_height() * icon_width / _icon->get_width(); } - if (rtl) { - icon_region = Rect2(Point2(size.width - (icon_ofs_region + icon_width + style->get_margin(SIDE_RIGHT)), style->get_margin(SIDE_TOP) + (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); - } else { - icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); - } + icon_size = Size2(icon_width, icon_height); + } + + if (icon_align_rtl_checked == ALIGN_LEFT) { + icon_region = Rect2(style_offset + Point2(icon_ofs_region, Math::floor((valign - icon_size.y) * 0.5)), icon_size); + } else if (icon_align_rtl_checked == ALIGN_CENTER) { + icon_region = Rect2(style_offset + Point2(icon_ofs_region + Math::floor((size.x - icon_size.x) * 0.5), Math::floor((valign - icon_size.y) * 0.5)), icon_size); } else { - if (rtl) { - icon_region = Rect2(Point2(size.width - (icon_ofs_region + _icon->get_size().width + style->get_margin(SIDE_RIGHT)), style->get_margin(SIDE_TOP) + Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); - } else { - icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); - } + icon_region = Rect2(style_offset + Point2(icon_ofs_region + size.x - icon_size.x, Math::floor((valign - icon_size.y) * 0.5)), icon_size); + } + + if (icon_region.size.width > 0) { + draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); } } Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_theme_constant("hseparation"), 0) : Point2(); + if (align_rtl_checked == ALIGN_CENTER && icon_align_rtl_checked == ALIGN_CENTER) { + icon_ofs.x = 0.0; + } int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; text_buf->set_width(clip_text ? text_clip : -1); @@ -262,20 +294,15 @@ void Button::_notification(int p_what) { Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0; - switch (align) { + switch (align_rtl_checked) { case ALIGN_LEFT: { - if (rtl) { - if (_internal_margin[SIDE_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); - } else { - text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; - } + if (icon_align_rtl_checked != ALIGN_LEFT) { + icon_ofs.x = 0.0; + } + if (_internal_margin[SIDE_LEFT] > 0) { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } else { - if (_internal_margin[SIDE_LEFT] > 0) { - text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); - } else { - text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; - } + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; } text_ofs.y += style->get_offset().y; } break; @@ -283,31 +310,24 @@ void Button::_notification(int p_what) { if (text_ofs.x < 0) { text_ofs.x = 0; } - text_ofs += icon_ofs; + if (icon_align_rtl_checked == ALIGN_LEFT) { + text_ofs += icon_ofs; + } text_ofs += style->get_offset(); } break; case ALIGN_RIGHT: { - if (rtl) { - if (_internal_margin[SIDE_LEFT] > 0) { - text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); - } else { - text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; - } + if (_internal_margin[SIDE_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); } else { - if (_internal_margin[SIDE_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); - } else { - text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; - } + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; } text_ofs.y += style->get_offset().y; + if (icon_align_rtl_checked == ALIGN_RIGHT) { + text_ofs.x -= icon_ofs.x; + } } break; } - if (rtl) { - text_ofs.x -= icon_ofs.x; - } - Color font_outline_color = get_theme_color("font_outline_color"); int outline_size = get_theme_constant("outline_size"); if (outline_size > 0 && font_outline_color.a > 0) { @@ -315,10 +335,6 @@ void Button::_notification(int p_what) { } text_buf->draw(ci, text_ofs, color); - - if (!_icon.is_null() && icon_region.size.width > 0) { - draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); - } } break; } } @@ -457,6 +473,16 @@ Button::TextAlign Button::get_text_align() const { return align; } +void Button::set_icon_align(TextAlign p_align) { + icon_align = p_align; + minimum_size_changed(); + update(); +} + +Button::TextAlign Button::get_icon_align() const { + return icon_align; +} + bool Button::_set(const StringName &p_name, const Variant &p_value) { String str = p_name; if (str.begins_with("opentype_features/")) { @@ -519,14 +545,16 @@ void Button::_bind_methods() { ClassDB::bind_method(D_METHOD("get_language"), &Button::get_language); ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_icon); ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_icon); - ClassDB::bind_method(D_METHOD("set_expand_icon"), &Button::set_expand_icon); - ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon); ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &Button::set_flat); + ClassDB::bind_method(D_METHOD("is_flat"), &Button::is_flat); ClassDB::bind_method(D_METHOD("set_clip_text", "enabled"), &Button::set_clip_text); ClassDB::bind_method(D_METHOD("get_clip_text"), &Button::get_clip_text); ClassDB::bind_method(D_METHOD("set_text_align", "align"), &Button::set_text_align); ClassDB::bind_method(D_METHOD("get_text_align"), &Button::get_text_align); - ClassDB::bind_method(D_METHOD("is_flat"), &Button::is_flat); + ClassDB::bind_method(D_METHOD("set_icon_align", "icon_align"), &Button::set_icon_align); + ClassDB::bind_method(D_METHOD("get_icon_align"), &Button::get_icon_align); + ClassDB::bind_method(D_METHOD("set_expand_icon"), &Button::set_expand_icon); + ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon); BIND_ENUM_CONSTANT(ALIGN_LEFT); BIND_ENUM_CONSTANT(ALIGN_CENTER); @@ -539,11 +567,12 @@ void Button::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_icon_align", "get_icon_align"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon"); } Button::Button(const String &p_text) { - text_buf.instance(); + text_buf.instantiate(); text_buf->set_flags(TextServer::BREAK_MANDATORY); set_mouse_filter(MOUSE_FILTER_STOP); diff --git a/scene/gui/button.h b/scene/gui/button.h index d968f63f51..253d079680 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -58,6 +58,7 @@ private: bool expand_icon = false; bool clip_text = false; TextAlign align = ALIGN_CENTER; + TextAlign icon_align = ALIGN_LEFT; float _internal_margin[4] = {}; void _shape(); @@ -102,6 +103,9 @@ public: void set_text_align(TextAlign p_align); TextAlign get_text_align() const; + void set_icon_align(TextAlign p_align); + TextAlign get_icon_align() const; + Button(const String &p_text = String()); ~Button(); }; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index d5000e88d7..ba1534ed5c 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -122,7 +122,7 @@ void CodeEdit::_notification(int p_what) { ERR_CONTINUE(l < 0 || l >= code_completion_options_count); Ref<TextLine> tl; - tl.instance(); + tl.instantiate(); tl->add_string(code_completion_options[l].display, cache.font, cache.font_size); int yofs = (row_height - tl->get_size().y) / 2; @@ -218,6 +218,11 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { + /* Ignore mouse clicks in IME input mode. */ + if (has_ime_text()) { + return; + } + if (code_completion_active && code_completion_rect.has_point(mb->get_position())) { if (!mb->is_pressed()) { return; @@ -243,11 +248,37 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } update(); } break; + default: + break; } return; } cancel_code_completion(); set_code_hint(""); + + if (mb->is_pressed()) { + Vector2i mpos = mb->get_position(); + if (is_layout_rtl()) { + mpos.x = get_size().x - mpos.x; + } + + int line, col; + _get_mouse_pos(Point2i(mpos.x, mpos.y), line, col); + + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { + if (is_line_folded(line)) { + int wrap_index = get_line_wrap_index_at_col(line, col); + if (wrap_index == times_line_wraps(line)) { + int eol_icon_width = cache.folded_eol_icon->get_width(); + int left_margin = get_total_gutter_width() + eol_icon_width + get_line_width(line, wrap_index) - get_h_scroll(); + if (mpos.x > left_margin && mpos.x <= left_margin + eol_icon_width + 3) { + unfold_line(line); + return; + } + } + } + } + } } Ref<InputEventKey> k = p_gui_input; @@ -329,7 +360,7 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } if (k->is_action("ui_text_backspace", true)) { - backspace_at_cursor(); + backspace(); _filter_code_completion_candidates(); accept_event(); return; @@ -356,6 +387,36 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { set_code_hint(""); } + /* Indentation */ + if (k->is_action("ui_text_indent", true)) { + do_indent(); + accept_event(); + return; + } + + if (k->is_action("ui_text_dedent", true)) { + do_unindent(); + accept_event(); + return; + } + + // Override new line actions, for auto indent + if (k->is_action("ui_text_newline_above", true)) { + _new_line(false, true); + accept_event(); + return; + } + if (k->is_action("ui_text_newline_blank", true)) { + _new_line(false); + accept_event(); + return; + } + if (k->is_action("ui_text_newline", true)) { + _new_line(); + accept_event(); + return; + } + /* Remove shift otherwise actions will not match. */ k = k->duplicate(); k->set_shift_pressed(false); @@ -380,9 +441,461 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const { if ((code_completion_active && code_completion_rect.has_point(p_pos)) || (is_readonly() && (!is_selecting_enabled() || get_line_count() == 0))) { return CURSOR_ARROW; } + + int line, col; + _get_mouse_pos(p_pos, line, col); + + if (is_line_folded(line)) { + int wrap_index = get_line_wrap_index_at_col(line, col); + if (wrap_index == times_line_wraps(line)) { + int eol_icon_width = cache.folded_eol_icon->get_width(); + int left_margin = get_total_gutter_width() + eol_icon_width + get_line_width(line, wrap_index) - get_h_scroll(); + if (p_pos.x > left_margin && p_pos.x <= left_margin + eol_icon_width + 3) { + return CURSOR_POINTING_HAND; + } + } + } + return TextEdit::get_cursor_shape(p_pos); } +/* Indent management */ +void CodeEdit::set_indent_size(const int p_size) { + ERR_FAIL_COND_MSG(p_size <= 0, "Indend size must be greater than 0."); + if (indent_size == p_size) { + return; + } + + indent_size = p_size; + if (indent_using_spaces) { + indent_text = String(" ").repeat(p_size); + } else { + indent_text = "\t"; + } + set_tab_size(p_size); +} + +int CodeEdit::get_indent_size() const { + return indent_size; +} + +void CodeEdit::set_indent_using_spaces(const bool p_use_spaces) { + indent_using_spaces = p_use_spaces; + if (indent_using_spaces) { + indent_text = String(" ").repeat(indent_size); + } else { + indent_text = "\t"; + } +} + +bool CodeEdit::is_indent_using_spaces() const { + return indent_using_spaces; +} + +void CodeEdit::set_auto_indent_enabled(bool p_enabled) { + auto_indent = p_enabled; +} + +bool CodeEdit::is_auto_indent_enabled() const { + return auto_indent; +} + +void CodeEdit::set_auto_indent_prefixes(const TypedArray<String> &p_prefixes) { + auto_indent_prefixes.clear(); + for (int i = 0; i < p_prefixes.size(); i++) { + const String prefix = p_prefixes[i]; + auto_indent_prefixes.insert(prefix[0]); + } +} + +TypedArray<String> CodeEdit::get_auto_indent_prefixes() const { + TypedArray<String> prefixes; + for (const Set<char32_t>::Element *E = auto_indent_prefixes.front(); E; E = E->next()) { + prefixes.push_back(String::chr(E->get())); + } + return prefixes; +} + +void CodeEdit::do_indent() { + if (is_readonly()) { + return; + } + + if (is_selection_active()) { + indent_lines(); + return; + } + + if (!indent_using_spaces) { + _insert_text_at_cursor("\t"); + return; + } + + int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor_get_column()); + if (spaces_to_add > 0) { + _insert_text_at_cursor(String(" ").repeat(spaces_to_add)); + } +} + +void CodeEdit::indent_lines() { + if (is_readonly()) { + return; + } + + begin_complex_operation(); + + /* This value informs us by how much we changed selection position by indenting right. */ + /* Default is 1 for tab indentation. */ + int selection_offset = 1; + + int start_line = cursor_get_line(); + int end_line = start_line; + if (is_selection_active()) { + start_line = get_selection_from_line(); + end_line = get_selection_to_line(); + + /* Ignore the last line if the selection is not past the first column. */ + if (get_selection_to_column() == 0) { + selection_offset = 0; + end_line--; + } + } + + for (int i = start_line; i <= end_line; i++) { + const String line_text = get_line(i); + if (line_text.size() == 0 && is_selection_active()) { + continue; + } + + if (!indent_using_spaces) { + set_line(i, '\t' + line_text); + continue; + } + + /* We don't really care where selection is - we just need to know indentation level at the beginning of the line. */ + /* Since we will add this many spaces, we want to move the whole selection and caret by this much. */ + int spaces_to_add = _calculate_spaces_till_next_right_indent(get_first_non_whitespace_column(i)); + set_line(i, String(" ").repeat(spaces_to_add) + line_text); + selection_offset = spaces_to_add; + } + + /* Fix selection and caret being off after shifting selection right.*/ + if (is_selection_active()) { + select(start_line, get_selection_from_column() + selection_offset, get_selection_to_line(), get_selection_to_column() + selection_offset); + } + cursor_set_column(cursor_get_column() + selection_offset, false); + + end_complex_operation(); +} + +void CodeEdit::do_unindent() { + if (is_readonly()) { + return; + } + + int cc = cursor_get_column(); + + if (is_selection_active() || cc <= 0) { + unindent_lines(); + return; + } + + int cl = cursor_get_line(); + const String &line = get_line(cl); + + if (line[cc - 1] == '\t') { + _remove_text(cl, cc - 1, cl, cc); + cursor_set_column(MAX(0, cc - 1)); + return; + } + + if (line[cc - 1] != ' ') { + return; + } + + int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); + if (spaces_to_remove > 0) { + for (int i = 1; i <= spaces_to_remove; i++) { + if (line[cc - i] != ' ') { + spaces_to_remove = i - 1; + break; + } + } + _remove_text(cl, cc - spaces_to_remove, cl, cc); + cursor_set_column(MAX(0, cc - spaces_to_remove)); + } +} + +void CodeEdit::unindent_lines() { + if (is_readonly()) { + return; + } + + begin_complex_operation(); + + /* Moving caret and selection after unindenting can get tricky because */ + /* changing content of line can move caret and selection on its own (if new line ends before previous position of either), */ + /* therefore we just remember initial values and at the end of the operation offset them by number of removed characters. */ + int removed_characters = 0; + int initial_selection_end_column = 0; + int initial_cursor_column = cursor_get_column(); + + int start_line = cursor_get_line(); + int end_line = start_line; + if (is_selection_active()) { + start_line = get_selection_from_line(); + end_line = get_selection_to_line(); + + /* Ignore the last line if the selection is not past the first column. */ + initial_selection_end_column = get_selection_to_column(); + if (initial_selection_end_column == 0) { + end_line--; + } + } + + bool first_line_edited = false; + bool last_line_edited = false; + + for (int i = start_line; i <= end_line; i++) { + String line_text = get_line(i); + + if (line_text.begins_with("\t")) { + line_text = line_text.substr(1, line_text.length()); + + set_line(i, line_text); + removed_characters = 1; + + first_line_edited = (i == start_line) ? true : first_line_edited; + last_line_edited = (i == end_line) ? true : last_line_edited; + continue; + } + + if (line_text.begins_with(" ")) { + /* When unindenting we aim to remove spaces before line that has selection no matter what is selected, */ + /* Here we remove only enough spaces to align text to nearest full multiple of indentation_size. */ + /* In case where selection begins at the start of indentation_size multiple we remove whole indentation level. */ + int spaces_to_remove = _calculate_spaces_till_next_left_indent(get_first_non_whitespace_column(i)); + line_text = line_text.substr(spaces_to_remove, line_text.length()); + + set_line(i, line_text); + removed_characters = spaces_to_remove; + + first_line_edited = (i == start_line) ? true : first_line_edited; + last_line_edited = (i == end_line) ? true : last_line_edited; + } + } + + if (is_selection_active()) { + /* Fix selection being off by one on the first line. */ + if (first_line_edited) { + select(get_selection_from_line(), get_selection_from_column() - removed_characters, get_selection_to_line(), initial_selection_end_column); + } + + /* Fix selection being off by one on the last line. */ + if (last_line_edited) { + select(get_selection_from_line(), get_selection_from_column(), get_selection_to_line(), initial_selection_end_column - removed_characters); + } + } + cursor_set_column(initial_cursor_column - removed_characters, false); + + end_complex_operation(); +} + +int CodeEdit::_calculate_spaces_till_next_left_indent(int p_column) const { + int spaces_till_indent = p_column % indent_size; + if (spaces_till_indent == 0) { + spaces_till_indent = indent_size; + } + return spaces_till_indent; +} + +int CodeEdit::_calculate_spaces_till_next_right_indent(int p_column) const { + return indent_size - p_column % indent_size; +} + +/* TODO: remove once brace completion is refactored. */ +static char32_t _get_right_pair_symbol(char32_t c) { + if (c == '"') { + return '"'; + } + if (c == '\'') { + return '\''; + } + if (c == '(') { + return ')'; + } + if (c == '[') { + return ']'; + } + if (c == '{') { + return '}'; + } + return 0; +} + +static bool _is_pair_left_symbol(char32_t c) { + return c == '"' || + c == '\'' || + c == '(' || + c == '[' || + c == '{'; +} + +void CodeEdit::_new_line(bool p_split_current_line, bool p_above) { + if (is_readonly()) { + return; + } + + const int cc = cursor_get_column(); + const int cl = cursor_get_line(); + const String line = get_line(cl); + + String ins = "\n"; + + /* Append current indentation. */ + int space_count = 0; + int line_col = 0; + for (; line_col < cc; line_col++) { + if (line[line_col] == '\t') { + ins += indent_text; + space_count = 0; + continue; + } + + if (line[line_col] == ' ') { + space_count++; + + if (space_count == indent_size) { + ins += indent_text; + space_count = 0; + } + continue; + } + break; + } + + if (is_line_folded(cl)) { + unfold_line(cl); + } + + /* Indent once again if the previous line needs it, ie ':'. */ + /* Then add an addition new line for any closing pairs aka '()'. */ + /* Skip this in comments or if we are going above. */ + bool brace_indent = false; + if (auto_indent && !p_above && cc > 0 && is_in_comment(cl) == -1) { + bool should_indent = false; + char32_t indent_char = ' '; + + for (; line_col < cc; line_col++) { + char32_t c = line[line_col]; + if (auto_indent_prefixes.has(c)) { + should_indent = true; + indent_char = c; + continue; + } + + /* Make sure this is the last char, trailing whitespace or comments are okay. */ + if (should_indent && (!_is_whitespace(c) && is_in_comment(cl, cc) == -1)) { + should_indent = false; + } + } + + if (should_indent) { + ins += indent_text; + + /* TODO: Change when brace completion is refactored. */ + char32_t closing_char = _get_right_pair_symbol(indent_char); + if (closing_char != 0 && closing_char == line[cc]) { + /* No need to move the brace below if we are not taking the text with us. */ + if (p_split_current_line) { + brace_indent = true; + ins += "\n" + ins.substr(1, ins.length() - 2); + } else { + brace_indent = false; + ins = "\n" + ins.substr(1, ins.length() - 2); + } + } + } + } + + begin_complex_operation(); + + bool first_line = false; + if (!p_split_current_line) { + if (p_above) { + if (cl > 0) { + cursor_set_line(cl - 1, false); + cursor_set_column(get_line(cursor_get_line()).length()); + } else { + cursor_set_column(0); + first_line = true; + } + } else { + cursor_set_column(line.length()); + } + } + + insert_text_at_cursor(ins); + + if (first_line) { + cursor_set_line(0); + } else if (brace_indent) { + cursor_set_line(cursor_get_line() - 1, false); + cursor_set_column(get_line(cursor_get_line()).length()); + } + + end_complex_operation(); +} + +void CodeEdit::backspace() { + if (is_readonly()) { + return; + } + + int cc = cursor_get_column(); + int cl = cursor_get_line(); + + if (cc == 0 && cl == 0) { + return; + } + + if (is_selection_active()) { + delete_selection(); + return; + } + + if (cl > 0 && is_line_hidden(cl - 1)) { + unfold_line(cursor_get_line() - 1); + } + + int prev_line = cc ? cl : cl - 1; + int prev_column = cc ? (cc - 1) : (get_line(cl - 1).length()); + + merge_gutters(cl, prev_line); + + /* TODO: Change when brace completion is refactored. */ + if (auto_brace_completion_enabled && cc > 0 && _is_pair_left_symbol(get_line(cl)[cc - 1])) { + _consume_backspace_for_pair_symbol(prev_line, prev_column); + cursor_set_line(prev_line, false, true); + cursor_set_column(prev_column); + return; + } + + /* For space indentation we need to do a simple unindent if there are no chars to the left, acting in the */ + /* same way as tabs. */ + if (indent_using_spaces && cc != 0) { + if (get_first_non_whitespace_column(cl) > cc) { + prev_column = cc - _calculate_spaces_till_next_left_indent(cc); + prev_line = cl; + } + } + + _remove_text(prev_line, prev_column, cl, cc); + + cursor_set_line(prev_line, false, true); + cursor_set_column(prev_column); +} + /* Main Gutter */ void CodeEdit::_update_draw_main_gutter() { set_gutter_draw(main_gutter, draw_breakpoints || draw_bookmarks || draw_executing_lines); @@ -561,7 +1074,7 @@ bool CodeEdit::is_line_numbers_zero_padded() const { void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { String fc = TS->format_number(String::num(p_line + 1).lpad(line_number_digits, line_number_padding)); Ref<TextLine> tl; - tl.instance(); + tl.instantiate(); tl->add_string(fc, cache.font, cache.font_size); int yofs = p_region.position.y + (get_row_height() - tl->get_size().y) / 2; Color number_color = get_line_gutter_item_color(p_line, line_number_gutter); @@ -581,7 +1094,7 @@ bool CodeEdit::is_drawing_fold_gutter() const { } void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_region) { - if (!can_fold(p_line) && !is_folded(p_line)) { + if (!can_fold_line(p_line) && !is_line_folded(p_line)) { set_line_gutter_clickable(p_line, fold_gutter, false); return; } @@ -593,13 +1106,193 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi p_region.position += Point2(horizontal_padding, vertical_padding); p_region.size -= Point2(horizontal_padding, vertical_padding) * 2; - if (can_fold(p_line)) { + if (can_fold_line(p_line)) { can_fold_icon->draw_rect(get_canvas_item(), p_region, false, folding_color); return; } folded_icon->draw_rect(get_canvas_item(), p_region, false, folding_color); } +/* Line Folding */ +void CodeEdit::set_line_folding_enabled(bool p_enabled) { + line_folding_enabled = p_enabled; + set_hiding_enabled(p_enabled); +} + +bool CodeEdit::is_line_folding_enabled() const { + return line_folding_enabled; +} + +bool CodeEdit::can_fold_line(int p_line) const { + ERR_FAIL_INDEX_V(p_line, get_line_count(), false); + if (!line_folding_enabled) { + return false; + } + + if (p_line + 1 >= get_line_count() || get_line(p_line).strip_edges().size() == 0) { + return false; + } + + if (is_line_hidden(p_line) || is_line_folded(p_line)) { + return false; + } + + /* Check for full multiline line or block strings / comments. */ + int in_comment = is_in_comment(p_line); + int in_string = (in_comment == -1) ? is_in_string(p_line) : -1; + if (in_string != -1 || in_comment != -1) { + if (get_delimiter_start_position(p_line, get_line(p_line).size() - 1).y != p_line) { + return false; + } + + int delimter_end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; + /* No end line, therefore we have a multiline region over the rest of the file. */ + if (delimter_end_line == -1) { + return true; + } + /* End line is the same therefore we have a block. */ + if (delimter_end_line == p_line) { + /* Check we are the start of the block. */ + if (p_line - 1 >= 0) { + if ((in_string != -1 && is_in_string(p_line - 1) != -1) || (in_comment != -1 && is_in_comment(p_line - 1) != -1)) { + return false; + } + } + /* Check it continues for at least one line. */ + return ((in_string != -1 && is_in_string(p_line + 1) != -1) || (in_comment != -1 && is_in_comment(p_line + 1) != -1)); + } + return ((in_string != -1 && is_in_string(delimter_end_line) != -1) || (in_comment != -1 && is_in_comment(delimter_end_line) != -1)); + } + + /* Otherwise check indent levels. */ + int start_indent = get_indent_level(p_line); + for (int i = p_line + 1; i < get_line_count(); i++) { + if (is_in_string(i) != -1 || is_in_comment(i) != -1 || get_line(i).strip_edges().size() == 0) { + continue; + } + return (get_indent_level(i) > start_indent); + } + return false; +} + +void CodeEdit::fold_line(int p_line) { + ERR_FAIL_INDEX(p_line, get_line_count()); + if (!is_line_folding_enabled() || !can_fold_line(p_line)) { + return; + } + + /* Find the last line to be hidden. */ + int end_line = get_line_count(); + + int in_comment = is_in_comment(p_line); + int in_string = (in_comment == -1) ? is_in_string(p_line) : -1; + if (in_string != -1 || in_comment != -1) { + end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; + /* End line is the same therefore we have a block. */ + if (end_line == p_line) { + for (int i = p_line + 1; i < get_line_count(); i++) { + if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) { + end_line = i - 1; + break; + } + } + } + } else { + int start_indent = get_indent_level(p_line); + for (int i = p_line + 1; i < get_line_count(); i++) { + if (get_line(p_line).strip_edges().size() == 0 || is_in_string(i) != -1 || is_in_comment(i) != -1) { + end_line = i; + continue; + } + + if (get_indent_level(i) <= start_indent && get_line(i).strip_edges().size() != 0) { + end_line = i - 1; + break; + } + } + } + + for (int i = p_line + 1; i <= end_line; i++) { + set_line_as_hidden(i, true); + } + + /* Fix selection. */ + if (is_selection_active()) { + if (is_line_hidden(get_selection_from_line()) && is_line_hidden(get_selection_to_line())) { + deselect(); + } else if (is_line_hidden(get_selection_from_line())) { + select(p_line, 9999, get_selection_to_line(), get_selection_to_column()); + } else if (is_line_hidden(get_selection_to_line())) { + select(get_selection_from_line(), get_selection_from_column(), p_line, 9999); + } + } + + /* Reset caret. */ + if (is_line_hidden(cursor_get_line())) { + cursor_set_line(p_line, false, false); + cursor_set_column(get_line(p_line).length(), false); + } + update(); +} + +void CodeEdit::unfold_line(int p_line) { + ERR_FAIL_INDEX(p_line, get_line_count()); + if (!is_line_folded(p_line) && !is_line_hidden(p_line)) { + return; + } + + int fold_start = p_line; + for (; fold_start > 0; fold_start--) { + if (is_line_folded(fold_start)) { + break; + } + } + fold_start = is_line_folded(fold_start) ? fold_start : p_line; + + for (int i = fold_start + 1; i < get_line_count(); i++) { + if (!is_line_hidden(i)) { + break; + } + set_line_as_hidden(i, false); + } + update(); +} + +void CodeEdit::fold_all_lines() { + for (int i = 0; i < get_line_count(); i++) { + fold_line(i); + } + update(); +} + +void CodeEdit::unfold_all_lines() { + unhide_all_lines(); +} + +void CodeEdit::toggle_foldable_line(int p_line) { + ERR_FAIL_INDEX(p_line, get_line_count()); + if (is_line_folded(p_line)) { + unfold_line(p_line); + return; + } + fold_line(p_line); +} + +bool CodeEdit::is_line_folded(int p_line) const { + ERR_FAIL_INDEX_V(p_line, get_line_count(), false); + return p_line + 1 < get_line_count() && !is_line_hidden(p_line) && is_line_hidden(p_line + 1); +} + +TypedArray<int> CodeEdit::get_folded_lines() const { + TypedArray<int> folded_lines; + for (int i = 0; i < get_line_count(); i++) { + if (is_line_folded(i)) { + folded_lines.push_back(i); + } + } + return folded_lines; +} + /* Delimiters */ // Strings void CodeEdit::add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only) { @@ -1050,6 +1743,25 @@ void CodeEdit::cancel_code_completion() { } void CodeEdit::_bind_methods() { + /* Indent management */ + ClassDB::bind_method(D_METHOD("set_indent_size", "size"), &CodeEdit::set_indent_size); + ClassDB::bind_method(D_METHOD("get_indent_size"), &CodeEdit::get_indent_size); + + ClassDB::bind_method(D_METHOD("set_indent_using_spaces", "use_spaces"), &CodeEdit::set_indent_using_spaces); + ClassDB::bind_method(D_METHOD("is_indent_using_spaces"), &CodeEdit::is_indent_using_spaces); + + ClassDB::bind_method(D_METHOD("set_auto_indent_enabled", "enable"), &CodeEdit::set_auto_indent_enabled); + ClassDB::bind_method(D_METHOD("is_auto_indent_enabled"), &CodeEdit::is_auto_indent_enabled); + + ClassDB::bind_method(D_METHOD("set_auto_indent_prefixes", "prefixes"), &CodeEdit::set_auto_indent_prefixes); + ClassDB::bind_method(D_METHOD("get_auto_indent_prefixes"), &CodeEdit::get_auto_indent_prefixes); + + ClassDB::bind_method(D_METHOD("do_indent"), &CodeEdit::do_indent); + ClassDB::bind_method(D_METHOD("do_unindent"), &CodeEdit::do_unindent); + + ClassDB::bind_method(D_METHOD("indent_lines"), &CodeEdit::indent_lines); + ClassDB::bind_method(D_METHOD("unindent_lines"), &CodeEdit::unindent_lines); + /* Main Gutter */ ClassDB::bind_method(D_METHOD("_main_gutter_draw_callback"), &CodeEdit::_main_gutter_draw_callback); @@ -1094,6 +1806,21 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_draw_fold_gutter", "enable"), &CodeEdit::set_draw_fold_gutter); ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &CodeEdit::is_drawing_fold_gutter); + /* Line folding */ + ClassDB::bind_method(D_METHOD("set_line_folding_enabled", "enabled"), &CodeEdit::set_line_folding_enabled); + ClassDB::bind_method(D_METHOD("is_line_folding_enabled"), &CodeEdit::is_line_folding_enabled); + + ClassDB::bind_method(D_METHOD("can_fold_line", "line"), &CodeEdit::can_fold_line); + + ClassDB::bind_method(D_METHOD("fold_line", "line"), &CodeEdit::fold_line); + ClassDB::bind_method(D_METHOD("unfold_line", "line"), &CodeEdit::unfold_line); + ClassDB::bind_method(D_METHOD("fold_all_lines"), &CodeEdit::fold_all_lines); + ClassDB::bind_method(D_METHOD("unfold_all_lines"), &CodeEdit::unfold_all_lines); + ClassDB::bind_method(D_METHOD("toggle_foldable_line", "line"), &CodeEdit::toggle_foldable_line); + + ClassDB::bind_method(D_METHOD("is_line_folded", "line"), &CodeEdit::is_line_folded); + ClassDB::bind_method(D_METHOD("get_folded_lines"), &CodeEdit::get_folded_lines); + /* Delimiters */ // Strings ClassDB::bind_method(D_METHOD("add_string_delimiter", "start_key", "end_key", "line_only"), &CodeEdit::add_string_delimiter, DEFVAL(false)); @@ -1121,8 +1848,8 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_delimiter_start_key", "delimiter_index"), &CodeEdit::get_delimiter_start_key); ClassDB::bind_method(D_METHOD("get_delimiter_end_key", "delimiter_index"), &CodeEdit::get_delimiter_end_key); - ClassDB::bind_method(D_METHOD("get_delimiter_start_postion", "line", "column"), &CodeEdit::get_delimiter_start_position); - ClassDB::bind_method(D_METHOD("get_delimiter_end_postion", "line", "column"), &CodeEdit::get_delimiter_end_position); + ClassDB::bind_method(D_METHOD("get_delimiter_start_position", "line", "column"), &CodeEdit::get_delimiter_start_position); + ClassDB::bind_method(D_METHOD("get_delimiter_end_position", "line", "column"), &CodeEdit::get_delimiter_end_position); /* Code hint */ ClassDB::bind_method(D_METHOD("set_code_hint", "code_hint"), &CodeEdit::set_code_hint); @@ -1175,6 +1902,8 @@ void CodeEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_fold_gutter"), "set_draw_fold_gutter", "is_drawing_fold_gutter"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "line_folding"), "set_line_folding_enabled", "is_line_folding_enabled"); + ADD_GROUP("Delimiters", "delimiter_"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "delimiter_strings"), "set_string_delimiters", "get_string_delimiters"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "delimiter_comments"), "set_comment_delimiters", "get_comment_delimiters"); @@ -1183,6 +1912,12 @@ void CodeEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "code_completion_enabled"), "set_code_completion_enabled", "is_code_completion_enabled"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "code_completion_prefixes"), "set_code_completion_prefixes", "get_code_comletion_prefixes"); + ADD_GROUP("Indentation", "indent_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "indent_size"), "set_indent_size", "get_indent_size"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_use_spaces"), "set_indent_using_spaces", "is_indent_using_spaces"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_automatic"), "set_auto_indent_enabled", "is_auto_indent_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "indent_automatic_prefixes"), "set_auto_indent_prefixes", "get_auto_indent_prefixes"); + /* Signals */ ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "line"))); ADD_SIGNAL(MethodInfo("request_code_completion")); @@ -1205,9 +1940,9 @@ void CodeEdit::_gutter_clicked(int p_line, int p_gutter) { } if (p_gutter == fold_gutter) { - if (is_folded(p_line)) { + if (is_line_folded(p_line)) { unfold_line(p_line); - } else if (can_fold(p_line)) { + } else if (can_fold_line(p_line)) { fold_line(p_line); } return; @@ -1526,6 +2261,9 @@ void CodeEdit::_clear_delimiters(DelimiterType p_type) { } } delimiter_cache.clear(); + if (!setting_delimiters) { + _update_delimiter_cache(); + } } TypedArray<String> CodeEdit::_get_delimiters(DelimiterType p_type) const { @@ -1806,6 +2544,12 @@ void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) { } CodeEdit::CodeEdit() { + /* Indent management */ + auto_indent_prefixes.insert(':'); + auto_indent_prefixes.insert('{'); + auto_indent_prefixes.insert('['); + auto_indent_prefixes.insert('('); + /* Text Direction */ set_layout_direction(LAYOUT_DIRECTION_LTR); set_text_direction(TEXT_DIRECTION_LTR); diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index 6305eacf83..25b518402b 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -53,6 +53,19 @@ public: }; private: + /* Indent management */ + int indent_size = 4; + String indent_text = "\t"; + + bool auto_indent = false; + Set<char32_t> auto_indent_prefixes; + + bool indent_using_spaces = false; + int _calculate_spaces_till_next_left_indent(int p_column) const; + int _calculate_spaces_till_next_right_indent(int p_column) const; + + void _new_line(bool p_split_current_line = true, bool p_above = false); + /* Main Gutter */ enum MainGutterType { MAIN_GUTTER_BREAKPOINT = 0x01, @@ -98,6 +111,9 @@ private: void _gutter_clicked(int p_line, int p_gutter); void _update_gutter_indexes(); + /* Line Folding */ + bool line_folding_enabled = true; + /* Delimiters */ enum DelimiterType { TYPE_STRING, @@ -203,6 +219,27 @@ protected: public: virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; + /* Indent management */ + void set_indent_size(const int p_size); + int get_indent_size() const; + + void set_indent_using_spaces(const bool p_use_spaces); + bool is_indent_using_spaces() const; + + void set_auto_indent_enabled(bool p_enabled); + bool is_auto_indent_enabled() const; + + void set_auto_indent_prefixes(const TypedArray<String> &p_prefixes); + TypedArray<String> get_auto_indent_prefixes() const; + + void do_indent(); + void do_unindent(); + + void indent_lines(); + void unindent_lines(); + + virtual void backspace() override; + /* Main Gutter */ void set_draw_breakpoints_gutter(bool p_draw); bool is_drawing_breakpoints_gutter() const; @@ -241,6 +278,21 @@ public: void set_draw_fold_gutter(bool p_draw); bool is_drawing_fold_gutter() const; + /* Line Folding */ + void set_line_folding_enabled(bool p_enabled); + bool is_line_folding_enabled() const; + + bool can_fold_line(int p_line) const; + + void fold_line(int p_line); + void unfold_line(int p_line); + void fold_all_lines(); + void unfold_all_lines(); + void toggle_foldable_line(int p_line); + + bool is_line_folded(int p_line) const; + TypedArray<int> get_folded_lines() const; + /* Delimiters */ void add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false); void remove_string_delimiter(const String &p_start_key); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index c0b4563615..659d14ae70 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -40,6 +40,8 @@ #endif #include "scene/main/window.h" +List<Color> ColorPicker::preset_cache; + void ColorPicker::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: { @@ -57,11 +59,17 @@ void ColorPicker::_notification(int p_what) { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - PackedColorArray saved_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "presets", PackedColorArray()); + if (preset_cache.is_empty()) { + PackedColorArray saved_presets = EditorSettings::get_singleton()->get_project_metadata("color_picker", "presets", PackedColorArray()); + for (int i = 0; i < saved_presets.size(); i++) { + preset_cache.push_back(saved_presets[i]); + } + } - for (int i = 0; i < saved_presets.size(); i++) { - add_preset(saved_presets[i]); + for (int i = 0; i < preset_cache.size(); i++) { + presets.push_back(preset_cache[i]); } + preset->update(); } #endif } break; @@ -88,7 +96,7 @@ Ref<Shader> ColorPicker::wheel_shader; Ref<Shader> ColorPicker::circle_shader; void ColorPicker::init_shaders() { - wheel_shader.instance(); + wheel_shader.instantiate(); wheel_shader->set_code( "shader_type canvas_item;" "void fragment() {" @@ -107,7 +115,7 @@ void ColorPicker::init_shaders() { " COLOR = vec4(clamp((abs(fract(((a - TAU) / TAU) + vec3(3.0, 2.0, 1.0) / 3.0) * 6.0 - 3.0) - 1.0), 0.0, 1.0), (b + b2 + b3 + b4) / 4.00);" "}"); - circle_shader.instance(); + circle_shader.instantiate(); circle_shader->set_code( "shader_type canvas_item;" "uniform float v = 1.0;" @@ -289,7 +297,7 @@ void ColorPicker::_value_changed(double) { emit_signal("color_changed", color); } -void ColorPicker::_html_entered(const String &p_html) { +void ColorPicker::_html_submitted(const String &p_html) { if (updating || text_is_constructor || !c_text->is_visible()) { return; } @@ -413,6 +421,7 @@ void ColorPicker::add_preset(const Color &p_color) { presets.move_to_back(presets.find(p_color)); } else { presets.push_back(p_color); + preset_cache.push_back(p_color); } preset->update(); @@ -427,6 +436,7 @@ void ColorPicker::add_preset(const Color &p_color) { void ColorPicker::erase_preset(const Color &p_color) { if (presets.find(p_color)) { presets.erase(presets.find(p_color)); + preset_cache.erase(preset_cache.find(p_color)); preset->update(); #ifdef TOOLS_ENABLED @@ -1041,7 +1051,7 @@ void ColorPicker::_html_focus_exit() { if (c_text->get_menu()->is_visible()) { return; } - _html_entered(c_text->get_text()); + _html_submitted(c_text->get_text()); _focus_exit(); } @@ -1204,7 +1214,7 @@ ColorPicker::ColorPicker() : hhb->add_child(c_text); c_text->set_h_size_flags(SIZE_EXPAND_FILL); - c_text->connect("text_entered", callable_mp(this, &ColorPicker::_html_entered)); + c_text->connect("text_submitted", callable_mp(this, &ColorPicker::_html_submitted)); c_text->connect("focus_entered", callable_mp(this, &ColorPicker::_focus_enter)); c_text->connect("focus_exited", callable_mp(this, &ColorPicker::_html_focus_exit)); @@ -1213,9 +1223,9 @@ ColorPicker::ColorPicker() : wheel_edit->set_custom_minimum_size(Size2(get_theme_constant("sv_width"), get_theme_constant("sv_height"))); hb_edit->add_child(wheel_edit); - wheel_mat.instance(); + wheel_mat.instantiate(); wheel_mat->set_shader(wheel_shader); - circle_mat.instance(); + circle_mat.instantiate(); circle_mat->set_shader(circle_shader); MarginContainer *wheel_margin(memnew(MarginContainer)); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 14113467d0..60da3957aa 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -58,6 +58,7 @@ public: private: static Ref<Shader> wheel_shader; static Ref<Shader> circle_shader; + static List<Color> preset_cache; Control *screen = nullptr; Control *uv_edit = memnew(Control); @@ -104,7 +105,7 @@ private: float v = 0.0; Color last_hsv; - void _html_entered(const String &p_html); + void _html_submitted(const String &p_html); void _value_changed(double); void _update_controls(); void _update_color(bool p_update_sliders = true); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 5afe813ee0..d42b505f7b 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -650,27 +650,11 @@ void Control::_notification(int p_notification) { } } -bool Control::clips_input() const { - if (get_script_instance()) { - return get_script_instance()->call(SceneStringNames::get_singleton()->_clips_input); - } - return false; -} - bool Control::has_point(const Point2 &p_point) const { - if (get_script_instance()) { - Variant v = p_point; - const Variant *p = &v; - Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->has_point, &p, 1, ce); - if (ce.error == Callable::CallError::CALL_OK) { - return ret; - } + bool ret; + if (GDVIRTUAL_CALL(_has_point, p_point, ret)) { + return ret; } - /*if (has_stylebox("mask")) { - Ref<StyleBox> mask = get_stylebox("mask"); - return mask->test_mask(p_point,Rect2(Point2(),get_size())); - }*/ return Rect2(Point2(), get_size()).has_point(p_point); } @@ -687,7 +671,7 @@ Variant Control::get_drag_data(const Point2 &p_point) { Object *obj = ObjectDB::get_instance(data.drag_owner); if (obj) { Control *c = Object::cast_to<Control>(obj); - return c->call("get_drag_data_fw", p_point, this); + return c->call("_get_drag_data_fw", p_point, this); } } @@ -695,7 +679,7 @@ Variant Control::get_drag_data(const Point2 &p_point) { Variant v = p_point; const Variant *p = &v; Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->get_drag_data, &p, 1, ce); + Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_get_drag_data, &p, 1, ce); if (ce.error == Callable::CallError::CALL_OK) { return ret; } @@ -709,7 +693,7 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const Object *obj = ObjectDB::get_instance(data.drag_owner); if (obj) { Control *c = Object::cast_to<Control>(obj); - return c->call("can_drop_data_fw", p_point, p_data, this); + return c->call("_can_drop_data_fw", p_point, p_data, this); } } @@ -717,7 +701,7 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const Variant v = p_point; const Variant *p[2] = { &v, &p_data }; Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->can_drop_data, p, 2, ce); + Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_can_drop_data, p, 2, ce); if (ce.error == Callable::CallError::CALL_OK) { return ret; } @@ -731,7 +715,7 @@ void Control::drop_data(const Point2 &p_point, const Variant &p_data) { Object *obj = ObjectDB::get_instance(data.drag_owner); if (obj) { Control *c = Object::cast_to<Control>(obj); - c->call("drop_data_fw", p_point, p_data, this); + c->call("_drop_data_fw", p_point, p_data, this); return; } } @@ -740,7 +724,7 @@ void Control::drop_data(const Point2 &p_point, const Variant &p_data) { Variant v = p_point; const Variant *p[2] = { &v, &p_data }; Callable::CallError ce; - Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->drop_data, p, 2, ce); + Variant ret = get_script_instance()->call(SceneStringNames::get_singleton()->_drop_data, p, 2, ce); if (ce.error == Callable::CallError::CALL_OK) { return; } @@ -1084,7 +1068,7 @@ Rect2 Control::get_parent_anchorable_rect() const { } else { #ifdef TOOLS_ENABLED Node *edited_root = get_tree()->get_edited_scene_root(); - if (edited_root && (this == edited_root || edited_root->is_a_parent_of(this))) { + if (edited_root && (this == edited_root || edited_root->is_ancestor_of(this))) { parent_rect.size = Size2(ProjectSettings::get_singleton()->get("display/window/size/width"), ProjectSettings::get_singleton()->get("display/window/size/height")); } else { parent_rect = get_viewport()->get_visible_rect(); @@ -1504,7 +1488,7 @@ Point2 Control::get_global_position() const { Point2 Control::get_screen_position() const { ERR_FAIL_COND_V(!is_inside_tree(), Point2()); - Point2 global_pos = get_global_position(); + Point2 global_pos = get_viewport()->get_canvas_transform().xform(get_global_position()); Window *w = Object::cast_to<Window>(get_viewport()); if (w && !w->is_embedding_subwindows()) { global_pos += w->get_position(); @@ -2473,14 +2457,6 @@ real_t Control::get_rotation() const { return data.rotation; } -void Control::set_rotation_degrees(real_t p_degrees) { - set_rotation(Math::deg2rad(p_degrees)); -} - -real_t Control::get_rotation_degrees() const { - return Math::rad2deg(get_rotation()); -} - void Control::_override_changed() { notification(NOTIFICATION_THEME_CHANGED); emit_signal(SceneStringNames::get_singleton()->theme_changed); @@ -2648,7 +2624,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_offsets"), &Control::set_global_position, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_set_global_position", "position"), &Control::_set_global_position); ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Control::set_rotation); - ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Control::set_rotation_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Control::set_scale); ClassDB::bind_method(D_METHOD("set_pivot_offset", "pivot_offset"), &Control::set_pivot_offset); ClassDB::bind_method(D_METHOD("get_offset", "offset"), &Control::get_offset); @@ -2657,7 +2632,6 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_position"), &Control::get_position); ClassDB::bind_method(D_METHOD("get_size"), &Control::get_size); ClassDB::bind_method(D_METHOD("get_rotation"), &Control::get_rotation); - ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Control::get_rotation_degrees); ClassDB::bind_method(D_METHOD("get_scale"), &Control::get_scale); ClassDB::bind_method(D_METHOD("get_pivot_offset"), &Control::get_pivot_offset); ClassDB::bind_method(D_METHOD("get_custom_minimum_size"), &Control::get_custom_minimum_size); @@ -2775,16 +2749,15 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo("_gui_input", PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"))); BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_get_minimum_size")); - MethodInfo get_drag_data = MethodInfo("get_drag_data", PropertyInfo(Variant::VECTOR2, "position")); + MethodInfo get_drag_data = MethodInfo("_get_drag_data", PropertyInfo(Variant::VECTOR2, "position")); get_drag_data.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; BIND_VMETHOD(get_drag_data); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); - BIND_VMETHOD(MethodInfo("drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); + BIND_VMETHOD(MethodInfo(Variant::BOOL, "_can_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); + BIND_VMETHOD(MethodInfo("_drop_data", PropertyInfo(Variant::VECTOR2, "position"), PropertyInfo(Variant::NIL, "data"))); BIND_VMETHOD(MethodInfo( PropertyInfo(Variant::OBJECT, "control", PROPERTY_HINT_RESOURCE_TYPE, "Control"), "_make_custom_tooltip", PropertyInfo(Variant::STRING, "for_text"))); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input")); ADD_GROUP("Anchor", "anchor_"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT); @@ -2807,11 +2780,10 @@ void Control::_bind_methods() { ADD_GROUP("Rect", "rect_"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_position", "get_position"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "_set_global_position", "get_global_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents"); @@ -2940,5 +2912,5 @@ void Control::_bind_methods() { ADD_SIGNAL(MethodInfo("minimum_size_changed")); ADD_SIGNAL(MethodInfo("theme_changed")); - BIND_VMETHOD(MethodInfo(Variant::BOOL, "has_point", PropertyInfo(Variant::VECTOR2, "point"))); + GDVIRTUAL_BIND(_has_point); } diff --git a/scene/gui/control.h b/scene/gui/control.h index a05025c32d..0642686a9f 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -32,6 +32,7 @@ #define CONTROL_H #include "core/math/transform_2d.h" +#include "core/object/gdvirtual.gen.inc" #include "core/templates/rid.h" #include "scene/gui/shortcut.h" #include "scene/main/canvas_item.h" @@ -264,6 +265,7 @@ private: static bool has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types); _FORCE_INLINE_ void _get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const; + GDVIRTUAL1RC(bool, _has_point, Vector2) protected: virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; @@ -329,7 +331,6 @@ public: virtual Size2 get_minimum_size() const; virtual Size2 get_combined_minimum_size() const; virtual bool has_point(const Point2 &p_point) const; - virtual bool clips_input() const; virtual void set_drag_forwarding(Control *p_target); virtual Variant get_drag_data(const Point2 &p_point); virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const; @@ -384,9 +385,7 @@ public: void set_rect(const Rect2 &p_rect); // Reset anchors to begin and set rect, for faster container children sorting. void set_rotation(real_t p_radians); - void set_rotation_degrees(real_t p_degrees); real_t get_rotation() const; - real_t get_rotation_degrees() const; void set_h_grow_direction(GrowDirection p_direction); GrowDirection get_h_grow_direction() const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index b6884bd37d..dceab00607 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -97,7 +97,7 @@ void AcceptDialog::_notification(int p_what) { } } -void AcceptDialog::_text_entered(const String &p_text) { +void AcceptDialog::_text_submitted(const String &p_text) { _ok_pressed(); } @@ -155,11 +155,11 @@ bool AcceptDialog::has_autowrap() { return label->has_autowrap(); } -void AcceptDialog::register_text_enter(Node *p_line_edit) { +void AcceptDialog::register_text_enter(Control *p_line_edit) { ERR_FAIL_NULL(p_line_edit); LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit); if (line_edit) { - line_edit->connect("text_entered", callable_mp(this, &AcceptDialog::_text_entered)); + line_edit->connect("text_submitted", callable_mp(this, &AcceptDialog::_text_submitted)); } } @@ -263,6 +263,28 @@ Button *AcceptDialog::add_cancel_button(const String &p_cancel) { return b; } +void AcceptDialog::remove_button(Control *p_button) { + Button *button = Object::cast_to<Button>(p_button); + ERR_FAIL_NULL(button); + ERR_FAIL_COND_MSG(button->get_parent() != hbc, vformat("Cannot remove button %s as it does not belong to this dialog.", button->get_name())); + ERR_FAIL_COND_MSG(button == ok, "Cannot remove dialog's OK button."); + + Node *right_spacer = hbc->get_child(button->get_index() + 1); + // Should always be valid but let's avoid crashing + if (right_spacer) { + hbc->remove_child(right_spacer); + memdelete(right_spacer); + } + hbc->remove_child(button); + + if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_custom_action))) { + button->disconnect("pressed", callable_mp(this, &AcceptDialog::_custom_action)); + } + if (button->is_connected("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed))) { + button->disconnect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); + } +} + void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_ok_button"), &AcceptDialog::get_ok_button); ClassDB::bind_method(D_METHOD("get_label"), &AcceptDialog::get_label); @@ -270,6 +292,7 @@ void AcceptDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_hide_on_ok"), &AcceptDialog::get_hide_on_ok); ClassDB::bind_method(D_METHOD("add_button", "text", "right", "action"), &AcceptDialog::add_button, DEFVAL(false), DEFVAL("")); ClassDB::bind_method(D_METHOD("add_cancel_button", "name"), &AcceptDialog::add_cancel_button); + ClassDB::bind_method(D_METHOD("remove_button", "button"), &AcceptDialog::remove_button); ClassDB::bind_method(D_METHOD("register_text_enter", "line_edit"), &AcceptDialog::register_text_enter); ClassDB::bind_method(D_METHOD("set_text", "text"), &AcceptDialog::set_text); ClassDB::bind_method(D_METHOD("get_text"), &AcceptDialog::get_text); diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index b072055d49..8e803a2a7c 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -69,7 +69,7 @@ protected: virtual void custom_action(const String &) {} // Not private since used by derived classes signal. - void _text_entered(const String &p_text); + void _text_submitted(const String &p_text); void _ok_pressed(); void _cancel_pressed(); @@ -77,11 +77,12 @@ public: Label *get_label() { return label; } static void set_swap_cancel_ok(bool p_swap); - void register_text_enter(Node *p_line_edit); + void register_text_enter(Control *p_line_edit); Button *get_ok_button() { return ok; } Button *add_button(const String &p_text, bool p_right = false, const String &p_action = ""); Button *add_cancel_button(const String &p_cancel = ""); + void remove_button(Control *p_button); void set_hide_on_ok(bool p_hide); bool get_hide_on_ok() const; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 806039d7ac..f8cee6daec 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -116,7 +116,7 @@ void FileDialog::_unhandled_input(const Ref<InputEvent> &p_event) { invalidate(); } break; case KEY_BACKSPACE: { - _dir_entered(".."); + _dir_submitted(".."); } break; default: { handled = false; @@ -156,7 +156,7 @@ void FileDialog::update_dir() { deselect_all(); } -void FileDialog::_dir_entered(String p_dir) { +void FileDialog::_dir_submitted(String p_dir) { dir_access->change_dir(p_dir); file->set_text(""); invalidate(); @@ -164,7 +164,7 @@ void FileDialog::_dir_entered(String p_dir) { _push_history(); } -void FileDialog::_file_entered(const String &p_file) { +void FileDialog::_file_submitted(const String &p_file) { _action_pressed(); } @@ -1020,8 +1020,8 @@ FileDialog::FileDialog() { tree->connect("cell_selected", callable_mp(this, &FileDialog::_tree_selected), varray(), CONNECT_DEFERRED); tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated), varray()); tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all)); - dir->connect("text_entered", callable_mp(this, &FileDialog::_dir_entered)); - file->connect("text_entered", callable_mp(this, &FileDialog::_file_entered)); + dir->connect("text_submitted", callable_mp(this, &FileDialog::_dir_submitted)); + file->connect("text_submitted", callable_mp(this, &FileDialog::_file_submitted)); filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected)); confirm_save = memnew(ConfirmationDialog); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 4996f00cb3..7fbafc4bb4 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -32,7 +32,7 @@ #define FILE_DIALOG_H #include "box_container.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "scene/gui/dialogs.h" #include "scene/gui/line_edit.h" #include "scene/gui/option_button.h" @@ -118,8 +118,8 @@ private: void _select_drive(int p_idx); void _tree_item_activated(); - void _dir_entered(String p_dir); - void _file_entered(const String &p_file); + void _dir_submitted(String p_dir); + void _file_submitted(const String &p_file); void _action_pressed(); void _save_confirm_pressed(); void _cancel_pressed(); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 5a4dacd897..39aa6749e7 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -40,13 +40,8 @@ #include "editor/editor_scale.h" #endif -#define ZOOM_SCALE 1.2 - -#define MIN_ZOOM (((1 / ZOOM_SCALE) / ZOOM_SCALE) / ZOOM_SCALE) -#define MAX_ZOOM (1 * ZOOM_SCALE * ZOOM_SCALE * ZOOM_SCALE) - -#define MINIMAP_OFFSET 12 -#define MINIMAP_PADDING 5 +constexpr int MINIMAP_OFFSET = 12; +constexpr int MINIMAP_PADDING = 5; bool GraphEditFilter::has_point(const Point2 &p_point) const { return ge->_filter_input(p_point); @@ -244,10 +239,6 @@ void GraphEdit::disconnect_node(const StringName &p_from, int p_from_port, const } } -bool GraphEdit::clips_input() const { - return true; -} - void GraphEdit::get_connection_list(List<Connection> *r_connections) const { *r_connections = connections; } @@ -824,7 +815,7 @@ void GraphEdit::_bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, } } -void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0) { +void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio) { //cubic bezier code float diff = p_to.x - p_from.x; float cp_offset; @@ -1072,8 +1063,9 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseMotion> mm = p_ev; if (mm.is_valid() && (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { - h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); - v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); + Vector2i relative = Input::get_singleton()->warp_mouse_motion(mm, get_global_rect()); + h_scroll->set_value(h_scroll->get_value() - relative.x); + v_scroll->set_value(v_scroll->get_value() - relative.y); } if (mm.is_valid() && dragging) { @@ -1322,18 +1314,20 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { minimap->update(); } - if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CTRL)) { - set_zoom_custom(zoom * ZOOM_SCALE, b->get_position()); - } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CTRL)) { - set_zoom_custom(zoom / ZOOM_SCALE, b->get_position()); - } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8); - } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { - v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8); - } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { - h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * b->get_factor() / 8); - } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { - h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8); + int scroll_direction = (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) - (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP); + if (scroll_direction != 0) { + if (b->is_ctrl_pressed()) { + if (b->is_shift_pressed()) { + // Horizontal scrolling. + h_scroll->set_value(h_scroll->get_value() + (h_scroll->get_page() * b->get_factor() / 8) * scroll_direction); + } else { + // Vertical scrolling. + v_scroll->set_value(v_scroll->get_value() + (v_scroll->get_page() * b->get_factor() / 8) * scroll_direction); + } + } else { + // Zooming. + set_zoom_custom(scroll_direction < 0 ? zoom * zoom_step : zoom / zoom_step, b->get_position()); + } } } @@ -1392,19 +1386,19 @@ void GraphEdit::set_zoom(float p_zoom) { } void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) { - p_zoom = CLAMP(p_zoom, MIN_ZOOM, MAX_ZOOM); + p_zoom = CLAMP(p_zoom, zoom_min, zoom_max); if (zoom == p_zoom) { return; } - zoom_minus->set_disabled(zoom == MIN_ZOOM); - zoom_plus->set_disabled(zoom == MAX_ZOOM); - Vector2 sbofs = (Vector2(h_scroll->get_value(), v_scroll->get_value()) + p_center) / zoom; zoom = p_zoom; top_layer->update(); + zoom_minus->set_disabled(zoom == zoom_min); + zoom_plus->set_disabled(zoom == zoom_max); + _update_scroll(); minimap->update(); connections_layer->update(); @@ -1415,6 +1409,7 @@ void GraphEdit::set_zoom_custom(float p_zoom, const Vector2 &p_center) { v_scroll->set_value(ofs.y); } + _update_zoom_label(); update(); } @@ -1422,6 +1417,61 @@ float GraphEdit::get_zoom() const { return zoom; } +void GraphEdit::set_zoom_step(float p_zoom_step) { + p_zoom_step = abs(p_zoom_step); + if (zoom_step == p_zoom_step) { + return; + } + + zoom_step = p_zoom_step; +} + +float GraphEdit::get_zoom_step() const { + return zoom_step; +} + +void GraphEdit::set_zoom_min(float p_zoom_min) { + ERR_FAIL_COND_MSG(p_zoom_min > zoom_max, "Cannot set min zoom level greater than max zoom level."); + + if (zoom_min == p_zoom_min) { + return; + } + + zoom_min = p_zoom_min; + set_zoom(zoom); +} + +float GraphEdit::get_zoom_min() const { + return zoom_min; +} + +void GraphEdit::set_zoom_max(float p_zoom_max) { + ERR_FAIL_COND_MSG(p_zoom_max < zoom_min, "Cannot set max zoom level lesser than min zoom level."); + + if (zoom_max == p_zoom_max) { + return; + } + + zoom_max = p_zoom_max; + set_zoom(zoom); +} + +float GraphEdit::get_zoom_max() const { + return zoom_max; +} + +void GraphEdit::set_show_zoom_label(bool p_enable) { + if (zoom_label->is_visible() == p_enable) { + return; + } + + zoom_label->set_visible(p_enable); +} + +bool GraphEdit::is_showing_zoom_label() const { + return zoom_label->is_visible(); +} + void GraphEdit::set_right_disconnects(bool p_enable) { right_disconnects = p_enable; } @@ -1462,7 +1512,7 @@ Array GraphEdit::_get_connection_list() const { } void GraphEdit::_zoom_minus() { - set_zoom(zoom / ZOOM_SCALE); + set_zoom(zoom / zoom_step); } void GraphEdit::_zoom_reset() { @@ -1470,7 +1520,13 @@ void GraphEdit::_zoom_reset() { } void GraphEdit::_zoom_plus() { - set_zoom(zoom * ZOOM_SCALE); + set_zoom(zoom * zoom_step); +} + +void GraphEdit::_update_zoom_label() { + int zoom_percent = static_cast<int>(Math::round(zoom * 100)); + String zoom_text = itos(zoom_percent) + "%"; + zoom_label->set_text(zoom_text); } void GraphEdit::add_valid_connection_type(int p_type, int p_with_type) { @@ -1611,6 +1667,18 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom); ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom); + ClassDB::bind_method(D_METHOD("set_zoom_min", "zoom_min"), &GraphEdit::set_zoom_min); + ClassDB::bind_method(D_METHOD("get_zoom_min"), &GraphEdit::get_zoom_min); + + ClassDB::bind_method(D_METHOD("set_zoom_max", "zoom_max"), &GraphEdit::set_zoom_max); + ClassDB::bind_method(D_METHOD("get_zoom_max"), &GraphEdit::get_zoom_max); + + ClassDB::bind_method(D_METHOD("set_zoom_step", "zoom_step"), &GraphEdit::set_zoom_step); + ClassDB::bind_method(D_METHOD("get_zoom_step"), &GraphEdit::get_zoom_step); + + ClassDB::bind_method(D_METHOD("set_show_zoom_label", "enable"), &GraphEdit::set_show_zoom_label); + ClassDB::bind_method(D_METHOD("is_showing_zoom_label"), &GraphEdit::is_showing_zoom_label); + ClassDB::bind_method(D_METHOD("set_snap", "pixels"), &GraphEdit::set_snap); ClassDB::bind_method(D_METHOD("get_snap"), &GraphEdit::get_snap); @@ -1645,9 +1713,18 @@ void GraphEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs"); ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom"); + + ADD_GROUP("Connection Lines", "connection_lines"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "connection_lines_thickness"), "set_connection_lines_thickness", "get_connection_lines_thickness"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "connection_lines_antialiased"), "set_connection_lines_antialiased", "is_connection_lines_antialiased"); + + ADD_GROUP("Zoom", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom"), "set_zoom", "get_zoom"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_min"), "set_zoom_min", "get_zoom_min"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_max"), "set_zoom_max", "get_zoom_max"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zoom_step"), "set_zoom_step", "get_zoom_step"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_zoom_label"), "set_show_zoom_label", "is_showing_zoom_label"); + ADD_GROUP("Minimap", "minimap"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "minimap_enabled"), "set_minimap_enabled", "is_minimap_enabled"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimap_size"), "set_minimap_size", "get_minimap_size"); @@ -1672,6 +1749,13 @@ void GraphEdit::_bind_methods() { GraphEdit::GraphEdit() { set_focus_mode(FOCUS_ALL); + // Allow dezooming 8 times from the default zoom level. + // At low zoom levels, text is unreadable due to its small size and poor filtering, + // but this is still useful for previewing and navigation. + zoom_min = (1 / Math::pow(zoom_step, 8)); + // Allow zooming 4 times from the default zoom level. + zoom_max = (1 * Math::pow(zoom_step, 4)); + top_layer = memnew(GraphEditFilter(this)); add_child(top_layer); top_layer->set_mouse_filter(MOUSE_FILTER_PASS); @@ -1708,6 +1792,18 @@ GraphEdit::GraphEdit() { top_layer->add_child(zoom_hb); zoom_hb->set_position(Vector2(10, 10)); + zoom_label = memnew(Label); + zoom_hb->add_child(zoom_label); + zoom_label->set_visible(false); + zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER); + zoom_label->set_align(Label::ALIGN_CENTER); +#ifdef TOOLS_ENABLED + zoom_label->set_custom_minimum_size(Size2(48, 0) * EDSCALE); +#else + zoom_label->set_custom_minimum_size(Size2(48, 0)); +#endif + _update_zoom_label(); + zoom_minus = memnew(Button); zoom_minus->set_flat(true); zoom_hb->add_child(zoom_minus); diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index fa3b113705..5251de1722 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -34,6 +34,7 @@ #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/graph_node.h" +#include "scene/gui/label.h" #include "scene/gui/scroll_bar.h" #include "scene/gui/slider.h" #include "scene/gui/spin_box.h" @@ -105,6 +106,7 @@ public: }; private: + Label *zoom_label; Button *zoom_minus; Button *zoom_reset; Button *zoom_plus; @@ -114,10 +116,6 @@ private: Button *minimap_button; - void _zoom_minus(); - void _zoom_reset(); - void _zoom_plus(); - HScrollBar *h_scroll; VScrollBar *v_scroll; @@ -144,6 +142,14 @@ private: Vector2 drag_accum; float zoom = 1.0; + float zoom_step = 1.2; + float zoom_min; + float zoom_max; + + void _zoom_minus(); + void _zoom_reset(); + void _zoom_plus(); + void _update_zoom_label(); bool box_selecting = false; bool box_selection_mode_additive = false; @@ -163,7 +169,7 @@ private: void _bake_segment2d(Vector<Vector2> &points, Vector<Color> &colors, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_min_depth, int p_max_depth, float p_tol, const Color &p_color, const Color &p_to_color, int &lines) const; - void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio); + void _draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, const Color &p_to_color, float p_width, float p_bezier_ratio = 1.0); void _graph_node_raised(Node *p_gn); void _graph_node_moved(Node *p_gn); @@ -229,7 +235,6 @@ protected: virtual void add_child_notify(Node *p_child) override; virtual void remove_child_notify(Node *p_child) override; void _notification(int p_what); - virtual bool clips_input() const override; public: Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port); @@ -247,6 +252,18 @@ public: void set_zoom_custom(float p_zoom, const Vector2 &p_center); float get_zoom() const; + void set_zoom_min(float p_zoom_min); + float get_zoom_min() const; + + void set_zoom_max(float p_zoom_max); + float get_zoom_max() const; + + void set_zoom_step(float p_zoom_step); + float get_zoom_step() const; + + void set_show_zoom_label(bool p_enable); + bool is_showing_zoom_label() const; + void set_minimap_size(Vector2 p_size); Vector2 get_minimap_size() const; void set_minimap_opacity(float p_opacity); diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 77c502cf8d..836bffdf46 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -757,7 +757,7 @@ void GraphNode::_connpos_update() { continue; } - Size2i size = c->get_combined_minimum_size(); + Size2i size = c->get_rect().size; int y = sb->get_margin(SIDE_TOP) + vofs; int h = size.y; @@ -1021,6 +1021,6 @@ void GraphNode::_bind_methods() { } GraphNode::GraphNode() { - title_buf.instance(); + title_buf.instantiate(); set_mouse_filter(MOUSE_FILTER_STOP); } diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index 541925a802..a54f5eef06 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -33,7 +33,7 @@ void GridContainer::_notification(int p_what) { switch (p_what) { case NOTIFICATION_SORT_CHILDREN: { - Map<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col). + Map<int, int> col_minw; // Max of min_width of all controls in each col (indexed by col). Map<int, int> row_minh; // Max of min_height of all controls in each row (indexed by row). Set<int> col_expanded; // Columns which have the SIZE_EXPAND flag set. Set<int> row_expanded; // Rows which have the SIZE_EXPAND flag set. diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 150980b2e9..b0d54bf8c9 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -57,7 +57,7 @@ int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bo item.icon_region = Rect2i(); item.icon_modulate = Color(1, 1, 1, 1); item.text = p_item; - item.text_buf.instance(); + item.text_buf.instantiate(); item.selectable = p_selectable; item.selected = false; item.disabled = false; @@ -80,7 +80,7 @@ int ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { item.icon_region = Rect2i(); item.icon_modulate = Color(1, 1, 1, 1); //item.text=p_item; - item.text_buf.instance(); + item.text_buf.instantiate(); item.selectable = p_selectable; item.selected = false; item.disabled = false; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index de0ee626b9..6580d794d1 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -217,6 +217,7 @@ void Label::_notification(int p_what) { for (int64_t i = lines_skipped; i < last_line; i++) { total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; } + total_h += style->get_margin(SIDE_TOP) + style->get_margin(SIDE_BOTTOM); int vbegin = 0, vsep = 0; if (lines_visible > 0) { @@ -452,6 +453,7 @@ void Label::set_text(const String &p_string) { visible_chars = get_total_character_count() * percent_visible; } update(); + minimum_size_changed(); } void Label::set_text_direction(Control::TextDirection p_text_direction) { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index c2ed9c1a3c..f2d0d9bb22 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -357,9 +357,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } } - // Default is ENTER, KP_ENTER. Cannot use ui_accept as default includes SPACE - if (k->is_action("ui_text_newline", true)) { - emit_signal("text_entered", text); + // Default is ENTER and KP_ENTER. Cannot use ui_accept as default includes SPACE + if (k->is_action("ui_text_submit", false)) { + emit_signal("text_submitted", text); if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_hide(); } @@ -1470,19 +1470,23 @@ int LineEdit::get_scroll_offset() const { } void LineEdit::insert_text_at_caret(String p_text) { - if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) { - String pre = text.substr(0, caret_column); - String post = text.substr(caret_column, text.length() - caret_column); - text = pre + p_text + post; - _shape(); - TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, caret_column, caret_column + p_text.length()); - if (dir != TextServer::DIRECTION_AUTO) { - input_direction = (TextDirection)dir; + if (max_length > 0) { + // Truncate text to append to fit in max_length, if needed. + int available_chars = max_length - text.length(); + if (p_text.length() > available_chars) { + emit_signal("text_change_rejected", p_text.substr(available_chars)); + p_text = p_text.substr(0, available_chars); } - set_caret_column(caret_column + p_text.length()); - } else { - emit_signal("text_change_rejected"); } + String pre = text.substr(0, caret_column); + String post = text.substr(caret_column, text.length() - caret_column); + text = pre + p_text + post; + _shape(); + TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, caret_column, caret_column + p_text.length()); + if (dir != TextServer::DIRECTION_AUTO) { + input_direction = (TextDirection)dir; + } + set_caret_column(caret_column + p_text.length()); } void LineEdit::clear_internal() { @@ -2158,8 +2162,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon); ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text"))); - ADD_SIGNAL(MethodInfo("text_change_rejected")); - ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text"))); + ADD_SIGNAL(MethodInfo("text_change_rejected", PropertyInfo(Variant::STRING, "rejected_substring"))); + ADD_SIGNAL(MethodInfo("text_submitted", PropertyInfo(Variant::STRING, "new_text"))); BIND_ENUM_CONSTANT(ALIGN_LEFT); BIND_ENUM_CONSTANT(ALIGN_CENTER); @@ -2198,7 +2202,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_align", "get_align"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "max_length"), "set_max_length", "get_max_length"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_length", PROPERTY_HINT_RANGE, "0,1000,1,or_greater"), "set_max_length", "get_max_length"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character"); @@ -2221,7 +2225,7 @@ void LineEdit::_bind_methods() { ADD_GROUP("Caret", "caret_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column"), "set_caret_column", "get_caret_column"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column", PROPERTY_HINT_RANGE, "0,1000,1,or_greater"), "set_caret_column", "get_caret_column"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled"); } diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index d45ffde715..ee0618a991 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -301,7 +301,7 @@ void LinkButton::_bind_methods() { } LinkButton::LinkButton() { - text_buf.instance(); + text_buf.instantiate(); set_focus_mode(FOCUS_NONE); set_default_cursor_shape(CURSOR_POINTING_HAND); } diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index 29a38ad5e3..8bf25ac915 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -30,6 +30,7 @@ #include "nine_patch_rect.h" +#include "scene/scene_string_names.h" #include "servers/rendering_server.h" void NinePatchRect::_notification(int p_what) { @@ -97,7 +98,7 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) { texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites */ minimum_size_changed(); - emit_signal("texture_changed"); + emit_signal(SceneStringNames::get_singleton()->texture_changed); } Ref<Texture2D> NinePatchRect::get_texture() const { diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index e4cbe984c9..74718395d3 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -80,8 +80,8 @@ class PopupMenu : public Popup { } Item() { - text_buf.instance(); - accel_text_buf.instance(); + text_buf.instantiate(); + accel_text_buf.instantiate(); checkable_type = CHECKABLE_TYPE_NONE; } }; diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index adc1ed67ca..4ea1e1eb9f 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -265,7 +265,7 @@ void Range::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "step"), "set_step", "get_step"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "page"), "set_page", "get_page"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "value"), "set_value", "get_value"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ratio", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_as_ratio", "get_as_ratio"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ratio", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_NONE), "set_as_ratio", "get_as_ratio"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exp_edit"), "set_exp_ratio", "is_ratio_exp"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rounded"), "set_use_rounded_values", "is_using_rounded_values"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_greater"), "set_allow_greater", "is_greater_allowed"); diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index f2e2823eff..d809fd502f 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -47,8 +47,8 @@ public: RichTextEffect(); }; -class CharFXTransform : public Reference { - GDCLASS(CharFXTransform, Reference); +class CharFXTransform : public RefCounted { + GDCLASS(CharFXTransform, RefCounted); protected: static void _bind_methods(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index a2c3b4ed8a..f32ad2144a 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -934,6 +934,11 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o } } + Vector2 fbg_line_off = off + p_ofs; + // Draw background color box + Vector2i chr_range = TS->shaped_text_get_range(rid); + _draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 0); + // Draw main text. Color selection_fg = get_theme_color("font_selected_color"); Color selection_bg = get_theme_color("selection_color"); @@ -1079,6 +1084,9 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o off.x += glyphs[i].advance; } } + // Draw foreground color box + _draw_fbg_boxes(ci, rid, fbg_line_off, it_from, it_to, chr_range.x, chr_range.y, 1); + off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom(); } @@ -2036,6 +2044,36 @@ bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) return false; } +Color RichTextLabel::_find_bgcolor(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_BGCOLOR) { + ItemBGColor *color = static_cast<ItemBGColor *>(item); + return color->color; + } + + item = item->parent; + } + + return Color(0, 0, 0, 0); +} + +Color RichTextLabel::_find_fgcolor(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_FGCOLOR) { + ItemFGColor *color = static_cast<ItemFGColor *>(item); + return color->color; + } + + item = item->parent; + } + + return Color(0, 0, 0, 0); +} + bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) { if (from && from != to) { if (from->type != ITEM_FONT && from->type != ITEM_COLOR && from->type != ITEM_UNDERLINE && from->type != ITEM_STRIKETHROUGH) { @@ -2546,6 +2584,22 @@ void RichTextLabel::push_rainbow(float p_saturation, float p_value, float p_freq _add_item(item, true); } +void RichTextLabel::push_bgcolor(const Color &p_color) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemBGColor *item = memnew(ItemBGColor); + + item->color = p_color; + _add_item(item, true); +} + +void RichTextLabel::push_fgcolor(const Color &p_color) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ItemFGColor *item = memnew(ItemFGColor); + + item->color = p_color; + _add_item(item, true); +} + void RichTextLabel::push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment) { ItemCustomFX *item = memnew(ItemCustomFX); item->custom_effect = p_custom_effect; @@ -3352,6 +3406,23 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { pos = brk_end + 1; tag_stack.push_front("rainbow"); set_process_internal(true); + + } else if (tag.begins_with("bgcolor=")) { + String color_str = tag.substr(8, tag.length()); + Color color = Color::from_string(color_str, base_color); + + push_bgcolor(color); + pos = brk_end + 1; + tag_stack.push_front("bgcolor"); + + } else if (tag.begins_with("fgcolor=")) { + String color_str = tag.substr(8, tag.length()); + Color color = Color::from_string(color_str, base_color); + + push_fgcolor(color); + pos = brk_end + 1; + tag_stack.push_front("fgcolor"); + } else { Vector<String> &expr = split_tag_block; if (expr.size() < 1) { @@ -3452,7 +3523,30 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) { } } -bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to) { +bool RichTextLabel::_search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search) { + List<Item *>::Element *E = p_from; + while (E != nullptr) { + ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. + ItemFrame *frame = static_cast<ItemFrame *>(E->get()); + if (p_reverse_search) { + for (int i = frame->lines.size() - 1; i >= 0; i--) { + if (_search_line(frame, i, p_string, -1, p_reverse_search)) { + return true; + } + } + } else { + for (int i = 0; i < frame->lines.size(); i++) { + if (_search_line(frame, i, p_string, 0, p_reverse_search)) { + return true; + } + } + } + E = p_reverse_search ? E->prev() : E->next(); + } + return false; +} + +bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search) { ERR_FAIL_COND_V(p_frame == nullptr, false); ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), false); @@ -3474,24 +3568,23 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p } break; case ITEM_TABLE: { ItemTable *table = static_cast<ItemTable *>(it); - int idx = 0; - for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { - ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. - ItemFrame *frame = static_cast<ItemFrame *>(E->get()); - - for (int i = 0; i < frame->lines.size(); i++) { - if (_search_line(frame, i, p_string, p_from, p_to)) { - return true; - } - } - idx++; + List<Item *>::Element *E = p_reverse_search ? table->subitems.back() : table->subitems.front(); + if (_search_table(table, E, p_string, p_reverse_search)) { + return true; } } break; default: break; } } - int sp = text.findn(p_string, 0); + + int sp = -1; + if (p_reverse_search) { + sp = text.rfindn(p_string, p_char_idx); + } else { + sp = text.findn(p_string, p_char_idx); + } + if (sp != -1) { selection.from_frame = p_frame; selection.from_line = p_line; @@ -3499,8 +3592,8 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p selection.from_char = sp; selection.to_frame = p_frame; selection.to_line = p_line; - selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length() - 1); - selection.to_char = sp + p_string.length() - 1; + selection.to_item = _get_item_at_pos(l.from, it_to, sp + p_string.length()); + selection.to_char = sp + p_string.length(); selection.active = true; return true; } @@ -3511,23 +3604,81 @@ bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) { ERR_FAIL_COND_V(!selection.enabled, false); + if (p_string.size() == 0) { + selection.active = false; + return false; + } + + int char_idx = p_search_previous ? -1 : 0; + int current_line = 0; + int ending_line = main->lines.size() - 1; if (p_from_selection && selection.active) { - for (int i = 0; i < main->lines.size(); i++) { - if (_search_line(main, i, p_string, selection.from_item, selection.to_item)) { - update(); - return true; - } + // First check to see if other results exist in current line + char_idx = p_search_previous ? selection.from_char - 1 : selection.to_char; + if (!(p_search_previous && char_idx < 0) && + _search_line(selection.from_frame, selection.from_line, p_string, char_idx, p_search_previous)) { + scroll_to_line(selection.from_frame->line + selection.from_line); + update(); + return true; } - } else { - for (int i = 0; i < main->lines.size(); i++) { - if (_search_line(main, i, p_string, nullptr, nullptr)) { - update(); - return true; + char_idx = p_search_previous ? -1 : 0; + + // Next, check to see if the current search result is in a table + if (selection.from_frame->parent != nullptr && selection.from_frame->parent->type == ITEM_TABLE) { + // Find last search result in table + ItemTable *parent_table = static_cast<ItemTable *>(selection.from_frame->parent); + List<Item *>::Element *parent_element = p_search_previous ? parent_table->subitems.back() : parent_table->subitems.front(); + + while (parent_element->get() != selection.from_frame) { + parent_element = p_search_previous ? parent_element->prev() : parent_element->next(); + ERR_FAIL_COND_V(parent_element == nullptr, false); + } + + // Search remainder of table + if (!(p_search_previous && parent_element == parent_table->subitems.front()) && + parent_element != parent_table->subitems.back()) { + parent_element = p_search_previous ? parent_element->prev() : parent_element->next(); // Don't want to search current item + ERR_FAIL_COND_V(parent_element == nullptr, false); + + // Search for next element + if (_search_table(parent_table, parent_element, p_string, p_search_previous)) { + scroll_to_line(selection.from_frame->line + selection.from_line); + update(); + return true; + } } } + + ending_line = selection.from_frame->line + selection.from_line; + current_line = p_search_previous ? ending_line - 1 : ending_line + 1; + } else if (p_search_previous) { + current_line = ending_line; + ending_line = 0; } - return false; + // Search remainder of the file + while (current_line != ending_line) { + // Wrap around + if (current_line < 0) { + current_line = main->lines.size() - 1; + } else if (current_line >= main->lines.size()) { + current_line = 0; + } + + if (_search_line(main, current_line, p_string, char_idx, p_search_previous)) { + scroll_to_line(current_line); + update(); + return true; + } + p_search_previous ? current_line-- : current_line++; + } + + if (p_from_selection && selection.active) { + // Check contents of selection + return _search_line(main, current_line, p_string, char_idx, p_search_previous); + } else { + return false; + } } String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const { @@ -3838,6 +3989,8 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_cell_size_override", "min_size", "max_size"), &RichTextLabel::set_cell_size_override); ClassDB::bind_method(D_METHOD("set_cell_padding", "padding"), &RichTextLabel::set_cell_padding); ClassDB::bind_method(D_METHOD("push_cell"), &RichTextLabel::push_cell); + ClassDB::bind_method(D_METHOD("push_fgcolor", "fgcolor"), &RichTextLabel::push_fgcolor); + ClassDB::bind_method(D_METHOD("push_bgcolor", "bgcolor"), &RichTextLabel::push_bgcolor); ClassDB::bind_method(D_METHOD("pop"), &RichTextLabel::pop); ClassDB::bind_method(D_METHOD("clear"), &RichTextLabel::clear); @@ -3932,7 +4085,7 @@ void RichTextLabel::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, "RichTextEffect", (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); @@ -3976,6 +4129,8 @@ void RichTextLabel::_bind_methods() { BIND_ENUM_CONSTANT(ITEM_WAVE); BIND_ENUM_CONSTANT(ITEM_TORNADO); BIND_ENUM_CONSTANT(ITEM_RAINBOW); + BIND_ENUM_CONSTANT(ITEM_BGCOLOR); + BIND_ENUM_CONSTANT(ITEM_FGCOLOR); BIND_ENUM_CONSTANT(ITEM_META); BIND_ENUM_CONSTANT(ITEM_DROPCAP); BIND_ENUM_CONSTANT(ITEM_CUSTOMFX); @@ -4028,6 +4183,65 @@ Size2 RichTextLabel::get_minimum_size() const { return size; } +void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item *it_from, Item *it_to, int start, int end, int fbg_flag) { + Vector2i fbg_index = Vector2i(end, start); + Color last_color = Color(0, 0, 0, 0); + bool draw_box = false; + // Draw a box based on color tags associated with glyphs + for (int i = start; i < end; i++) { + Item *it = _get_item_at_pos(it_from, it_to, i); + Color color = Color(0, 0, 0, 0); + + if (fbg_flag == 0) { + color = _find_bgcolor(it); + } else { + color = _find_fgcolor(it); + } + + bool change_to_color = ((color.a > 0) && ((last_color.a - 0.0) < 0.01)); + bool change_from_color = (((color.a - 0.0) < 0.01) && (last_color.a > 0.0)); + bool change_color = (((color.a > 0) == (last_color.a > 0)) && (color != last_color)); + + if (change_to_color) { + fbg_index.x = MIN(i, fbg_index.x); + fbg_index.y = MAX(i, fbg_index.y); + } + + if (change_from_color || change_color) { + fbg_index.x = MIN(i, fbg_index.x); + fbg_index.y = MAX(i, fbg_index.y); + draw_box = true; + } + + if (draw_box) { + Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, fbg_index.y); + for (int j = 0; j < sel.size(); j++) { + Vector2 rect_off = line_off + Vector2(sel[j].x, -TS->shaped_text_get_ascent(p_rid)); + Vector2 rect_size = Vector2(sel[j].y - sel[j].x, TS->shaped_text_get_size(p_rid).y); + RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color); + } + fbg_index = Vector2i(end, start); + draw_box = false; + } + + if (change_color) { + fbg_index.x = MIN(i, fbg_index.x); + fbg_index.y = MAX(i, fbg_index.y); + } + + last_color = color; + } + + if (last_color.a > 0) { + Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, end); + for (int i = 0; i < sel.size(); i++) { + Vector2 rect_off = line_off + Vector2(sel[i].x, -TS->shaped_text_get_ascent(p_rid)); + Vector2 rect_size = Vector2(sel[i].y - sel[i].x, TS->shaped_text_get_size(p_rid).y); + RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color); + } + } +} + Ref<RichTextEffect> RichTextLabel::_get_custom_effect_by_code(String p_bbcode_identifier) { for (int i = 0; i < custom_effects.size(); i++) { if (!custom_effects[i].is_valid()) { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index e3e457d1f2..999d8b05fd 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -75,6 +75,8 @@ public: ITEM_WAVE, ITEM_TORNADO, ITEM_RAINBOW, + ITEM_BGCOLOR, + ITEM_FGCOLOR, ITEM_META, ITEM_DROPCAP, ITEM_CUSTOMFX @@ -100,7 +102,7 @@ private: int char_offset = 0; int char_count = 0; - Line() { text_buf.instance(); } + Line() { text_buf.instantiate(); } }; struct Item { @@ -307,13 +309,23 @@ private: ItemRainbow() { type = ITEM_RAINBOW; } }; + struct ItemBGColor : public Item { + Color color; + ItemBGColor() { type = ITEM_BGCOLOR; } + }; + + struct ItemFGColor : public Item { + Color color; + ItemFGColor() { type = ITEM_FGCOLOR; } + }; + struct ItemCustomFX : public ItemFX { Ref<CharFXTransform> char_fx_transform; Ref<RichTextEffect> custom_effect; ItemCustomFX() { type = ITEM_CUSTOMFX; - char_fx_transform.instance(); + char_fx_transform.instantiate(); } virtual ~ItemCustomFX() { @@ -392,7 +404,8 @@ private: void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr); String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const; - bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to); + bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search); + bool _search_table(ItemTable *p_table, List<Item *>::Element *p_from, const String &p_string, bool p_reverse_search); void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset); void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width); @@ -421,6 +434,8 @@ private: bool _find_underline(Item *p_item); bool _find_strikethrough(Item *p_item); bool _find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item = nullptr); + Color _find_bgcolor(Item *p_item); + Color _find_fgcolor(Item *p_item); bool _find_layout_subitem(Item *from, Item *to); void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack); @@ -436,6 +451,8 @@ private: Ref<RichTextEffect> _get_custom_effect_by_code(String p_bbcode_identifier); virtual Dictionary parse_expressions_for_values(Vector<String> p_expressions); + void _draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item *it_from, Item *it_to, int start, int end, int fbg_flag); + bool use_bbcode = false; String bbcode; @@ -473,6 +490,8 @@ public: void push_wave(float p_frequency, float p_amplitude); void push_tornado(float p_frequency, float p_radius); void push_rainbow(float p_saturation, float p_value, float p_frequency); + void push_bgcolor(const Color &p_color); + void push_fgcolor(const Color &p_color); void push_customfx(Ref<RichTextEffect> p_custom_effect, Dictionary p_environment); void set_table_column_expand(int p_column, bool p_expand, int p_ratio = 1); void set_cell_row_background_color(const Color &p_odd_row_bg, const Color &p_even_row_bg); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 5f872644ab..177f146b6a 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -32,10 +32,6 @@ #include "core/os/os.h" #include "scene/main/window.h" -bool ScrollContainer::clips_input() const { - return true; -} - Size2 ScrollContainer::get_minimum_size() const { Ref<StyleBox> sb = get_theme_stylebox("bg"); Size2 min_size; @@ -239,13 +235,13 @@ void ScrollContainer::_update_scrollbar_position() { } void ScrollContainer::_gui_focus_changed(Control *p_control) { - if (follow_focus && is_a_parent_of(p_control)) { + if (follow_focus && is_ancestor_of(p_control)) { ensure_control_visible(p_control); } } void ScrollContainer::ensure_control_visible(Control *p_control) { - ERR_FAIL_COND_MSG(!is_a_parent_of(p_control), "Must be a parent of the control."); + ERR_FAIL_COND_MSG(!is_ancestor_of(p_control), "Must be an ancestor of the control."); Rect2 global_rect = get_global_rect(); Rect2 other_rect = p_control->get_global_rect(); diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index c77a0d62f5..4733fdabca 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -108,8 +108,6 @@ public: VScrollBar *get_v_scrollbar(); void ensure_control_visible(Control *p_control); - virtual bool clips_input() const override; - TypedArray<String> get_configuration_warnings() const override; ScrollContainer(); diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp index cbbcf9e069..962c6dcc60 100644 --- a/scene/gui/shortcut.cpp +++ b/scene/gui/shortcut.cpp @@ -42,7 +42,7 @@ Ref<InputEvent> Shortcut::get_shortcut() const { } bool Shortcut::is_shortcut(const Ref<InputEvent> &p_event) const { - return shortcut.is_valid() && shortcut->shortcut_match(p_event); + return shortcut.is_valid() && shortcut->is_match(p_event, true); } String Shortcut::get_as_text() const { diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index a407ef21cb..5947f3b99e 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -172,7 +172,7 @@ void Slider::_notification(int p_what) { int widget_width = style->get_minimum_size().width + style->get_center_size().width; float areasize = size.height - grabber->get_size().height; style->draw(ci, Rect2i(Point2i(size.width / 2 - widget_width / 2, 0), Size2i(widget_width, size.height))); - grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().width / 2))); + grabber_area->draw(ci, Rect2i(Point2i((size.width - widget_width) / 2, size.height - areasize * ratio - grabber->get_size().height / 2), Size2i(widget_width, areasize * ratio + grabber->get_size().height / 2))); if (ticks > 1) { int grabber_offset = (grabber->get_size().height / 2 - tick->get_height() / 2); diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 9dc2afdb2d..941dd30057 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -50,9 +50,9 @@ void SpinBox::_value_changed(double) { line_edit->set_text(value); } -void SpinBox::_text_entered(const String &p_string) { +void SpinBox::_text_submitted(const String &p_string) { Ref<Expression> expr; - expr.instance(); + expr.instantiate(); String num = TS->parse_number(p_string); // Ignore the prefix and suffix in the expression @@ -140,6 +140,8 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { accept_event(); } } break; + default: + break; } } @@ -172,7 +174,7 @@ void SpinBox::_line_edit_focus_exit() { return; } - _text_entered(line_edit->get_text()); + _text_submitted(line_edit->get_text()); } inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) { @@ -251,7 +253,7 @@ bool SpinBox::is_editable() const { } void SpinBox::apply() { - _text_entered(line_edit->get_text()); + _text_submitted(line_edit->get_text()); } void SpinBox::_bind_methods() { @@ -283,7 +285,7 @@ SpinBox::SpinBox() { line_edit->set_align(LineEdit::ALIGN_LEFT); //connect("value_changed",this,"_value_changed"); - line_edit->connect("text_entered", callable_mp(this, &SpinBox::_text_entered), Vector<Variant>(), CONNECT_DEFERRED); + line_edit->connect("text_submitted", callable_mp(this, &SpinBox::_text_submitted), Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("focus_exited", callable_mp(this, &SpinBox::_line_edit_focus_exit), Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("gui_input", callable_mp(this, &SpinBox::_line_edit_input)); diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index e116adb64c..fb10379296 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -45,7 +45,7 @@ class SpinBox : public Range { void _range_click_timeout(); void _release_mouse(); - void _text_entered(const String &p_string); + void _text_submitted(const String &p_string); virtual void _value_changed(double) override; String prefix; String suffix; diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index df4cf9a740..9796b32c6b 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -38,7 +38,7 @@ Control *SplitContainer::_getch(int p_idx) const { for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c || !c->is_visible_in_tree()) { + if (!c || !c->is_visible()) { continue; } if (c->is_set_as_top_level()) { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index acf0641005..133966013b 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -586,7 +586,7 @@ void TabContainer::_refresh_texts() { Control *control = Object::cast_to<Control>(tabs[i]); String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name())); Ref<TextLine> name; - name.instance(); + name.instantiate(); name->set_direction(rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); name->add_string(text, font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); text_buf.push_back(name); diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 471b26be75..6f1cff9ec8 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -256,6 +256,7 @@ void Tabs::_notification(int p_what) { _update_cache(); update(); } break; + case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_TRANSLATION_CHANGED: { for (int i = 0; i < tabs.size(); ++i) { _shape(i); @@ -742,7 +743,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) { Tab t; t.text = p_str; t.xl_text = tr(p_str); - t.text_buf.instance(); + t.text_buf.instantiate(); t.text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); t.text_buf->add_string(t.xl_text, get_theme_font("font"), get_theme_font_size("font_size"), Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); t.icon = p_icon; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 07ccad70b1..6f96b530a6 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -102,14 +102,6 @@ static char32_t _get_right_pair_symbol(char32_t c) { return 0; } -static int _find_first_non_whitespace_column_of_line(const String &line) { - int left = 0; - while (left < line.length() && _is_whitespace(line[left])) { - left++; - } - return left; -} - /////////////////////////////////////////////////////////////////////////////// void TextEdit::Text::set_font(const Ref<Font> &p_font) { @@ -120,8 +112,12 @@ void TextEdit::Text::set_font_size(int p_font_size) { font_size = p_font_size; } -void TextEdit::Text::set_indent_size(int p_indent_size) { - indent_size = p_indent_size; +void TextEdit::Text::set_tab_size(int p_tab_size) { + tab_size = p_tab_size; +} + +int TextEdit::Text::get_tab_size() const { + return tab_size; } void TextEdit::Text::set_font_features(const Dictionary &p_features) { @@ -137,8 +133,11 @@ void TextEdit::Text::set_draw_control_chars(bool p_draw_control_chars) { draw_control_chars = p_draw_control_chars; } -int TextEdit::Text::get_line_width(int p_line) const { +int TextEdit::Text::get_line_width(int p_line, int p_wrap_index) const { ERR_FAIL_INDEX_V(p_line, text.size(), 0); + if (p_wrap_index != -1) { + return text[p_line].data_buf->get_line_width(p_wrap_index); + } return text[p_line].data_buf->get_size().x; } @@ -201,9 +200,9 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ } // Apply tab align. - if (indent_size > 0) { + if (tab_size > 0) { Vector<float> tabs; - tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size); + tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size); text.write[p_line].data_buf->tab_align(tabs); } } @@ -211,9 +210,9 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ void TextEdit::Text::invalidate_all_lines() { for (int i = 0; i < text.size(); i++) { text.write[i].data_buf->set_width(width); - if (indent_size > 0) { + if (tab_size > 0) { Vector<float> tabs; - tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size); + tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size); text.write[i].data_buf->tab_align(tabs); } } @@ -819,7 +818,7 @@ void TextEdit::_notification(int p_what) { if (draw_minimap) { int minimap_visible_lines = _get_minimap_visible_rows(); int minimap_line_height = (minimap_char_size.y + minimap_line_spacing); - int minimap_tab_size = minimap_char_size.x * indent_size; + int minimap_tab_size = minimap_char_size.x * text.get_tab_size(); // calculate viewport size and y offset int viewport_height = (draw_amount - 1) * minimap_line_height; @@ -1111,7 +1110,7 @@ void TextEdit::_notification(int p_what) { } Ref<TextLine> tl; - tl.instance(); + tl.instantiate(); tl->add_string(text, cache.font, cache.font_size); int yofs = ofs_y + (row_height - tl->get_size().y) / 2; @@ -1354,7 +1353,8 @@ void TextEdit::_notification(int p_what) { } } - if (line_wrap_index == line_wrap_amount && is_folded(line)) { + // is_line_folded + if (line_wrap_index == line_wrap_amount && line < text.size() - 1 && is_line_hidden(line + 1)) { int xofs = char_ofs + char_margin + ofs_x + (cache.folded_eol_icon->get_width() / 2); if (xofs >= xmargin_beg && xofs < xmargin_end) { int yofs = (text_height - cache.folded_eol_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); @@ -1691,7 +1691,13 @@ void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column } } -void TextEdit::backspace_at_cursor() { +void TextEdit::backspace() { + ScriptInstance *si = get_script_instance(); + if (si && si->has_method("_backspace")) { + si->call("_backspace"); + return; + } + if (readonly) { return; } @@ -1700,34 +1706,15 @@ void TextEdit::backspace_at_cursor() { return; } + if (is_selection_active()) { + delete_selection(); + return; + } + int prev_line = cursor.column ? cursor.line : cursor.line - 1; int prev_column = cursor.column ? (cursor.column - 1) : (text[cursor.line - 1].length()); - if (cursor.line != prev_line) { - for (int i = 0; i < gutters.size(); i++) { - if (!gutters[i].overwritable) { - continue; - } - - if (text.get_line_gutter_text(cursor.line, i) != "") { - text.set_line_gutter_text(prev_line, i, text.get_line_gutter_text(cursor.line, i)); - text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i)); - } - - if (text.get_line_gutter_icon(cursor.line, i).is_valid()) { - text.set_line_gutter_icon(prev_line, i, text.get_line_gutter_icon(cursor.line, i)); - text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i)); - } - - if (text.get_line_gutter_metadata(cursor.line, i) != "") { - text.set_line_gutter_metadata(prev_line, i, text.get_line_gutter_metadata(cursor.line, i)); - } - - if (text.is_line_gutter_clickable(cursor.line, i)) { - text.set_line_gutter_clickable(prev_line, i, true); - } - } - } + merge_gutters(cursor.line, prev_line); if (is_line_hidden(cursor.line)) { set_line_as_hidden(prev_line, true); @@ -1738,168 +1725,13 @@ void TextEdit::backspace_at_cursor() { _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { - // Handle space indentation. - if (cursor.column != 0 && indent_using_spaces) { - // Check if there are no other chars before cursor, just indentation. - bool unindent = true; - int i = 0; - while (i < cursor.column && i < text[cursor.line].length()) { - if (!_is_whitespace(text[cursor.line][i])) { - unindent = false; - break; - } - i++; - } - - // Then we can remove all spaces as a single character. - if (unindent) { - // We want to remove spaces up to closest indent, or whole indent if cursor is pointing at it. - int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column); - prev_column = cursor.column - spaces_to_delete; - _remove_text(cursor.line, prev_column, cursor.line, cursor.column); - } else { - _remove_text(prev_line, prev_column, cursor.line, cursor.column); - } - } else { - _remove_text(prev_line, prev_column, cursor.line, cursor.column); - } + _remove_text(prev_line, prev_column, cursor.line, cursor.column); } cursor_set_line(prev_line, false, true); cursor_set_column(prev_column); } -void TextEdit::indent_selected_lines_right() { - int start_line; - int end_line; - - // This value informs us by how much we changed selection position by indenting right. - // Default is 1 for tab indentation. - int selection_offset = 1; - begin_complex_operation(); - - if (is_selection_active()) { - start_line = get_selection_from_line(); - end_line = get_selection_to_line(); - } else { - start_line = cursor.line; - end_line = start_line; - } - - // Ignore if the cursor is not past the first column. - if (is_selection_active() && get_selection_to_column() == 0) { - selection_offset = 0; - end_line--; - } - - for (int i = start_line; i <= end_line; i++) { - String line_text = get_line(i); - if (line_text.size() == 0 && is_selection_active()) { - continue; - } - if (indent_using_spaces) { - // We don't really care where selection is - we just need to know indentation level at the beginning of the line. - int left = _find_first_non_whitespace_column_of_line(line_text); - int spaces_to_add = _calculate_spaces_till_next_right_indent(left); - // Since we will add these many spaces, we want to move the whole selection and cursor by this much. - selection_offset = spaces_to_add; - for (int j = 0; j < spaces_to_add; j++) { - line_text = ' ' + line_text; - } - } else { - line_text = '\t' + line_text; - } - set_line(i, line_text); - } - - // Fix selection and cursor being off after shifting selection right. - if (is_selection_active()) { - select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset); - } - cursor_set_column(cursor.column + selection_offset, false); - end_complex_operation(); - update(); -} - -void TextEdit::indent_selected_lines_left() { - int start_line; - int end_line; - - // Moving cursor and selection after unindenting can get tricky because - // changing content of line can move cursor and selection on its own (if new line ends before previous position of either), - // therefore we just remember initial values and at the end of the operation offset them by number of removed characters. - int removed_characters = 0; - int initial_selection_end_column = selection.to_column; - int initial_cursor_column = cursor.column; - - begin_complex_operation(); - - if (is_selection_active()) { - start_line = get_selection_from_line(); - end_line = get_selection_to_line(); - } else { - start_line = cursor.line; - end_line = start_line; - } - - // Ignore if the cursor is not past the first column. - if (is_selection_active() && get_selection_to_column() == 0) { - end_line--; - } - String first_line_text = get_line(start_line); - String last_line_text = get_line(end_line); - - for (int i = start_line; i <= end_line; i++) { - String line_text = get_line(i); - - if (line_text.begins_with("\t")) { - line_text = line_text.substr(1, line_text.length()); - set_line(i, line_text); - removed_characters = 1; - } else if (line_text.begins_with(" ")) { - // When unindenting we aim to remove spaces before line that has selection no matter what is selected, - // so we start of by finding first non whitespace character of line - int left = _find_first_non_whitespace_column_of_line(line_text); - - // Here we remove only enough spaces to align text to nearest full multiple of indentation_size. - // In case where selection begins at the start of indentation_size multiple we remove whole indentation level. - int spaces_to_remove = _calculate_spaces_till_next_left_indent(left); - - line_text = line_text.substr(spaces_to_remove, line_text.length()); - set_line(i, line_text); - removed_characters = spaces_to_remove; - } - } - - if (is_selection_active()) { - // Fix selection being off by one on the first line. - if (first_line_text != get_line(start_line)) { - select(selection.from_line, selection.from_column - removed_characters, - selection.to_line, initial_selection_end_column); - } - // Fix selection being off by one on the last line. - if (last_line_text != get_line(end_line)) { - select(selection.from_line, selection.from_column, - selection.to_line, initial_selection_end_column - removed_characters); - } - } - cursor_set_column(initial_cursor_column - removed_characters, false); - end_complex_operation(); - update(); -} - -int TextEdit::_calculate_spaces_till_next_left_indent(int column) { - int spaces_till_indent = column % indent_size; - if (spaces_till_indent == 0) { - spaces_till_indent = indent_size; - } - return spaces_till_indent; -} - -int TextEdit::_calculate_spaces_till_next_right_indent(int column) { - return indent_size - column % indent_size; -} - void TextEdit::_swap_current_input_direction() { if (input_direction == TEXT_DIRECTION_LTR) { input_direction = TEXT_DIRECTION_RTL; @@ -1915,94 +1747,8 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) { return; } - String ins = "\n"; - - // Keep indentation. - int space_count = 0; - for (int i = 0; i < cursor.column; i++) { - if (text[cursor.line][i] == '\t') { - if (indent_using_spaces) { - ins += space_indent; - } else { - ins += "\t"; - } - space_count = 0; - } else if (text[cursor.line][i] == ' ') { - space_count++; - - if (space_count == indent_size) { - if (indent_using_spaces) { - ins += space_indent; - } else { - ins += "\t"; - } - space_count = 0; - } - } else { - break; - } - } - - if (is_folded(cursor.line)) { - unfold_line(cursor.line); - } - - bool brace_indent = false; - - // No need to indent if we are going upwards. - if (auto_indent && !p_above) { - // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment - // (i.e. colon/brace precedes current cursor position). - if (cursor.column > 0) { - bool indent_char_found = false; - bool should_indent = false; - char indent_char = ':'; - char c = text[cursor.line][cursor.column]; - - for (int i = 0; i < cursor.column; i++) { - c = text[cursor.line][i]; - switch (c) { - case ':': - case '{': - case '[': - case '(': - indent_char_found = true; - should_indent = true; - indent_char = c; - continue; - } - - if (indent_char_found && is_line_comment(cursor.line)) { - should_indent = true; - break; - } else if (indent_char_found && !_is_whitespace(c)) { - should_indent = false; - indent_char_found = false; - } - } - - if (!is_line_comment(cursor.line) && should_indent) { - if (indent_using_spaces) { - ins += space_indent; - } else { - ins += "\t"; - } - - // No need to move the brace below if we are not taking the text with us. - char32_t closing_char = _get_right_pair_symbol(indent_char); - if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column])) { - if (p_split_current_line) { - brace_indent = true; - ins += "\n" + ins.substr(1, ins.length() - 2); - } else { - brace_indent = false; - ins = "\n" + ins.substr(1, ins.length() - 2); - } - } - } - } - } begin_complex_operation(); + bool first_line = false; if (!p_split_current_line) { if (p_above) { @@ -2018,83 +1764,13 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) { } } - insert_text_at_cursor(ins); + insert_text_at_cursor("\n"); if (first_line) { cursor_set_line(0); - } else if (brace_indent) { - cursor_set_line(cursor.line - 1, false); - cursor_set_column(text[cursor.line].length()); - } - end_complex_operation(); -} - -void TextEdit::_indent_right() { - if (readonly) { - return; } - if (is_selection_active()) { - indent_selected_lines_right(); - } else { - // Simple indent. - if (indent_using_spaces) { - // Insert only as much spaces as needed till next indentation level. - int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); - String indent_to_insert = String(); - for (int i = 0; i < spaces_to_add; i++) { - indent_to_insert = ' ' + indent_to_insert; - } - _insert_text_at_cursor(indent_to_insert); - } else { - _insert_text_at_cursor("\t"); - } - } -} - -void TextEdit::_indent_left() { - if (readonly) { - return; - } - - if (is_selection_active()) { - indent_selected_lines_left(); - } else { - // Simple unindent. - int cc = cursor.column; - const String &line = text[cursor.line]; - - int left = _find_first_non_whitespace_column_of_line(line); - cc = MIN(cc, left); - - while (cc < indent_size && cc < left && line[cc] == ' ') { - cc++; - } - - if (cc > 0 && cc <= text[cursor.line].length()) { - if (text[cursor.line][cc - 1] == '\t') { - // Tabs unindentation. - _remove_text(cursor.line, cc - 1, cursor.line, cc); - if (cursor.column >= left) { - cursor_set_column(MAX(0, cursor.column - 1)); - } - update(); - } else { - // Spaces unindentation. - int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); - if (spaces_to_remove > 0) { - _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); - if (cursor.column > left - spaces_to_remove) { // Inside text? - cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); - } - update(); - } - } - } else if (cc == 0 && line.length() > 0 && line[0] == '\t') { - _remove_text(cursor.line, 0, cursor.line, 1); - update(); - } - } + end_complex_operation(); } void TextEdit::_move_cursor_left(bool p_select, bool p_move_by_word) { @@ -2331,20 +2007,24 @@ void TextEdit::_move_cursor_page_down(bool p_select) { } } -void TextEdit::_backspace(bool p_word, bool p_all_to_left) { +void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) { if (readonly) { return; } - if (is_selection_active()) { - _delete_selection(); + if (is_selection_active() || (!p_all_to_left && !p_word)) { + backspace(); return; } + if (p_all_to_left) { int cursor_current_column = cursor.column; cursor.column = 0; _remove_text(cursor.line, 0, cursor.line, cursor_current_column); - } else if (p_word) { + return; + } + + if (p_word) { int line = cursor.line; int column = cursor.column; @@ -2360,12 +2040,7 @@ void TextEdit::_backspace(bool p_word, bool p_all_to_left) { cursor_set_line(line, false); cursor_set_column(column); - } else { - // One character. - if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) { - unfold_line(cursor.line - 1); - } - backspace_at_cursor(); + return; } } @@ -2375,7 +2050,7 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) { } if (is_selection_active()) { - _delete_selection(); + delete_selection(); return; } int curline_len = text[cursor.line].length(); @@ -2420,15 +2095,16 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) { update(); } -void TextEdit::_delete_selection() { - if (is_selection_active()) { - selection.active = false; - update(); - _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); - cursor_set_line(selection.from_line, false, false); - cursor_set_column(selection.from_column); - update(); +void TextEdit::delete_selection() { + if (!is_selection_active()) { + return; } + + selection.active = false; + _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); + cursor_set_line(selection.from_line, false, false); + cursor_set_column(selection.from_column); + update(); } void TextEdit::_move_cursor_document_start(bool p_select) { @@ -2463,7 +2139,7 @@ void TextEdit::_move_cursor_document_end(bool p_select) { void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection) { if (p_had_selection) { - _delete_selection(); + delete_selection(); } // Remove the old character if in insert mode and no selection. @@ -2692,15 +2368,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { left_margin += gutters[i].width; } - // Unfold on folded icon click. - if (is_folded(row)) { - left_margin += gutter_padding + text.get_line_width(row) - cursor.x_ofs; - if (mpos.x > left_margin && mpos.x <= left_margin + cache.folded_eol_icon->get_width() + 3) { - unfold_line(row); - return; - } - } - // minimap if (draw_minimap) { _update_minimap_click(); @@ -2955,31 +2622,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - // INDENTATION. - if (k->is_action("ui_text_dedent", true)) { - _indent_left(); - accept_event(); - return; - } - if (k->is_action("ui_text_indent", true)) { - _indent_right(); - accept_event(); - return; - } - // BACKSPACE AND DELETE. if (k->is_action("ui_text_backspace_all_to_left", true)) { - _backspace(false, true); + _do_backspace(false, true); accept_event(); return; } if (k->is_action("ui_text_backspace_word", true)) { - _backspace(true); + _do_backspace(true); accept_event(); return; } if (k->is_action("ui_text_backspace", true)) { - _backspace(); + _do_backspace(); accept_event(); return; } @@ -3703,10 +3358,6 @@ void TextEdit::center_viewport_to_cursor() { scrolling = false; minimap_clicked = false; - if (is_line_hidden(cursor.line)) { - unfold_line(cursor.line); - } - set_line_as_center_visible(cursor.line, get_cursor_wrap_index()); int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.minimap_width; if (v_scroll->is_visible_in_tree()) { @@ -4124,15 +3775,6 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { return CURSOR_ARROW; } - - // EOL fold icon. - if (is_folded(row)) { - gutter += gutter_padding + text.get_line_width(row) - cursor.x_ofs; - if (p_pos.x > gutter - 3 && p_pos.x <= gutter + cache.folded_eol_icon->get_width() + 3) { - return CURSOR_POINTING_HAND; - } - } - return get_default_cursor_shape(); } @@ -4318,6 +3960,10 @@ String TextEdit::get_line(int line) const { return text[line]; }; +bool TextEdit::has_ime_text() const { + return !ime_text.is_empty(); +} + void TextEdit::_clear() { clear_undo_history(); text.clear(); @@ -4362,14 +4008,6 @@ bool TextEdit::is_wrap_enabled() const { return wrap_enabled; } -void TextEdit::set_max_chars(int p_max_chars) { - max_chars = p_max_chars; -} - -int TextEdit::get_max_chars() const { - return max_chars; -} - void TextEdit::_reset_caret_blink_timer() { if (caret_blink_enabled) { draw_caret = true; @@ -4404,7 +4042,7 @@ void TextEdit::_update_caches() { cache.selection_color = get_theme_color("selection_color"); cache.current_line_color = get_theme_color("current_line_color"); cache.line_length_guideline_color = get_theme_color("line_length_guideline_color"); - cache.code_folding_color = get_theme_color("code_folding_color"); + cache.code_folding_color = get_theme_color("code_folding_color", "CodeEdit"); cache.brace_mismatch_color = get_theme_color("brace_mismatch_color"); cache.word_highlighted_color = get_theme_color("word_highlighted_color"); cache.search_result_color = get_theme_color("search_result_color"); @@ -4417,7 +4055,7 @@ void TextEdit::_update_caches() { #endif cache.tab_icon = get_theme_icon("tab"); cache.space_icon = get_theme_icon("space"); - cache.folded_eol_icon = get_theme_icon("GuiEllipsis", "EditorIcons"); + cache.folded_eol_icon = get_theme_icon("folded_eol_icon", "CodeEdit"); TextServer::Direction dir; if (text_direction == Control::TEXT_DIRECTION_INHERITED) { @@ -4526,6 +4164,10 @@ int TextEdit::get_gutter_width(int p_gutter) const { return gutters[p_gutter].width; } +int TextEdit::get_total_gutter_width() const { + return gutters_width + gutter_padding; +} + void TextEdit::set_gutter_draw(int p_gutter, bool p_draw) { ERR_FAIL_INDEX(p_gutter, gutters.size()); gutters.write[p_gutter].draw = p_draw; @@ -4558,6 +4200,39 @@ bool TextEdit::is_gutter_overwritable(int p_gutter) const { return gutters[p_gutter].overwritable; } +void TextEdit::merge_gutters(int p_from_line, int p_to_line) { + ERR_FAIL_INDEX(p_from_line, text.size()); + ERR_FAIL_INDEX(p_to_line, text.size()); + if (p_from_line == p_to_line) { + return; + } + + for (int i = 0; i < gutters.size(); i++) { + if (!gutters[i].overwritable) { + continue; + } + + if (text.get_line_gutter_text(p_from_line, i) != "") { + text.set_line_gutter_text(p_to_line, i, text.get_line_gutter_text(p_from_line, i)); + text.set_line_gutter_item_color(p_to_line, i, text.get_line_gutter_item_color(p_from_line, i)); + } + + if (text.get_line_gutter_icon(p_from_line, i).is_valid()) { + text.set_line_gutter_icon(p_to_line, i, text.get_line_gutter_icon(p_from_line, i)); + text.set_line_gutter_item_color(p_to_line, i, text.get_line_gutter_item_color(p_from_line, i)); + } + + if (text.get_line_gutter_metadata(p_from_line, i) != "") { + text.set_line_gutter_metadata(p_to_line, i, text.get_line_gutter_metadata(p_from_line, i)); + } + + if (text.is_line_gutter_clickable(p_from_line, i)) { + text.set_line_gutter_clickable(p_to_line, i, true); + } + } + update(); +} + void TextEdit::set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback) { ERR_FAIL_INDEX(p_gutter, gutters.size()); ERR_FAIL_NULL(p_object); @@ -4643,18 +4318,6 @@ Color TextEdit::get_line_background_color(int p_line) { return text.get_line_background_color(p_line); } -void TextEdit::add_keyword(const String &p_keyword) { - keywords.insert(p_keyword); -} - -void TextEdit::clear_keywords() { - keywords.clear(); -} - -void TextEdit::set_auto_indent(bool p_auto_indent) { - auto_indent = p_auto_indent; -} - void TextEdit::cut() { if (readonly) { return; @@ -4670,7 +4333,7 @@ void TextEdit::cut() { _remove_text(cursor.line, 0, cursor.line + 1, 0); } else { _remove_text(cursor.line, 0, cursor.line, text[cursor.line].length()); - backspace_at_cursor(); + backspace(); cursor_set_line(cursor.line + 1); } @@ -5107,14 +4770,6 @@ bool TextEdit::is_line_hidden(int p_line) const { return text.is_hidden(p_line); } -void TextEdit::fold_all_lines() { - for (int i = 0; i < text.size(); i++) { - fold_line(i); - } - _update_scrollbars(); - update(); -} - void TextEdit::unhide_all_lines() { for (int i = 0; i < text.size(); i++) { text.set_hidden(i, false); @@ -5225,7 +4880,6 @@ int TextEdit::get_last_unhidden_line() const { int TextEdit::get_indent_level(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), 0); - // Counts number of tabs and spaces before line starts. int tab_count = 0; int whitespace_count = 0; int line_length = text[p_line].size(); @@ -5238,175 +4892,27 @@ int TextEdit::get_indent_level(int p_line) const { break; } } - return tab_count * indent_size + whitespace_count; + return tab_count * text.get_tab_size() + whitespace_count; } -bool TextEdit::is_line_comment(int p_line) const { - // Checks to see if this line is the start of a comment. - ERR_FAIL_INDEX_V(p_line, text.size(), false); - - int line_length = text[p_line].size(); - for (int i = 0; i < line_length - 1; i++) { - if (_is_whitespace(text[p_line][i])) { - continue; - } - if (_is_symbol(text[p_line][i])) { - if (text[p_line][i] == '\\') { - i++; // Skip quoted anything. - continue; - } - return text[p_line][i] == '#' || (i + 1 < line_length && text[p_line][i] == '/' && text[p_line][i + 1] == '/'); - } - break; - } - return false; -} - -bool TextEdit::can_fold(int p_line) const { - ERR_FAIL_INDEX_V(p_line, text.size(), false); - if (!is_hiding_enabled()) { - return false; - } - if (p_line + 1 >= text.size()) { - return false; - } - if (text[p_line].strip_edges().size() == 0) { - return false; - } - if (is_folded(p_line)) { - return false; - } - if (is_line_hidden(p_line)) { - return false; - } - if (is_line_comment(p_line)) { - return false; - } - - int start_indent = get_indent_level(p_line); - - for (int i = p_line + 1; i < text.size(); i++) { - if (text[i].strip_edges().size() == 0) { - continue; - } - int next_indent = get_indent_level(i); - if (is_line_comment(i)) { - continue; - } else if (next_indent > start_indent) { - return true; - } else { - return false; - } - } - - return false; -} - -bool TextEdit::is_folded(int p_line) const { - ERR_FAIL_INDEX_V(p_line, text.size(), false); - if (p_line + 1 >= text.size()) { - return false; - } - return !is_line_hidden(p_line) && is_line_hidden(p_line + 1); -} - -Vector<int> TextEdit::get_folded_lines() const { - Vector<int> folded_lines; - - for (int i = 0; i < text.size(); i++) { - if (is_folded(i)) { - folded_lines.push_back(i); - } - } - return folded_lines; -} - -void TextEdit::fold_line(int p_line) { - ERR_FAIL_INDEX(p_line, text.size()); - if (!is_hiding_enabled()) { - return; - } - if (!can_fold(p_line)) { - return; - } - - // Hide lines below this one. - int start_indent = get_indent_level(p_line); - int last_line = start_indent; - for (int i = p_line + 1; i < text.size(); i++) { - if (text[i].strip_edges().size() != 0) { - if (is_line_comment(i)) { - continue; - } else if (get_indent_level(i) > start_indent) { - last_line = i; - } else { - break; - } - } - } - for (int i = p_line + 1; i <= last_line; i++) { - set_line_as_hidden(i, true); - } - - // Fix selection. - if (is_selection_active()) { - if (is_line_hidden(selection.from_line) && is_line_hidden(selection.to_line)) { - deselect(); - } else if (is_line_hidden(selection.from_line)) { - select(p_line, 9999, selection.to_line, selection.to_column); - } else if (is_line_hidden(selection.to_line)) { - select(selection.from_line, selection.from_column, p_line, 9999); - } - } - - // Reset cursor. - if (is_line_hidden(cursor.line)) { - cursor_set_line(p_line, false, false); - cursor_set_column(get_line(p_line).length(), false); - } - _update_scrollbars(); - update(); -} - -void TextEdit::unfold_line(int p_line) { - ERR_FAIL_INDEX(p_line, text.size()); - - if (!is_folded(p_line) && !is_line_hidden(p_line)) { - return; - } - int fold_start; - for (fold_start = p_line; fold_start > 0; fold_start--) { - if (is_folded(fold_start)) { - break; - } - } - fold_start = is_folded(fold_start) ? fold_start : p_line; - - for (int i = fold_start + 1; i < text.size(); i++) { - if (is_line_hidden(i)) { - set_line_as_hidden(i, false); - } else { - break; - } - } - _update_scrollbars(); - update(); -} - -void TextEdit::toggle_fold_line(int p_line) { - ERR_FAIL_INDEX(p_line, text.size()); +int TextEdit::get_first_non_whitespace_column(int p_line) const { + ERR_FAIL_INDEX_V(p_line, text.size(), 0); - if (!is_folded(p_line)) { - fold_line(p_line); - } else { - unfold_line(p_line); + int col = 0; + while (col < text[p_line].length() && _is_whitespace(text[p_line][col])) { + col++; } + return col; } int TextEdit::get_line_count() const { return text.size(); } +int TextEdit::get_line_width(int p_line, int p_wrap_offset) const { + return text.get_line_width(p_line, p_wrap_offset); +} + void TextEdit::_do_text_op(const TextOperation &p_op, bool p_reverse) { ERR_FAIL_COND(p_op.type == TextOperation::TYPE_NONE); @@ -5572,32 +5078,18 @@ void TextEdit::_push_current_op() { } } -void TextEdit::set_indent_using_spaces(const bool p_use_spaces) { - indent_using_spaces = p_use_spaces; -} - -bool TextEdit::is_indent_using_spaces() const { - return indent_using_spaces; -} - -void TextEdit::set_indent_size(const int p_size) { - ERR_FAIL_COND_MSG(p_size <= 0, "Indend size must be greater than 0."); - if (indent_size != p_size) { - indent_size = p_size; - text.set_indent_size(p_size); - text.invalidate_all_lines(); - } - - space_indent = ""; - for (int i = 0; i < p_size; i++) { - space_indent += " "; +void TextEdit::set_tab_size(const int p_size) { + ERR_FAIL_COND_MSG(p_size <= 0, "Tab size must be greater than 0."); + if (p_size == text.get_tab_size()) { + return; } - + text.set_tab_size(p_size); + text.invalidate_all_lines(); update(); } -int TextEdit::get_indent_size() { - return indent_size; +int TextEdit::get_tab_size() const { + return text.get_tab_size(); } void TextEdit::set_draw_tabs(bool p_draw) { @@ -6190,6 +5682,11 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_language", "language"), &TextEdit::set_language); ClassDB::bind_method(D_METHOD("get_language"), &TextEdit::get_language); + ClassDB::bind_method(D_METHOD("get_first_non_whitespace_column", "line"), &TextEdit::get_first_non_whitespace_column); + ClassDB::bind_method(D_METHOD("get_indent_level", "line"), &TextEdit::get_indent_level); + ClassDB::bind_method(D_METHOD("set_tab_size", "size"), &TextEdit::set_tab_size); + ClassDB::bind_method(D_METHOD("get_tab_size"), &TextEdit::get_tab_size); + ClassDB::bind_method(D_METHOD("set_text", "text"), &TextEdit::set_text); ClassDB::bind_method(D_METHOD("insert_text_at_cursor", "text"), &TextEdit::insert_text_at_cursor); @@ -6244,6 +5741,10 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled); ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled); + ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection); + ClassDB::bind_method(D_METHOD("backspace"), &TextEdit::backspace); + BIND_VMETHOD(MethodInfo("_backspace")); + ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut); ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy); ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste); @@ -6270,18 +5771,6 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_draw_spaces"), &TextEdit::set_draw_spaces); ClassDB::bind_method(D_METHOD("is_drawing_spaces"), &TextEdit::is_drawing_spaces); - ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled); - ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); - ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden); - ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden); - ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines); - ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); - ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); - ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line); - ClassDB::bind_method(D_METHOD("toggle_fold_line", "line"), &TextEdit::toggle_fold_line); - ClassDB::bind_method(D_METHOD("can_fold", "line"), &TextEdit::can_fold); - ClassDB::bind_method(D_METHOD("is_folded", "line"), &TextEdit::is_folded); - ClassDB::bind_method(D_METHOD("set_highlight_all_occurrences", "enable"), &TextEdit::set_highlight_all_occurrences); ClassDB::bind_method(D_METHOD("is_highlight_all_occurrences_enabled"), &TextEdit::is_highlight_all_occurrences_enabled); @@ -6311,6 +5800,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_gutter_clickable", "gutter"), &TextEdit::is_gutter_clickable); ClassDB::bind_method(D_METHOD("set_gutter_overwritable", "gutter", "overwritable"), &TextEdit::set_gutter_overwritable); ClassDB::bind_method(D_METHOD("is_gutter_overwritable", "gutter"), &TextEdit::is_gutter_overwritable); + ClassDB::bind_method(D_METHOD("merge_gutters", "from_line", "to_line"), &TextEdit::merge_gutters); ClassDB::bind_method(D_METHOD("set_gutter_custom_draw", "column", "object", "callback"), &TextEdit::set_gutter_custom_draw); // Line gutters. @@ -6365,7 +5855,6 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_enabled"), "set_wrap_enabled", "is_wrap_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical"), "set_v_scroll", "get_v_scroll"); ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll"); @@ -6438,7 +5927,7 @@ TextEdit::TextEdit() { _update_caches(); set_default_cursor_shape(CURSOR_IBEAM); - text.set_indent_size(indent_size); + text.set_tab_size(text.get_tab_size()); text.clear(); h_scroll = memnew(HScrollBar); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index f963e664d1..dcd5c6d0f8 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -96,7 +96,7 @@ private: bool hidden = false; Line() { - data_buf.instance(); + data_buf.instantiate(); } }; @@ -112,11 +112,12 @@ private: int width = -1; - int indent_size = 4; + int tab_size = 4; int gutter_count = 0; public: - void set_indent_size(int p_indent_size); + void set_tab_size(int p_tab_size); + int get_tab_size() const; void set_font(const Ref<Font> &p_font); void set_font_size(int p_font_size); void set_font_features(const Dictionary &p_features); @@ -124,7 +125,7 @@ private: void set_draw_control_chars(bool p_draw_control_chars); int get_line_height(int p_line, int p_wrap_index) const; - int get_line_width(int p_line) const; + int get_line_width(int p_line, int p_wrap_index = -1) const; int get_max_width(bool p_exclude_hidden = false) const; void set_width(float p_width); @@ -257,11 +258,7 @@ private: uint32_t version = 0; uint32_t saved_version = 0; - int max_chars = 0; bool readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly. - bool indent_using_spaces = false; - int indent_size = 4; - String space_indent = " "; Timer *caret_blink_timer; bool caret_blink_enabled = false; @@ -296,7 +293,6 @@ private: bool scroll_past_end_of_file_enabled = false; bool brace_matching_enabled = false; bool highlight_current_line = false; - bool auto_indent = false; String cut_copy_line; bool insert_mode = false; @@ -349,11 +345,8 @@ private: void update_cursor_wrap_offset(); void _update_wrap_at(bool p_force = false); - bool line_wraps(int line) const; - int times_line_wraps(int line) const; Vector<String> get_wrap_rows_text(int p_line) const; int get_cursor_wrap_index() const; - int get_line_wrap_index_at_col(int p_line, int p_column) const; int get_char_count(); double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const; @@ -423,14 +416,9 @@ private: void _clear(); - int _calculate_spaces_till_next_left_indent(int column); - int _calculate_spaces_till_next_right_indent(int column); - // Methods used in shortcuts void _swap_current_input_direction(); void _new_line(bool p_split_current = true, bool p_above = false); - void _indent_right(); - void _indent_left(); void _move_cursor_left(bool p_select, bool p_move_by_word = false); void _move_cursor_right(bool p_select, bool p_move_by_word = false); void _move_cursor_up(bool p_select); @@ -439,9 +427,8 @@ private: void _move_cursor_to_line_end(bool p_select); void _move_cursor_page_up(bool p_select); void _move_cursor_page_down(bool p_select); - void _backspace(bool p_word = false, bool p_all_to_left = false); + void _do_backspace(bool p_word = false, bool p_all_to_left = false); void _delete(bool p_word = false, bool p_all_to_right = false); - void _delete_selection(); void _move_cursor_document_start(bool p_select); void _move_cursor_document_end(bool p_select); void _handle_unicode_character(uint32_t unicode, bool p_had_selection); @@ -514,6 +501,7 @@ public: void set_gutter_width(int p_gutter, int p_width); int get_gutter_width(int p_gutter) const; + int get_total_gutter_width() const; void set_gutter_draw(int p_gutter, bool p_draw); bool is_gutter_drawn(int p_gutter) const; @@ -524,6 +512,8 @@ public: void set_gutter_overwritable(int p_gutter, bool p_overwritable); bool is_gutter_overwritable(int p_gutter) const; + void merge_gutters(int p_from_line, int p_to_line); + void set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback); // Line gutters. @@ -622,32 +612,24 @@ public: void insert_text_at_cursor(const String &p_text); void insert_at(const String &p_text, int at); int get_line_count() const; + int get_line_width(int p_line, int p_wrap_offset = -1) const; + int get_line_wrap_index_at_col(int p_line, int p_column) const; void set_line_as_hidden(int p_line, bool p_hidden); bool is_line_hidden(int p_line) const; - void fold_all_lines(); void unhide_all_lines(); int num_lines_from(int p_line_from, int visible_amount) const; int num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const; int get_last_unhidden_line() const; - bool can_fold(int p_line) const; - bool is_folded(int p_line) const; - Vector<int> get_folded_lines() const; - void fold_line(int p_line); - void unfold_line(int p_line); - void toggle_fold_line(int p_line); - String get_text(); String get_line(int line) const; + bool has_ime_text() const; void set_line(int line, String new_text); int get_row_height() const; - void backspace_at_cursor(); - void indent_selected_lines_left(); - void indent_selected_lines_right(); int get_indent_level(int p_line) const; - bool is_line_comment(int p_line) const; + int get_first_non_whitespace_column(int p_line) const; inline void set_scroll_pass_end_of_file(bool p_enabled) { scroll_past_end_of_file_enabled = p_enabled; @@ -660,7 +642,6 @@ public: brace_matching_enabled = p_enabled; update(); } - void set_auto_indent(bool p_auto_indent); void center_viewport_to_cursor(); @@ -696,14 +677,16 @@ public: void set_readonly(bool p_readonly); bool is_readonly() const; - void set_max_chars(int p_max_chars); - int get_max_chars() const; - void set_wrap_enabled(bool p_wrap_enabled); bool is_wrap_enabled() const; + bool line_wraps(int line) const; + int times_line_wraps(int line) const; void clear(); + void delete_selection(); + + virtual void backspace(); void cut(); void copy(); void paste(); @@ -735,10 +718,8 @@ public: void redo(); void clear_undo_history(); - void set_indent_using_spaces(const bool p_use_spaces); - bool is_indent_using_spaces() const; - void set_indent_size(const int p_size); - int get_indent_size(); + void set_tab_size(const int p_size); + int get_tab_size() const; void set_draw_tabs(bool p_draw); bool is_drawing_tabs() const; void set_draw_spaces(bool p_draw); @@ -749,9 +730,6 @@ public: void set_insert_mode(bool p_enabled); bool is_insert_mode() const; - void add_keyword(const String &p_keyword); - void clear_keywords(); - double get_v_scroll() const; void set_v_scroll(double p_scroll); diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index f43e3d1a9d..8659ea06a2 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -295,11 +295,13 @@ void TextureButton::set_normal_texture(const Ref<Texture2D> &p_normal) { void TextureButton::set_pressed_texture(const Ref<Texture2D> &p_pressed) { pressed = p_pressed; update(); + minimum_size_changed(); } void TextureButton::set_hover_texture(const Ref<Texture2D> &p_hover) { hover = p_hover; update(); + minimum_size_changed(); } void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) { @@ -310,6 +312,7 @@ void TextureButton::set_disabled_texture(const Ref<Texture2D> &p_disabled) { void TextureButton::set_click_mask(const Ref<BitMap> &p_click_mask) { click_mask = p_click_mask; update(); + minimum_size_changed(); } Ref<Texture2D> TextureButton::get_normal_texture() const { diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 46ce9d5ca9..5e5dec3579 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -221,43 +221,87 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu double width_texture = 0.0; double first_section_size = 0.0; double last_section_size = 0.0; - switch (mode) { - case FILL_LEFT_TO_RIGHT: - case FILL_RIGHT_TO_LEFT: { + switch (p_mode) { + case FILL_LEFT_TO_RIGHT: { width_total = dst_rect.size.x; width_texture = texture_size.x; first_section_size = topleft.x; last_section_size = bottomright.x; } break; - case FILL_TOP_TO_BOTTOM: - case FILL_BOTTOM_TO_TOP: { + case FILL_RIGHT_TO_LEFT: { + width_total = dst_rect.size.x; + width_texture = texture_size.x; + // In contrast to `FILL_LEFT_TO_RIGHT`, `first_section_size` and `last_section_size` should switch value. + first_section_size = bottomright.x; + last_section_size = topleft.x; + } break; + case FILL_TOP_TO_BOTTOM: { width_total = dst_rect.size.y; width_texture = texture_size.y; first_section_size = topleft.y; last_section_size = bottomright.y; } break; + case FILL_BOTTOM_TO_TOP: { + width_total = dst_rect.size.y; + width_texture = texture_size.y; + // Similar to `FILL_RIGHT_TO_LEFT`. + first_section_size = bottomright.y; + last_section_size = topleft.y; + } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { - // TODO: Implement + width_total = dst_rect.size.x; + width_texture = texture_size.x; + first_section_size = topleft.x; + last_section_size = bottomright.x; } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { - // TODO: Implement + width_total = dst_rect.size.y; + width_texture = texture_size.y; + first_section_size = topleft.y; + last_section_size = bottomright.y; } break; case FILL_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: { - // Those modes are circular, not relevant for nine patch + // Those modes are circular, not relevant for nine patch. } break; + case FILL_MODE_MAX: + break; } double width_filled = width_total * p_ratio; double middle_section_size = MAX(0.0, width_texture - first_section_size - last_section_size); - middle_section_size *= MIN(1.0, (MAX(0.0, width_filled - first_section_size) / MAX(1.0, width_total - first_section_size - last_section_size))); - last_section_size = MAX(0.0, last_section_size - (width_total - width_filled)); - first_section_size = MIN(first_section_size, width_filled); - width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); + // Maximum middle texture size. + double max_middle_texture_size = middle_section_size; + + // Maximum real middle texture size. + double max_middle_real_size = MAX(0.0, width_total - (first_section_size + last_section_size)); + + switch (p_mode) { + case FILL_BILINEAR_LEFT_AND_RIGHT: + case FILL_BILINEAR_TOP_AND_BOTTOM: { + last_section_size = MAX(0.0, last_section_size - (width_total - width_filled) * 0.5); + first_section_size = MAX(0.0, first_section_size - (width_total - width_filled) * 0.5); + + // When `width_filled` increases, `middle_section_size` only increases when either of `first_section_size` and `last_section_size` is zero. + // Also, it should always be smaller than or equal to `(width_total - (first_section_size + last_section_size))`. + double real_middle_size = width_filled - first_section_size - last_section_size; + middle_section_size *= MIN(max_middle_real_size, real_middle_size) / max_middle_real_size; + + width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); + } break; + case FILL_MODE_MAX: + break; + default: { + middle_section_size *= MIN(1.0, (MAX(0.0, width_filled - first_section_size) / MAX(1.0, width_total - first_section_size - last_section_size))); + last_section_size = MAX(0.0, last_section_size - (width_total - width_filled)); + first_section_size = MIN(first_section_size, width_filled); + width_texture = MIN(width_texture, first_section_size + middle_section_size + last_section_size); + } + } - switch (mode) { + switch (p_mode) { case FILL_LEFT_TO_RIGHT: { src_rect.size.x = width_texture; dst_rect.size.x = width_filled; @@ -287,16 +331,32 @@ void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_textu bottomright.y = first_section_size; } break; case FILL_BILINEAR_LEFT_AND_RIGHT: { - // TODO: Implement + double center_mapped_from_real_width = (width_total * 0.5 - topleft.x) / max_middle_real_size * max_middle_texture_size + topleft.x; + double drift_from_unscaled_center = (src_rect.size.x * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.x - topleft.x); + src_rect.position.x += center_mapped_from_real_width + drift_from_unscaled_center - width_texture * 0.5; + src_rect.size.x = width_texture; + dst_rect.position.x += (width_total - width_filled) * 0.5; + dst_rect.size.x = width_filled; + topleft.x = first_section_size; + bottomright.x = last_section_size; } break; case FILL_BILINEAR_TOP_AND_BOTTOM: { - // TODO: Implement + double center_mapped_from_real_width = (width_total * 0.5 - topleft.y) / max_middle_real_size * max_middle_texture_size + topleft.y; + double drift_from_unscaled_center = (src_rect.size.y * 0.5 - center_mapped_from_real_width) * (last_section_size - first_section_size) / (bottomright.y - topleft.y); + src_rect.position.y += center_mapped_from_real_width + drift_from_unscaled_center - width_texture * 0.5; + src_rect.size.y = width_texture; + dst_rect.position.y += (width_total - width_filled) * 0.5; + dst_rect.size.y = width_filled; + topleft.y = first_section_size; + bottomright.y = last_section_size; } break; case FILL_CLOCKWISE: case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: case FILL_COUNTER_CLOCKWISE: { - // Those modes are circular, not relevant for nine patch + // Those modes are circular, not relevant for nine patch. } break; + case FILL_MODE_MAX: + break; } } @@ -310,19 +370,34 @@ void TextureProgressBar::_notification(int p_what) { const float corners[12] = { -0.125, -0.375, -0.625, -0.875, 0.125, 0.375, 0.625, 0.875, 1.125, 1.375, 1.625, 1.875 }; switch (p_what) { case NOTIFICATION_DRAW: { - if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP)) { + if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP || mode == FILL_BILINEAR_LEFT_AND_RIGHT || mode == FILL_BILINEAR_TOP_AND_BOTTOM)) { if (under.is_valid()) { - draw_nine_patch_stretched(under, FILL_LEFT_TO_RIGHT, 1.0, tint_under); + draw_nine_patch_stretched(under, mode, 1.0, tint_under); } if (progress.is_valid()) { draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress); } if (over.is_valid()) { - draw_nine_patch_stretched(over, FILL_LEFT_TO_RIGHT, 1.0, tint_over); + draw_nine_patch_stretched(over, mode, 1.0, tint_over); } } else { if (under.is_valid()) { - draw_texture(under, Point2(), tint_under); + switch (mode) { + case FILL_CLOCKWISE: + case FILL_COUNTER_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { + if (nine_patch_stretch) { + Rect2 region = Rect2(Point2(), get_size()); + draw_texture_rect(under, region, false, tint_under); + } else { + draw_texture(under, Point2(), tint_under); + } + } break; + case FILL_MODE_MAX: + break; + default: + draw_texture(under, Point2(), tint_under); + } } if (progress.is_valid()) { Size2 s = progress->get_size(); @@ -353,7 +428,7 @@ void TextureProgressBar::_notification(int p_what) { float val = get_as_ratio() * rad_max_degrees / 360; if (val == 1) { Rect2 region = Rect2(Point2(), s); - draw_texture_rect_region(progress, region, region, tint_progress); + draw_texture_rect(progress, region, false, tint_progress); } else if (val != 0) { Array pts; float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1; @@ -416,12 +491,29 @@ void TextureProgressBar::_notification(int p_what) { Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio())); draw_texture_rect_region(progress, region, region, tint_progress); } break; + case FILL_MODE_MAX: + break; default: draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress); } } if (over.is_valid()) { - draw_texture(over, Point2(), tint_over); + switch (mode) { + case FILL_CLOCKWISE: + case FILL_COUNTER_CLOCKWISE: + case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: { + if (nine_patch_stretch) { + Rect2 region = Rect2(Point2(), get_size()); + draw_texture_rect(over, region, false, tint_over); + } else { + draw_texture(over, Point2(), tint_over); + } + } break; + case FILL_MODE_MAX: + break; + default: + draw_texture(over, Point2(), tint_over); + } } } } break; @@ -429,7 +521,7 @@ void TextureProgressBar::_notification(int p_what) { } void TextureProgressBar::set_fill_mode(int p_fill) { - ERR_FAIL_INDEX(p_fill, 9); + ERR_FAIL_INDEX(p_fill, FILL_MODE_MAX); mode = (FillMode)p_fill; update(); } @@ -512,7 +604,7 @@ void TextureProgressBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_under_texture", "get_under_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_over_texture", "get_over_texture"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_progress_texture", "get_progress_texture"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom),Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode"); ADD_GROUP("Tint", "tint_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under"), "set_tint_under", "get_tint_under"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over"), "set_tint_over", "get_tint_over"); diff --git a/scene/gui/texture_progress_bar.h b/scene/gui/texture_progress_bar.h index a3883a7017..d147c43a26 100644 --- a/scene/gui/texture_progress_bar.h +++ b/scene/gui/texture_progress_bar.h @@ -54,7 +54,8 @@ public: FILL_COUNTER_CLOCKWISE, FILL_BILINEAR_LEFT_AND_RIGHT, FILL_BILINEAR_TOP_AND_BOTTOM, - FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE + FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE, + FILL_MODE_MAX, }; void set_fill_mode(int p_fill); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index f66cc13af5..4d2cb81f23 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -99,39 +99,44 @@ void TreeItem::_change_tree(Tree *p_tree) { c = c->next; } - if (tree && tree->root == this) { - tree->root = nullptr; - } + if (tree) { + if (tree->root == this) { + tree->root = nullptr; + } - if (tree && tree->popup_edited_item == this) { - tree->popup_edited_item = nullptr; - tree->pressing_for_editor = false; - } + if (tree->popup_edited_item == this) { + tree->popup_edited_item = nullptr; + tree->pressing_for_editor = false; + } - if (tree && tree->cache.hover_item == this) { - tree->cache.hover_item = nullptr; - } + if (tree->cache.hover_item == this) { + tree->cache.hover_item = nullptr; + } - if (tree && tree->selected_item == this) { - tree->selected_item = nullptr; - } + if (tree->selected_item == this) { + tree->selected_item = nullptr; + } - if (tree && tree->drop_mode_over == this) { - tree->drop_mode_over = nullptr; - } + if (tree->drop_mode_over == this) { + tree->drop_mode_over = nullptr; + } - if (tree && tree->single_select_defer == this) { - tree->single_select_defer = nullptr; - } + if (tree->single_select_defer == this) { + tree->single_select_defer = nullptr; + } + + if (tree->edited_item == this) { + tree->edited_item = nullptr; + tree->pressing_for_editor = false; + } - if (tree && tree->edited_item == this) { - tree->edited_item = nullptr; - tree->pressing_for_editor = false; + tree->update(); } tree = p_tree; if (tree) { + tree->update(); cells.resize(tree->columns.size()); } } @@ -451,6 +456,7 @@ TreeItem *TreeItem::create_child(int p_idx) { TreeItem *ti = memnew(TreeItem(tree)); if (tree) { ti->cells.resize(tree->columns.size()); + tree->update(); } TreeItem *l_prev = nullptr; @@ -489,11 +495,11 @@ TreeItem *TreeItem::create_child(int p_idx) { return ti; } -Tree *TreeItem::get_tree() { +Tree *TreeItem::get_tree() const { return tree; } -TreeItem *TreeItem::get_next() { +TreeItem *TreeItem::get_next() const { return next; } @@ -516,11 +522,11 @@ TreeItem *TreeItem::get_prev() { return prev; } -TreeItem *TreeItem::get_parent() { +TreeItem *TreeItem::get_parent() const { return parent; } -TreeItem *TreeItem::get_first_child() { +TreeItem *TreeItem::get_first_child() const { return first_child; } @@ -654,11 +660,7 @@ void TreeItem::move_before(TreeItem *p_item) { next = p_item; p_item->prev = this; - if (old_tree && old_tree != tree) { - old_tree->update(); - } - - if (tree) { + if (tree && old_tree == tree) { tree->update(); } } @@ -696,11 +698,7 @@ void TreeItem::move_after(TreeItem *p_item) { parent->children_cache.append(this); } - if (old_tree && old_tree != tree) { - old_tree->update(); - } - - if (tree) { + if (tree && old_tree == tree) { tree->update(); } } @@ -953,6 +951,56 @@ bool TreeItem::is_folding_disabled() const { return disable_folding; } +Size2 TreeItem::get_minimum_size(int p_column) { + ERR_FAIL_INDEX_V(p_column, cells.size(), Size2()); + Tree *tree = get_tree(); + ERR_FAIL_COND_V(!tree, Size2()); + + Size2 size; + + // Default offset? + //size.width += (disable_folding || tree->hide_folding) ? tree->cache.hseparation : tree->cache.item_margin; + + // Text. + const TreeItem::Cell &cell = cells[p_column]; + if (!cell.text.is_empty()) { + if (cell.dirty) { + tree->update_item_cell(this, p_column); + } + Size2 text_size = cell.text_buf->get_size(); + size.width += text_size.width; + size.height = MAX(size.height, text_size.height); + } + + // Icon. + if (cell.mode == CELL_MODE_CHECK) { + size.width += tree->cache.checked->get_width() + tree->cache.hseparation; + } + if (cell.icon.is_valid()) { + Size2i icon_size = cell.get_icon_size(); + if (cell.icon_max_w > 0 && icon_size.width > cell.icon_max_w) { + icon_size.width = cell.icon_max_w; + } + size.width += icon_size.width + tree->cache.hseparation; + size.height = MAX(size.height, icon_size.height); + } + + // Buttons. + for (int i = 0; i < cell.buttons.size(); i++) { + Ref<Texture2D> texture = cell.buttons[i].texture; + if (texture.is_valid()) { + Size2 button_size = texture->get_size() + tree->cache.button_pressed->get_minimum_size(); + size.width += button_size.width; + size.height = MAX(size.height, button_size.height); + } + } + if (cell.buttons.size() >= 2) { + size.width += (cell.buttons.size() - 1) * tree->cache.button_margin; + } + + return size; +} + Variant TreeItem::_call_recursive_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (p_argcount < 1) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; @@ -1202,6 +1250,9 @@ void Tree::update_cache() { cache.item_margin = get_theme_constant("item_margin"); cache.button_margin = get_theme_constant("button_margin"); + cache.font_outline_color = get_theme_color("font_outline_color"); + cache.font_outline_size = get_theme_constant("outline_size"); + cache.draw_guides = get_theme_constant("draw_guides"); cache.guide_color = get_theme_color("guide_color"); cache.draw_relationship_lines = get_theme_constant("draw_relationship_lines"); @@ -1463,7 +1514,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int htotal = 0; int label_h = compute_item_height(p_item); - bool rtl = is_layout_rtl(); + bool rtl = cache.rtl; /* Calculate height of the label part */ label_h += cache.vseparation; @@ -1509,6 +1560,20 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } + if (!rtl && p_item->cells[i].buttons.size()) { + int button_w = 0; + for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { + Ref<Texture2D> b = p_item->cells[i].buttons[j].texture; + button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin; + } + + int total_ofs = ofs - cache.offset.x; + + if (total_ofs + w > p_draw_size.width) { + w = MAX(button_w, p_draw_size.width - total_ofs); + } + } + int bw = 0; for (int j = p_item->cells[i].buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = p_item->cells[i].buttons[j].texture; @@ -1633,8 +1698,8 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color"); - Color font_outline_color = get_theme_color("font_outline_color"); - int outline_size = get_theme_constant("outline_size"); + Color font_outline_color = cache.font_outline_color; + int outline_size = cache.font_outline_size; Color icon_col = p_item->cells[i].icon_color; if (p_item->cells[i].dirty) { @@ -1846,78 +1911,76 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int prev_hl_ofs = base_ofs; while (c) { - if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { - int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); - int parent_ofs = p_pos.x + cache.item_margin; - Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; + if (htotal >= 0) { + int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c); - if (c->get_first_child() != nullptr) { - root_pos -= Point2i(cache.arrow->get_width(), 0); - } + // Draw relationship lines. + if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { + int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); + int parent_ofs = p_pos.x + cache.item_margin; + Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; - float line_width = cache.relationship_line_width; - float parent_line_width = cache.parent_hl_line_width; - float children_line_width = cache.children_hl_line_width; + if (c->get_first_child() != nullptr) { + root_pos -= Point2i(cache.arrow->get_width(), 0); + } + + float line_width = cache.relationship_line_width; + float parent_line_width = cache.parent_hl_line_width; + float children_line_width = cache.children_hl_line_width; #ifdef TOOLS_ENABLED - line_width *= Math::round(EDSCALE); - parent_line_width *= Math::round(EDSCALE); - children_line_width *= Math::round(EDSCALE); + line_width *= Math::round(EDSCALE); + parent_line_width *= Math::round(EDSCALE); + children_line_width *= Math::round(EDSCALE); #endif - Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; + Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs; - int more_prev_ofs = 0; + int more_prev_ofs = 0; - if (root_pos.y + line_width >= 0) { - if (rtl) { - root_pos.x = get_size().width - root_pos.x; - parent_pos.x = get_size().width - parent_pos.x; - } + if (root_pos.y + line_width >= 0) { + if (rtl) { + root_pos.x = get_size().width - root_pos.x; + parent_pos.x = get_size().width - parent_pos.x; + } - // Order of parts on this bend: the horizontal line first, then the vertical line. - if (_is_branch_selected(c)) { - // If this item or one of its children is selected, we draw the line using parent highlight style. - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width); - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); - - more_prev_ofs = cache.parent_hl_line_margin; - prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); - } else if (p_item->is_selected(0)) { - // If parent item is selected (but this item is not), we draw the line using children highlight style. - // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. - if (_is_sibling_branch_selected(c)) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + // Order of parts on this bend: the horizontal line first, then the vertical line. + if (_is_branch_selected(c)) { + // If this item or one of its children is selected, we draw the line using parent highlight style. + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.parent_hl_line_color, parent_line_width); RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + more_prev_ofs = cache.parent_hl_line_margin; prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); + } else if (p_item->is_selected(0)) { + // If parent item is selected (but this item is not), we draw the line using children highlight style. + // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. + if (_is_sibling_branch_selected(c)) { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(parent_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + + prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); + } else { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width); + } } else { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(children_line_width / 2), root_pos.y), cache.children_hl_line_color, children_line_width); - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(children_line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(children_line_width / 2)), cache.children_hl_line_color, children_line_width); - } - } else { - // If nothing of the above is true, we draw the line using normal style. - // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. - if (_is_sibling_branch_selected(c)) { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width); - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); + // If nothing of the above is true, we draw the line using normal style. + // Siblings of the selected branch can be drawn with a slight offset and their vertical line must appear as highlighted. + if (_is_sibling_branch_selected(c)) { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + cache.parent_hl_line_margin, root_pos.y), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(parent_line_width / 2)), Point2i(parent_pos.x, prev_hl_ofs), cache.parent_hl_line_color, parent_line_width); - prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); - } else { - RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); - RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width); + prev_hl_ofs = root_pos.y + Math::floor(parent_line_width / 2); + } else { + RenderingServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x + Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); + RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y + Math::floor(line_width / 2)), Point2i(parent_pos.x, prev_ofs + Math::floor(line_width / 2)), cache.relationship_line_color, line_width); + } } } - } - if (htotal < 0) { - return -1; + prev_ofs = root_pos.y + more_prev_ofs; } - prev_ofs = root_pos.y + more_prev_ofs; - } - - if (htotal >= 0) { - int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c); if (child_h < 0) { if (cache.draw_relationship_lines == 0) { @@ -2090,13 +2153,24 @@ void Tree::_range_click_timeout() { } } + if (!root) { + return; + } + click_handled = false; Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); + + int x_limit = get_size().width - cache.bg->get_minimum_size().width; + if (h_scroll->is_visible()) { + x_limit -= h_scroll->get_minimum_size().width; + } + + cache.rtl = is_layout_rtl(); propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case) blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, false, root, MOUSE_BUTTON_LEFT, mb); + propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, false, root, MOUSE_BUTTON_LEFT, mb); blocked--; if (range_click_timer->is_one_shot()) { @@ -2119,7 +2193,7 @@ void Tree::_range_click_timeout() { } } -int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod) { +int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod) { int item_h = compute_item_height(p_item) + cache.vseparation; bool skip = (p_item == root && hide_root); @@ -2144,6 +2218,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool int col = -1; int col_ofs = 0; int col_width = 0; + + int limit_w = x_limit; + for (int i = 0; i < columns.size(); i++) { col_width = get_column_width(i); @@ -2159,6 +2236,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool if (x > col_width) { col_ofs += col_width; x -= col_width; + limit_w -= col_width; continue; } @@ -2172,10 +2250,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool int margin = x_ofs + cache.item_margin; //-cache.hseparation; //int lm = cache.bg->get_margin(SIDE_LEFT); col_width -= margin; + limit_w -= margin; col_ofs += margin; x -= margin; } else { col_width -= cache.hseparation; + limit_w -= cache.hseparation; x -= cache.hseparation; } @@ -2189,6 +2269,16 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool bool already_selected = c.selected; bool already_cursor = (p_item == selected_item) && col == selected_col; + if (!cache.rtl && p_item->cells[col].buttons.size()) { + int button_w = 0; + for (int j = p_item->cells[col].buttons.size() - 1; j >= 0; j--) { + Ref<Texture2D> b = p_item->cells[col].buttons[j].texture; + button_w += b->get_size().width + cache.button_pressed->get_minimum_size().width + cache.button_margin; + } + + col_width = MAX(button_w, MIN(limit_w, col_width)); + } + for (int j = c.buttons.size() - 1; j >= 0; j--) { Ref<Texture2D> b = c.buttons[j].texture; int w = b->get_size().width + cache.button_pressed->get_minimum_size().width; @@ -2210,6 +2300,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool //emit_signal("button_pressed"); return -1; } + col_width -= w + cache.button_margin; } @@ -2420,7 +2511,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool TreeItem *c = p_item->first_child; while (c) { - int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_double_click, c, p_button, p_mod); + int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, x_limit, p_double_click, c, p_button, p_mod); if (child_h < 0) { return -1; // break, stop propagating, no need to anymore @@ -2451,10 +2542,10 @@ void Tree::_text_editor_modal_close() { return; } - _text_editor_enter(text_editor->get_text()); + _text_editor_submit(text_editor->get_text()); } -void Tree::_text_editor_enter(String p_text) { +void Tree::_text_editor_submit(String p_text) { popup_editor->hide(); if (!popup_edited_item) { @@ -3098,8 +3189,14 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { pressing_for_editor = false; propagate_mouse_activated = false; + int x_limit = get_size().width - cache.bg->get_minimum_size().width; + if (h_scroll->is_visible()) { + x_limit -= h_scroll->get_minimum_size().width; + } + + cache.rtl = is_layout_rtl(); blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, b->is_double_click(), root, b->get_button_index(), b); + propagate_mouse_event(pos + cache.offset, 0, 0, x_limit + cache.offset.width, b->is_double_click(), root, b->get_button_index(), b); blocked--; if (pressing_for_editor) { @@ -3161,6 +3258,8 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } break; + default: + break; } } @@ -3276,7 +3375,7 @@ Size2 Tree::get_internal_min_size() const { size.height += get_item_height(root); } for (int i = 0; i < columns.size(); i++) { - size.width += columns[i].min_width; + size.width += get_column_minimum_width(i); } return size; @@ -3300,26 +3399,38 @@ void Tree::update_scrollbars() { h_scroll->set_begin(Point2(0, size.height - hmin.height)); h_scroll->set_end(Point2(size.width - vmin.width, size.height)); - Size2 min = get_internal_min_size(); + Size2 internal_min_size = get_internal_min_size(); - if (min.height < size.height - hmin.height) { - v_scroll->hide(); - cache.offset.y = 0; - } else { + bool display_vscroll = internal_min_size.height + cache.bg->get_margin(SIDE_TOP) > size.height; + bool display_hscroll = internal_min_size.width + cache.bg->get_margin(SIDE_LEFT) > size.width; + for (int i = 0; i < 2; i++) { + // Check twice, as both values are dependent on each other. + if (display_hscroll) { + display_vscroll = internal_min_size.height + cache.bg->get_margin(SIDE_TOP) + hmin.height > size.height; + } + if (display_vscroll) { + display_hscroll = internal_min_size.width + cache.bg->get_margin(SIDE_LEFT) + vmin.width > size.width; + } + } + + if (display_vscroll) { v_scroll->show(); - v_scroll->set_max(min.height); + v_scroll->set_max(internal_min_size.height); v_scroll->set_page(size.height - hmin.height - tbh); cache.offset.y = v_scroll->get_value(); + } else { + v_scroll->hide(); + cache.offset.y = 0; } - if (min.width < size.width - vmin.width) { - h_scroll->hide(); - cache.offset.x = 0; - } else { + if (display_hscroll) { h_scroll->show(); - h_scroll->set_max(min.width); + h_scroll->set_max(internal_min_size.width); h_scroll->set_page(size.width - vmin.width); cache.offset.x = h_scroll->get_value(); + } else { + h_scroll->hide(); + cache.offset.x = 0; } } @@ -3437,6 +3548,9 @@ void Tree::_notification(int p_what) { Point2 draw_ofs; draw_ofs += bg->get_offset(); Size2 draw_size = get_size() - bg->get_minimum_size(); + if (h_scroll->is_visible()) { + draw_size.width -= h_scroll->get_minimum_size().width; + } bg->draw(ci, Rect2(Point2(), get_size())); @@ -3445,7 +3559,9 @@ void Tree::_notification(int p_what) { draw_ofs.y += tbh; draw_size.y -= tbh; - if (root) { + cache.rtl = is_layout_rtl(); + + if (root && get_size().x > 0 && get_size().y > 0) { draw_item(Point2(), draw_ofs, draw_size, root); } @@ -3456,7 +3572,7 @@ void Tree::_notification(int p_what) { Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button); Ref<Font> f = cache.tb_font; Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh); - if (is_layout_rtl()) { + if (cache.rtl) { tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x; } sb->draw(ci, tbrect); @@ -3513,7 +3629,17 @@ void Tree::_update_all() { } Size2 Tree::get_minimum_size() const { - return Size2(1, 1); + if (h_scroll_enabled && v_scroll_enabled) { + return Size2(); + } else { + Vector2 min_size = get_internal_min_size(); + Ref<StyleBox> bg = cache.bg; + if (bg.is_valid()) { + min_size.x += bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT); + min_size.y += bg->get_margin(SIDE_TOP) + bg->get_margin(SIDE_BOTTOM); + } + return Vector2(h_scroll_enabled ? 0 : min_size.x, v_scroll_enabled ? 0 : min_size.y); + } } TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) { @@ -3541,11 +3667,11 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) { return ti; } -TreeItem *Tree::get_root() { +TreeItem *Tree::get_root() const { return root; } -TreeItem *Tree::get_last_item() { +TreeItem *Tree::get_last_item() const { TreeItem *last = root; while (last) { @@ -3675,13 +3801,13 @@ bool Tree::is_root_hidden() const { return hide_root; } -void Tree::set_column_min_width(int p_column, int p_min_width) { +void Tree::set_column_custom_minimum_width(int p_column, int p_min_width) { ERR_FAIL_INDEX(p_column, columns.size()); - if (p_min_width < 1) { + if (p_min_width < 0) { return; } - columns.write[p_column].min_width = p_min_width; + columns.write[p_column].custom_min_width = p_min_width; update(); } @@ -3692,6 +3818,36 @@ void Tree::set_column_expand(int p_column, bool p_expand) { update(); } +void Tree::set_column_expand_ratio(int p_column, int p_ratio) { + ERR_FAIL_INDEX(p_column, columns.size()); + columns.write[p_column].expand_ratio = p_ratio; + update(); +} + +void Tree::set_column_clip_content(int p_column, bool p_fit) { + ERR_FAIL_INDEX(p_column, columns.size()); + + columns.write[p_column].clip_content = p_fit; + update(); +} + +bool Tree::is_column_expanding(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), false); + + return columns[p_column].expand; +} +int Tree::get_column_expand_ratio(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), 1); + + return columns[p_column].expand_ratio; +} + +bool Tree::is_column_clipping_content(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), false); + + return columns[p_column].clip_content; +} + TreeItem *Tree::get_selected() const { return selected_item; } @@ -3748,44 +3904,81 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) { return nullptr; } -int Tree::get_column_width(int p_column) const { +int Tree::get_column_minimum_width(int p_column) const { ERR_FAIL_INDEX_V(p_column, columns.size(), -1); - if (!columns[p_column].expand) { - return columns[p_column].min_width; + int min_width = columns[p_column].custom_min_width; + + if (show_column_titles) { + min_width = MAX(cache.font->get_string_size(columns[p_column].title).width, min_width); + } + + if (!columns[p_column].clip_content) { + int depth = 0; + TreeItem *next; + for (TreeItem *item = get_root(); item; item = next) { + next = item->get_next_visible(); + // Compute the depth in tree. + if (next && p_column == 0) { + if (next->get_parent() == item) { + depth += 1; + } else { + TreeItem *common_parent = item->get_parent(); + while (common_parent != next->get_parent()) { + common_parent = common_parent->get_parent(); + depth -= 1; + } + } + } + + // Get the item minimum size. + Size2 item_size = item->get_minimum_size(p_column); + if (p_column == 0) { + item_size.width += cache.item_margin * depth; + } + min_width = MAX(min_width, item_size.width); + } } - int expand_area = get_size().width; + return min_width; +} - Ref<StyleBox> bg = cache.bg; +int Tree::get_column_width(int p_column) const { + ERR_FAIL_INDEX_V(p_column, columns.size(), -1); - if (bg.is_valid()) { - expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT); - } + int column_width = get_column_minimum_width(p_column); - if (v_scroll->is_visible_in_tree()) { - expand_area -= v_scroll->get_combined_minimum_size().width; - } + if (columns[p_column].expand) { + int expand_area = get_size().width; - int expanding_columns = 0; - int expanding_total = 0; + Ref<StyleBox> bg = cache.bg; - for (int i = 0; i < columns.size(); i++) { - if (!columns[i].expand) { - expand_area -= columns[i].min_width; - } else { - expanding_total += columns[i].min_width; - expanding_columns++; + if (bg.is_valid()) { + expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT); } - } - if (expand_area < expanding_total) { - return columns[p_column].min_width; - } + if (v_scroll->is_visible_in_tree()) { + expand_area -= v_scroll->get_combined_minimum_size().width; + } + + int expanding_total = 0; - ERR_FAIL_COND_V(expanding_columns == 0, -1); // shouldn't happen + for (int i = 0; i < columns.size(); i++) { + expand_area -= get_column_minimum_width(i); + if (columns[i].expand) { + expanding_total += columns[i].expand_ratio; + } + } - return expand_area * columns[p_column].min_width / expanding_total; + if (expand_area >= expanding_total && expanding_total > 0) { + column_width += expand_area * columns[p_column].expand_ratio / expanding_total; + } + } + + if (p_column < columns.size() - 1) { + column_width += cache.hseparation; + } + return column_width; } void Tree::propagate_set_columns(TreeItem *p_item) { @@ -4047,6 +4240,24 @@ void Tree::scroll_to_item(TreeItem *p_item) { } } +void Tree::set_h_scroll_enabled(bool p_enable) { + h_scroll_enabled = p_enable; + minimum_size_changed(); +} + +bool Tree::is_h_scroll_enabled() const { + return h_scroll_enabled; +} + +void Tree::set_v_scroll_enabled(bool p_enable) { + v_scroll_enabled = p_enable; + minimum_size_changed(); +} + +bool Tree::is_v_scroll_enabled() const { + return v_scroll_enabled; +} + TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards) { TreeItem *from = p_at; TreeItem *loop = nullptr; // Safe-guard against infinite loop. @@ -4422,8 +4633,14 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root); - ClassDB::bind_method(D_METHOD("set_column_min_width", "column", "min_width"), &Tree::set_column_min_width); + ClassDB::bind_method(D_METHOD("set_column_custom_minimum_width", "column", "min_width"), &Tree::set_column_custom_minimum_width); ClassDB::bind_method(D_METHOD("set_column_expand", "column", "expand"), &Tree::set_column_expand); + ClassDB::bind_method(D_METHOD("set_column_expand_ratio", "column", "ratio"), &Tree::set_column_expand_ratio); + ClassDB::bind_method(D_METHOD("set_column_clip_content", "column", "enable"), &Tree::set_column_clip_content); + ClassDB::bind_method(D_METHOD("is_column_expanding", "column"), &Tree::is_column_expanding); + ClassDB::bind_method(D_METHOD("is_column_clipping_content", "column"), &Tree::is_column_clipping_content); + ClassDB::bind_method(D_METHOD("get_column_expand_ratio", "column"), &Tree::get_column_expand_ratio); + ClassDB::bind_method(D_METHOD("get_column_width", "column"), &Tree::get_column_width); ClassDB::bind_method(D_METHOD("set_hide_root", "enable"), &Tree::set_hide_root); @@ -4468,6 +4685,12 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_scroll"), &Tree::get_scroll); ClassDB::bind_method(D_METHOD("scroll_to_item", "item"), &Tree::_scroll_to_item); + ClassDB::bind_method(D_METHOD("set_h_scroll_enabled", "h_scroll"), &Tree::set_h_scroll_enabled); + ClassDB::bind_method(D_METHOD("is_h_scroll_enabled"), &Tree::is_h_scroll_enabled); + + ClassDB::bind_method(D_METHOD("set_v_scroll_enabled", "h_scroll"), &Tree::set_v_scroll_enabled); + ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &Tree::is_v_scroll_enabled); + ClassDB::bind_method(D_METHOD("set_hide_folding", "hide"), &Tree::set_hide_folding); ClassDB::bind_method(D_METHOD("is_folding_hidden"), &Tree::is_folding_hidden); @@ -4487,6 +4710,8 @@ void Tree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden"); ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In Between"), "set_drop_mode_flags", "get_drop_mode_flags"); ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_h_scroll_enabled", "is_h_scroll_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_v_scroll_enabled", "is_v_scroll_enabled"); ADD_SIGNAL(MethodInfo("item_selected")); ADD_SIGNAL(MethodInfo("cell_selected")); @@ -4554,7 +4779,7 @@ Tree::Tree() { h_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &Tree::_scroll_moved)); - text_editor->connect("text_entered", callable_mp(this, &Tree::_text_editor_enter)); + text_editor->connect("text_submitted", callable_mp(this, &Tree::_text_editor_submit)); popup_editor->connect("popup_hide", callable_mp(this, &Tree::_text_editor_modal_close)); popup_menu->connect("id_pressed", callable_mp(this, &Tree::popup_select)); value_editor->connect("value_changed", callable_mp(this, &Tree::value_editor_changed)); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 5176d01497..10e6642303 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -115,7 +115,7 @@ private: Ref<Font> custom_font; Cell() { - text_buf.instance(); + text_buf.instantiate(); } Size2 get_icon_size() const; @@ -315,16 +315,18 @@ public: void set_disable_folding(bool p_disable); bool is_folding_disabled() const; + Size2 get_minimum_size(int p_column); + /* Item manipulation */ TreeItem *create_child(int p_idx = -1); - Tree *get_tree(); + Tree *get_tree() const; TreeItem *get_prev(); - TreeItem *get_next(); - TreeItem *get_parent(); - TreeItem *get_first_child(); + TreeItem *get_next() const; + TreeItem *get_parent() const; + TreeItem *get_first_child() const; TreeItem *get_prev_visible(bool p_wrap = false); TreeItem *get_next_visible(bool p_wrap = false); @@ -408,15 +410,17 @@ private: int drop_mode_flags = 0; struct ColumnInfo { - int min_width = 1; + int custom_min_width = 0; + int expand_ratio = 1; bool expand = true; + bool clip_content = false; String title; Ref<TextLine> text_buf; Dictionary opentype_features; String language; Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED; ColumnInfo() { - text_buf.instance(); + text_buf.instantiate(); } }; @@ -448,8 +452,8 @@ private: void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color); int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false); - int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod); - void _text_editor_enter(String p_text); + int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, int x_limit, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod); + void _text_editor_submit(String p_text); void _text_editor_modal_close(); void value_editor_changed(double p_value); @@ -502,6 +506,7 @@ private: Color parent_hl_line_color; Color children_hl_line_color; Color custom_button_font_highlight; + Color font_outline_color; int hseparation = 0; int vseparation = 0; @@ -516,6 +521,7 @@ private: int draw_guides = 0; int scroll_border = 0; int scroll_speed = 0; + int font_outline_size = 0; enum ClickType { CLICK_NONE, @@ -538,6 +544,8 @@ private: Point2i text_editor_position; + bool rtl = false; + } cache; int _get_title_button_height() const; @@ -546,6 +554,9 @@ private: HScrollBar *h_scroll; VScrollBar *v_scroll; + bool h_scroll_enabled = true; + bool v_scroll_enabled = true; + Size2 get_internal_min_size() const; void update_cache(); void update_scrollbars(); @@ -623,12 +634,19 @@ public: void clear(); TreeItem *create_item(TreeItem *p_parent = nullptr, int p_idx = -1); - TreeItem *get_root(); - TreeItem *get_last_item(); + TreeItem *get_root() const; + TreeItem *get_last_item() const; - void set_column_min_width(int p_column, int p_min_width); + void set_column_custom_minimum_width(int p_column, int p_min_width); void set_column_expand(int p_column, bool p_expand); + void set_column_expand_ratio(int p_column, int p_ratio); + void set_column_clip_content(int p_column, bool p_fit); + int get_column_minimum_width(int p_column) const; int get_column_width(int p_column) const; + int get_column_expand_ratio(int p_column) const; + + bool is_column_expanding(int p_column) const; + bool is_column_clipping_content(int p_column) const; void set_hide_root(bool p_enabled); bool is_root_hidden() const; @@ -679,6 +697,10 @@ public: Point2 get_scroll() const; void scroll_to_item(TreeItem *p_item); + void set_h_scroll_enabled(bool p_enable); + bool is_h_scroll_enabled() const; + void set_v_scroll_enabled(bool p_enable); + bool is_v_scroll_enabled() const; void set_cursor_can_exit_tree(bool p_enable); diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 0590ae2415..229b5384ea 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -452,12 +452,12 @@ void VideoPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "VideoStream"), "set_stream", "get_stream"); //ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), "set_loop", "has_loop") ; ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01"), "set_volume_db", "get_volume_db"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume", PROPERTY_HINT_EXP_RANGE, "0,15,0.01", 0), "set_volume", "get_volume"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume", PROPERTY_HINT_RANGE, "0,15,0.01,exp", PROPERTY_USAGE_NONE), "set_volume", "get_volume"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_paused", "is_paused"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand"); ADD_PROPERTY(PropertyInfo(Variant::INT, "buffering_msec", PROPERTY_HINT_RANGE, "10,1000"), "set_buffering_msec", "get_buffering_msec"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stream_position", PROPERTY_HINT_RANGE, "0,1280000,0.1", 0), "set_stream_position", "get_stream_position"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stream_position", PROPERTY_HINT_RANGE, "0,1280000,0.1", PROPERTY_USAGE_NONE), "set_stream_position", "get_stream_position"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 181fe606c8..f81a3ef630 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -239,7 +239,7 @@ bool CanvasItemMaterial::get_particles_anim_loop() const { void CanvasItemMaterial::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("particles_anim_") && !particles_animation) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -876,6 +876,17 @@ void CanvasItem::draw_set_transform_matrix(const Transform2D &p_matrix) { RenderingServer::get_singleton()->canvas_item_add_set_transform(canvas_item, p_matrix); } +void CanvasItem::draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) { + ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + + RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, p_animation_length, p_slice_begin, p_slice_end, p_offset); +} + +void CanvasItem::draw_end_animation() { + ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + + RenderingServer::get_singleton()->canvas_item_add_animation_slice(canvas_item, 1, 0, 2, 0); +} void CanvasItem::draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); @@ -1159,6 +1170,8 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_multimesh", "multimesh", "texture"), &CanvasItem::draw_multimesh); ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform, DEFVAL(0.0), DEFVAL(Size2(1.0, 1.0))); ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix); + ClassDB::bind_method(D_METHOD("draw_animation_slice", "animation_length", "slice_begin", "slice_end", "offset"), &CanvasItem::draw_animation_slice, DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("draw_end_animation"), &CanvasItem::draw_end_animation); ClassDB::bind_method(D_METHOD("get_transform"), &CanvasItem::get_transform); ClassDB::bind_method(D_METHOD("get_global_transform"), &CanvasItem::get_global_transform); ClassDB::bind_method(D_METHOD("get_global_transform_with_canvas"), &CanvasItem::get_global_transform_with_canvas); @@ -1205,7 +1218,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "self_modulate"), "set_self_modulate", "get_self_modulate"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_behind_parent"), "set_draw_behind_parent", "is_draw_behind_parent_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", 0), "_set_on_top", "_is_on_top"); //compatibility + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_on_top", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_on_top", "_is_on_top"); //compatibility ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_children"), "set_clip_children", "is_clipping_children"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask"); @@ -1214,7 +1227,7 @@ void CanvasItem::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat"); ADD_GROUP("Material", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material"); // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled"); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 1c64cafab8..afdd18d76b 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -356,6 +356,8 @@ public: void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0)); void draw_set_transform_matrix(const Transform2D &p_matrix); + void draw_animation_slice(double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset = 0); + void draw_end_animation(); static CanvasItem *get_current_item_drawn(); diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 85d7edd64b..4540e42b4c 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -103,14 +103,6 @@ real_t CanvasLayer::get_rotation() const { return rot; } -void CanvasLayer::set_rotation_degrees(real_t p_degrees) { - set_rotation(Math::deg2rad(p_degrees)); -} - -real_t CanvasLayer::get_rotation_degrees() const { - return Math::rad2deg(get_rotation()); -} - void CanvasLayer::set_scale(const Vector2 &p_scale) { if (locrotscale_dirty) { _update_locrotscale(); @@ -277,9 +269,6 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &CanvasLayer::set_rotation); ClassDB::bind_method(D_METHOD("get_rotation"), &CanvasLayer::get_rotation); - ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &CanvasLayer::set_rotation_degrees); - ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &CanvasLayer::get_rotation_degrees); - ClassDB::bind_method(D_METHOD("set_scale", "scale"), &CanvasLayer::set_scale); ClassDB::bind_method(D_METHOD("get_scale"), &CanvasLayer::get_scale); @@ -298,12 +287,11 @@ void CanvasLayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer"); ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); ADD_GROUP("", ""); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", PROPERTY_USAGE_NONE), "set_custom_viewport", "get_custom_viewport"); ADD_GROUP("Follow Viewport", "follow_viewport"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale"); diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 899039340a..5de1ebf18d 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -79,9 +79,6 @@ public: void set_rotation(real_t p_radians); real_t get_rotation() const; - void set_rotation_degrees(real_t p_degrees); - real_t get_rotation_degrees() const; - void set_scale(const Size2 &p_scale); Size2 get_scale() const; diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index 927b114fbc..775dfa4c46 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -322,7 +322,8 @@ bool HTTPRequest::_update_connection() { } else { // Did not request yet, do request - Error err = client->request_raw(method, request_string, headers, request_data); + int size = request_data.size(); + Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size); if (err != OK) { call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray()); return true; @@ -627,7 +628,7 @@ void HTTPRequest::_bind_methods() { } HTTPRequest::HTTPRequest() { - client.instance(); + client = Ref<HTTPClient>(HTTPClient::create()); timer = memnew(Timer); timer->set_one_shot(true); timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout)); diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 92b0ff28e9..22e822253f 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -31,8 +31,8 @@ #ifndef HTTPREQUEST_H #define HTTPREQUEST_H +#include "core/io/file_access.h" #include "core/io/http_client.h" -#include "core/os/file_access.h" #include "core/os/thread.h" #include "core/templates/safe_refcount.h" #include "node.h" diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp index 1661984e30..89dac5f5a8 100644 --- a/scene/main/instance_placeholder.cpp +++ b/scene/main/instance_placeholder.cpp @@ -88,7 +88,7 @@ Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene if (!ps.is_valid()) { return nullptr; } - Node *scene = ps->instance(); + Node *scene = ps->instantiate(); if (!scene) { return nullptr; } diff --git a/scene/main/node.cpp b/scene/main/node.cpp index dc7057f339..787b283e8c 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -35,6 +35,7 @@ #include "core/object/message_queue.h" #include "core/string/print_string.h" #include "instance_placeholder.h" +#include "scene/animation/tween.h" #include "scene/debugger/scene_debugger.h" #include "scene/resources/packed_scene.h" #include "scene/scene_string_names.h" @@ -292,7 +293,7 @@ void Node::_propagate_exit_tree() { void Node::move_child(Node *p_child, int p_pos) { ERR_FAIL_NULL(p_child); - ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1, "Invalid new child position: " + itos(p_pos) + "."); + ERR_FAIL_INDEX_MSG(p_pos, data.children.size() + 1, vformat("Invalid new child position: %d.", p_pos)); ERR_FAIL_COND_MSG(p_child->data.parent != this, "Child is not a child of this node."); ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, move_child() failed. Consider using call_deferred(\"move_child\") instead (or \"popup\" if this is from a popup)."); @@ -402,6 +403,7 @@ void Node::set_process_mode(ProcessMode p_mode) { } bool prev_can_process = can_process(); + bool prev_enabled = _is_enabled(); data.process_mode = p_mode; @@ -416,6 +418,7 @@ void Node::set_process_mode(ProcessMode p_mode) { } bool next_can_process = can_process(); + bool next_enabled = _is_enabled(); int pause_notification = 0; @@ -425,7 +428,16 @@ void Node::set_process_mode(ProcessMode p_mode) { pause_notification = NOTIFICATION_UNPAUSED; } - _propagate_process_owner(data.process_owner, pause_notification); + int enabled_notification = 0; + + if (prev_enabled && !next_enabled) { + enabled_notification = NOTIFICATION_DISABLED; + } else if (!prev_enabled && next_enabled) { + enabled_notification = NOTIFICATION_ENABLED; + } + + _propagate_process_owner(data.process_owner, pause_notification, enabled_notification); + #ifdef TOOLS_ENABLED // This is required for the editor to update the visibility of disabled nodes // It's very expensive during runtime to change, so editor-only @@ -454,17 +466,21 @@ Node::ProcessMode Node::get_process_mode() const { return data.process_mode; } -void Node::_propagate_process_owner(Node *p_owner, int p_notification) { +void Node::_propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification) { data.process_owner = p_owner; - if (p_notification != 0) { - notification(p_notification); + if (p_pause_notification != 0) { + notification(p_pause_notification); + } + + if (p_enabled_notification != 0) { + notification(p_enabled_notification); } for (int i = 0; i < data.children.size(); i++) { Node *c = data.children[i]; if (c->data.process_mode == PROCESS_MODE_INHERIT) { - c->_propagate_process_owner(p_owner, p_notification); + c->_propagate_process_owner(p_owner, p_pause_notification, p_enabled_notification); } } } @@ -491,36 +507,24 @@ bool Node::is_network_master() const { /***** RPC CONFIG ********/ -uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode) { - uint16_t mid = get_node_rpc_method_id(p_method); - if (mid == UINT16_MAX) { - // It's new - NetData nd; - nd.name = p_method; - nd.mode = p_mode; - data.rpc_methods.push_back(nd); - return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15); - } else { - int c_mid = (~(1 << 15)) & mid; - data.rpc_methods.write[c_mid].mode = p_mode; - return mid; - } -} - -uint16_t Node::rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode) { - uint16_t pid = get_node_rset_property_id(p_property); - if (pid == UINT16_MAX) { - // It's new - NetData nd; - nd.name = p_property; - nd.mode = p_mode; - data.rpc_properties.push_back(nd); - return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15); - } else { - int c_pid = (~(1 << 15)) & pid; - data.rpc_properties.write[c_pid].mode = p_mode; - return pid; +uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, MultiplayerPeer::TransferMode p_transfer_mode, int p_channel) { + for (int i = 0; i < data.rpc_methods.size(); i++) { + if (data.rpc_methods[i].name == p_method) { + MultiplayerAPI::RPCConfig &nd = data.rpc_methods.write[i]; + nd.rpc_mode = p_rpc_mode; + nd.transfer_mode = p_transfer_mode; + nd.channel = p_channel; + return i | (1 << 15); + } } + // New method + MultiplayerAPI::RPCConfig nd; + nd.name = p_method; + nd.rpc_mode = p_rpc_mode; + nd.transfer_mode = p_transfer_mode; + nd.channel = p_channel; + data.rpc_methods.push_back(nd); + return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15); } /***** RPC FUNCTIONS ********/ @@ -536,7 +540,7 @@ void Node::rpc(const StringName &p_method, VARIANT_ARG_DECLARE) { argc++; } - rpcp(0, false, p_method, argptr, argc); + rpcp(0, p_method, argptr, argc); } void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) { @@ -550,35 +554,7 @@ void Node::rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE argc++; } - rpcp(p_peer_id, false, p_method, argptr, argc); -} - -void Node::rpc_unreliable(const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - rpcp(0, true, p_method, argptr, argc); -} - -void Node::rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_DECLARE) { - VARIANT_ARGPTRS; - - int argc = 0; - for (int i = 0; i < VARIANT_ARG_MAX; i++) { - if (argptr[i]->get_type() == Variant::NIL) { - break; - } - argc++; - } - - rpcp(p_peer_id, true, p_method, argptr, argc); + rpcp(p_peer_id, p_method, argptr, argc); } Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { @@ -597,7 +573,7 @@ Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallEr StringName method = *p_args[0]; - rpcp(0, false, method, &p_args[1], p_argcount - 1); + rpcp(0, method, &p_args[1], p_argcount - 1); r_error.error = Callable::CallError::CALL_OK; return Variant(); @@ -627,92 +603,17 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal int peer_id = *p_args[0]; StringName method = *p_args[1]; - rpcp(peer_id, false, method, &p_args[2], p_argcount - 2); - - r_error.error = Callable::CallError::CALL_OK; - return Variant(); -} - -Variant Node::_rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - if (p_argcount < 1) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 1; - return Variant(); - } - - if (p_args[0]->get_type() != Variant::STRING_NAME) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::STRING_NAME; - return Variant(); - } - - StringName method = *p_args[0]; - - rpcp(0, true, method, &p_args[1], p_argcount - 1); - - r_error.error = Callable::CallError::CALL_OK; - return Variant(); -} - -Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { - if (p_argcount < 2) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument = 2; - return Variant(); - } - - if (p_args[0]->get_type() != Variant::INT) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::INT; - return Variant(); - } - - if (p_args[1]->get_type() != Variant::STRING_NAME) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::STRING_NAME; - return Variant(); - } - - int peer_id = *p_args[0]; - StringName method = *p_args[1]; - - rpcp(peer_id, true, method, &p_args[2], p_argcount - 2); + rpcp(peer_id, method, &p_args[2], p_argcount - 2); r_error.error = Callable::CallError::CALL_OK; return Variant(); } -void Node::rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) { - ERR_FAIL_COND(!is_inside_tree()); - get_multiplayer()->rpcp(this, p_peer_id, p_unreliable, p_method, p_arg, p_argcount); -} - -void Node::rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) { +void Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) { ERR_FAIL_COND(!is_inside_tree()); - get_multiplayer()->rsetp(this, p_peer_id, p_unreliable, p_property, p_value); + get_multiplayer()->rpcp(this, p_peer_id, true, p_method, p_arg, p_argcount); } -/******** RSET *********/ -void Node::rset(const StringName &p_property, const Variant &p_value) { - rsetp(0, false, p_property, p_value); -} - -void Node::rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value) { - rsetp(p_peer_id, false, p_property, p_value); -} - -void Node::rset_unreliable(const StringName &p_property, const Variant &p_value) { - rsetp(0, true, p_property, p_value); -} - -void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value) { - rsetp(p_peer_id, true, p_property, p_value); -} - -//////////// end of rpc Ref<MultiplayerAPI> Node::get_multiplayer() const { if (multiplayer.is_valid()) { return multiplayer; @@ -731,99 +632,11 @@ void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { multiplayer = p_multiplayer; } -uint16_t Node::get_node_rpc_method_id(const StringName &p_method) const { - for (int i = 0; i < data.rpc_methods.size(); i++) { - if (data.rpc_methods[i].name == p_method) { - // Returns `i` with the high bit set to 1 so we know that this id comes - // from the node and not the script. - return i | (1 << 15); - } - } - return UINT16_MAX; -} - -StringName Node::get_node_rpc_method(const uint16_t p_rpc_method_id) const { - // Make sure this is a node generated ID. - if (((1 << 15) & p_rpc_method_id) > 0) { - int mid = (~(1 << 15)) & p_rpc_method_id; - if (mid < data.rpc_methods.size()) { - return data.rpc_methods[mid].name; - } - } - return StringName(); -} - -MultiplayerAPI::RPCMode Node::get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const { - // Make sure this is a node generated ID. - if (((1 << 15) & p_rpc_method_id) > 0) { - int mid = (~(1 << 15)) & p_rpc_method_id; - if (mid < data.rpc_methods.size()) { - return data.rpc_methods[mid].mode; - } - } - return MultiplayerAPI::RPC_MODE_DISABLED; -} - -MultiplayerAPI::RPCMode Node::get_node_rpc_mode(const StringName &p_method) const { - return get_node_rpc_mode_by_id(get_node_rpc_method_id(p_method)); -} - -uint16_t Node::get_node_rset_property_id(const StringName &p_property) const { - for (int i = 0; i < data.rpc_properties.size(); i++) { - if (data.rpc_properties[i].name == p_property) { - // Returns `i` with the high bit set to 1 so we know that this id comes - // from the node and not the script. - return i | (1 << 15); - } - } - return UINT16_MAX; -} - -StringName Node::get_node_rset_property(const uint16_t p_rset_property_id) const { - // Make sure this is a node generated ID. - if (((1 << 15) & p_rset_property_id) > 0) { - int mid = (~(1 << 15)) & p_rset_property_id; - if (mid < data.rpc_properties.size()) { - return data.rpc_properties[mid].name; - } - } - return StringName(); -} - -MultiplayerAPI::RPCMode Node::get_node_rset_mode_by_id(const uint16_t p_rset_property_id) const { - if (((1 << 15) & p_rset_property_id) > 0) { - int mid = (~(1 << 15)) & p_rset_property_id; - if (mid < data.rpc_properties.size()) { - return data.rpc_properties[mid].mode; - } - } - return MultiplayerAPI::RPC_MODE_DISABLED; +Vector<MultiplayerAPI::RPCConfig> Node::get_node_rpc_methods() const { + return data.rpc_methods; } -MultiplayerAPI::RPCMode Node::get_node_rset_mode(const StringName &p_property) const { - return get_node_rset_mode_by_id(get_node_rset_property_id(p_property)); -} - -String Node::get_rpc_md5() const { - String rpc_list; - for (int i = 0; i < data.rpc_methods.size(); i += 1) { - rpc_list += String(data.rpc_methods[i].name); - } - for (int i = 0; i < data.rpc_properties.size(); i += 1) { - rpc_list += String(data.rpc_properties[i].name); - } - if (get_script_instance()) { - Vector<ScriptNetData> rpc = get_script_instance()->get_rpc_methods(); - for (int i = 0; i < rpc.size(); i += 1) { - rpc_list += String(rpc[i].name); - } - rpc = get_script_instance()->get_rset_properties(); - for (int i = 0; i < rpc.size(); i += 1) { - rpc_list += String(rpc[i].name); - } - } - return rpc_list.md5_text(); -} +//////////// end of rpc bool Node::can_process_notification(int p_what) const { switch (p_what) { @@ -871,6 +684,27 @@ bool Node::_can_process(bool p_paused) const { } } +bool Node::_is_enabled() const { + ProcessMode process_mode; + + if (data.process_mode == PROCESS_MODE_INHERIT) { + if (!data.process_owner) { + process_mode = PROCESS_MODE_PAUSABLE; + } else { + process_mode = data.process_owner->data.process_mode; + } + } else { + process_mode = data.process_mode; + } + + return (process_mode != PROCESS_MODE_DISABLED); +} + +bool Node::is_enabled() const { + ERR_FAIL_COND_V(!is_inside_tree(), false); + return _is_enabled(); +} + float Node::get_physics_process_delta_time() const { if (data.tree) { return data.tree->get_physics_process_time(); @@ -1240,8 +1074,11 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) { void Node::add_child(Node *p_child, bool p_legible_unique_name) { ERR_FAIL_NULL(p_child); - ERR_FAIL_COND_MSG(p_child == this, "Can't add child '" + p_child->get_name() + "' to itself."); // adding to itself! - ERR_FAIL_COND_MSG(p_child->data.parent, "Can't add child '" + p_child->get_name() + "' to '" + get_name() + "', already has a parent '" + p_child->data.parent->get_name() + "'."); //Fail if node has a parent + ERR_FAIL_COND_MSG(p_child == this, vformat("Can't add child '%s' to itself.", p_child->get_name())); // adding to itself! + ERR_FAIL_COND_MSG(p_child->data.parent, vformat("Can't add child '%s' to '%s', already has a parent '%s'.", p_child->get_name(), get_name(), p_child->data.parent->get_name())); //Fail if node has a parent +#ifdef DEBUG_ENABLED + ERR_FAIL_COND_MSG(p_child->is_ancestor_of(this), vformat("Can't add child '%s' to '%s' as it would result in a cyclic dependency since '%s' is already a parent of '%s'.", p_child->get_name(), get_name(), p_child->get_name(), get_name())); +#endif ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_node() failed. Consider using call_deferred(\"add_child\", child) instead."); /* Validate name */ @@ -1252,7 +1089,7 @@ void Node::add_child(Node *p_child, bool p_legible_unique_name) { void Node::add_sibling(Node *p_sibling, bool p_legible_unique_name) { ERR_FAIL_NULL(p_sibling); - ERR_FAIL_COND_MSG(p_sibling == this, "Can't add sibling '" + p_sibling->get_name() + "' to itself."); // adding to itself! + ERR_FAIL_COND_MSG(p_sibling == this, vformat("Can't add sibling '%s' to itself.", p_sibling->get_name())); // adding to itself! ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, add_sibling() failed. Consider using call_deferred(\"add_sibling\", sibling) instead."); get_parent()->add_child(p_sibling, p_legible_unique_name); @@ -1307,7 +1144,7 @@ void Node::remove_child(Node *p_child) { } } - ERR_FAIL_COND_MSG(idx == -1, "Cannot remove child node " + p_child->get_name() + " as it is not a child of this node."); + ERR_FAIL_COND_MSG(idx == -1, vformat("Cannot remove child node '%s' as it is not a child of this node.", p_child->get_name())); //ERR_FAIL_COND( p_child->data.blocked > 0 ); //if (data.scene) { does not matter @@ -1483,7 +1320,7 @@ Node *Node::find_parent(const String &p_mask) const { return nullptr; } -bool Node::is_a_parent_of(const Node *p_node) const { +bool Node::is_ancestor_of(const Node *p_node) const { ERR_FAIL_NULL_V(p_node, false); Node *p = p_node->data.parent; while (p) { @@ -1886,6 +1723,13 @@ int Node::get_index() const { return data.pos; } +Ref<Tween> Node::create_tween() { + ERR_FAIL_COND_V_MSG(!data.tree, nullptr, "Can't create Tween when not inside scene tree."); + Ref<Tween> tween = get_tree()->create_tween(); + tween->bind_node(this); + return tween; +} + void Node::remove_and_skip() { ERR_FAIL_COND(!data.parent); @@ -1941,7 +1785,7 @@ String Node::get_editor_description() const { void Node::set_editable_instance(Node *p_node, bool p_editable) { ERR_FAIL_NULL(p_node); - ERR_FAIL_COND(!is_a_parent_of(p_node)); + ERR_FAIL_COND(!is_ancestor_of(p_node)); if (!p_editable) { p_node->data.editable_instance = false; // Avoid this flag being needlessly saved; @@ -1956,13 +1800,13 @@ bool Node::is_editable_instance(const Node *p_node) const { if (!p_node) { return false; // Easier, null is never editable. :) } - ERR_FAIL_COND_V(!is_a_parent_of(p_node), false); + ERR_FAIL_COND_V(!is_ancestor_of(p_node), false); return p_node->data.editable_instance; } Node *Node::get_deepest_editable_node(Node *p_start_node) const { ERR_FAIL_NULL_V(p_start_node, nullptr); - ERR_FAIL_COND_V(!is_a_parent_of(p_start_node), p_start_node); + ERR_FAIL_COND_V(!is_ancestor_of(p_start_node), p_start_node); Node const *iterated_item = p_start_node; Node *node = p_start_node; @@ -2005,7 +1849,7 @@ bool Node::get_scene_instance_load_placeholder() const { Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const { Node *node = nullptr; - bool instanced = false; + bool instantiated = false; if (Object::cast_to<InstancePlaceholder>(this)) { const InstancePlaceholder *ip = Object::cast_to<const InstancePlaceholder>(this); @@ -2022,13 +1866,13 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const ges = PackedScene::GEN_EDIT_STATE_INSTANCE; } #endif - node = res->instance(ges); + node = res->instantiate(ges); ERR_FAIL_COND_V(!node, nullptr); - instanced = true; + instantiated = true; } else { - Object *obj = ClassDB::instance(get_class()); + Object *obj = ClassDB::instantiate(get_class()); ERR_FAIL_COND_V(!obj, nullptr); node = Object::cast_to<Node>(obj); if (!node) { @@ -2048,9 +1892,9 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const List<const Node *> node_tree; node_tree.push_front(this); - if (instanced) { - // Since nodes in the instanced hierarchy won't be duplicated explicitly, we need to make an inventory - // of all the nodes in the tree of the instanced scene in order to transfer the values of the properties + if (instantiated) { + // Since nodes in the instantiated hierarchy won't be duplicated explicitly, we need to make an inventory + // of all the nodes in the tree of the instantiated scene in order to transfer the values of the properties Vector<const Node *> instance_roots; instance_roots.push_back(this); @@ -2058,8 +1902,8 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { for (int i = 0; i < N->get()->get_child_count(); ++i) { Node *descendant = N->get()->get_child(i); - // Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later - // but remember non-instanced nodes that are hidden below instanced ones + // Skip nodes not really belonging to the instantiated hierarchy; they'll be processed normally later + // but remember non-instantiated nodes that are hidden below instantiated ones if (!instance_roots.has(descendant->get_owner())) { if (descendant->get_parent() && descendant->get_parent() != this && descendant->data.owner != descendant->get_parent()) { hidden_roots.push_back(descendant); @@ -2142,7 +1986,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const if (get_child(i)->data.parent_owned) { continue; } - if (instanced && get_child(i)->data.owner == this) { + if (instantiated && get_child(i)->data.owner == this) { continue; //part of instance } @@ -2266,7 +2110,7 @@ void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resourc // because re-targeting of connections from some descendant to another is not possible // if the emitter node comes later in tree order than the receiver void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { - if ((this != p_original) && !(p_original->is_a_parent_of(this))) { + if ((this != p_original) && !(p_original->is_ancestor_of(this))) { return; } @@ -2391,7 +2235,7 @@ void Node::_replace_connections_target(Node *p_new_target) { if (c.flags & CONNECT_PERSIST) { c.signal.get_object()->disconnect(c.signal.get_name(), Callable(this, c.callable.get_method())); bool valid = p_new_target->has_method(c.callable.get_method()) || Ref<Script>(p_new_target->get_script()).is_null() || Ref<Script>(p_new_target->get_script())->has_method(c.callable.get_method()); - ERR_CONTINUE_MSG(!valid, "Attempt to connect signal '" + c.signal.get_object()->get_class() + "." + c.signal.get_name() + "' to nonexistent method '" + c.callable.get_object()->get_class() + "." + c.callable.get_method() + "'."); + ERR_CONTINUE_MSG(!valid, vformat("Attempt to connect signal '%s.%s' to nonexistent method '%s.%s'.", c.signal.get_object()->get_class(), c.signal.get_name(), c.callable.get_object()->get_class(), c.callable.get_method())); c.signal.get_object()->connect(c.signal.get_name(), Callable(p_new_target, c.callable.get_method()), c.binds, c.flags); } } @@ -2649,7 +2493,9 @@ String Node::get_configuration_warnings_as_string() const { if (i > 0) { all_warnings += "\n\n"; } - all_warnings += String(warnings[i]); + // Format as a bullet point list to make multiple warnings easier to distinguish + // from each other. + all_warnings += String::utf8("• ") + String(warnings[i]); } return all_warnings; } @@ -2659,7 +2505,7 @@ void Node::update_configuration_warnings() { if (!is_inside_tree()) { return; } - if (get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) { + if (get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { get_tree()->emit_signal(SceneStringNames::get_singleton()->node_configuration_warning_changed, this); } #endif @@ -2706,7 +2552,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_node_and_resource", "path"), &Node::_get_node_and_resource); ClassDB::bind_method(D_METHOD("is_inside_tree"), &Node::is_inside_tree); - ClassDB::bind_method(D_METHOD("is_a_parent_of", "node"), &Node::is_a_parent_of); + ClassDB::bind_method(D_METHOD("is_ancestor_of", "node"), &Node::is_ancestor_of); ClassDB::bind_method(D_METHOD("is_greater_than", "node"), &Node::is_greater_than); ClassDB::bind_method(D_METHOD("get_path"), &Node::get_path); ClassDB::bind_method(D_METHOD("get_path_to", "node"), &Node::get_path_to); @@ -2755,6 +2601,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("is_physics_processing_internal"), &Node::is_physics_processing_internal); ClassDB::bind_method(D_METHOD("get_tree"), &Node::get_tree); + ClassDB::bind_method(D_METHOD("create_tween"), &Node::create_tween); ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false)); @@ -2776,8 +2623,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer); ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer); ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer); - ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config); - ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config); + ClassDB::bind_method(D_METHOD("rpc_config", "method", "rpc_mode", "transfer_mode", "channel"), &Node::rpc_config, DEFVAL(MultiplayerPeer::TRANSFER_MODE_RELIABLE), DEFVAL(0)); ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description); ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description); @@ -2794,22 +2640,13 @@ void Node::_bind_methods() { mi.name = "rpc"; ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc", &Node::_rpc_bind, mi); - mi.name = "rpc_unreliable"; - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable", &Node::_rpc_unreliable_bind, mi); mi.arguments.push_front(PropertyInfo(Variant::INT, "peer_id")); mi.name = "rpc_id"; ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_id", &Node::_rpc_id_bind, mi); - mi.name = "rpc_unreliable_id"; - ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "rpc_unreliable_id", &Node::_rpc_unreliable_id_bind, mi); } - ClassDB::bind_method(D_METHOD("rset", "property", "value"), &Node::rset); - ClassDB::bind_method(D_METHOD("rset_id", "peer_id", "property", "value"), &Node::rset_id); - ClassDB::bind_method(D_METHOD("rset_unreliable", "property", "value"), &Node::rset_unreliable); - ClassDB::bind_method(D_METHOD("rset_unreliable_id", "peer_id", "property", "value"), &Node::rset_unreliable_id); - ClassDB::bind_method(D_METHOD("update_configuration_warnings"), &Node::update_configuration_warnings); BIND_CONSTANT(NOTIFICATION_ENTER_TREE); @@ -2829,6 +2666,11 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS); BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE); + BIND_CONSTANT(NOTIFICATION_DISABLED); + BIND_CONSTANT(NOTIFICATION_ENABLED); + + BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE); + BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE); BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER); BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT); @@ -2865,11 +2707,11 @@ void Node::_bind_methods() { ADD_SIGNAL(MethodInfo("tree_exiting")); ADD_SIGNAL(MethodInfo("tree_exited")); - ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name"); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer"); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_name", "get_name"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_filename", "get_filename"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_owner", "get_owner"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "", "get_multiplayer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "set_custom_multiplayer", "get_custom_multiplayer"); ADD_GROUP("Process", "process_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,When Paused,Always,Disabled"), "set_process_mode", "get_process_mode"); diff --git a/scene/main/node.h b/scene/main/node.h index 6ca2317d9e..c6727ce884 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -41,6 +41,9 @@ class Viewport; class SceneState; +class Tween; +class PropertyTweener; + class Node : public Object { GDCLASS(Node, Object); OBJ_CATEGORY("Nodes"); @@ -80,11 +83,6 @@ private: SceneTree::Group *group = nullptr; }; - struct NetData { - StringName name; - MultiplayerAPI::RPCMode mode = MultiplayerAPI::RPCMode::RPC_MODE_DISABLED; - }; - struct Data { String filename; Ref<SceneState> instance_state; @@ -116,8 +114,7 @@ private: Node *process_owner = nullptr; int network_master = 1; // Server by default. - Vector<NetData> rpc_methods; - Vector<NetData> rpc_properties; + Vector<MultiplayerAPI::RPCConfig> rpc_methods; // Variables used to properly sort the node when processing, ignored otherwise. // TODO: Should move all the stuff below to bits. @@ -169,7 +166,7 @@ private: void _propagate_after_exit_tree(); void _propagate_validate_owner(); void _print_stray_nodes(); - void _propagate_process_owner(Node *p_owner, int p_notification); + void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification); Array _get_node_and_resource(const NodePath &p_path); void _duplicate_signals(const Node *p_original, Node *p_copy) const; @@ -179,9 +176,7 @@ private: Array _get_groups() const; Variant _rpc_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - Variant _rpc_unreliable_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); Variant _rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); - Variant _rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); friend class SceneTree; @@ -189,6 +184,7 @@ private: void _propagate_pause_notification(bool p_enable); _FORCE_INLINE_ bool _can_process(bool p_paused) const; + _FORCE_INLINE_ bool _is_enabled() const; protected: void _block() { data.blocked++; } @@ -232,6 +228,8 @@ public: NOTIFICATION_INTERNAL_PROCESS = 25, NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26, NOTIFICATION_POST_ENTER_TREE = 27, + NOTIFICATION_DISABLED = 28, + NOTIFICATION_ENABLED = 29, //keep these linked to node NOTIFICATION_WM_MOUSE_ENTER = 1002, @@ -253,6 +251,10 @@ public: NOTIFICATION_APPLICATION_FOCUS_IN = MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN, NOTIFICATION_APPLICATION_FOCUS_OUT = MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT, NOTIFICATION_TEXT_SERVER_CHANGED = MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED, + + // Editor specific node notifications + NOTIFICATION_EDITOR_PRE_SAVE = 9001, + NOTIFICATION_EDITOR_POST_SAVE = 9002, }; /* NODE/TREE */ @@ -283,7 +285,7 @@ public: _FORCE_INLINE_ bool is_inside_tree() const { return data.inside_tree; } - bool is_a_parent_of(const Node *p_node) const; + bool is_ancestor_of(const Node *p_node) const; bool is_greater_than(const Node *p_node) const; NodePath get_path() const; @@ -312,6 +314,8 @@ public: void remove_and_skip(); int get_index() const; + Ref<Tween> create_tween(); + void print_tree(); void print_tree_pretty(); @@ -384,6 +388,7 @@ public: ProcessMode get_process_mode() const; bool can_process() const; bool can_process_notification(int p_what) const; + bool is_enabled() const; void request_ready(); @@ -425,42 +430,17 @@ public: int get_network_master() const; bool is_network_master() const; - uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_mode); // config a local method for RPC - uint16_t rset_config(const StringName &p_property, MultiplayerAPI::RPCMode p_mode); // config a local property for RPC - - void rpc(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode - void rpc_unreliable(const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode - void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode - void rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode + uint16_t rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_rpc_mode, MultiplayerPeer::TransferMode p_transfer_mode, int p_channel = 0); // config a local method for RPC + Vector<MultiplayerAPI::RPCConfig> get_node_rpc_methods() const; - void rset(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode - void rset_unreliable(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode - void rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode - void rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode - - void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount); - void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value); + void rpc(const StringName &p_method, VARIANT_ARG_LIST); // RPC, honors RPCMode, TransferMode, channel + void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); // RPC to specific peer(s), honors RPCMode, TransferMode, channel + void rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount); Ref<MultiplayerAPI> get_multiplayer() const; Ref<MultiplayerAPI> get_custom_multiplayer() const; void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer); - /// Returns the rpc method ID, otherwise UINT32_MAX - uint16_t get_node_rpc_method_id(const StringName &p_method) const; - StringName get_node_rpc_method(const uint16_t p_rpc_method_id) const; - MultiplayerAPI::RPCMode get_node_rpc_mode_by_id(const uint16_t p_rpc_method_id) const; - MultiplayerAPI::RPCMode get_node_rpc_mode(const StringName &p_method) const; - - /// Returns the rpc property ID, otherwise UINT32_MAX - uint16_t get_node_rset_property_id(const StringName &p_property) const; - StringName get_node_rset_property(const uint16_t p_rset_property_id) const; - MultiplayerAPI::RPCMode get_node_rset_mode_by_id(const uint16_t p_rpc_method_id) const; - MultiplayerAPI::RPCMode get_node_rset_mode(const StringName &p_property) const; - - /// Can be used to check if the rpc methods and the rset properties are the - /// same across the peers. - String get_rpc_md5() const; - Node(); ~Node(); }; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 3e08f86fc9..fefe4c9f0d 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -33,14 +33,15 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" #include "core/input/input.h" +#include "core/io/dir_access.h" #include "core/io/marshalls.h" #include "core/io/resource_loader.h" #include "core/object/message_queue.h" -#include "core/os/dir_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/print_string.h" #include "node.h" +#include "scene/animation/tween.h" #include "scene/debugger/scene_debugger.h" #include "scene/resources/font.h" #include "scene/resources/material.h" @@ -412,8 +413,10 @@ bool SceneTree::physics_process(float p_time) { _notify_group_pause("physics_process", Node::NOTIFICATION_PHYSICS_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack + + process_tweens(p_time, true); + flush_transform_notifications(); - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); root_lock--; _flush_delete_queue(); @@ -445,7 +448,6 @@ bool SceneTree::process(float p_time) { _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack flush_transform_notifications(); //transforms after world update, to avoid unnecessary enter/exit notifications - call_group_flags(GROUP_CALL_REALTIME, "_viewports", "update_worlds"); root_lock--; @@ -478,6 +480,8 @@ bool SceneTree::process(float p_time) { E = N; } + process_tweens(p_time, false); + flush_transform_notifications(); //additional transforms after timers update _call_idle_callbacks(); @@ -512,6 +516,32 @@ bool SceneTree::process(float p_time) { return _quit; } +void SceneTree::process_tweens(float p_delta, bool p_physics) { + // This methods works similarly to how SceneTreeTimers are handled. + List<Ref<Tween>>::Element *L = tweens.back(); + + for (List<Ref<Tween>>::Element *E = tweens.front(); E;) { + List<Ref<Tween>>::Element *N = E->next(); + // Don't process if paused or process mode doesn't match. + if ((paused && E->get()->should_pause()) || (p_physics == (E->get()->get_process_mode() == Tween::TWEEN_PROCESS_IDLE))) { + if (E == L) { + break; + } + E = N; + continue; + } + + if (!E->get()->step(p_delta)) { + E->get()->set_valid(false); + tweens.erase(E); + } + if (E == L) { + break; + } + E = N; + } +} + void SceneTree::finalize() { _flush_delete_queue(); @@ -593,7 +623,7 @@ void SceneTree::set_quit_on_go_back(bool p_enable) { #ifdef TOOLS_ENABLED bool SceneTree::is_node_being_edited(const Node *p_node) const { - return Engine::get_singleton()->is_editor_hint() && edited_scene_root && (edited_scene_root->is_a_parent_of(p_node) || edited_scene_root == p_node); + return Engine::get_singleton()->is_editor_hint() && edited_scene_root && (edited_scene_root->is_ancestor_of(p_node) || edited_scene_root == p_node); } #endif @@ -1063,7 +1093,7 @@ Error SceneTree::change_scene(const String &p_path) { Error SceneTree::change_scene_to(const Ref<PackedScene> &p_scene) { Node *new_scene = nullptr; if (p_scene.is_valid()) { - new_scene = p_scene->instance(); + new_scene = p_scene->instantiate(); ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); } @@ -1084,31 +1114,32 @@ void SceneTree::add_current_scene(Node *p_current) { Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_always) { Ref<SceneTreeTimer> stt; - stt.instance(); + stt.instantiate(); stt->set_process_always(p_process_always); stt->set_time_left(p_delay_sec); timers.push_back(stt); return stt; } -void SceneTree::_network_peer_connected(int p_id) { - emit_signal("network_peer_connected", p_id); -} - -void SceneTree::_network_peer_disconnected(int p_id) { - emit_signal("network_peer_disconnected", p_id); +Ref<Tween> SceneTree::create_tween() { + Ref<Tween> tween; + tween.instantiate(); + tween->set_valid(true); + tweens.push_back(tween); + return tween; } -void SceneTree::_connected_to_server() { - emit_signal("connected_to_server"); -} +Array SceneTree::get_processed_tweens() { + Array ret; + ret.resize(tweens.size()); -void SceneTree::_connection_failed() { - emit_signal("connection_failed"); -} + int i = 0; + for (List<Ref<Tween>>::Element *E = tweens.front(); E; E = E->next()) { + ret[i] = E->get(); + i++; + } -void SceneTree::_server_disconnected() { - emit_signal("server_disconnected"); + return ret; } Ref<MultiplayerAPI> SceneTree::get_multiplayer() const { @@ -1126,58 +1157,8 @@ bool SceneTree::is_multiplayer_poll_enabled() const { void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) { ERR_FAIL_COND(!p_multiplayer.is_valid()); - if (multiplayer.is_valid()) { - multiplayer->disconnect("network_peer_connected", callable_mp(this, &SceneTree::_network_peer_connected)); - multiplayer->disconnect("network_peer_disconnected", callable_mp(this, &SceneTree::_network_peer_disconnected)); - multiplayer->disconnect("connected_to_server", callable_mp(this, &SceneTree::_connected_to_server)); - multiplayer->disconnect("connection_failed", callable_mp(this, &SceneTree::_connection_failed)); - multiplayer->disconnect("server_disconnected", callable_mp(this, &SceneTree::_server_disconnected)); - } - multiplayer = p_multiplayer; multiplayer->set_root_node(root); - - multiplayer->connect("network_peer_connected", callable_mp(this, &SceneTree::_network_peer_connected)); - multiplayer->connect("network_peer_disconnected", callable_mp(this, &SceneTree::_network_peer_disconnected)); - multiplayer->connect("connected_to_server", callable_mp(this, &SceneTree::_connected_to_server)); - multiplayer->connect("connection_failed", callable_mp(this, &SceneTree::_connection_failed)); - multiplayer->connect("server_disconnected", callable_mp(this, &SceneTree::_server_disconnected)); -} - -void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer) { - multiplayer->set_network_peer(p_network_peer); -} - -Ref<NetworkedMultiplayerPeer> SceneTree::get_network_peer() const { - return multiplayer->get_network_peer(); -} - -bool SceneTree::is_network_server() const { - return multiplayer->is_network_server(); -} - -bool SceneTree::has_network_peer() const { - return multiplayer->has_network_peer(); -} - -int SceneTree::get_network_unique_id() const { - return multiplayer->get_network_unique_id(); -} - -Vector<int> SceneTree::get_network_connected_peers() const { - return multiplayer->get_network_connected_peers(); -} - -int SceneTree::get_rpc_sender_id() const { - return multiplayer->get_rpc_sender_id(); -} - -void SceneTree::set_refuse_new_network_connections(bool p_refuse) { - multiplayer->set_refuse_new_network_connections(p_refuse); -} - -bool SceneTree::is_refusing_new_network_connections() const { - return multiplayer->is_refusing_new_network_connections(); } void SceneTree::_bind_methods() { @@ -1199,6 +1180,8 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("create_tween"), &SceneTree::create_tween); + ClassDB::bind_method(D_METHOD("get_processed_tweens"), &SceneTree::get_processed_tweens); ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count); ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); @@ -1244,26 +1227,14 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_multiplayer"), &SceneTree::get_multiplayer); ClassDB::bind_method(D_METHOD("set_multiplayer_poll_enabled", "enabled"), &SceneTree::set_multiplayer_poll_enabled); ClassDB::bind_method(D_METHOD("is_multiplayer_poll_enabled"), &SceneTree::is_multiplayer_poll_enabled); - ClassDB::bind_method(D_METHOD("set_network_peer", "peer"), &SceneTree::set_network_peer); - ClassDB::bind_method(D_METHOD("get_network_peer"), &SceneTree::get_network_peer); - ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server); - ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer); - ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &SceneTree::get_network_connected_peers); - ClassDB::bind_method(D_METHOD("get_network_unique_id"), &SceneTree::get_network_unique_id); - ClassDB::bind_method(D_METHOD("get_rpc_sender_id"), &SceneTree::get_rpc_sender_id); - ClassDB::bind_method(D_METHOD("set_refuse_new_network_connections", "refuse"), &SceneTree::set_refuse_new_network_connections); - ClassDB::bind_method(D_METHOD("is_refusing_new_network_connections"), &SceneTree::is_refusing_new_network_connections); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections"); - ADD_PROPERTY_DEFAULT("refuse_new_network_connections", false); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "", "get_root"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_multiplayer", "get_multiplayer"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_edited_scene_root", "get_edited_scene_root"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_current_scene", "get_current_scene"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_root"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", PROPERTY_USAGE_NONE), "set_multiplayer", "get_multiplayer"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled"); ADD_SIGNAL(MethodInfo("tree_changed")); @@ -1277,11 +1248,6 @@ void SceneTree::_bind_methods() { ADD_SIGNAL(MethodInfo("physics_frame")); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); - ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("connected_to_server")); - ADD_SIGNAL(MethodInfo("connection_failed")); - ADD_SIGNAL(MethodInfo("server_disconnected")); BIND_ENUM_CONSTANT(GROUP_CALL_DEFAULT); BIND_ENUM_CONSTANT(GROUP_CALL_REVERSE); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index a2f2adb8f8..0be0e185a5 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -47,9 +47,10 @@ class Window; class Material; class Mesh; class SceneDebugger; +class Tween; -class SceneTreeTimer : public Reference { - GDCLASS(SceneTreeTimer, Reference); +class SceneTreeTimer : public RefCounted { + GDCLASS(SceneTreeTimer, RefCounted); float time_left = 0.0; bool process_always = true; @@ -151,19 +152,13 @@ private: //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2); List<Ref<SceneTreeTimer>> timers; + List<Ref<Tween>> tweens; ///network/// Ref<MultiplayerAPI> multiplayer; bool multiplayer_poll = true; - void _network_peer_connected(int p_id); - void _network_peer_disconnected(int p_id); - - void _connected_to_server(); - void _connection_failed(); - void _server_disconnected(); - static SceneTree *singleton; friend class Node; @@ -171,6 +166,7 @@ private: void node_added(Node *p_node); void node_removed(Node *p_node); void node_renamed(Node *p_node); + void process_tweens(float p_delta, bool p_physics_frame); Group *add_to_group(const StringName &p_group, Node *p_node); void remove_from_group(const StringName &p_group, Node *p_node); @@ -318,6 +314,8 @@ public: Error reload_current_scene(); Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_always = true); + Ref<Tween> create_tween(); + Array get_processed_tweens(); //used by Main::start, don't use otherwise void add_current_scene(Node *p_current); @@ -332,16 +330,6 @@ public: void set_multiplayer_poll_enabled(bool p_enabled); bool is_multiplayer_poll_enabled() const; void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer); - void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer); - Ref<NetworkedMultiplayerPeer> get_network_peer() const; - bool is_network_server() const; - bool has_network_peer() const; - int get_network_unique_id() const; - Vector<int> get_network_connected_peers() const; - int get_rpc_sender_id() const; - - void set_refuse_new_network_connections(bool p_refuse); - bool is_refusing_new_network_connections() const; static void add_idle_callback(IdleCallback p_callback); diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index cb3b2cb392..d22a6b2875 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -63,7 +63,12 @@ bool ShaderGlobalsOverride::_set(const StringName &p_name, const Variant &p_valu if (o) { o->override = p_value; if (active) { - RS::get_singleton()->global_variable_set_override(*r, p_value); + if (o->override.get_type() == Variant::OBJECT) { + RID tex_rid = p_value; + RS::get_singleton()->global_variable_set_override(*r, tex_rid); + } else { + RS::get_singleton()->global_variable_set_override(*r, p_value); + } } o->in_use = p_value.get_type() != Variant::NIL; return true; @@ -169,7 +174,7 @@ void ShaderGlobalsOverride::_get_property_list(List<PropertyInfo> *p_list) const pinfo.type = Variant::TRANSFORM2D; } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM: { - pinfo.type = Variant::TRANSFORM; + pinfo.type = Variant::TRANSFORM3D; } break; case RS::GLOBAL_VAR_TYPE_MAT4: { pinfo.type = Variant::PACKED_INT32_ARRAY; @@ -228,7 +233,12 @@ void ShaderGlobalsOverride::_activate() { while ((K = overrides.next(K))) { Override *o = overrides.getptr(*K); if (o->in_use && o->override.get_type() != Variant::NIL) { - RS::get_singleton()->global_variable_set_override(*K, o->override); + if (o->override.get_type() == Variant::OBJECT) { + RID tex_rid = o->override; + RS::get_singleton()->global_variable_set_override(*K, tex_rid); + } else { + RS::get_singleton()->global_variable_set_override(*K, o->override); + } } } diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index 4bc159f6aa..f52237251c 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -37,7 +37,7 @@ void Timer::_notification(int p_what) { case NOTIFICATION_READY: { if (autostart) { #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) { + if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root() == this || get_tree()->get_edited_scene_root()->is_ancestor_of(this))) { break; } #endif @@ -207,11 +207,11 @@ void Timer::_bind_methods() { ADD_SIGNAL(MethodInfo("timeout")); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.001,4096,0.001,or_greater"), "set_wait_time", "get_wait_time"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_RANGE, "0.001,4096,0.001,or_greater,exp"), "set_wait_time", "get_wait_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", 0), "set_paused", "is_paused"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_left", PROPERTY_HINT_NONE, "", 0), "", "get_time_left"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_paused", "is_paused"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_left", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_time_left"); BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS); BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 77667cf188..9a2e0c5230 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -183,22 +183,9 @@ public: ///////////////////////////////////// -void Viewport::update_worlds() { - if (!is_inside_tree()) { - return; - } - - Rect2 abstracted_rect = Rect2(Vector2(), get_visible_rect().size); - Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(abstracted_rect); - find_world_2d()->_update_viewport(this, xformed_rect); - find_world_2d()->_update(); - - find_world_3d()->_update(get_tree()->get_frame()); -} - void Viewport::_collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { - Transform object_transform = p_object->get_global_transform(); - Transform camera_transform = p_camera->get_global_transform(); + Transform3D object_transform = p_object->get_global_transform(); + Transform3D camera_transform = p_camera->get_global_transform(); ObjectID id = p_object->get_instance_id(); //avoid sending the fake event unnecessarily if nothing really changed in the context @@ -441,8 +428,6 @@ void Viewport::_notification(int p_what) { _update_listener(); _update_listener_2d(); - find_world_2d()->_register_viewport(this, Rect2()); - add_to_group("_viewports"); if (get_tree()->is_debugging_collisions_hint()) { //2D @@ -499,9 +484,6 @@ void Viewport::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { _gui_cancel_tooltip(); - if (world_2d.is_valid()) { - world_2d->_remove_viewport(this); - } RenderingServer::get_singleton()->viewport_set_scenario(viewport, RID()); RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas); @@ -553,7 +535,7 @@ void Viewport::_notification(int p_what) { RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count); for (int i = 0; i < point_count; i++) { - Transform point_transform; + Transform3D point_transform; point_transform.origin = points[i]; RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform); } @@ -612,7 +594,7 @@ void Viewport::_process_picking() { if (!has_mouse_event) { Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_device(InputEvent::DEVICE_ID_INTERNAL); mm->set_global_position(physics_last_mousepos); @@ -662,9 +644,9 @@ void Viewport::_process_picking() { physics_last_mouse_state.meta = mb->is_meta_pressed(); if (mb->is_pressed()) { - physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1)); + physics_last_mouse_state.mouse_mask |= (MouseButton)(1 << (mb->get_button_index() - 1)); } else { - physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1)); + physics_last_mouse_state.mouse_mask &= (MouseButton) ~(1 << (mb->get_button_index() - 1)); // If touch mouse raised, assume we don't know last mouse pos until new events come if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) { @@ -947,6 +929,15 @@ bool Viewport::is_audio_listener_2d() const { return audio_listener_2d; } +void Viewport::set_disable_3d(bool p_disable) { + disable_3d = p_disable; + RenderingServer::get_singleton()->viewport_set_disable_3d(viewport, disable_3d); +} + +bool Viewport::is_3d_disabled() const { + return disable_3d; +} + void Viewport::enable_canvas_transform_override(bool p_enable) { if (override_canvas_transform == p_enable) { return; @@ -1156,7 +1147,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) { } if (is_inside_tree()) { - find_world_2d()->_remove_viewport(this); RenderingServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas); } @@ -1172,7 +1162,6 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) { if (is_inside_tree()) { current_canvas = find_world_2d()->get_canvas(); RenderingServer::get_singleton()->viewport_attach_canvas(viewport, current_canvas); - find_world_2d()->_register_viewport(this, Rect2()); } } @@ -1341,19 +1330,19 @@ bool Viewport::is_camera_override_enabled() const { return camera_override; } -void Viewport::set_camera_override_transform(const Transform &p_transform) { +void Viewport::set_camera_override_transform(const Transform3D &p_transform) { if (camera_override) { camera_override.transform = p_transform; RenderingServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform); } } -Transform Viewport::get_camera_override_transform() const { +Transform3D Viewport::get_camera_override_transform() const { if (camera_override) { return camera_override.transform; } - return Transform(); + return Transform3D(); } void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { @@ -1766,7 +1755,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ Control *c = Object::cast_to<Control>(p_node); - if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) { + if (!c || !c->is_clipping_contents() || c->has_point(matrix.affine_inverse().xform(p_global))) { for (int i = p_node->get_child_count() - 1; i >= 0; i--) { CanvasItem *ci = Object::cast_to<CanvasItem>(p_node->get_child(i)); if (!ci || ci->is_set_as_top_level()) { @@ -1790,7 +1779,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ } Control *drag_preview = _gui_get_drag_preview(); - if (!drag_preview || (c != drag_preview && !drag_preview->is_a_parent_of(c))) { + if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) { r_inv_xform = matrix; return c; } @@ -2547,6 +2536,8 @@ void Viewport::_gui_remove_control(Control *p_control) { } Window *Viewport::get_base_window() const { + ERR_FAIL_COND_V(!is_inside_tree(), nullptr); + Viewport *v = const_cast<Viewport *>(this); Window *w = Object::cast_to<Window>(v); while (!w) { @@ -2603,10 +2594,10 @@ void Viewport::_drop_mouse_focus() { for (int i = 0; i < 3; i++) { if (mask & (1 << i)) { Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_position(c->get_local_mouse_position()); mb->set_global_position(c->get_local_mouse_position()); - mb->set_button_index(i + 1); + mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(false); c->call(SceneStringNames::get_singleton()->_gui_input, mb); } @@ -2679,12 +2670,12 @@ void Viewport::_post_gui_grab_click_focus() { for (int i = 0; i < 3; i++) { if (mask & (1 << i)) { Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); //send unclick mb->set_position(click); - mb->set_button_index(i + 1); + mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(false); gui.mouse_focus->call(SceneStringNames::get_singleton()->_gui_input, mb); } @@ -2697,12 +2688,12 @@ void Viewport::_post_gui_grab_click_focus() { for (int i = 0; i < 3; i++) { if (mask & (1 << i)) { Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); //send click mb->set_position(click); - mb->set_button_index(i + 1); + mb->set_button_index(MouseButton(i + 1)); mb->set_pressed(true); gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb); } @@ -3041,7 +3032,7 @@ void Viewport::input(const Ref<InputEvent> &p_event, bool p_local_coords) { return; } - if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { + if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this)) { return; } @@ -3083,7 +3074,7 @@ void Viewport::unhandled_input(const Ref<InputEvent> &p_event, bool p_local_coor return; } - if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) { + if (Engine::get_singleton()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_ancestor_of(this)) { return; } @@ -3277,8 +3268,8 @@ Viewport::DebugDraw Viewport::get_debug_draw() const { return debug_draw; } -int Viewport::get_render_info(RenderInfo p_info) { - return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfo(p_info)); +int Viewport::get_render_info(RenderInfoType p_type, RenderInfo p_info) { + return RS::get_singleton()->viewport_get_render_info(viewport, RS::ViewportRenderInfoType(p_type), RS::ViewportRenderInfo(p_info)); } void Viewport::set_snap_controls_to_pixels(bool p_enable) { @@ -3336,6 +3327,7 @@ bool Viewport::is_input_handled() const { return local_input_handled; } else { const Viewport *vp = this; + ERR_FAIL_COND_V(!is_inside_tree(), false); while (true) { if (Object::cast_to<Window>(vp)) { break; @@ -3507,7 +3499,7 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw); ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw); - ClassDB::bind_method(D_METHOD("get_render_info", "info"), &Viewport::get_render_info); + ClassDB::bind_method(D_METHOD("get_render_info", "type", "info"), &Viewport::get_render_info); ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr); ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr); @@ -3522,8 +3514,6 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("input", "event", "in_local_coords"), &Viewport::input, DEFVAL(false)); ClassDB::bind_method(D_METHOD("unhandled_input", "event", "in_local_coords"), &Viewport::unhandled_input, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("update_worlds"), &Viewport::update_worlds); - ClassDB::bind_method(D_METHOD("set_use_own_world_3d", "enable"), &Viewport::set_use_own_world_3d); ClassDB::bind_method(D_METHOD("is_using_own_world_3d"), &Viewport::is_using_own_world_3d); @@ -3535,6 +3525,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_as_audio_listener_2d", "enable"), &Viewport::set_as_audio_listener_2d); ClassDB::bind_method(D_METHOD("is_audio_listener_2d"), &Viewport::is_audio_listener_2d); + ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d); + ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled); + ClassDB::bind_method(D_METHOD("get_mouse_position"), &Viewport::get_mouse_position); ClassDB::bind_method(D_METHOD("warp_mouse", "to_position"), &Viewport::warp_mouse); @@ -3595,12 +3588,13 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", PROPERTY_USAGE_NONE), "set_world_2d", "get_world_2d"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled"); ADD_GROUP("Rendering", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)"), "set_msaa", "get_msaa"); ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled (Fastest),FXAA (Fast)"), "set_screen_space_aa", "get_screen_space_aa"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding"); @@ -3629,8 +3623,8 @@ void Viewport::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_1", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 1); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_2", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 2); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_3", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 3); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_canvas_transform", "get_canvas_transform"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_canvas_transform", "get_canvas_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_canvas_transform", "get_global_canvas_transform"); ADD_SIGNAL(MethodInfo("size_changed")); ADD_SIGNAL(MethodInfo("gui_focus_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Control"))); @@ -3656,22 +3650,23 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(SCREEN_SPACE_AA_MAX); BIND_ENUM_CONSTANT(RENDER_INFO_OBJECTS_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_INFO_VERTICES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_INFO_MATERIAL_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_INFO_SHADER_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(RENDER_INFO_SURFACE_CHANGES_IN_FRAME); + BIND_ENUM_CONSTANT(RENDER_INFO_PRIMITIVES_IN_FRAME); BIND_ENUM_CONSTANT(RENDER_INFO_DRAW_CALLS_IN_FRAME); BIND_ENUM_CONSTANT(RENDER_INFO_MAX); + BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_VISIBLE); + BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_SHADOW); + BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_MAX); + BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLED); BIND_ENUM_CONSTANT(DEBUG_DRAW_UNSHADED); BIND_ENUM_CONSTANT(DEBUG_DRAW_LIGHTING); BIND_ENUM_CONSTANT(DEBUG_DRAW_OVERDRAW); BIND_ENUM_CONSTANT(DEBUG_DRAW_WIREFRAME); BIND_ENUM_CONSTANT(DEBUG_DRAW_NORMAL_BUFFER); - BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_ALBEDO); - BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_LIGHTING); - BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_PROBE_EMISSION); + BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_ALBEDO); + BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_LIGHTING); + BIND_ENUM_CONSTANT(DEBUG_DRAW_VOXEL_GI_EMISSION); BIND_ENUM_CONSTANT(DEBUG_DRAW_SHADOW_ATLAS); BIND_ENUM_CONSTANT(DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS); BIND_ENUM_CONSTANT(DEBUG_DRAW_SCENE_LUMINANCE); @@ -3717,7 +3712,7 @@ Viewport::Viewport() { viewport = RenderingServer::get_singleton()->viewport_create(); texture_rid = RenderingServer::get_singleton()->viewport_get_texture(viewport); - default_texture.instance(); + default_texture.instantiate(); default_texture->vp = const_cast<Viewport *>(this); viewport_textures.insert(default_texture.ptr()); default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index a55df4fbc2..0f3bb8707d 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -115,14 +115,17 @@ public: enum RenderInfo { RENDER_INFO_OBJECTS_IN_FRAME, - RENDER_INFO_VERTICES_IN_FRAME, - RENDER_INFO_MATERIAL_CHANGES_IN_FRAME, - RENDER_INFO_SHADER_CHANGES_IN_FRAME, - RENDER_INFO_SURFACE_CHANGES_IN_FRAME, + RENDER_INFO_PRIMITIVES_IN_FRAME, RENDER_INFO_DRAW_CALLS_IN_FRAME, RENDER_INFO_MAX }; + enum RenderInfoType { + RENDER_INFO_TYPE_VISIBLE, + RENDER_INFO_TYPE_SHADOW, + RENDER_INFO_TYPE_MAX + }; + enum DebugDraw { DEBUG_DRAW_DISABLED, DEBUG_DRAW_UNSHADED, @@ -130,9 +133,9 @@ public: DEBUG_DRAW_OVERDRAW, DEBUG_DRAW_WIREFRAME, DEBUG_DRAW_NORMAL_BUFFER, - DEBUG_DRAW_GI_PROBE_ALBEDO, - DEBUG_DRAW_GI_PROBE_LIGHTING, - DEBUG_DRAW_GI_PROBE_EMISSION, + DEBUG_DRAW_VOXEL_GI_ALBEDO, + DEBUG_DRAW_VOXEL_GI_LIGHTING, + DEBUG_DRAW_VOXEL_GI_EMISSION, DEBUG_DRAW_SHADOW_ATLAS, DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS, DEBUG_DRAW_SCENE_LUMINANCE, @@ -193,7 +196,7 @@ private: Set<Listener3D *> listeners; struct CameraOverrideData { - Transform transform; + Transform3D transform; enum Projection { PROJECTION_PERSPECTIVE, PROJECTION_ORTHOGONAL @@ -254,8 +257,8 @@ private: List<Ref<InputEvent>> physics_picking_events; ObjectID physics_object_capture; ObjectID physics_object_over; - Transform physics_last_object_transform; - Transform physics_last_camera_transform; + Transform3D physics_last_object_transform; + Transform3D physics_last_camera_transform; ObjectID physics_last_id; bool physics_has_last_mousepos = false; Vector2 physics_last_mousepos = Vector2(Math_INF, Math_INF); @@ -288,6 +291,8 @@ private: void _update_listener(); void _update_listener_2d(); + bool disable_3d = false; + void _propagate_enter_world(Node *p_node); void _propagate_exit_world(Node *p_node); void _propagate_viewport_notification(Node *p_node, int p_what); @@ -397,8 +402,6 @@ private: void _gui_input_event(Ref<InputEvent> p_event); - void update_worlds(); - _FORCE_INLINE_ Transform2D _get_input_pre_xform() const; Ref<InputEvent> _make_input_local(const Ref<InputEvent> &ev); @@ -493,8 +496,8 @@ public: void enable_camera_override(bool p_enable); bool is_camera_override_enabled() const; - void set_camera_override_transform(const Transform &p_transform); - Transform get_camera_override_transform() const; + void set_camera_override_transform(const Transform3D &p_transform); + Transform3D get_camera_override_transform() const; void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far); void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far); @@ -505,6 +508,9 @@ public: void set_as_audio_listener_2d(bool p_enable); bool is_audio_listener_2d() const; + void set_disable_3d(bool p_disable); + bool is_3d_disabled() const; + void update_canvas_items(); Rect2 get_visible_rect() const; @@ -593,7 +599,7 @@ public: void set_debug_draw(DebugDraw p_debug_draw); DebugDraw get_debug_draw() const; - int get_render_info(RenderInfo p_info); + int get_render_info(RenderInfoType p_type, RenderInfo p_info); void set_snap_controls_to_pixels(bool p_enable); bool is_snap_controls_to_pixels_enabled() const; @@ -696,6 +702,7 @@ VARIANT_ENUM_CAST(Viewport::SDFScale); VARIANT_ENUM_CAST(Viewport::SDFOversize); VARIANT_ENUM_CAST(SubViewport::ClearMode); VARIANT_ENUM_CAST(Viewport::RenderInfo); +VARIANT_ENUM_CAST(Viewport::RenderInfoType); VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureFilter); VARIANT_ENUM_CAST(Viewport::DefaultCanvasItemTextureRepeat); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index d793be1869..9299f8d6be 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -227,7 +227,8 @@ void Window::_make_window() { } } - window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), f, Rect2i(position, size)); + DisplayServer::VSyncMode vsync_mode = DisplayServer::get_singleton()->window_get_vsync_mode(DisplayServer::MAIN_WINDOW_ID); + window_id = DisplayServer::get_singleton()->create_sub_window(DisplayServer::WindowMode(mode), vsync_mode, f, Rect2i(position, size)); ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID); DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); @@ -1393,6 +1394,8 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded); + ClassDB::bind_method(D_METHOD("get_contents_minimum_size"), &Window::get_contents_minimum_size); + ClassDB::bind_method(D_METHOD("set_content_scale_size", "size"), &Window::set_content_scale_size); ClassDB::bind_method(D_METHOD("get_content_scale_size"), &Window::get_content_scale_size); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index e8ee4cb9fc..ea0df685a1 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -31,6 +31,7 @@ #include "register_scene_types.h" #include "core/config/project_settings.h" +#include "core/extension/native_extension_manager.h" #include "core/object/class_db.h" #include "core/os/os.h" #include "scene/2d/animated_sprite_2d.h" @@ -55,6 +56,7 @@ #include "scene/2d/parallax_background.h" #include "scene/2d/parallax_layer.h" #include "scene/2d/path_2d.h" +#include "scene/2d/physical_bone_2d.h" #include "scene/2d/physics_body_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/2d/position_2d.h" @@ -64,8 +66,7 @@ #include "scene/2d/sprite_2d.h" #include "scene/2d/tile_map.h" #include "scene/2d/touch_screen_button.h" -#include "scene/2d/visibility_notifier_2d.h" -#include "scene/2d/y_sort.h" +#include "scene/2d/visible_on_screen_notifier_2d.h" #include "scene/animation/animation_blend_space_1d.h" #include "scene/animation/animation_blend_space_2d.h" #include "scene/animation/animation_blend_tree.h" @@ -146,6 +147,7 @@ #include "scene/resources/font.h" #include "scene/resources/gradient.h" #include "scene/resources/height_map_shape_3d.h" +#include "scene/resources/immediate_mesh.h" #include "scene/resources/line_shape_2d.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" @@ -161,6 +163,15 @@ #include "scene/resources/rectangle_shape_2d.h" #include "scene/resources/resource_format_text.h" #include "scene/resources/segment_shape_2d.h" +#include "scene/resources/skeleton_modification_2d.h" +#include "scene/resources/skeleton_modification_2d_ccdik.h" +#include "scene/resources/skeleton_modification_2d_fabrik.h" +#include "scene/resources/skeleton_modification_2d_jiggle.h" +#include "scene/resources/skeleton_modification_2d_lookat.h" +#include "scene/resources/skeleton_modification_2d_physicalbones.h" +#include "scene/resources/skeleton_modification_2d_stackholder.h" +#include "scene/resources/skeleton_modification_2d_twoboneik.h" +#include "scene/resources/skeleton_modification_stack_2d.h" #include "scene/resources/sky.h" #include "scene/resources/sky_material.h" #include "scene/resources/sphere_shape_3d.h" @@ -174,33 +185,28 @@ #include "scene/resources/video_stream.h" #include "scene/resources/visual_shader.h" #include "scene/resources/visual_shader_nodes.h" +#include "scene/resources/visual_shader_particle_nodes.h" #include "scene/resources/visual_shader_sdf_nodes.h" #include "scene/resources/world_2d.h" #include "scene/resources/world_3d.h" #include "scene/resources/world_margin_shape_3d.h" #include "scene/scene_string_names.h" -// Needed by animation code, so keep when 3D disabled. -#include "scene/3d/node_3d.h" -#include "scene/3d/skeleton_3d.h" - #include "scene/main/shader_globals_override.h" #ifndef _3D_DISABLED #include "scene/3d/area_3d.h" #include "scene/3d/audio_stream_player_3d.h" -#include "scene/3d/baked_lightmap.h" #include "scene/3d/bone_attachment_3d.h" #include "scene/3d/camera_3d.h" #include "scene/3d/collision_polygon_3d.h" #include "scene/3d/collision_shape_3d.h" #include "scene/3d/cpu_particles_3d.h" #include "scene/3d/decal.h" -#include "scene/3d/gi_probe.h" #include "scene/3d/gpu_particles_3d.h" #include "scene/3d/gpu_particles_collision_3d.h" -#include "scene/3d/immediate_geometry_3d.h" #include "scene/3d/light_3d.h" +#include "scene/3d/lightmap_gi.h" #include "scene/3d/lightmap_probe.h" #include "scene/3d/listener_3d.h" #include "scene/3d/mesh_instance_3d.h" @@ -208,6 +214,7 @@ #include "scene/3d/navigation_agent_3d.h" #include "scene/3d/navigation_obstacle_3d.h" #include "scene/3d/navigation_region_3d.h" +#include "scene/3d/node_3d.h" #include "scene/3d/occluder_instance_3d.h" #include "scene/3d/path_3d.h" #include "scene/3d/physics_body_3d.h" @@ -217,12 +224,14 @@ #include "scene/3d/ray_cast_3d.h" #include "scene/3d/reflection_probe.h" #include "scene/3d/remote_transform_3d.h" +#include "scene/3d/skeleton_3d.h" #include "scene/3d/skeleton_ik_3d.h" #include "scene/3d/soft_body_3d.h" #include "scene/3d/spring_arm_3d.h" #include "scene/3d/sprite_3d.h" #include "scene/3d/vehicle_body_3d.h" -#include "scene/3d/visibility_notifier_3d.h" +#include "scene/3d/visible_on_screen_notifier_3d.h" +#include "scene/3d/voxel_gi.h" #include "scene/3d/world_environment.h" #include "scene/3d/xr_nodes.h" #include "scene/resources/environment.h" @@ -252,33 +261,33 @@ void register_scene_types() { Node::init_node_hrcr(); - resource_loader_font.instance(); + resource_loader_font.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_font); #ifndef DISABLE_DEPRECATED - resource_loader_compat_font.instance(); + resource_loader_compat_font.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_compat_font); #endif /* DISABLE_DEPRECATED */ - resource_loader_stream_texture.instance(); + resource_loader_stream_texture.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_stream_texture); - resource_loader_texture_layered.instance(); + resource_loader_texture_layered.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_texture_layered); - resource_loader_texture_3d.instance(); + resource_loader_texture_3d.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_texture_3d); - resource_saver_text.instance(); + resource_saver_text.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_text, true); - resource_loader_text.instance(); + resource_loader_text.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_text, true); - resource_saver_shader.instance(); + resource_saver_shader.instantiate(); ResourceSaver::add_resource_format_saver(resource_saver_shader, true); - resource_loader_shader.instance(); + resource_loader_shader.instantiate(); ResourceLoader::add_resource_format_loader(resource_loader_shader, true); OS::get_singleton()->yield(); //may take time to init @@ -395,17 +404,15 @@ void register_scene_types() { AcceptDialog::set_swap_cancel_ok(swap_cancel_ok); #endif - /* REGISTER 3D */ - - // Needed even with _3D_DISABLED as used in animation code. - ClassDB::register_class<Node3D>(); - ClassDB::register_virtual_class<Node3DGizmo>(); - ClassDB::register_class<Skin>(); - ClassDB::register_virtual_class<SkinReference>(); - ClassDB::register_class<Skeleton3D>(); + /* REGISTER ANIMATION */ ClassDB::register_class<AnimationPlayer>(); ClassDB::register_class<Tween>(); + ClassDB::register_virtual_class<Tweener>(); + ClassDB::register_class<PropertyTweener>(); + ClassDB::register_class<IntervalTweener>(); + ClassDB::register_class<CallbackTweener>(); + ClassDB::register_class<MethodTweener>(); ClassDB::register_class<AnimationTree>(); ClassDB::register_class<AnimationNode>(); @@ -432,7 +439,14 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init + /* REGISTER 3D */ + #ifndef _3D_DISABLED + ClassDB::register_class<Node3D>(); + ClassDB::register_virtual_class<Node3DGizmo>(); + ClassDB::register_class<Skin>(); + ClassDB::register_virtual_class<SkinReference>(); + ClassDB::register_class<Skeleton3D>(); ClassDB::register_virtual_class<VisualInstance3D>(); ClassDB::register_virtual_class<GeometryInstance3D>(); ClassDB::register_class<Camera3D>(); @@ -445,7 +459,6 @@ void register_scene_types() { ClassDB::register_class<MeshInstance3D>(); ClassDB::register_class<OccluderInstance3D>(); ClassDB::register_class<Occluder3D>(); - ClassDB::register_class<ImmediateGeometry3D>(); ClassDB::register_virtual_class<SpriteBase3D>(); ClassDB::register_class<Sprite3D>(); ClassDB::register_class<AnimatedSprite3D>(); @@ -455,10 +468,10 @@ void register_scene_types() { ClassDB::register_class<SpotLight3D>(); ClassDB::register_class<ReflectionProbe>(); ClassDB::register_class<Decal>(); - ClassDB::register_class<GIProbe>(); - ClassDB::register_class<GIProbeData>(); - ClassDB::register_class<BakedLightmap>(); - ClassDB::register_class<BakedLightmapData>(); + ClassDB::register_class<VoxelGI>(); + ClassDB::register_class<VoxelGIData>(); + ClassDB::register_class<LightmapGI>(); + ClassDB::register_class<LightmapGIData>(); ClassDB::register_class<LightmapProbe>(); ClassDB::register_virtual_class<Lightmapper>(); ClassDB::register_class<GPUParticles3D>(); @@ -484,7 +497,7 @@ void register_scene_types() { ClassDB::register_class<StaticBody3D>(); ClassDB::register_class<RigidBody3D>(); ClassDB::register_class<KinematicCollision3D>(); - ClassDB::register_class<KinematicBody3D>(); + ClassDB::register_class<CharacterBody3D>(); ClassDB::register_class<SpringArm3D>(); ClassDB::register_class<PhysicalBone3D>(); @@ -505,8 +518,8 @@ void register_scene_types() { ClassDB::register_class<Curve3D>(); ClassDB::register_class<Path3D>(); ClassDB::register_class<PathFollow3D>(); - ClassDB::register_class<VisibilityNotifier3D>(); - ClassDB::register_class<VisibilityEnabler3D>(); + ClassDB::register_class<VisibleOnScreenNotifier3D>(); + ClassDB::register_class<VisibleOnScreenEnabler3D>(); ClassDB::register_class<WorldEnvironment>(); ClassDB::register_class<RemoteTransform3D>(); @@ -553,6 +566,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeVectorFunc>(); ClassDB::register_class<VisualShaderNodeColorFunc>(); ClassDB::register_class<VisualShaderNodeTransformFunc>(); + ClassDB::register_class<VisualShaderNodeUVFunc>(); ClassDB::register_class<VisualShaderNodeDotProduct>(); ClassDB::register_class<VisualShaderNodeVectorLen>(); ClassDB::register_class<VisualShaderNodeDeterminant>(); @@ -572,6 +586,7 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeTransformDecompose>(); ClassDB::register_class<VisualShaderNodeTexture>(); ClassDB::register_class<VisualShaderNodeCurveTexture>(); + ClassDB::register_class<VisualShaderNodeCurve3Texture>(); ClassDB::register_virtual_class<VisualShaderNodeSample3D>(); ClassDB::register_class<VisualShaderNodeTexture2DArray>(); ClassDB::register_class<VisualShaderNodeTexture3D>(); @@ -605,6 +620,17 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeTextureSDFNormal>(); ClassDB::register_class<VisualShaderNodeSDFRaymarch>(); + ClassDB::register_class<VisualShaderNodeParticleOutput>(); + ClassDB::register_virtual_class<VisualShaderNodeParticleEmitter>(); + ClassDB::register_class<VisualShaderNodeParticleSphereEmitter>(); + ClassDB::register_class<VisualShaderNodeParticleBoxEmitter>(); + ClassDB::register_class<VisualShaderNodeParticleRingEmitter>(); + ClassDB::register_class<VisualShaderNodeParticleMultiplyByAxisAngle>(); + ClassDB::register_class<VisualShaderNodeParticleConeVelocity>(); + ClassDB::register_class<VisualShaderNodeParticleRandomness>(); + ClassDB::register_class<VisualShaderNodeParticleAccelerator>(); + ClassDB::register_class<VisualShaderNodeParticleEmit>(); + ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); ClassDB::register_class<CanvasTexture>(); @@ -629,14 +655,14 @@ void register_scene_types() { ClassDB::register_virtual_class<PhysicsBody2D>(); ClassDB::register_class<StaticBody2D>(); ClassDB::register_class<RigidBody2D>(); - ClassDB::register_class<KinematicBody2D>(); + ClassDB::register_class<CharacterBody2D>(); ClassDB::register_class<KinematicCollision2D>(); ClassDB::register_class<Area2D>(); ClassDB::register_class<CollisionShape2D>(); ClassDB::register_class<CollisionPolygon2D>(); ClassDB::register_class<RayCast2D>(); - ClassDB::register_class<VisibilityNotifier2D>(); - ClassDB::register_class<VisibilityEnabler2D>(); + ClassDB::register_class<VisibleOnScreenNotifier2D>(); + ClassDB::register_class<VisibleOnScreenEnabler2D>(); ClassDB::register_class<Polygon2D>(); ClassDB::register_class<Skeleton2D>(); ClassDB::register_class<Bone2D>(); @@ -645,7 +671,6 @@ void register_scene_types() { ClassDB::register_class<DirectionalLight2D>(); ClassDB::register_class<LightOccluder2D>(); ClassDB::register_class<OccluderPolygon2D>(); - ClassDB::register_class<YSort>(); ClassDB::register_class<BackBufferCopy>(); OS::get_singleton()->yield(); //may take time to init @@ -666,6 +691,18 @@ void register_scene_types() { ClassDB::register_class<TouchScreenButton>(); ClassDB::register_class<RemoteTransform2D>(); + ClassDB::register_class<SkeletonModificationStack2D>(); + ClassDB::register_class<SkeletonModification2D>(); + ClassDB::register_class<SkeletonModification2DLookAt>(); + ClassDB::register_class<SkeletonModification2DCCDIK>(); + ClassDB::register_class<SkeletonModification2DFABRIK>(); + ClassDB::register_class<SkeletonModification2DJiggle>(); + ClassDB::register_class<SkeletonModification2DTwoBoneIK>(); + ClassDB::register_class<SkeletonModification2DStackHolder>(); + + ClassDB::register_class<PhysicalBone2D>(); + ClassDB::register_class<SkeletonModification2DPhysicalBones>(); + OS::get_singleton()->yield(); //may take time to init /* REGISTER RESOURCES */ @@ -681,6 +718,7 @@ void register_scene_types() { ClassDB::register_virtual_class<Mesh>(); ClassDB::register_class<ArrayMesh>(); + ClassDB::register_class<ImmediateMesh>(); ClassDB::register_class<MultiMesh>(); ClassDB::register_class<SurfaceTool>(); ClassDB::register_class<MeshDataTool>(); @@ -737,6 +775,7 @@ void register_scene_types() { ClassDB::register_class<AtlasTexture>(); ClassDB::register_class<MeshTexture>(); ClassDB::register_class<CurveTexture>(); + ClassDB::register_class<Curve3Texture>(); ClassDB::register_class<GradientTexture>(); ClassDB::register_class<ProxyTexture>(); ClassDB::register_class<AnimatedTexture>(); @@ -822,6 +861,11 @@ void register_scene_types() { ClassDB::add_compatibility_class("ToolButton", "Button"); ClassDB::add_compatibility_class("Navigation3D", "Node3D"); ClassDB::add_compatibility_class("Navigation2D", "Node2D"); + ClassDB::add_compatibility_class("YSort", "Node2D"); + ClassDB::add_compatibility_class("GIProbe", "VoxelGI"); + ClassDB::add_compatibility_class("GIProbeData", "VoxelGIData"); + ClassDB::add_compatibility_class("BakedLightmap", "LightmapGI"); + ClassDB::add_compatibility_class("BakedLightmapData", "LightmapGIData"); // Renamed in 4.0. // Keep alphabetical ordering to easily locate classes and avoid duplicates. @@ -867,7 +911,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("HingeJoint", "HingeJoint3D"); ClassDB::add_compatibility_class("ImmediateGeometry", "ImmediateGeometry3D"); ClassDB::add_compatibility_class("Joint", "Joint3D"); - ClassDB::add_compatibility_class("KinematicBody", "KinematicBody3D"); + ClassDB::add_compatibility_class("KinematicBody", "CharacterBody3D"); + ClassDB::add_compatibility_class("KinematicBody2D", "CharacterBody2D"); ClassDB::add_compatibility_class("KinematicCollision", "KinematicCollision3D"); ClassDB::add_compatibility_class("Light", "Light3D"); ClassDB::add_compatibility_class("Listener", "Listener3D"); @@ -893,14 +938,12 @@ void register_scene_types() { ClassDB::add_compatibility_class("Physics2DServerSW", "PhysicsServer2DSW"); ClassDB::add_compatibility_class("Physics2DServer", "PhysicsServer2D"); ClassDB::add_compatibility_class("Physics2DShapeQueryParameters", "PhysicsShapeQueryParameters2D"); - ClassDB::add_compatibility_class("Physics2DShapeQueryResult", "PhysicsShapeQueryResult2D"); ClassDB::add_compatibility_class("Physics2DTestMotionResult", "PhysicsTestMotionResult2D"); ClassDB::add_compatibility_class("PhysicsBody", "PhysicsBody3D"); ClassDB::add_compatibility_class("PhysicsDirectBodyState", "PhysicsDirectBodyState3D"); ClassDB::add_compatibility_class("PhysicsDirectSpaceState", "PhysicsDirectSpaceState3D"); ClassDB::add_compatibility_class("PhysicsServer", "PhysicsServer3D"); ClassDB::add_compatibility_class("PhysicsShapeQueryParameters", "PhysicsShapeQueryParameters3D"); - ClassDB::add_compatibility_class("PhysicsShapeQueryResult", "PhysicsShapeQueryResult3D"); ClassDB::add_compatibility_class("PinJoint", "PinJoint3D"); ClassDB::add_compatibility_class("PlaneShape", "WorldMarginShape3D"); ClassDB::add_compatibility_class("ProceduralSky", "Sky"); @@ -929,8 +972,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("VehicleWheel", "VehicleWheel3D"); ClassDB::add_compatibility_class("ViewportContainer", "SubViewportContainer"); ClassDB::add_compatibility_class("Viewport", "SubViewport"); - ClassDB::add_compatibility_class("VisibilityEnabler", "VisibilityEnabler3D"); - ClassDB::add_compatibility_class("VisibilityNotifier", "VisibilityNotifier3D"); + ClassDB::add_compatibility_class("VisibilityEnabler", "VisibleOnScreenEnabler3D"); + ClassDB::add_compatibility_class("VisibilityNotifier", "VisibleOnScreenNotifier3D"); ClassDB::add_compatibility_class("VisualServer", "RenderingServer"); ClassDB::add_compatibility_class("VisualShaderNodeScalarConstant", "VisualShaderNodeFloatConstant"); ClassDB::add_compatibility_class("VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc"); @@ -949,6 +992,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("World", "World3D"); ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D"); ClassDB::add_compatibility_class("Light2D", "PointLight2D"); + ClassDB::add_compatibility_class("VisibilityNotifier2D", "VisibleOnScreenNotifier2D"); + ClassDB::add_compatibility_class("VisibilityNotifier3D", "VisibleOnScreenNotifier3D"); #endif /* DISABLE_DEPRECATED */ @@ -996,9 +1041,13 @@ void register_scene_types() { } } SceneDebugger::initialize(); + + NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SCENE); } void unregister_scene_types() { + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SCENE); + SceneDebugger::deinitialize(); clear_default_theme(); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 6f64ac6d04..640ec50eb9 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -43,8 +43,8 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { if (tracks.size() == track && what == "type") { String type = p_value; - if (type == "transform") { - add_track(TYPE_TRANSFORM); + if (type == "transform" || type == "transform3d") { + add_track(TYPE_TRANSFORM3D); } else if (type == "value") { add_track(TYPE_VALUE); } else if (type == "method") { @@ -75,7 +75,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) { } else if (what == "enabled") { track_set_enabled(track, p_value); } else if (what == "keys" || what == "key_values") { - if (track_get_type(track) == TYPE_TRANSFORM) { + if (track_get_type(track) == TYPE_TRANSFORM3D) { TransformTrack *tt = static_cast<TransformTrack *>(tracks[track]); Vector<float> values = p_value; int vcount = values.size(); @@ -318,7 +318,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { ERR_FAIL_INDEX_V(track, tracks.size(), false); if (what == "type") { switch (track_get_type(track)) { - case TYPE_TRANSFORM: + case TYPE_TRANSFORM3D: r_ret = "transform"; break; case TYPE_VALUE: @@ -351,7 +351,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { } else if (what == "enabled") { r_ret = track_is_enabled(track); } else if (what == "keys") { - if (track_get_type(track) == TYPE_TRANSFORM) { + if (track_get_type(track) == TYPE_TRANSFORM3D) { Vector<float> keys; int kk = track_get_key_count(track); keys.resize(kk * 12); @@ -361,7 +361,7 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const { int idx = 0; for (int i = 0; i < track_get_key_count(track); i++) { Vector3 loc; - Quat rot; + Quaternion rot; Vector3 scale; transform_track_get_key(track, i, &loc, &rot, &scale); @@ -590,7 +590,7 @@ int Animation::add_track(TrackType p_type, int p_at_pos) { } switch (p_type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = memnew(TransformTrack); tracks.insert(p_at_pos, tt); } break; @@ -628,7 +628,7 @@ void Animation::remove_track(int p_track) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); _clear(tt->transforms); @@ -671,7 +671,7 @@ int Animation::get_track_count() const { } Animation::TrackType Animation::track_get_type(int p_track) const { - ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_TRANSFORM); + ERR_FAIL_INDEX_V(p_track, tracks.size(), TYPE_TRANSFORM3D); return tracks[p_track]->type; } @@ -773,12 +773,12 @@ void Animation::_clear(T &p_keys) { p_keys.clear(); } -Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const { +Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); Track *t = tracks[p_track]; TransformTrack *tt = static_cast<TransformTrack *>(t); - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); ERR_FAIL_INDEX_V(p_key, tt->transforms.size(), ERR_INVALID_PARAMETER); if (r_loc) { @@ -794,10 +794,10 @@ Error Animation::transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, return OK; } -int Animation::transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quat &p_rot, const Vector3 &p_scale) { +int Animation::transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quaternion &p_rot, const Vector3 &p_scale) { ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, -1); + ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, -1); TransformTrack *tt = static_cast<TransformTrack *>(t); @@ -823,7 +823,7 @@ void Animation::track_remove_key(int p_track, int p_idx) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX(p_idx, tt->transforms.size()); tt->transforms.remove(p_idx); @@ -869,7 +869,7 @@ int Animation::track_find_key(int p_track, float p_time, bool p_exact) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); int k = _find(tt->transforms, p_time); if (k < 0 || k >= tt->transforms.size()) { @@ -951,14 +951,14 @@ void Animation::track_insert_key(int p_track, float p_time, const Variant &p_key Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { Dictionary d = p_key; Vector3 loc; if (d.has("location")) { loc = d["location"]; } - Quat rot; + Quaternion rot; if (d.has("rotation")) { rot = d["rotation"]; } @@ -1053,7 +1053,7 @@ int Animation::track_get_key_count(int p_track) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); return tt->transforms.size(); } break; @@ -1088,7 +1088,7 @@ Variant Animation::track_get_key_value(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), Variant()); @@ -1156,7 +1156,7 @@ float Animation::track_get_key_time(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1); return tt->transforms[p_key_idx].time; @@ -1201,7 +1201,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, float p_time) { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); TKey<TransformKey> key = tt->transforms[p_key_idx]; @@ -1265,7 +1265,7 @@ float Animation::track_get_key_transition(int p_track, int p_key_idx) const { Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX_V(p_key_idx, tt->transforms.size(), -1); return tt->transforms[p_key_idx].transition; @@ -1301,7 +1301,7 @@ void Animation::track_set_key_value(int p_track, int p_key_idx, const Variant &p Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); @@ -1384,7 +1384,7 @@ void Animation::track_set_key_transition(int p_track, int p_key_idx, float p_tra Track *t = tracks[p_track]; switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { TransformTrack *tt = static_cast<TransformTrack *>(t); ERR_FAIL_INDEX(p_key_idx, tt->transforms.size()); tt->transforms.write[p_key_idx].transition = p_transition; @@ -1462,7 +1462,7 @@ Vector3 Animation::_interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_ return p_a.lerp(p_b, p_c); } -Quat Animation::_interpolate(const Quat &p_a, const Quat &p_b, float p_c) const { +Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b, float p_c) const { return p_a.slerp(p_b, p_c); } @@ -1490,7 +1490,7 @@ Vector3 Animation::_cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a return p_a.cubic_interpolate(p_b, p_pre_a, p_post_b, p_c); } -Quat Animation::_cubic_interpolate(const Quat &p_pre_a, const Quat &p_a, const Quat &p_b, const Quat &p_post_b, float p_c) const { +Quaternion Animation::_cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, float p_c) const { return p_a.cubic_slerp(p_b, p_pre_a, p_post_b, p_c); } @@ -1555,11 +1555,11 @@ Variant Animation::_cubic_interpolate(const Variant &p_pre_a, const Variant &p_a return a.cubic_interpolate(b, pa, pb, p_c); } - case Variant::QUAT: { - Quat a = p_a; - Quat b = p_b; - Quat pa = p_pre_a; - Quat pb = p_post_b; + case Variant::QUATERNION: { + Quaternion a = p_a; + Quaternion b = p_b; + Quaternion pa = p_pre_a; + Quaternion pb = p_post_b; return a.cubic_slerp(b, pa, pb, p_c); } @@ -1728,10 +1728,10 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola // do a barrel roll } -Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const { +Error Animation::transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const { ERR_FAIL_INDEX_V(p_track, tracks.size(), ERR_INVALID_PARAMETER); Track *t = tracks[p_track]; - ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(t->type != TYPE_TRANSFORM3D, ERR_INVALID_PARAMETER); TransformTrack *tt = static_cast<TransformTrack *>(t); @@ -1932,7 +1932,7 @@ void Animation::track_get_key_indices_in_range(int p_track, float p_time, float // handle loop by splitting switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { const TransformTrack *tt = static_cast<const TransformTrack *>(t); _track_get_key_indices_in_range(tt->transforms, from_time, length, p_indices); _track_get_key_indices_in_range(tt->transforms, 0, to_time, p_indices); @@ -1988,7 +1988,7 @@ void Animation::track_get_key_indices_in_range(int p_track, float p_time, float } switch (t->type) { - case TYPE_TRANSFORM: { + case TYPE_TRANSFORM3D: { const TransformTrack *tt = static_cast<const TransformTrack *>(t); _track_get_key_indices_in_range(tt->transforms, from_time, to_time, p_indices); @@ -2681,7 +2681,7 @@ void Animation::_bind_methods() { ADD_SIGNAL(MethodInfo("tracks_changed")); BIND_ENUM_CONSTANT(TYPE_VALUE); - BIND_ENUM_CONSTANT(TYPE_TRANSFORM); + BIND_ENUM_CONSTANT(TYPE_TRANSFORM3D); BIND_ENUM_CONSTANT(TYPE_METHOD); BIND_ENUM_CONSTANT(TYPE_BEZIER); BIND_ENUM_CONSTANT(TYPE_AUDIO); @@ -2751,9 +2751,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons { //rotation - const Quat &q0 = t0.value.rot; - const Quat &q1 = t1.value.rot; - const Quat &q2 = t2.value.rot; + const Quaternion &q0 = t0.value.rot; + const Quaternion &q1 = t1.value.rot; + const Quaternion &q2 = t2.value.rot; //localize both to rotation from q0 @@ -2763,8 +2763,8 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons } } else { - Quat r02 = (q0.inverse() * q2).normalized(); - Quat r01 = (q0.inverse() * q1).normalized(); + Quaternion r02 = (q0.inverse() * q2).normalized(); + Quaternion r01 = (q0.inverse() * q1).normalized(); Vector3 v02, v01; real_t a02, a01; @@ -2877,7 +2877,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err, float p_allowed_angular_err, float p_max_optimizable_angle) { ERR_FAIL_INDEX(p_idx, tracks.size()); - ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM); + ERR_FAIL_COND(tracks[p_idx]->type != TYPE_TRANSFORM3D); TransformTrack *tt = static_cast<TransformTrack *>(tracks[p_idx]); bool prev_erased = false; TKey<TransformKey> first_erased; @@ -2917,7 +2917,7 @@ void Animation::_transform_track_optimize(int p_idx, float p_allowed_linear_err, void Animation::optimize(float p_allowed_linear_err, float p_allowed_angular_err, float p_max_optimizable_angle) { for (int i = 0; i < tracks.size(); i++) { - if (tracks[i]->type == TYPE_TRANSFORM) { + if (tracks[i]->type == TYPE_TRANSFORM3D) { _transform_track_optimize(i, p_allowed_linear_err, p_allowed_angular_err, p_max_optimizable_angle); } } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 66bc71c834..1484007333 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -42,7 +42,7 @@ class Animation : public Resource { public: enum TrackType { TYPE_VALUE, ///< Set a value in a property, can be interpolated. - TYPE_TRANSFORM, ///< Transform a node or a bone. + TYPE_TRANSFORM3D, ///< Transform a node or a bone. TYPE_METHOD, ///< Call any method on a specific node. TYPE_BEZIER, ///< Bezier curve TYPE_AUDIO, @@ -88,7 +88,7 @@ private: struct TransformKey { Vector3 loc; - Quat rot; + Quaternion rot; Vector3 scale; }; @@ -97,7 +97,7 @@ private: struct TransformTrack : public Track { Vector<TKey<TransformKey>> transforms; - TransformTrack() { type = TYPE_TRANSFORM; } + TransformTrack() { type = TYPE_TRANSFORM3D; } }; /* PROPERTY VALUE TRACK */ @@ -186,13 +186,13 @@ private: _FORCE_INLINE_ Animation::TransformKey _interpolate(const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, float p_c) const; _FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, float p_c) const; - _FORCE_INLINE_ Quat _interpolate(const Quat &p_a, const Quat &p_b, float p_c) const; + _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, float p_c) const; _FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, float p_c) const; _FORCE_INLINE_ float _interpolate(const float &p_a, const float &p_b, float p_c) const; _FORCE_INLINE_ Animation::TransformKey _cubic_interpolate(const Animation::TransformKey &p_pre_a, const Animation::TransformKey &p_a, const Animation::TransformKey &p_b, const Animation::TransformKey &p_post_b, float p_c) const; _FORCE_INLINE_ Vector3 _cubic_interpolate(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, float p_c) const; - _FORCE_INLINE_ Quat _cubic_interpolate(const Quat &p_pre_a, const Quat &p_a, const Quat &p_b, const Quat &p_post_b, float p_c) const; + _FORCE_INLINE_ Quaternion _cubic_interpolate(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, float p_c) const; _FORCE_INLINE_ Variant _cubic_interpolate(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, float p_c) const; _FORCE_INLINE_ float _cubic_interpolate(const float &p_pre_a, const float &p_a, const float &p_b, const float &p_post_b, float p_c) const; @@ -213,7 +213,7 @@ private: private: Array _transform_track_interpolate(int p_track, float p_time) const { Vector3 loc; - Quat rot; + Quaternion rot; Vector3 scale; transform_track_interpolate(p_track, p_time, &loc, &rot, &scale); Array ret; @@ -291,8 +291,8 @@ public: float track_get_key_time(int p_track, int p_key_idx) const; float track_get_key_transition(int p_track, int p_key_idx) const; - int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quat &p_rot = Quat(), const Vector3 &p_scale = Vector3()); - Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const; + int transform_track_insert_key(int p_track, float p_time, const Vector3 &p_loc, const Quaternion &p_rot = Quaternion(), const Vector3 &p_scale = Vector3()); + Error transform_track_get_key(int p_track, int p_key, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; void track_set_interpolation_type(int p_track, InterpolationType p_interp); InterpolationType track_get_interpolation_type(int p_track) const; @@ -321,7 +321,7 @@ public: void track_set_interpolation_loop_wrap(int p_track, bool p_enable); bool track_get_interpolation_loop_wrap(int p_track) const; - Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quat *r_rot, Vector3 *r_scale) const; + Error transform_track_interpolate(int p_track, float p_time, Vector3 *r_loc, Quaternion *r_rot, Vector3 *r_scale) const; Variant value_track_interpolate(int p_track, float p_time) const; void value_track_get_key_indices(int p_track, float p_time, float p_delta, List<int> *p_indices) const; diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 9a9f019dda..8ffd2df112 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -30,8 +30,8 @@ #include "audio_stream_sample.h" +#include "core/io/file_access.h" #include "core/io/marshalls.h" -#include "core/os/file_access.h" void AudioStreamPlaybackSample::start(float p_from_pos) { if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM) { @@ -596,7 +596,7 @@ Error AudioStreamSample::save_to_wav(const String &p_path) { Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() { Ref<AudioStreamPlaybackSample> sample; - sample.instance(); + sample.instantiate(); sample->base = Ref<AudioStreamSample>(this); return sample; } diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index 0ffeb8a5bf..de557494c3 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -487,7 +487,7 @@ Vector<Vector<Vector2>> BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, flo Point2i from; Ref<BitMap> fill; - fill.instance(); + fill.instantiate(); fill->create(get_size()); Vector<Vector<Vector2>> polygons; @@ -525,7 +525,7 @@ void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) { Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect); Ref<BitMap> copy; - copy.instance(); + copy.instantiate(); copy->create(get_size()); copy->bitmask = bitmask; @@ -604,7 +604,7 @@ Array BitMap::_opaque_to_polygons_bind(const Rect2 &p_rect, float p_epsilon) con void BitMap::resize(const Size2 &p_new_size) { Ref<BitMap> new_bitmap; - new_bitmap.instance(); + new_bitmap.instantiate(); new_bitmap->create(p_new_size); int lw = MIN(width, p_new_size.width); int lh = MIN(height, p_new_size.height); @@ -621,7 +621,7 @@ void BitMap::resize(const Size2 &p_new_size) { Ref<Image> BitMap::convert_to_image() const { Ref<Image> image; - image.instance(); + image.instantiate(); image->create(width, height, false, Image::FORMAT_L8); for (int i = 0; i < width; i++) { diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index 6e7adc0bd7..008914c5ee 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -56,6 +56,26 @@ void BoxShape3D::_update_shape() { Shape3D::_update_shape(); } +#ifndef DISABLE_DEPRECATED +bool BoxShape3D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "extents") { // Compatibility with Godot 3.x. + // Convert to `size`, twice as big. + set_size((Vector3)p_value * 2); + return true; + } + return false; +} + +bool BoxShape3D::_get(const StringName &p_name, Variant &r_property) const { + if (p_name == "extents") { // Compatibility with Godot 3.x. + // Convert to `extents`, half as big. + r_property = size / 2; + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + void BoxShape3D::set_size(const Vector3 &p_size) { size = p_size; _update_shape(); diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h index fce05d61ed..91978a0e6a 100644 --- a/scene/resources/box_shape_3d.h +++ b/scene/resources/box_shape_3d.h @@ -39,6 +39,10 @@ class BoxShape3D : public Shape3D { protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_property) const; +#endif // DISABLE_DEPRECATED virtual void _update_shape() override; diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp index 34c6bc05bc..b633196424 100644 --- a/scene/resources/camera_effects.cpp +++ b/scene/resources/camera_effects.cpp @@ -175,11 +175,11 @@ void CameraEffects::_bind_methods() { ADD_GROUP("DOF Blur", "dof_blur_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_far_enabled"), "set_dof_blur_far_enabled", "is_dof_blur_far_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_distance", "get_dof_blur_far_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_far_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_far_transition", "get_dof_blur_far_transition"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dof_blur_near_enabled"), "set_dof_blur_near_enabled", "is_dof_blur_near_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_EXP_RANGE, "0.01,8192,0.01"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_distance", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_distance", "get_dof_blur_near_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_near_transition", PROPERTY_HINT_RANGE, "0.01,8192,0.01,exp"), "set_dof_blur_near_transition", "get_dof_blur_near_transition"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "dof_blur_amount", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_dof_blur_amount", "get_dof_blur_amount"); // Override exposure diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index b91a5c0b7f..5464a46df4 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -445,7 +445,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1)); theme->set_color("selection_color", "TextEdit", control_selection_color); - theme->set_color("code_folding_color", "TextEdit", Color(0.8, 0.8, 0.8, 0.8)); theme->set_color("current_line_color", "TextEdit", Color(0.25, 0.25, 0.26, 0.8)); theme->set_color("caret_color", "TextEdit", control_font_color); theme->set_color("caret_background_color", "TextEdit", Color(0, 0, 0)); @@ -469,6 +468,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("executing_line", "CodeEdit", make_icon(arrow_right_png)); theme->set_icon("can_fold", "CodeEdit", make_icon(arrow_down_png)); theme->set_icon("folded", "CodeEdit", make_icon(arrow_right_png)); + theme->set_icon("folded_eol_icon", "CodeEdit", make_icon(ellipsis_png)); theme->set_font("font", "CodeEdit", Ref<Font>()); theme->set_font_size("font_size", "CodeEdit", -1); @@ -487,8 +487,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("bookmark_color", "CodeEdit", Color(0.5, 0.64, 1, 0.8)); theme->set_color("breakpoint_color", "CodeEdit", Color(0.9, 0.29, 0.3)); theme->set_color("executing_line_color", "CodeEdit", Color(0.98, 0.89, 0.27)); - theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8)); theme->set_color("current_line_color", "CodeEdit", Color(0.25, 0.25, 0.26, 0.8)); + theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8)); theme->set_color("caret_color", "CodeEdit", control_font_color); theme->set_color("caret_background_color", "CodeEdit", Color(0, 0, 0)); theme->set_color("brace_mismatch_color", "CodeEdit", Color(1, 0.2, 0.2)); @@ -559,7 +559,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // ScrollContainer Ref<StyleBoxEmpty> empty; - empty.instance(); + empty.instantiate(); theme->set_stylebox("bg", "ScrollContainer", empty); // WindowDialog @@ -979,7 +979,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const void make_default_theme(bool p_hidpi, Ref<Font> p_font) { Ref<Theme> t; - t.instance(); + t.instantiate(); Ref<StyleBox> default_style; Ref<Texture2D> default_icon; @@ -993,10 +993,10 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { // The default DynamicFont is chosen to have a small file size since it's // embedded in both editor and export template binaries. Ref<Font> dynamic_font; - dynamic_font.instance(); + dynamic_font.instantiate(); Ref<FontData> dynamic_font_data; - dynamic_font_data.instance(); + dynamic_font_data.instantiate(); dynamic_font_data->load_memory(_font_OpenSans_SemiBold, _font_OpenSans_SemiBold_size, "ttf", default_font_size); dynamic_font->add_data(dynamic_font_data); diff --git a/scene/resources/default_theme/ellipsis.png b/scene/resources/default_theme/ellipsis.png Binary files differnew file mode 100644 index 0000000000..c949e2c95b --- /dev/null +++ b/scene/resources/default_theme/ellipsis.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 190f2a03d9..7d747e3c9e 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -74,6 +74,10 @@ static const unsigned char dropdown_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x4, 0x0, 0x0, 0x0, 0x6e, 0x6, 0x76, 0x0, 0x0, 0x0, 0x0, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x60, 0x60, 0xf8, 0xc0, 0xcc, 0x0, 0x2, 0x60, 0x16, 0x98, 0x78, 0x67, 0x8, 0x81, 0x6f, 0x4d, 0xde, 0x9a, 0x0, 0x5, 0xde, 0x3a, 0x3d, 0xfc, 0x8f, 0x80, 0xaf, 0xba, 0x18, 0xde, 0x29, 0x2, 0x19, 0xbf, 0x61, 0x2, 0x6f, 0x62, 0x18, 0x3e, 0xb0, 0xbd, 0x97, 0x4, 0x32, 0xff, 0x80, 0xb9, 0xb1, 0x20, 0x93, 0xc0, 0x42, 0x8, 0x2e, 0x54, 0xe8, 0x9d, 0xdc, 0x9b, 0x54, 0x10, 0xb, 0x21, 0xc4, 0x4, 0x63, 0x1, 0x0, 0x86, 0x1f, 0x3b, 0x1e, 0x92, 0x22, 0x3f, 0x40, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char ellipsis_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0xe, 0x0, 0x0, 0x0, 0x8, 0x8, 0x6, 0x0, 0x0, 0x0, 0xc9, 0x11, 0xce, 0xcc, 0x0, 0x0, 0x0, 0x4, 0x73, 0x42, 0x49, 0x54, 0x8, 0x8, 0x8, 0x8, 0x7c, 0x8, 0x64, 0x88, 0x0, 0x0, 0x0, 0x78, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x95, 0xd1, 0x31, 0xa, 0xc2, 0x50, 0x10, 0x4, 0xd0, 0xb7, 0x1f, 0xf, 0x60, 0x67, 0xa, 0xf, 0x12, 0x6f, 0x60, 0xe9, 0x51, 0x5, 0x3d, 0x44, 0xee, 0x61, 0xa1, 0xa5, 0xf6, 0x81, 0xb5, 0xc8, 0x47, 0x82, 0x84, 0x4f, 0xb2, 0xdd, 0xb0, 0x33, 0xb3, 0xb3, 0x4c, 0x40, 0x66, 0xee, 0x71, 0xc2, 0x1, 0x3b, 0xcb, 0x33, 0xe2, 0x85, 0x21, 0x22, 0xde, 0x51, 0x45, 0x97, 0x86, 0x60, 0xc9, 0xe0, 0x5a, 0xea, 0xa5, 0xb5, 0x22, 0x95, 0xdb, 0x97, 0x1a, 0xf, 0x6e, 0xb8, 0xcf, 0x8, 0x2d, 0xdc, 0x95, 0xd9, 0x22, 0xfe, 0x9c, 0x9b, 0x38, 0x32, 0xf3, 0x8c, 0xe3, 0x86, 0xa8, 0xf0, 0x28, 0x18, 0x4c, 0xf, 0xaf, 0x9d, 0x11, 0x43, 0xf0, 0xab, 0xa3, 0x47, 0xa7, 0x5d, 0xc7, 0xd3, 0x54, 0xc7, 0xe7, 0xb, 0xb9, 0xce, 0x1f, 0xc6, 0x2d, 0x99, 0x55, 0xc7, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char error_icon_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0xb5, 0xfa, 0x37, 0xea, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x2, 0x62, 0x4b, 0x47, 0x44, 0x0, 0xff, 0x87, 0x8f, 0xcc, 0xbf, 0x0, 0x0, 0x0, 0xe, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0x60, 0x18, 0x5, 0xa3, 0x0, 0x1, 0x0, 0x2, 0x10, 0x0, 0x1, 0x14, 0xc2, 0xc0, 0x92, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index c04b271d81..8550af8bcb 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -1329,7 +1329,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_density", PROPERTY_HINT_RANGE, "0,1,0.0001,or_greater"), "set_volumetric_fog_density", "get_volumetric_fog_density"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "volumetric_fog_light", PROPERTY_HINT_COLOR_NO_ALPHA), "set_volumetric_fog_light", "get_volumetric_fog_light"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_light_energy", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_light_energy", "get_volumetric_fog_light_energy"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_EXP_RANGE, "0.00,16,0.01"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_gi_inject", PROPERTY_HINT_RANGE, "0.00,16,0.01,exp"), "set_volumetric_fog_gi_inject", "get_volumetric_fog_gi_inject"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_length", PROPERTY_HINT_RANGE, "0,1024,0.01,or_greater"), "set_volumetric_fog_length", "get_volumetric_fog_length"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_detail_spread", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_volumetric_fog_detail_spread", "get_volumetric_fog_detail_spread"); ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 6f87c524d8..032171847d 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -813,7 +813,7 @@ Size2 Font::get_string_size(const String &p_text, int p_size) const { if (cache.has(hash)) { buffer = cache.get(hash); } else { - buffer.instance(); + buffer.instantiate(); int size = p_size <= 0 ? data[0]->get_base_size() : p_size; buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); cache.insert(hash, buffer); @@ -838,7 +838,7 @@ Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p if (cache_wrap.has(wrp_hash)) { lines_buffer = cache_wrap.get(wrp_hash); } else { - lines_buffer.instance(); + lines_buffer.instantiate(); int size = p_size <= 0 ? data[0]->get_base_size() : p_size; lines_buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); lines_buffer->set_width(p_width); @@ -870,7 +870,7 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t if (cache.has(hash)) { buffer = cache.get(hash); } else { - buffer.instance(); + buffer.instantiate(); int size = p_size <= 0 ? data[0]->get_base_size() : p_size; buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); cache.insert(hash, buffer); @@ -905,7 +905,7 @@ void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const S if (cache_wrap.has(wrp_hash)) { lines_buffer = cache_wrap.get(wrp_hash); } else { - lines_buffer.instance(); + lines_buffer.instantiate(); int size = p_size <= 0 ? data[0]->get_base_size() : p_size; lines_buffer->add_string(p_text, Ref<Font>(this), size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale()); lines_buffer->set_width(p_width); @@ -1041,7 +1041,7 @@ RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_origina } Ref<FontData> dfont; - dfont.instance(); + dfont.instantiate(); dfont->load_resource(p_path); if (r_error) { @@ -1096,11 +1096,11 @@ RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_o } Ref<FontData> dfont; - dfont.instance(); + dfont.instantiate(); dfont->load_resource(p_path); Ref<Font> font; - font.instance(); + font.instantiate(); font->add_data(dfont); if (r_error) { diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp new file mode 100644 index 0000000000..ebe65605f8 --- /dev/null +++ b/scene/resources/immediate_mesh.cpp @@ -0,0 +1,416 @@ +/*************************************************************************/ +/* immediate_mesh.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "immediate_mesh.h" + +void ImmediateMesh::surface_begin(PrimitiveType p_primitive, const Ref<Material> &p_material) { + ERR_FAIL_COND_MSG(surface_active, "Already creating a new surface."); + active_surface_data.primitive = p_primitive; + active_surface_data.material = p_material; + surface_active = true; +} +void ImmediateMesh::surface_set_color(const Color &p_color) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + + if (!uses_colors) { + colors.resize(vertices.size()); + for (uint32_t i = 0; i < colors.size(); i++) { + colors[i] = p_color; + } + uses_colors = true; + } + + current_color = p_color; +} +void ImmediateMesh::surface_set_normal(const Vector3 &p_normal) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + + if (!uses_normals) { + normals.resize(vertices.size()); + for (uint32_t i = 0; i < normals.size(); i++) { + normals[i] = p_normal; + } + uses_normals = true; + } + + current_normal = p_normal; +} +void ImmediateMesh::surface_set_tangent(const Plane &p_tangent) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + if (!uses_tangents) { + tangents.resize(vertices.size()); + for (uint32_t i = 0; i < tangents.size(); i++) { + tangents[i] = p_tangent; + } + uses_tangents = true; + } + + current_tangent = p_tangent; +} +void ImmediateMesh::surface_set_uv(const Vector2 &p_uv) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + if (!uses_uvs) { + uvs.resize(vertices.size()); + for (uint32_t i = 0; i < uvs.size(); i++) { + uvs[i] = p_uv; + } + uses_uvs = true; + } + + current_uv = p_uv; +} +void ImmediateMesh::surface_set_uv2(const Vector2 &p_uv2) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + if (!uses_uv2s) { + uv2s.resize(vertices.size()); + for (uint32_t i = 0; i < uv2s.size(); i++) { + uv2s[i] = p_uv2; + } + uses_uv2s = true; + } + + current_uv2 = p_uv2; +} +void ImmediateMesh::surface_add_vertex(const Vector3 &p_vertex) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + ERR_FAIL_COND_MSG(vertices.size() && active_surface_data.vertex_2d, "Can't mix 2D and 3D vertices in a surface."); + + if (uses_colors) { + colors.push_back(current_color); + } + if (uses_normals) { + normals.push_back(current_normal); + } + if (uses_tangents) { + tangents.push_back(current_tangent); + } + if (uses_uvs) { + uvs.push_back(current_uv); + } + if (uses_uv2s) { + uv2s.push_back(current_uv2); + } + vertices.push_back(p_vertex); +} + +void ImmediateMesh::surface_add_vertex_2d(const Vector2 &p_vertex) { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + ERR_FAIL_COND_MSG(vertices.size() && !active_surface_data.vertex_2d, "Can't mix 2D and 3D vertices in a surface."); + + if (uses_colors) { + colors.push_back(current_color); + } + if (uses_normals) { + normals.push_back(current_normal); + } + if (uses_tangents) { + tangents.push_back(current_tangent); + } + if (uses_uvs) { + uvs.push_back(current_uv); + } + if (uses_uv2s) { + uv2s.push_back(current_uv2); + } + Vector3 v(p_vertex.x, p_vertex.y, 0); + vertices.push_back(v); + + active_surface_data.vertex_2d = true; +} +void ImmediateMesh::surface_end() { + ERR_FAIL_COND_MSG(!surface_active, "Not creating any surface. Use surface_begin() to do it."); + ERR_FAIL_COND_MSG(!vertices.size(), "No vertices were added, surface cant be created."); + + uint32_t format = ARRAY_FORMAT_VERTEX; + + uint32_t vertex_stride = 0; + if (active_surface_data.vertex_2d) { + format |= ARRAY_FLAG_USE_2D_VERTICES; + vertex_stride = sizeof(float) * 2; + } else { + vertex_stride = sizeof(float) * 3; + } + + uint32_t normal_offset = 0; + if (uses_normals) { + format |= ARRAY_FORMAT_NORMAL; + normal_offset = vertex_stride; + vertex_stride += sizeof(uint32_t); + } + uint32_t tangent_offset = 0; + if (uses_tangents) { + format |= ARRAY_FORMAT_TANGENT; + tangent_offset += vertex_stride; + vertex_stride += sizeof(uint32_t); + } + + AABB aabb; + + { + surface_vertex_create_cache.resize(vertex_stride * vertices.size()); + uint8_t *surface_vertex_ptr = surface_vertex_create_cache.ptrw(); + for (uint32_t i = 0; i < vertices.size(); i++) { + { + float *vtx = (float *)&surface_vertex_ptr[i * vertex_stride]; + vtx[0] = vertices[i].x; + vtx[1] = vertices[i].y; + if (!active_surface_data.vertex_2d) { + vtx[2] = vertices[i].z; + } + if (i == 0) { + aabb.position = vertices[i]; + } else { + aabb.expand_to(vertices[i]); + } + } + if (uses_normals) { + uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + normal_offset]; + + Vector3 n = normals[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5); + + uint32_t value = 0; + value |= CLAMP(int(n.x * 1023.0), 0, 1023); + value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10; + value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20; + + *normal = value; + } + if (uses_tangents) { + uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + tangent_offset]; + Plane t = tangents[i]; + uint32_t value = 0; + value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023); + value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; + value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; + if (t.d > 0) { + value |= 3 << 30; + } + + *tangent = value; + } + } + } + + if (uses_colors || uses_uvs || uses_uv2s) { + uint32_t attribute_stride = 0; + + if (uses_colors) { + format |= ARRAY_FORMAT_COLOR; + attribute_stride += sizeof(uint8_t) * 4; + } + uint32_t uv_offset = 0; + if (uses_uvs) { + format |= ARRAY_FORMAT_TEX_UV; + uv_offset = attribute_stride; + attribute_stride += sizeof(float) * 2; + } + uint32_t uv2_offset = 0; + if (uses_uv2s) { + format |= ARRAY_FORMAT_TEX_UV2; + uv2_offset = attribute_stride; + attribute_stride += sizeof(float) * 2; + } + + surface_attribute_create_cache.resize(vertices.size() * attribute_stride); + + uint8_t *surface_attribute_ptr = surface_attribute_create_cache.ptrw(); + + for (uint32_t i = 0; i < vertices.size(); i++) { + if (uses_colors) { + uint8_t *color8 = (uint8_t *)&surface_attribute_ptr[i * attribute_stride]; + + color8[0] = uint8_t(CLAMP(colors[i].r * 255.0, 0.0, 255.0)); + color8[1] = uint8_t(CLAMP(colors[i].g * 255.0, 0.0, 255.0)); + color8[2] = uint8_t(CLAMP(colors[i].b * 255.0, 0.0, 255.0)); + color8[3] = uint8_t(CLAMP(colors[i].a * 255.0, 0.0, 255.0)); + } + if (uses_uvs) { + float *uv = (float *)&surface_attribute_ptr[i * attribute_stride + uv_offset]; + + uv[0] = uvs[i].x; + uv[1] = uvs[i].y; + } + + if (uses_uv2s) { + float *uv2 = (float *)&surface_attribute_ptr[i * attribute_stride + uv2_offset]; + + uv2[0] = uv2s[i].x; + uv2[1] = uv2s[i].y; + } + } + } + + RS::SurfaceData sd; + + sd.primitive = RS::PrimitiveType(active_surface_data.primitive); + sd.format = format; + sd.vertex_data = surface_vertex_create_cache; + if (uses_colors || uses_uvs || uses_uv2s) { + sd.attribute_data = surface_attribute_create_cache; + } + sd.vertex_count = vertices.size(); + sd.aabb = aabb; + if (active_surface_data.material.is_valid()) { + sd.material = active_surface_data.material->get_rid(); + } + + RS::get_singleton()->mesh_add_surface(mesh, sd); + + active_surface_data.aabb = aabb; + + active_surface_data.format = format; + active_surface_data.array_len = vertices.size(); + + surfaces.push_back(active_surface_data); + + colors.clear(); + normals.clear(); + tangents.clear(); + uvs.clear(); + uv2s.clear(); + vertices.clear(); + + uses_colors = false; + uses_normals = false; + uses_tangents = false; + uses_uvs = false; + uses_uv2s = false; + + surface_active = false; +} + +void ImmediateMesh::clear_surfaces() { + RS::get_singleton()->mesh_clear(mesh); + surfaces.clear(); + surface_active = false; + + colors.clear(); + normals.clear(); + tangents.clear(); + uvs.clear(); + uv2s.clear(); + vertices.clear(); + + uses_colors = false; + uses_normals = false; + uses_tangents = false; + uses_uvs = false; + uses_uv2s = false; +} + +int ImmediateMesh::get_surface_count() const { + return surfaces.size(); +} +int ImmediateMesh::surface_get_array_len(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), -1); + return surfaces[p_idx].array_len; +} +int ImmediateMesh::surface_get_array_index_len(int p_idx) const { + return 0; +} +bool ImmediateMesh::surface_is_softbody_friendly(int p_idx) const { + return false; +} +Array ImmediateMesh::surface_get_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, int(surfaces.size()), Array()); + return RS::get_singleton()->mesh_surface_get_arrays(mesh, p_surface); +} +Array ImmediateMesh::surface_get_blend_shape_arrays(int p_surface) const { + return Array(); +} +Dictionary ImmediateMesh::surface_get_lods(int p_surface) const { + return Dictionary(); +} +uint32_t ImmediateMesh::surface_get_format(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), 0); + return surfaces[p_idx].format; +} +Mesh::PrimitiveType ImmediateMesh::surface_get_primitive_type(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), PRIMITIVE_MAX); + return surfaces[p_idx].primitive; +} +void ImmediateMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) { + ERR_FAIL_INDEX(p_idx, int(surfaces.size())); + surfaces[p_idx].material = p_material; + RID mat; + if (p_material.is_valid()) { + mat = p_material->get_rid(); + } + RS::get_singleton()->mesh_surface_set_material(mesh, p_idx, mat); +} +Ref<Material> ImmediateMesh::surface_get_material(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, int(surfaces.size()), Ref<Material>()); + return surfaces[p_idx].material; +} +int ImmediateMesh::get_blend_shape_count() const { + return 0; +} +StringName ImmediateMesh::get_blend_shape_name(int p_index) const { + return StringName(); +} +void ImmediateMesh::set_blend_shape_name(int p_index, const StringName &p_name) { +} + +AABB ImmediateMesh::get_aabb() const { + AABB aabb; + for (uint32_t i = 0; i < surfaces.size(); i++) { + if (i == 0) { + aabb = surfaces[i].aabb; + } else { + aabb.merge(surfaces[i].aabb); + } + } + return aabb; +} + +void ImmediateMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("surface_begin", "primitive", "material"), &ImmediateMesh::surface_begin, DEFVAL(Ref<Material>())); + ClassDB::bind_method(D_METHOD("surface_set_color", "color"), &ImmediateMesh::surface_set_color); + ClassDB::bind_method(D_METHOD("surface_set_normal", "normal"), &ImmediateMesh::surface_set_normal); + ClassDB::bind_method(D_METHOD("surface_set_tangent", "tangent"), &ImmediateMesh::surface_set_tangent); + ClassDB::bind_method(D_METHOD("surface_set_uv", "uv"), &ImmediateMesh::surface_set_uv); + ClassDB::bind_method(D_METHOD("surface_set_uv2", "uv2"), &ImmediateMesh::surface_set_uv2); + ClassDB::bind_method(D_METHOD("surface_add_vertex", "vertex"), &ImmediateMesh::surface_add_vertex); + ClassDB::bind_method(D_METHOD("surface_add_vertex_2d", "vertex"), &ImmediateMesh::surface_add_vertex_2d); + ClassDB::bind_method(D_METHOD("surface_end"), &ImmediateMesh::surface_end); + + ClassDB::bind_method(D_METHOD("clear_surfaces"), &ImmediateMesh::clear_surfaces); +} + +RID ImmediateMesh::get_rid() const { + return mesh; +} + +ImmediateMesh::ImmediateMesh() { + mesh = RS::get_singleton()->mesh_create(); +} +ImmediateMesh::~ImmediateMesh() { + RS::get_singleton()->free(mesh); +} diff --git a/scene/resources/immediate_mesh.h b/scene/resources/immediate_mesh.h new file mode 100644 index 0000000000..7010d40719 --- /dev/null +++ b/scene/resources/immediate_mesh.h @@ -0,0 +1,117 @@ +/*************************************************************************/ +/* immediate_mesh.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef IMMEDIATE_MESH_H +#define IMMEDIATE_MESH_H + +#include "core/templates/local_vector.h" +#include "scene/resources/mesh.h" + +class ImmediateMesh : public Mesh { + GDCLASS(ImmediateMesh, Mesh) + + RID mesh; + + bool uses_colors = false; + bool uses_normals = false; + bool uses_tangents = false; + bool uses_uvs = false; + bool uses_uv2s = false; + + Color current_color; + Vector3 current_normal; + Plane current_tangent; + Vector2 current_uv; + Vector2 current_uv2; + + LocalVector<Color> colors; + LocalVector<Vector3> normals; + LocalVector<Plane> tangents; + LocalVector<Vector2> uvs; + LocalVector<Vector2> uv2s; + LocalVector<Vector3> vertices; + + struct Surface { + PrimitiveType primitive; + Ref<Material> material; + bool vertex_2d = false; + int array_len = 0; + uint32_t format = 0; + AABB aabb; + }; + + LocalVector<Surface> surfaces; + + bool surface_active = false; + Surface active_surface_data; + + Vector<uint8_t> surface_vertex_create_cache; + Vector<uint8_t> surface_attribute_create_cache; + +protected: + static void _bind_methods(); + +public: + void surface_begin(PrimitiveType p_primitive, const Ref<Material> &p_material = Ref<Material>()); + void surface_set_color(const Color &p_color); + void surface_set_normal(const Vector3 &p_normal); + void surface_set_tangent(const Plane &p_tangent); + void surface_set_uv(const Vector2 &p_uv); + void surface_set_uv2(const Vector2 &p_uv2); + void surface_add_vertex(const Vector3 &p_vertex); + void surface_add_vertex_2d(const Vector2 &p_vertex); + void surface_end(); + + void clear_surfaces(); + + virtual int get_surface_count() const override; + virtual int surface_get_array_len(int p_idx) const override; + virtual int surface_get_array_index_len(int p_idx) const override; + virtual bool surface_is_softbody_friendly(int p_idx) const override; + virtual Array surface_get_arrays(int p_surface) const override; + virtual Array surface_get_blend_shape_arrays(int p_surface) const override; + virtual Dictionary surface_get_lods(int p_surface) const override; + virtual uint32_t surface_get_format(int p_idx) const override; + virtual PrimitiveType surface_get_primitive_type(int p_idx) const override; + virtual void surface_set_material(int p_idx, const Ref<Material> &p_material) override; + virtual Ref<Material> surface_get_material(int p_idx) const override; + virtual int get_blend_shape_count() const override; + virtual StringName get_blend_shape_name(int p_index) const override; + virtual void set_blend_shape_name(int p_index, const StringName &p_name) override; + + virtual AABB get_aabb() const override; + + virtual RID get_rid() const override; + + ImmediateMesh(); + ~ImmediateMesh(); +}; + +#endif // IMMEDIATEMESH_H diff --git a/scene/resources/line_shape_2d.h b/scene/resources/line_shape_2d.h index 9f0405ad29..210a1aa9e6 100644 --- a/scene/resources/line_shape_2d.h +++ b/scene/resources/line_shape_2d.h @@ -36,7 +36,8 @@ class LineShape2D : public Shape2D { GDCLASS(LineShape2D, Shape2D); - Vector2 normal = Vector2(0, 1); + // LineShape2D is often used for one-way platforms, where the normal pointing up makes sense. + Vector2 normal = Vector2(0, -1); real_t distance = 0.0; void _update_shape(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 100fccc783..a264c2d1eb 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -77,7 +77,7 @@ RID Material::get_rid() const { void Material::_validate_property(PropertyInfo &property) const { if (!_can_do_next_pass() && property.name == "next_pass") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -130,7 +130,7 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) { } } if (pr) { - RenderingServer::get_singleton()->material_set_param(_get_material(), pr, p_value); + set_shader_param(pr, p_value); return true; } } @@ -152,7 +152,12 @@ bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const { } if (pr) { - r_ret = RenderingServer::get_singleton()->material_get_param(_get_material(), pr); + const Map<StringName, Variant>::Element *E = param_cache.find(pr); + if (E) { + r_ret = E->get(); + } else { + r_ret = Variant(); + } return true; } } @@ -219,11 +224,31 @@ Ref<Shader> ShaderMaterial::get_shader() const { } void ShaderMaterial::set_shader_param(const StringName &p_param, const Variant &p_value) { - RS::get_singleton()->material_set_param(_get_material(), p_param, p_value); + if (p_value.get_type() == Variant::NIL) { + param_cache.erase(p_param); + RS::get_singleton()->material_set_param(_get_material(), p_param, Variant()); + } else { + param_cache[p_param] = p_value; + if (p_value.get_type() == Variant::OBJECT) { + RID tex_rid = p_value; + if (tex_rid == RID()) { + param_cache.erase(p_param); + RS::get_singleton()->material_set_param(_get_material(), p_param, Variant()); + } else { + RS::get_singleton()->material_set_param(_get_material(), p_param, tex_rid); + } + } else { + RS::get_singleton()->material_set_param(_get_material(), p_param, p_value); + } + } } Variant ShaderMaterial::get_shader_param(const StringName &p_param) const { - return RS::get_singleton()->material_get_param(_get_material(), p_param); + if (param_cache.has(p_param)) { + return param_cache[p_param]; + } else { + return Variant(); + } } void ShaderMaterial::_shader_changed() { @@ -345,7 +370,6 @@ void BaseMaterial3D::init_shaders() { shader_names->refraction_texture_channel = "refraction_texture_channel"; shader_names->transmittance_color = "transmittance_color"; - shader_names->transmittance_curve = "transmittance_curve"; shader_names->transmittance_depth = "transmittance_depth"; shader_names->transmittance_boost = "transmittance_boost"; @@ -505,9 +529,6 @@ void BaseMaterial3D::_update_shader() { case DIFFUSE_LAMBERT_WRAP: code += ",diffuse_lambert_wrap"; break; - case DIFFUSE_OREN_NAYAR: - code += ",diffuse_oren_nayar"; - break; case DIFFUSE_TOON: code += ",diffuse_toon"; break; @@ -695,7 +716,6 @@ void BaseMaterial3D::_update_shader() { code += "uniform vec4 transmittance_color : hint_color;\n"; code += "uniform float transmittance_depth;\n"; code += "uniform sampler2D texture_subsurface_transmittance : hint_white," + texfilter_str + ";\n"; - code += "uniform float transmittance_curve;\n"; code += "uniform float transmittance_boost;\n"; } @@ -825,9 +845,9 @@ void BaseMaterial3D::_update_shader() { code += "\tTANGENT+= vec3(1.0,0.0,0.0) * abs(NORMAL.z);\n"; code += "\tTANGENT = normalize(TANGENT);\n"; - code += "\tBINORMAL = vec3(0.0,-1.0,0.0) * abs(NORMAL.x);\n"; - code += "\tBINORMAL+= vec3(0.0,0.0,1.0) * abs(NORMAL.y);\n"; - code += "\tBINORMAL+= vec3(0.0,-1.0,0.0) * abs(NORMAL.z);\n"; + code += "\tBINORMAL = vec3(0.0,1.0,0.0) * abs(NORMAL.x);\n"; + code += "\tBINORMAL+= vec3(0.0,0.0,-1.0) * abs(NORMAL.y);\n"; + code += "\tBINORMAL+= vec3(0.0,1.0,0.0) * abs(NORMAL.z);\n"; code += "\tBINORMAL = normalize(BINORMAL);\n"; } @@ -881,6 +901,20 @@ void BaseMaterial3D::_update_shader() { code += "\tvec2 base_uv2 = UV2;\n"; } + if (features[FEATURE_HEIGHT_MAPPING] && flags[FLAG_UV1_USE_TRIPLANAR]) { + // Display both resource name and albedo texture name. + // Materials are often built-in to scenes, so displaying the resource name alone may not be meaningful. + // On the other hand, albedo textures are almost always external to the scene. + if (textures[TEXTURE_ALBEDO].is_valid()) { + WARN_PRINT(vformat("%s (albedo %s): Height mapping is not supported on triplanar materials. Ignoring height mapping in favor of triplanar mapping.", get_path(), textures[TEXTURE_ALBEDO]->get_path())); + } else if (!get_path().is_empty()) { + WARN_PRINT(vformat("%s: Height mapping is not supported on triplanar materials. Ignoring height mapping in favor of triplanar mapping.", get_path())); + } else { + // Resource wasn't saved yet. + WARN_PRINT("Height mapping is not supported on triplanar materials. Ignoring height mapping in favor of triplanar mapping."); + } + } + if (!RenderingServer::get_singleton()->is_low_end() && features[FEATURE_HEIGHT_MAPPING] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //heightmap not supported with triplanar code += "\t{\n"; code += "\t\tvec3 view_dir = normalize(normalize(-VERTEX)*mat3(TANGENT*heightmap_flip.x,-BINORMAL*heightmap_flip.y,NORMAL));\n"; // binormal is negative due to mikktspace, flip 'unflips' it ;-) @@ -891,7 +925,7 @@ void BaseMaterial3D::_update_shader() { code += "\t\tfloat current_layer_depth = 0.0;\n"; code += "\t\tvec2 P = view_dir.xy * heightmap_scale;\n"; code += "\t\tvec2 delta = P / num_layers;\n"; - code += "\t\tvec2 ofs = base_uv;\n"; + code += "\t\tvec2 ofs = base_uv;\n"; if (flags[FLAG_INVERT_HEIGHTMAP]) { code += "\t\tfloat depth = texture(texture_heightmap, ofs).r;\n"; } else { @@ -990,9 +1024,9 @@ void BaseMaterial3D::_update_shader() { code += "\tSPECULAR = specular;\n"; } else { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tfloat orm_tex = triplanar_texture(texture_orm,uv1_power_normal,uv1_triplanar_pos);\n"; + code += "\tvec4 orm_tex = triplanar_texture(texture_orm,uv1_power_normal,uv1_triplanar_pos);\n"; } else { - code += "\tfloat orm_tex = texture(texture_orm,base_uv);\n"; + code += "\tvec4 orm_tex = texture(texture_orm,base_uv);\n"; } code += "\tROUGHNESS = orm_tex.g;\n"; @@ -1183,7 +1217,6 @@ void BaseMaterial3D::_update_shader() { code += "\tSSS_TRANSMITTANCE_COLOR=transmittance_color*trans_color_tex;\n"; code += "\tSSS_TRANSMITTANCE_DEPTH=transmittance_depth;\n"; - code += "\tSSS_TRANSMITTANCE_CURVE=transmittance_curve;\n"; code += "\tSSS_TRANSMITTANCE_BOOST=transmittance_boost;\n"; } @@ -1427,15 +1460,6 @@ float BaseMaterial3D::get_transmittance_depth() const { return transmittance_depth; } -void BaseMaterial3D::set_transmittance_curve(float p_curve) { - transmittance_curve = p_curve; - RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_curve, p_curve); -} - -float BaseMaterial3D::get_transmittance_curve() const { - return transmittance_curve; -} - void BaseMaterial3D::set_transmittance_boost(float p_boost) { transmittance_boost = p_boost; RS::get_singleton()->material_set_param(_get_material(), shader_names->transmittance_boost, p_boost); @@ -1699,7 +1723,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { _validate_high_end("heightmap", property); if (property.name.begins_with("particles_anim_") && billboard_mode != BILLBOARD_PARTICLES) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) { @@ -1729,33 +1753,33 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { // alpha scissor slider isn't needed when alpha antialiasing is enabled if (property.name == "alpha_scissor_threshold" && transparency != TRANSPARENCY_ALPHA_SCISSOR) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } // alpha hash scale slider is only needed if transparency is alpha hash if (property.name == "alpha_hash_scale" && transparency != TRANSPARENCY_ALPHA_HASH) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "alpha_antialiasing_mode" && !can_select_aa) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } // we can't choose an antialiasing mode if alpha isn't possible if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "blend_mode" && alpha_aa_enabled) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if ((property.name == "heightmap_min_layers" || property.name == "heightmap_max_layers") && !deep_parallax) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } - if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture" || property.name == "subsurf_scatter_transmittance_curve")) { - property.usage = 0; + if (flags[FLAG_SUBSURFACE_MODE_SKIN] && (property.name == "subsurf_scatter_transmittance_color" || property.name == "subsurf_scatter_transmittance_texture")) { + property.usage = PROPERTY_USAGE_NONE; } if (orm) { @@ -1764,12 +1788,12 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.hint_string = "Unshaded,Per-Pixel"; } if (property.name.begins_with("roughness") || property.name.begins_with("metallic") || property.name.begins_with("ao_texture")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } else { if (property.name == "orm_texture") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -1777,47 +1801,47 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { if (shading_mode != SHADING_MODE_PER_VERTEX) { //these may still work per vertex if (property.name.begins_with("ao")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("emission")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("metallic")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("rim")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("roughness")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("subsurf_scatter")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } //these definitely only need per pixel if (property.name.begins_with("anisotropy")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("clearcoat")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("normal")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("backlight")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("transmittance")) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -2066,7 +2090,7 @@ BaseMaterial3D::TextureChannel BaseMaterial3D::get_refraction_texture_channel() return refraction_texture_channel; } -RID BaseMaterial3D::get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y) { +Ref<Material> BaseMaterial3D::get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard, bool p_billboard_y, RID *r_shader_rid) { int version = 0; if (p_shaded) { version = 1; @@ -2091,11 +2115,14 @@ RID BaseMaterial3D::get_material_rid_for_2d(bool p_shaded, bool p_transparent, b } if (materials_for_2d[version].is_valid()) { - return materials_for_2d[version]->get_rid(); + if (r_shader_rid) { + *r_shader_rid = materials_for_2d[version]->get_shader_rid(); + } + return materials_for_2d[version]; } Ref<StandardMaterial3D> material; - material.instance(); + material.instantiate(); material->set_shading_mode(p_shaded ? SHADING_MODE_PER_PIXEL : SHADING_MODE_UNSHADED); material->set_transparency(p_transparent ? (p_opaque_prepass ? TRANSPARENCY_ALPHA_DEPTH_PRE_PASS : (p_cut_alpha ? TRANSPARENCY_ALPHA_SCISSOR : TRANSPARENCY_ALPHA)) : TRANSPARENCY_DISABLED); @@ -2109,7 +2136,11 @@ RID BaseMaterial3D::get_material_rid_for_2d(bool p_shaded, bool p_transparent, b materials_for_2d[version] = material; - return materials_for_2d[version]->get_rid(); + if (r_shader_rid) { + *r_shader_rid = materials_for_2d[version]->get_shader_rid(); + } + + return materials_for_2d[version]; } void BaseMaterial3D::set_on_top_of_alpha() { @@ -2178,6 +2209,8 @@ BaseMaterial3D::EmissionOperator BaseMaterial3D::get_emission_operator() const { } RID BaseMaterial3D::get_shader_rid() const { + MutexLock lock(material_mutex); + ((BaseMaterial3D *)this)->_update_shader(); ERR_FAIL_COND_V(!shader_map.has(current_key), RID()); return shader_map[current_key].shader; } @@ -2249,9 +2282,6 @@ void BaseMaterial3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transmittance_depth", "depth"), &BaseMaterial3D::set_transmittance_depth); ClassDB::bind_method(D_METHOD("get_transmittance_depth"), &BaseMaterial3D::get_transmittance_depth); - ClassDB::bind_method(D_METHOD("set_transmittance_curve", "curve"), &BaseMaterial3D::set_transmittance_curve); - ClassDB::bind_method(D_METHOD("get_transmittance_curve"), &BaseMaterial3D::get_transmittance_curve); - ClassDB::bind_method(D_METHOD("set_transmittance_boost", "boost"), &BaseMaterial3D::set_transmittance_boost); ClassDB::bind_method(D_METHOD("get_transmittance_boost"), &BaseMaterial3D::get_transmittance_boost); @@ -2400,7 +2430,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Shading", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "shading_mode", PROPERTY_HINT_ENUM, "Unshaded,Per-Pixel,Per-Vertex"), "set_shading_mode", "get_shading_mode"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Oren Nayar,Toon"), "set_diffuse_mode", "get_diffuse_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "diffuse_mode", PROPERTY_HINT_ENUM, "Burley,Lambert,Lambert Wrap,Toon"), "set_diffuse_mode", "get_diffuse_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Blinn,Phong,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT); @@ -2486,7 +2516,6 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::COLOR, "subsurf_scatter_transmittance_color"), "set_transmittance_color", "get_transmittance_color"); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_transmittance_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_TRANSMITTANCE); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_depth", PROPERTY_HINT_RANGE, "0.001,8,0.001,or_greater"), "set_transmittance_depth", "get_transmittance_depth"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_curve", PROPERTY_HINT_EXP_EASING, "0.01,16,0.01"), "set_transmittance_curve", "get_transmittance_curve"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_transmittance_boost", PROPERTY_HINT_RANGE, "0.00,1.0,0.01"), "set_transmittance_boost", "get_transmittance_boost"); ADD_GROUP("Back Lighting", "backlight_"); @@ -2654,7 +2683,6 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); BIND_ENUM_CONSTANT(DIFFUSE_LAMBERT); BIND_ENUM_CONSTANT(DIFFUSE_LAMBERT_WRAP); - BIND_ENUM_CONSTANT(DIFFUSE_OREN_NAYAR); BIND_ENUM_CONSTANT(DIFFUSE_TOON); BIND_ENUM_CONSTANT(SPECULAR_SCHLICK_GGX); @@ -2704,7 +2732,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_backlight(Color(0, 0, 0)); set_transmittance_color(Color(1, 1, 1, 1)); set_transmittance_depth(0.1); - set_transmittance_curve(1.0); set_transmittance_boost(0.0); set_refraction(0.05); set_point_size(1); diff --git a/scene/resources/material.h b/scene/resources/material.h index ad1b7b3e33..e2838e1399 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -79,6 +79,8 @@ class ShaderMaterial : public Material { GDCLASS(ShaderMaterial, Material); Ref<Shader> shader; + Map<StringName, Variant> param_cache; + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -243,7 +245,6 @@ public: DIFFUSE_BURLEY, DIFFUSE_LAMBERT, DIFFUSE_LAMBERT_WRAP, - DIFFUSE_OREN_NAYAR, DIFFUSE_TOON, DIFFUSE_MAX }; @@ -390,7 +391,6 @@ private: StringName heightmap_scale; StringName subsurface_scattering_strength; StringName transmittance_color; - StringName transmittance_curve; StringName transmittance_depth; StringName transmittance_boost; StringName backlight; @@ -459,7 +459,6 @@ private: float transmittance_amount; Color transmittance_color; float transmittance_depth; - float transmittance_curve; float transmittance_boost; Color backlight; @@ -603,9 +602,6 @@ public: void set_transmittance_depth(float p_depth); float get_transmittance_depth() const; - void set_transmittance_curve(float p_curve); - float get_transmittance_curve() const; - void set_transmittance_boost(float p_boost); float get_transmittance_boost() const; @@ -739,7 +735,7 @@ public: static void finish_shaders(); static void flush_changes(); - static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false); + static Ref<Material> get_material_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false, RID *r_shader_rid = nullptr); virtual RID get_shader_rid() const override; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 33ad15b938..2f92872ad5 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -30,6 +30,7 @@ #include "mesh.h" +#include "core/math/convex_hull.h" #include "core/templates/pair.h" #include "scene/resources/concave_polygon_shape_3d.h" #include "scene/resources/convex_polygon_shape_3d.h" @@ -221,9 +222,17 @@ Vector<Face3> Mesh::get_faces() const { */ } -Ref<Shape3D> Mesh::create_convex_shape() const { - Vector<Vector3> vertices; +Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const { + if (p_simplify) { + Vector<Ref<Shape3D>> decomposed = convex_decompose(1); + if (decomposed.size() == 1) { + return decomposed[0]; + } else { + ERR_PRINT("Convex shape simplification failed, falling back to simpler process."); + } + } + Vector<Vector3> vertices; for (int i = 0; i < get_surface_count(); i++) { Array a = surface_get_arrays(i); ERR_FAIL_COND_V(a.is_empty(), Ref<ConvexPolygonShape3D>()); @@ -232,6 +241,18 @@ Ref<Shape3D> Mesh::create_convex_shape() const { } Ref<ConvexPolygonShape3D> shape = memnew(ConvexPolygonShape3D); + + if (p_clean) { + Geometry3D::MeshData md; + Error err = ConvexHullComputer::convex_hull(vertices, md); + if (err == OK) { + shape->set_points(md.vertices); + return shape; + } else { + ERR_PRINT("Convex shape cleaning failed, falling back to simpler process."); + } + } + shape->set_points(vertices); return shape; } @@ -543,12 +564,12 @@ void Mesh::clear_cache() const { debug_lines.clear(); } -Vector<Ref<Shape3D>> Mesh::convex_decompose() const { +Vector<Ref<Shape3D>> Mesh::convex_decompose(int p_max_convex_hulls) const { ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape3D>>()); const Vector<Face3> faces = get_faces(); - Vector<Vector<Face3>> decomposed = convex_composition_function(faces); + Vector<Vector<Face3>> decomposed = convex_composition_function(faces, p_max_convex_hulls); Vector<Ref<Shape3D>> ret; @@ -571,7 +592,7 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const { } Ref<ConvexPolygonShape3D> shape; - shape.instance(); + shape.instantiate(); shape->set_points(convex_points); ret.push_back(shape); } @@ -582,164 +603,328 @@ Vector<Ref<Shape3D>> Mesh::convex_decompose() const { int Mesh::get_builtin_bind_pose_count() const { return 0; } -Transform Mesh::get_builtin_bind_pose(int p_index) const { - return Transform(); + +Transform3D Mesh::get_builtin_bind_pose(int p_index) const { + return Transform3D(); } Mesh::Mesh() { } -#if 0 -static Vector<uint8_t> _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_format, uint32_t p_elements) { - enum ArrayType { - OLD_ARRAY_VERTEX = 0, - OLD_ARRAY_NORMAL = 1, - OLD_ARRAY_TANGENT = 2, - OLD_ARRAY_COLOR = 3, - OLD_ARRAY_TEX_UV = 4, - OLD_ARRAY_TEX_UV2 = 5, - OLD_ARRAY_BONES = 6, - OLD_ARRAY_WEIGHTS = 7, - OLD_ARRAY_INDEX = 8, - OLD_ARRAY_MAX = 9 - }; - - enum ArrayFormat { - /* OLD_ARRAY FORMAT FLAGS */ - OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory - OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL, - OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT, - OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR, - OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV, - OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2, - OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES, - OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS, - OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX, - - OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1), - OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE), - OLD_ARRAY_COMPRESS_DEFAULT = OLD_ARRAY_COMPRESS_NORMAL | OLD_ARRAY_COMPRESS_TANGENT | OLD_ARRAY_COMPRESS_COLOR | OLD_ARRAY_COMPRESS_TEX_UV | OLD_ARRAY_COMPRESS_TEX_UV2, - - OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1, - OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3, - }; - - bool vertex_16bit = p_format & ((1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE))); - bool has_bones = (p_format & OLD_ARRAY_FORMAT_BONES); - bool bone_8 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_INDEX << 2)); - bool weight_32 = has_bones && !(p_format & (OLD_ARRAY_COMPRESS_TEX_UV2 << 2)); - - print_line("convert vertex16: " + itos(vertex_16bit) + " convert bone 8 " + itos(bone_8) + " convert weight 32 " + itos(weight_32)); - - if (!vertex_16bit && !bone_8 && !weight_32) { - return p_src; - } +enum OldArrayType { + OLD_ARRAY_VERTEX, + OLD_ARRAY_NORMAL, + OLD_ARRAY_TANGENT, + OLD_ARRAY_COLOR, + OLD_ARRAY_TEX_UV, + OLD_ARRAY_TEX_UV2, + OLD_ARRAY_BONES, + OLD_ARRAY_WEIGHTS, + OLD_ARRAY_INDEX, + OLD_ARRAY_MAX, +}; + +enum OldArrayFormat { + /* OLD_ARRAY FORMAT FLAGS */ + OLD_ARRAY_FORMAT_VERTEX = 1 << OLD_ARRAY_VERTEX, // mandatory + OLD_ARRAY_FORMAT_NORMAL = 1 << OLD_ARRAY_NORMAL, + OLD_ARRAY_FORMAT_TANGENT = 1 << OLD_ARRAY_TANGENT, + OLD_ARRAY_FORMAT_COLOR = 1 << OLD_ARRAY_COLOR, + OLD_ARRAY_FORMAT_TEX_UV = 1 << OLD_ARRAY_TEX_UV, + OLD_ARRAY_FORMAT_TEX_UV2 = 1 << OLD_ARRAY_TEX_UV2, + OLD_ARRAY_FORMAT_BONES = 1 << OLD_ARRAY_BONES, + OLD_ARRAY_FORMAT_WEIGHTS = 1 << OLD_ARRAY_WEIGHTS, + OLD_ARRAY_FORMAT_INDEX = 1 << OLD_ARRAY_INDEX, + + OLD_ARRAY_COMPRESS_BASE = (OLD_ARRAY_INDEX + 1), + OLD_ARRAY_COMPRESS_VERTEX = 1 << (OLD_ARRAY_VERTEX + OLD_ARRAY_COMPRESS_BASE), // mandatory + OLD_ARRAY_COMPRESS_NORMAL = 1 << (OLD_ARRAY_NORMAL + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TANGENT = 1 << (OLD_ARRAY_TANGENT + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_COLOR = 1 << (OLD_ARRAY_COLOR + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TEX_UV = 1 << (OLD_ARRAY_TEX_UV + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_TEX_UV2 = 1 << (OLD_ARRAY_TEX_UV2 + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_BONES = 1 << (OLD_ARRAY_BONES + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_WEIGHTS = 1 << (OLD_ARRAY_WEIGHTS + OLD_ARRAY_COMPRESS_BASE), + OLD_ARRAY_COMPRESS_INDEX = 1 << (OLD_ARRAY_INDEX + OLD_ARRAY_COMPRESS_BASE), + + OLD_ARRAY_FLAG_USE_2D_VERTICES = OLD_ARRAY_COMPRESS_INDEX << 1, + OLD_ARRAY_FLAG_USE_16_BIT_BONES = OLD_ARRAY_COMPRESS_INDEX << 2, + OLD_ARRAY_FLAG_USE_DYNAMIC_UPDATE = OLD_ARRAY_COMPRESS_INDEX << 3, - bool vertex_2d = (p_format & (OLD_ARRAY_COMPRESS_INDEX << 1)); +}; - uint32_t src_stride = p_src.size() / p_elements; - uint32_t dst_stride = src_stride + (vertex_16bit ? 4 : 0) + (bone_8 ? 4 : 0) - (weight_32 ? 8 : 0); +static Array _convert_old_array(const Array &p_old) { + Array new_array; + new_array.resize(Mesh::ARRAY_MAX); + new_array[Mesh::ARRAY_VERTEX] = p_old[OLD_ARRAY_VERTEX]; + new_array[Mesh::ARRAY_NORMAL] = p_old[OLD_ARRAY_NORMAL]; + new_array[Mesh::ARRAY_TANGENT] = p_old[OLD_ARRAY_TANGENT]; + new_array[Mesh::ARRAY_COLOR] = p_old[OLD_ARRAY_COLOR]; + new_array[Mesh::ARRAY_TEX_UV] = p_old[OLD_ARRAY_TEX_UV]; + new_array[Mesh::ARRAY_TEX_UV2] = p_old[OLD_ARRAY_TEX_UV2]; + new_array[Mesh::ARRAY_BONES] = p_old[OLD_ARRAY_BONES]; + new_array[Mesh::ARRAY_WEIGHTS] = p_old[OLD_ARRAY_WEIGHTS]; + new_array[Mesh::ARRAY_INDEX] = p_old[OLD_ARRAY_INDEX]; + return new_array; +} + +static Mesh::PrimitiveType _old_primitives[7] = { + Mesh::PRIMITIVE_POINTS, + Mesh::PRIMITIVE_LINES, + Mesh::PRIMITIVE_LINE_STRIP, + Mesh::PRIMITIVE_LINES, + Mesh::PRIMITIVE_TRIANGLES, + Mesh::PRIMITIVE_TRIANGLE_STRIP, + Mesh::PRIMITIVE_TRIANGLE_STRIP +}; - Vector<uint8_t> ret = p_src; +void _fix_array_compatibility(const Vector<uint8_t> &p_src, uint32_t p_old_format, uint32_t p_new_format, uint32_t p_elements, Vector<uint8_t> &vertex_data, Vector<uint8_t> &attribute_data, Vector<uint8_t> &skin_data) { + uint32_t dst_vertex_stride; + uint32_t dst_attribute_stride; + uint32_t dst_skin_stride; + uint32_t dst_offsets[Mesh::ARRAY_MAX]; + RenderingServer::get_singleton()->mesh_surface_make_offsets_from_format(p_new_format & (~RS::ARRAY_FORMAT_INDEX), p_elements, 0, dst_offsets, dst_vertex_stride, dst_attribute_stride, dst_skin_stride); - ret.resize(dst_stride * p_elements); - { - uint8_t *w = ret.ptrw(); - const uint8_t *r = p_src.ptr(); - - for (uint32_t i = 0; i < p_elements; i++) { - uint32_t remaining = src_stride; - const uint8_t *src = (const uint8_t *)(r + src_stride * i); - uint8_t *dst = (uint8_t *)(w + dst_stride * i); - - if (!vertex_2d) { //3D - if (vertex_16bit) { - float *dstw = (float *)dst; - const uint16_t *srcr = (const uint16_t *)src; - dstw[0] = Math::half_to_float(srcr[0]); - dstw[1] = Math::half_to_float(srcr[1]); - dstw[2] = Math::half_to_float(srcr[2]); - remaining -= 8; - src += 8; + vertex_data.resize(dst_vertex_stride * p_elements); + attribute_data.resize(dst_attribute_stride * p_elements); + skin_data.resize(dst_skin_stride * p_elements); + + uint8_t *dst_vertex_ptr = vertex_data.ptrw(); + uint8_t *dst_attribute_ptr = attribute_data.ptrw(); + uint8_t *dst_skin_ptr = skin_data.ptrw(); + + const uint8_t *src_vertex_ptr = p_src.ptr(); + uint32_t src_vertex_stride = p_src.size() / p_elements; + + uint32_t src_offset = 0; + for (uint32_t j = 0; j < OLD_ARRAY_INDEX; j++) { + if (!(p_old_format & (1 << j))) { + continue; + } + switch (j) { + case OLD_ARRAY_VERTEX: { + if (p_old_format & OLD_ARRAY_FLAG_USE_2D_VERTICES) { + if (p_old_format & OLD_ARRAY_COMPRESS_VERTEX) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + } + src_offset += sizeof(uint16_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + } + src_offset += sizeof(float) * 2; + } } else { - src += 12; - remaining -= 12; + if (p_old_format & OLD_ARRAY_COMPRESS_VERTEX) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + dst[2] = Math::half_to_float(src[2]); + } + src_offset += sizeof(uint16_t) * 4; //+pad + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride]; + float *dst = (float *)&dst_vertex_ptr[i * dst_vertex_stride]; + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + src_offset += sizeof(float) * 3; + } } - dst += 12; - } else { - if (vertex_16bit) { - float *dstw = (float *)dst; - const uint16_t *srcr = (const uint16_t *)src; - dstw[0] = Math::half_to_float(srcr[0]); - dstw[1] = Math::half_to_float(srcr[1]); - remaining -= 4; - src += 4; + } break; + case OLD_ARRAY_NORMAL: { + if (p_old_format & OLD_ARRAY_COMPRESS_NORMAL) { + const float multiplier = 1.f / 127.f * 1023.0f; + + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); + *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + } + src_offset += sizeof(uint32_t); } else { - src += 8; - remaining -= 8; + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_NORMAL]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); + *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + } + src_offset += sizeof(float) * 3; } - dst += 8; - } - - if (has_bones) { - remaining -= bone_8 ? 4 : 8; - remaining -= weight_32 ? 16 : 8; - } - - for (uint32_t j = 0; j < remaining; j++) { - dst[j] = src[j]; - } - if (has_bones) { - dst += remaining; - src += remaining; - - if (bone_8) { - const uint8_t *src_bones = (const uint8_t *)src; - uint16_t *dst_bones = (uint16_t *)dst; + } break; + case OLD_ARRAY_TANGENT: { + if (p_old_format & OLD_ARRAY_COMPRESS_TANGENT) { + const float multiplier = 1.f / 127.f * 1023.0f; + + for (uint32_t i = 0; i < p_elements; i++) { + const int8_t *src = (const int8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * multiplier), 0, 1023); + *dst |= CLAMP(int(src[1] * multiplier), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * multiplier), 0, 1023) << 20; + if (src[3] > 0) { + *dst |= 3 << 30; + } + } + src_offset += sizeof(uint32_t); + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_vertex_ptr[i * dst_vertex_stride + dst_offsets[Mesh::ARRAY_TANGENT]]; + + *dst = 0; + *dst |= CLAMP(int(src[0] * 1023.0), 0, 1023); + *dst |= CLAMP(int(src[1] * 1023.0), 0, 1023) << 10; + *dst |= CLAMP(int(src[2] * 1023.0), 0, 1023) << 20; + if (src[3] > 0) { + *dst |= 3 << 30; + } + } + src_offset += sizeof(float) * 4; + } - dst_bones[0] = src_bones[0]; - dst_bones[1] = src_bones[1]; - dst_bones[2] = src_bones[2]; - dst_bones[3] = src_bones[3]; + } break; + case OLD_ARRAY_COLOR: { + if (p_old_format & OLD_ARRAY_COMPRESS_COLOR) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint32_t *src = (const uint32_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint32_t *dst = (uint32_t *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_COLOR]]; - src += 4; + *dst = *src; + } + src_offset += sizeof(uint32_t); } else { - for (uint32_t j = 0; j < 8; j++) { - dst[j] = src[j]; + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint8_t *dst = (uint8_t *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_COLOR]]; + + dst[0] = uint8_t(CLAMP(src[0] * 255.0, 0.0, 255.0)); + dst[1] = uint8_t(CLAMP(src[1] * 255.0, 0.0, 255.0)); + dst[2] = uint8_t(CLAMP(src[2] * 255.0, 0.0, 255.0)); + dst[3] = uint8_t(CLAMP(src[3] * 255.0, 0.0, 255.0)); } - - src += 8; + src_offset += sizeof(float) * 4; } + } break; + case OLD_ARRAY_TEX_UV: { + if (p_old_format & OLD_ARRAY_COMPRESS_TEX_UV) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV]]; + + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + } + src_offset += sizeof(uint16_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV]]; - dst += 8; + dst[0] = src[0]; + dst[1] = src[1]; + } + src_offset += sizeof(float) * 2; + } - if (weight_32) { - const float *src_weights = (const float *)src; - uint16_t *dst_weights = (uint16_t *)dst; + } break; + case OLD_ARRAY_TEX_UV2: { + if (p_old_format & OLD_ARRAY_COMPRESS_TEX_UV2) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV2]]; - dst_weights[0] = CLAMP(src_weights[0] * 65535, 0, 65535); //16bits unorm - dst_weights[1] = CLAMP(src_weights[1] * 65535, 0, 65535); - dst_weights[2] = CLAMP(src_weights[2] * 65535, 0, 65535); - dst_weights[3] = CLAMP(src_weights[3] * 65535, 0, 65535); + dst[0] = Math::half_to_float(src[0]); + dst[1] = Math::half_to_float(src[1]); + } + src_offset += sizeof(uint16_t) * 2; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + float *dst = (float *)&dst_attribute_ptr[i * dst_attribute_stride + dst_offsets[Mesh::ARRAY_TEX_UV2]]; + dst[0] = src[0]; + dst[1] = src[1]; + } + src_offset += sizeof(float) * 2; + } + } break; + case OLD_ARRAY_BONES: { + if (p_old_format & OLD_ARRAY_FLAG_USE_16_BIT_BONES) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_BONES]]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + src_offset += sizeof(uint16_t) * 4; + } else { + for (uint32_t i = 0; i < p_elements; i++) { + const uint8_t *src = (const uint8_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_BONES]]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + src_offset += sizeof(uint8_t) * 4; + } + } break; + case OLD_ARRAY_WEIGHTS: { + if (p_old_format & OLD_ARRAY_COMPRESS_WEIGHTS) { + for (uint32_t i = 0; i < p_elements; i++) { + const uint16_t *src = (const uint16_t *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_WEIGHTS]]; + + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + src_offset += sizeof(uint16_t) * 4; } else { - for (uint32_t j = 0; j < 8; j++) { - dst[j] = src[j]; + for (uint32_t i = 0; i < p_elements; i++) { + const float *src = (const float *)&src_vertex_ptr[i * src_vertex_stride + src_offset]; + uint16_t *dst = (uint16_t *)&dst_skin_ptr[i * dst_skin_stride + dst_offsets[Mesh::ARRAY_WEIGHTS]]; + + dst[0] = uint16_t(CLAMP(src[0] * 65535.0, 0, 65535.0)); + dst[1] = uint16_t(CLAMP(src[1] * 65535.0, 0, 65535.0)); + dst[2] = uint16_t(CLAMP(src[2] * 65535.0, 0, 65535.0)); + dst[3] = uint16_t(CLAMP(src[3] * 65535.0, 0, 65535.0)); } + src_offset += sizeof(float) * 4; } + } break; + default: { } } } - - return ret; } -#endif bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { String sname = p_name; @@ -778,10 +963,13 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { if (d.has("arrays")) { //oldest format (2.x) ERR_FAIL_COND_V(!d.has("morph_arrays"), false); - add_surface_from_arrays(PrimitiveType(int(d["primitive"])), d["arrays"], d["morph_arrays"]); + Array morph_arrays = d["morph_arrays"]; + for (int i = 0; i < morph_arrays.size(); i++) { + morph_arrays[i] = _convert_old_array(morph_arrays[i]); + } + add_surface_from_arrays(_old_primitives[int(d["primitive"])], _convert_old_array(d["arrays"]), morph_arrays); } else if (d.has("array_data")) { -#if 0 //print_line("array data (old style"); //older format (3.x) Vector<uint8_t> array_data = d["array_data"]; @@ -791,48 +979,76 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } ERR_FAIL_COND_V(!d.has("format"), false); - uint32_t format = d["format"]; + uint32_t old_format = d["format"]; uint32_t primitive = d["primitive"]; - uint32_t primitive_remap[7] = { - PRIMITIVE_POINTS, - PRIMITIVE_LINES, - PRIMITIVE_LINE_STRIP, - PRIMITIVE_LINES, - PRIMITIVE_TRIANGLES, - PRIMITIVE_TRIANGLE_STRIP, - PRIMITIVE_TRIANGLE_STRIP - }; - - primitive = primitive_remap[primitive]; //compatibility + primitive = _old_primitives[primitive]; //compatibility ERR_FAIL_COND_V(!d.has("vertex_count"), false); int vertex_count = d["vertex_count"]; - array_data = _fix_array_compatibility(array_data, format, vertex_count); + uint32_t new_format = ARRAY_FORMAT_VERTEX; + + if (old_format & OLD_ARRAY_FORMAT_NORMAL) { + new_format |= ARRAY_FORMAT_NORMAL; + } + if (old_format & OLD_ARRAY_FORMAT_TANGENT) { + new_format |= ARRAY_FORMAT_TANGENT; + } + if (old_format & OLD_ARRAY_FORMAT_COLOR) { + new_format |= ARRAY_FORMAT_COLOR; + } + if (old_format & OLD_ARRAY_FORMAT_TEX_UV) { + new_format |= ARRAY_FORMAT_TEX_UV; + } + if (old_format & OLD_ARRAY_FORMAT_TEX_UV2) { + new_format |= ARRAY_FORMAT_TEX_UV2; + } + if (old_format & OLD_ARRAY_FORMAT_BONES) { + new_format |= ARRAY_FORMAT_BONES; + } + if (old_format & OLD_ARRAY_FORMAT_WEIGHTS) { + new_format |= ARRAY_FORMAT_WEIGHTS; + } + if (old_format & OLD_ARRAY_FORMAT_INDEX) { + new_format |= ARRAY_FORMAT_INDEX; + } + if (old_format & OLD_ARRAY_FLAG_USE_2D_VERTICES) { + new_format |= OLD_ARRAY_FLAG_USE_2D_VERTICES; + } + + Vector<uint8_t> vertex_array; + Vector<uint8_t> attribute_array; + Vector<uint8_t> skin_array; + + _fix_array_compatibility(array_data, old_format, new_format, vertex_count, vertex_array, attribute_array, skin_array); int index_count = 0; if (d.has("index_count")) { index_count = d["index_count"]; } - Vector<Vector<uint8_t>> blend_shapes; + Vector<uint8_t> blend_shapes; if (d.has("blend_shape_data")) { Array blend_shape_data = d["blend_shape_data"]; for (int i = 0; i < blend_shape_data.size(); i++) { + Vector<uint8_t> blend_vertex_array; + Vector<uint8_t> blend_attribute_array; + Vector<uint8_t> blend_skin_array; + Vector<uint8_t> shape = blend_shape_data[i]; - shape = _fix_array_compatibility(shape, format, vertex_count); + _fix_array_compatibility(shape, old_format, new_format, vertex_count, blend_vertex_array, blend_attribute_array, blend_skin_array); - blend_shapes.push_back(shape); + blend_shapes.append_array(blend_vertex_array); } } //clear unused flags - print_line("format pre: " + itos(format)); - format &= ~uint32_t((1 << (ARRAY_VERTEX + ARRAY_COMPRESS_BASE)) | (ARRAY_COMPRESS_INDEX << 2) | (ARRAY_COMPRESS_TEX_UV2 << 2)); - print_line("format post: " + itos(format)); + print_line("format pre: " + itos(old_format)); + + print_line("format post: " + itos(new_format)); ERR_FAIL_COND_V(!d.has("aabb"), false); AABB aabb = d["aabb"]; @@ -847,8 +1063,8 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) { } } - add_surface(format, PrimitiveType(primitive), array_data, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb); -#endif + add_surface(new_format, PrimitiveType(primitive), vertex_array, attribute_array, skin_array, vertex_count, array_index_data, index_count, aabb, blend_shapes, bone_aabb); + } else { ERR_FAIL_V(false); } @@ -1119,9 +1335,9 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < surfaces.size(); i++) { p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); if (surfaces[i].is_2d) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial,ShaderMaterial", PROPERTY_USAGE_EDITOR)); } else { - p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial", PROPERTY_USAGE_EDITOR)); } } } @@ -1334,9 +1550,21 @@ String ArrayMesh::surface_get_name(int p_idx) const { return surfaces[p_idx].name; } -void ArrayMesh::surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { +void ArrayMesh::surface_update_vertex_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { + ERR_FAIL_INDEX(p_surface, surfaces.size()); + RS::get_singleton()->mesh_surface_update_vertex_region(mesh, p_surface, p_offset, p_data); + emit_changed(); +} + +void ArrayMesh::surface_update_attribute_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { + ERR_FAIL_INDEX(p_surface, surfaces.size()); + RS::get_singleton()->mesh_surface_update_attribute_region(mesh, p_surface, p_offset, p_data); + emit_changed(); +} + +void ArrayMesh::surface_update_skin_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data) { ERR_FAIL_INDEX(p_surface, surfaces.size()); - RS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data); + RS::get_singleton()->mesh_surface_update_skin_region(mesh, p_surface, p_offset, p_data); emit_changed(); } @@ -1410,12 +1638,12 @@ struct ArrayMeshLightmapSurface { uint32_t format = 0; }; -Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { +Error ArrayMesh::lightmap_unwrap(const Transform3D &p_base_transform, float p_texel_size) { Vector<uint8_t> null_cache; return lightmap_unwrap_cached(p_base_transform, p_texel_size, null_cache, null_cache, false); } -Error ArrayMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache) { +Error ArrayMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache) { ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED); ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes."); @@ -1431,7 +1659,7 @@ Error ArrayMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float Basis basis = p_base_transform.get_basis(); Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length()); - Transform transform; + Transform3D transform; transform.scale(scale); Basis normal_basis = transform.basis.inverse().transposed(); @@ -1536,7 +1764,7 @@ Error ArrayMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float for (int i = 0; i < lightmap_surfaces.size(); i++) { Ref<SurfaceTool> st; - st.instance(); + st.instantiate(); st->begin(Mesh::PRIMITIVE_TRIANGLES); st->set_material(lightmap_surfaces[i].material); surfaces_tools.push_back(st); //stay there @@ -1634,7 +1862,9 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces); - ClassDB::bind_method(D_METHOD("surface_update_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_region); + ClassDB::bind_method(D_METHOD("surface_update_vertex_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_vertex_region); + ClassDB::bind_method(D_METHOD("surface_update_attribute_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_attribute_region); + ClassDB::bind_method(D_METHOD("surface_update_skin_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_skin_region); ClassDB::bind_method(D_METHOD("surface_get_array_len", "surf_idx"), &ArrayMesh::surface_get_array_len); ClassDB::bind_method(D_METHOD("surface_get_array_index_len", "surf_idx"), &ArrayMesh::surface_get_array_index_len); ClassDB::bind_method(D_METHOD("surface_get_format", "surf_idx"), &ArrayMesh::surface_get_format); @@ -1643,7 +1873,7 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("surface_set_name", "surf_idx", "name"), &ArrayMesh::surface_set_name); ClassDB::bind_method(D_METHOD("surface_get_name", "surf_idx"), &ArrayMesh::surface_get_name); ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape); - ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape); + ClassDB::bind_method(D_METHOD("create_convex_shape", "clean", "simplify"), &ArrayMesh::create_convex_shape, DEFVAL(true), DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline); ClassDB::bind_method(D_METHOD("regen_normal_maps"), &ArrayMesh::regen_normal_maps); ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normal_maps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index aa830d7b50..27b0eb098b 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -149,7 +149,7 @@ public: void generate_debug_mesh_indices(Vector<Vector3> &r_points); Ref<Shape3D> create_trimesh_shape() const; - Ref<Shape3D> create_convex_shape() const; + Ref<Shape3D> create_convex_shape(bool p_clean = true, bool p_simplify = false) const; Ref<Mesh> create_outline(float p_margin) const; @@ -159,14 +159,14 @@ public: Size2i get_lightmap_size_hint() const; void clear_cache() const; - typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &); + typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &p_faces, int p_max_convex_hulls); static ConvexDecompositionFunc convex_composition_function; - Vector<Ref<Shape3D>> convex_decompose() const; + Vector<Ref<Shape3D>> convex_decompose(int p_max_convex_hulls = -1) const; virtual int get_builtin_bind_pose_count() const; - virtual Transform get_builtin_bind_pose(int p_index) const; + virtual Transform3D get_builtin_bind_pose(int p_index) const; Mesh(); }; @@ -233,7 +233,9 @@ public: void set_blend_shape_mode(BlendShapeMode p_mode); BlendShapeMode get_blend_shape_mode() const; - void surface_update_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); + void surface_update_vertex_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); + void surface_update_attribute_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); + void surface_update_skin_region(int p_surface, int p_offset, const Vector<uint8_t> &p_data); int get_surface_count() const override; @@ -262,8 +264,8 @@ public: void regen_normal_maps(); - Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); - Error lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache = true); + Error lightmap_unwrap(const Transform3D &p_base_transform = Transform3D(), float p_texel_size = 0.05); + Error lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache = true); virtual void reload_from_file() override; diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h index f5c8f11437..b0ebfba7ee 100644 --- a/scene/resources/mesh_data_tool.h +++ b/scene/resources/mesh_data_tool.h @@ -33,8 +33,8 @@ #include "scene/resources/mesh.h" -class MeshDataTool : public Reference { - GDCLASS(MeshDataTool, Reference); +class MeshDataTool : public RefCounted { + GDCLASS(MeshDataTool, RefCounted); int format = 0; struct Vertex { diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index ad90481fbd..33c9ca6d1e 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -97,10 +97,10 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const { String name = "item/" + itos(E->key()) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, name + "name")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "mesh_transform")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "mesh_transform")); p_list->push_back(PropertyInfo(Variant::ARRAY, name + "shapes")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh")); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "navmesh_transform")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, name + "navmesh_transform")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "preview", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER)); } } @@ -145,7 +145,7 @@ void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navm notify_property_list_changed(); } -void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) { +void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform3D &p_transform) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].navmesh_transform = p_transform; notify_change_to_owners(); @@ -180,8 +180,8 @@ Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const { return item_map[p_item].navmesh; } -Transform MeshLibrary::get_item_navmesh_transform(int p_item) const { - ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); +Transform3D MeshLibrary::get_item_navmesh_transform(int p_item) const { + ERR_FAIL_COND_V_MSG(!item_map.has(p_item), Transform3D(), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); return item_map[p_item].navmesh_transform; } diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 1da624c275..1e8a6bf3ff 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -44,14 +44,14 @@ class MeshLibrary : public Resource { public: struct ShapeData { Ref<Shape3D> shape; - Transform local_transform; + Transform3D local_transform; }; struct Item { String name; Ref<Mesh> mesh; Vector<ShapeData> shapes; Ref<Texture2D> preview; - Transform navmesh_transform; + Transform3D navmesh_transform; Ref<NavigationMesh> navmesh; }; @@ -73,13 +73,13 @@ public: void set_item_name(int p_item, const String &p_name); void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh); void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh); - void set_item_navmesh_transform(int p_item, const Transform &p_transform); + void set_item_navmesh_transform(int p_item, const Transform3D &p_transform); void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes); void set_item_preview(int p_item, const Ref<Texture2D> &p_preview); String get_item_name(int p_item) const; Ref<Mesh> get_item_mesh(int p_item) const; Ref<NavigationMesh> get_item_navmesh(int p_item) const; - Transform get_item_navmesh_transform(int p_item) const; + Transform3D get_item_navmesh_transform(int p_item) const; Vector<ShapeData> get_item_shapes(int p_item) const; Ref<Texture2D> get_item_preview(int p_item) const; diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index 4991887eb3..8894f0bb11 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -50,7 +50,7 @@ void MultiMesh::_set_transform_array(const Vector<Vector3> &p_array) { const Vector3 *r = xforms.ptr(); for (int i = 0; i < len / 4; i++) { - Transform t; + Transform3D t; t.basis[0] = r[i * 4 + 0]; t.basis[1] = r[i * 4 + 1]; t.basis[2] = r[i * 4 + 2]; @@ -75,7 +75,7 @@ Vector<Vector3> MultiMesh::_get_transform_array() const { Vector3 *w = xforms.ptrw(); for (int i = 0; i < instance_count; i++) { - Transform t = get_instance_transform(i); + Transform3D t = get_instance_transform(i); w[i * 4 + 0] = t.basis[0]; w[i * 4 + 1] = t.basis[1]; w[i * 4 + 2] = t.basis[2]; @@ -236,7 +236,7 @@ int MultiMesh::get_visible_instance_count() const { return visible_instance_count; } -void MultiMesh::set_instance_transform(int p_instance, const Transform &p_transform) { +void MultiMesh::set_instance_transform(int p_instance, const Transform3D &p_transform) { RenderingServer::get_singleton()->multimesh_instance_set_transform(multimesh, p_instance, p_transform); } @@ -244,7 +244,7 @@ void MultiMesh::set_instance_transform_2d(int p_instance, const Transform2D &p_t RenderingServer::get_singleton()->multimesh_instance_set_transform_2d(multimesh, p_instance, p_transform); } -Transform MultiMesh::get_instance_transform(int p_instance) const { +Transform3D MultiMesh::get_instance_transform(int p_instance) const { return RenderingServer::get_singleton()->multimesh_instance_get_transform(multimesh, p_instance); } @@ -349,10 +349,10 @@ void MultiMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_custom_data_array"), &MultiMesh::_set_custom_data_array); ClassDB::bind_method(D_METHOD("_get_custom_data_array"), &MultiMesh::_get_custom_data_array); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", 0), "_set_transform_array", "_get_transform_array"); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "transform_2d_array", PROPERTY_HINT_NONE, "", 0), "_set_transform_2d_array", "_get_transform_2d_array"); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "color_array", PROPERTY_HINT_NONE, "", 0), "_set_color_array", "_get_color_array"); - ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "custom_data_array", PROPERTY_HINT_NONE, "", 0), "_set_custom_data_array", "_get_custom_data_array"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_transform_array", "_get_transform_array"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "transform_2d_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_transform_2d_array", "_get_transform_2d_array"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "color_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_color_array", "_get_color_array"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "custom_data_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_custom_data_array", "_get_custom_data_array"); #endif BIND_ENUM_CONSTANT(TRANSFORM_2D); diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index ca5c42d47a..2fe0927e6f 100644 --- a/scene/resources/multimesh.h +++ b/scene/resources/multimesh.h @@ -92,9 +92,9 @@ public: void set_visible_instance_count(int p_count); int get_visible_instance_count() const; - void set_instance_transform(int p_instance, const Transform &p_transform); + void set_instance_transform(int p_instance, const Transform3D &p_transform); void set_instance_transform_2d(int p_instance, const Transform2D &p_transform); - Transform get_instance_transform(int p_instance) const; + Transform3D get_instance_transform(int p_instance) const; Transform2D get_instance_transform_2d(int p_instance) const; void set_instance_color(int p_instance, const Color &p_color); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 0a25bb2ed1..d2be2bdba1 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -501,14 +501,14 @@ void NavigationMesh::_bind_methods() { void NavigationMesh::_validate_property(PropertyInfo &property) const { if (property.name == "geometry/collision_mask") { if (parsed_geometry_type == PARSED_GEOMETRY_MESH_INSTANCES) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } } if (property.name == "geometry/source_group_name") { if (source_geometry_mode == SOURCE_GEOMETRY_NAVMESH_CHILDREN) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; return; } } diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index ab8a4b7934..9bb2a4ddb8 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -41,11 +41,11 @@ #define PACKED_SCENE_VERSION 2 -bool SceneState::can_instance() const { +bool SceneState::can_instantiate() const { return nodes.size() > 0; } -Node *SceneState::instance(GenEditState p_edit_state) const { +Node *SceneState::instantiate(GenEditState p_edit_state) const { // nodes where instancing failed (because something is missing) List<Node *> stray_instances; @@ -109,7 +109,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { //scene inheritance on root node Ref<PackedScene> sdata = props[base_scene_idx]; ERR_FAIL_COND_V(!sdata.is_valid(), nullptr); - node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); //only main gets main edit state + node = sdata->instantiate(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); //only main gets main edit state ERR_FAIL_COND_V(!node, nullptr); if (p_edit_state != GEN_EDIT_STATE_DISABLED) { node->set_scene_inherited_state(sdata->get_state()); @@ -122,7 +122,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { if (disable_placeholders) { Ref<PackedScene> sdata = ResourceLoader::load(path, "PackedScene"); ERR_FAIL_COND_V(!sdata.is_valid(), nullptr); - node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); + node = sdata->instantiate(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); ERR_FAIL_COND_V(!node, nullptr); } else { InstancePlaceholder *ip = memnew(InstancePlaceholder); @@ -133,7 +133,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } else { Ref<PackedScene> sdata = props[n.instance & FLAG_MASK]; ERR_FAIL_COND_V(!sdata.is_valid(), nullptr); - node = sdata->instance(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); + node = sdata->instantiate(p_edit_state == GEN_EDIT_STATE_DISABLED ? PackedScene::GEN_EDIT_STATE_DISABLED : PackedScene::GEN_EDIT_STATE_INSTANCE); ERR_FAIL_COND_V(!node, nullptr); } @@ -152,7 +152,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { if (ClassDB::is_class_enabled(snames[n.type])) { //node belongs to this scene and must be created - obj = ClassDB::instance(snames[n.type]); + obj = ClassDB::instantiate(snames[n.type]); } if (!Object::cast_to<Node>(obj)) { @@ -180,7 +180,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } if (node) { - // may not have found the node (part of instanced scene and removed) + // may not have found the node (part of instantiated scene and removed) // if found all is good, otherwise ignore //properties @@ -266,7 +266,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { parent->move_child(node, n.index); } } else { - //it may be possible that an instanced scene has changed + //it may be possible that an instantiated scene has changed //and the node has nowhere to go anymore stray_instances.push_back(node); //can't be added, go to stray list } @@ -368,7 +368,7 @@ static int _vm_get_variant(const Variant &p_variant, HashMap<Variant, int, Varia Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map<StringName, int> &name_map, HashMap<Variant, int, VariantHasher, VariantComparator> &variant_map, Map<Node *, int> &node_map, Map<Node *, int> &nodepath_map) { // this function handles all the work related to properly packing scenes, be it - // instanced or inherited. + // instantiated or inherited. // given the complexity of this process, an attempt will be made to properly // document it. if you fail to understand something, please ask! @@ -377,7 +377,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map return OK; } - // save the child instanced scenes that are chosen as editable, so they can be restored + // save the child instantiated scenes that are chosen as editable, so they can be restored // upon load back if (p_node != p_owner && p_node->get_filename() != String() && p_owner->is_editable_instance(p_node)) { editable_instances.push_back(p_owner->get_path_to(p_node)); @@ -386,7 +386,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map NodeData nd; nd.name = _nm_get_string(p_node->get_name(), name_map); - nd.instance = -1; //not instanced by default + nd.instance = -1; //not instantiated by default //really convoluted condition, but it basically checks that index is only saved when part of an inherited scene OR the node parent is from the edited scene if (p_owner->get_scene_inherited_state().is_null() && (p_node == p_owner || (p_node->get_owner() == p_owner && (p_node->get_parent() == p_owner || p_node->get_parent()->get_owner() == p_owner)))) { @@ -396,18 +396,18 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map //This (hopefully) happens if the node is a scene root, so its index is irrelevant. nd.index = -1; } else { - //part of an inherited scene, or parent is from an instanced scene + //part of an inherited scene, or parent is from an instantiated scene nd.index = p_node->get_index(); } - // if this node is part of an instanced scene or sub-instanced scene + // if this node is part of an instantiated scene or sub-instantiated scene // we need to get the corresponding instance states. // with the instance states, we can query for identical properties/groups // and only save what has changed List<PackState> pack_state_stack; - bool instanced_by_owner = true; + bool instantiated_by_owner = true; { Node *n = p_node; @@ -423,11 +423,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map ps.node = node; ps.state = state; pack_state_stack.push_back(ps); - instanced_by_owner = false; + instantiated_by_owner = false; } } - if (p_node->get_filename() != String() && p_node->get_owner() == p_owner && instanced_by_owner) { + if (p_node->get_filename() != String() && p_node->get_owner() == p_owner && instantiated_by_owner) { if (p_node->get_scene_instance_load_placeholder()) { //it's a placeholder, use the placeholder path nd.instance = _vm_get_variant(p_node->get_filename(), variant_map); @@ -471,7 +471,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map StringName type = p_node->get_class(); Ref<Script> script = p_node->get_script(); - if (script.is_valid()) { + if (Engine::get_singleton()->is_editor_hint() && script.is_valid()) { + // Should be called in the editor only and not at runtime, + // otherwise it can cause problems because of missing instance state support. script->update_exports(); } @@ -500,8 +502,8 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map // } if (pack_state_stack.size()) { - // we are on part of an instanced subscene - // or part of instanced scene. + // we are on part of an instantiated subscene + // or part of instantiated scene. // only save what has been changed // only save changed properties in instance @@ -571,7 +573,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map } /* if (instance_state_node>=0 && instance_state->is_node_in_group(instance_state_node,gi.name)) - continue; //group was instanced, don't add here + continue; //group was instantiated, don't add here */ bool skip = false; @@ -594,7 +596,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map // save the right owner // for the saved scene root this is -1 // for nodes of the saved scene this is 0 - // for nodes of instanced scenes this is >0 + // for nodes of instantiated scenes this is >0 if (p_node == p_owner) { //saved scene root @@ -612,20 +614,20 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map //this node is not part of an instancing process, so save the type nd.type = _nm_get_string(p_node->get_class(), name_map); } else { - // this node is part of an instanced process, so do not save the type. - // instead, save that it was instanced + // this node is part of an instantiated process, so do not save the type. + // instead, save that it was instantiated nd.type = TYPE_INSTANCED; } // determine whether to save this node or not - // if this node is part of an instanced sub-scene, we can skip storing it if basically + // if this node is part of an instantiated sub-scene, we can skip storing it if basically // no properties changed and no groups were added to it. // below condition is true for all nodes of the scene being saved, and ones in subscenes // that hold changes bool save_node = nd.properties.size() || nd.groups.size(); // some local properties or groups exist save_node = save_node || p_node == p_owner; // owner is always saved - save_node = save_node || (p_node->get_owner() == p_owner && instanced_by_owner); //part of scene and not instanced + save_node = save_node || (p_node->get_owner() == p_owner && instantiated_by_owner); //part of scene and not instantiated int idx = nodes.size(); int parent_node = NO_PARENT_SAVED; @@ -893,6 +895,13 @@ Error SceneState::pack(Node *p_scene) { node_paths.write[E->get()] = scene->get_path_to(E->key()); } + if (Engine::get_singleton()->is_editor_hint()) { + // Build node path cache + for (Map<Node *, int>::Element *E = node_map.front(); E; E = E->next()) { + node_path_cache[scene->get_path_to(E->key())] = E->get(); + } + } + return OK; } @@ -927,10 +936,12 @@ Ref<SceneState> SceneState::_get_base_scene_state() const { } int SceneState::find_node_by_path(const NodePath &p_node) const { + ERR_FAIL_COND_V_MSG(node_path_cache.size() == 0, -1, "This operation requires the node cache to have been built."); + if (!node_path_cache.has(p_node)) { if (_get_base_scene_state().is_valid()) { int idx = _get_base_scene_state()->find_node_by_path(p_node); - if (idx >= 0) { + if (idx != -1) { int rkey = _find_base_scene_node_remap_key(idx); if (rkey == -1) { rkey = nodes.size() + base_scene_node_remap.size(); @@ -946,7 +957,7 @@ int SceneState::find_node_by_path(const NodePath &p_node) const { if (_get_base_scene_state().is_valid() && !base_scene_node_remap.has(nid)) { //for nodes that _do_ exist in current scene, still try to look for - //the node in the instanced scene, as a property may be missing + //the node in the instantiated scene, as a property may be missing //from the local one int idx = _get_base_scene_state()->find_node_by_path(p_node); if (idx != -1) { @@ -1614,16 +1625,16 @@ void PackedScene::clear() { state->clear(); } -bool PackedScene::can_instance() const { - return state->can_instance(); +bool PackedScene::can_instantiate() const { + return state->can_instantiate(); } -Node *PackedScene::instance(GenEditState p_edit_state) const { +Node *PackedScene::instantiate(GenEditState p_edit_state) const { #ifndef TOOLS_ENABLED ERR_FAIL_COND_V_MSG(p_edit_state != GEN_EDIT_STATE_DISABLED, nullptr, "Edit state is only for editors, does not work without tools compiled."); #endif - Node *s = state->instance((SceneState::GenEditState)p_edit_state); + Node *s = state->instantiate((SceneState::GenEditState)p_edit_state); if (!s) { return nullptr; } @@ -1671,8 +1682,8 @@ void PackedScene::reset_state() { } void PackedScene::_bind_methods() { ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack); - ClassDB::bind_method(D_METHOD("instance", "edit_state"), &PackedScene::instance, DEFVAL(GEN_EDIT_STATE_DISABLED)); - ClassDB::bind_method(D_METHOD("can_instance"), &PackedScene::can_instance); + ClassDB::bind_method(D_METHOD("instantiate", "edit_state"), &PackedScene::instantiate, DEFVAL(GEN_EDIT_STATE_DISABLED)); + ClassDB::bind_method(D_METHOD("can_instantiate"), &PackedScene::can_instantiate); ClassDB::bind_method(D_METHOD("_set_bundled_scene"), &PackedScene::_set_bundled_scene); ClassDB::bind_method(D_METHOD("_get_bundled_scene"), &PackedScene::_get_bundled_scene); ClassDB::bind_method(D_METHOD("get_state"), &PackedScene::get_state); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 78a0aeaa9a..55708f7914 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -34,8 +34,8 @@ #include "core/io/resource.h" #include "scene/main/node.h" -class SceneState : public Reference { - GDCLASS(SceneState, Reference); +class SceneState : public RefCounted { + GDCLASS(SceneState, RefCounted); Vector<StringName> names; Vector<Variant> variants; @@ -136,8 +136,8 @@ public: void clear(); - bool can_instance() const; - Node *instance(GenEditState p_edit_state) const; + bool can_instantiate() const; + Node *instantiate(GenEditState p_edit_state) const; //unbuild API @@ -213,8 +213,8 @@ public: void clear(); - bool can_instance() const; - Node *instance(GenEditState p_edit_state = GEN_EDIT_STATE_DISABLED) const; + bool can_instantiate() const; + Node *instantiate(GenEditState p_edit_state = GEN_EDIT_STATE_DISABLED) const; void recreate_state(); void replace_state(Ref<SceneState> p_by); diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 60d5566f08..2bde98abe0 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -852,52 +852,54 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture2D tex_parameters[p_param] = p_texture; + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + switch (p_param) { case PARAM_INITIAL_LINEAR_VELOCITY: { //do none for this one } break; case PARAM_ANGULAR_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angular_velocity_texture, tex_rid); _adjust_curve_range(p_texture, -360, 360); } break; case PARAM_ORBIT_VELOCITY: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->orbit_velocity_texture, tex_rid); _adjust_curve_range(p_texture, -500, 500); } break; case PARAM_LINEAR_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->linear_accel_texture, tex_rid); _adjust_curve_range(p_texture, -200, 200); } break; case PARAM_RADIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->radial_accel_texture, tex_rid); _adjust_curve_range(p_texture, -200, 200); } break; case PARAM_TANGENTIAL_ACCEL: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->tangent_accel_texture, tex_rid); _adjust_curve_range(p_texture, -200, 200); } break; case PARAM_DAMPING: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->damping_texture, tex_rid); _adjust_curve_range(p_texture, 0, 100); } break; case PARAM_ANGLE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->angle_texture, tex_rid); _adjust_curve_range(p_texture, -360, 360); } break; case PARAM_SCALE: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->scale_texture, tex_rid); _adjust_curve_range(p_texture, 0, 1); } break; case PARAM_HUE_VARIATION: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->hue_variation_texture, tex_rid); _adjust_curve_range(p_texture, -1, 1); } break; case PARAM_ANIM_SPEED: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_speed_texture, tex_rid); _adjust_curve_range(p_texture, 0, 200); } break; case PARAM_ANIM_OFFSET: { - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, tex_rid); } break; case PARAM_MAX: break; // Can't happen, but silences warning @@ -923,7 +925,8 @@ Color ParticlesMaterial::get_color() const { void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { color_ramp = p_texture; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture); + RID tex_rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, tex_rid); _queue_shader_change(); notify_property_list_changed(); } @@ -965,17 +968,20 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) { void ParticlesMaterial::set_emission_point_texture(const Ref<Texture2D> &p_points) { emission_point_texture = p_points; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points); + RID tex_rid = p_points.is_valid() ? p_points->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, tex_rid); } void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture2D> &p_normals) { emission_normal_texture = p_normals; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals); + RID tex_rid = p_normals.is_valid() ? p_normals->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, tex_rid); } void ParticlesMaterial::set_emission_color_texture(const Ref<Texture2D> &p_colors) { emission_color_texture = p_colors; - RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors); + RID tex_rid = p_colors.is_valid() ? p_colors->get_rid() : RID(); + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, tex_rid); _queue_shader_change(); } @@ -1041,39 +1047,39 @@ RID ParticlesMaterial::get_shader_rid() const { void ParticlesMaterial::_validate_property(PropertyInfo &property) const { if (property.name == "color" && color_ramp.is_valid()) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_sphere_radius" && emission_shape != EMISSION_SHAPE_SPHERE) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_box_extents" && emission_shape != EMISSION_SHAPE_BOX) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if ((property.name == "emission_point_texture" || property.name == "emission_color_texture") && (emission_shape < EMISSION_SHAPE_POINTS)) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_normal_texture" && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "emission_point_count" && (emission_shape != EMISSION_SHAPE_POINTS && emission_shape != EMISSION_SHAPE_DIRECTED_POINTS)) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "sub_emitter_frequency" && sub_emitter_mode != SUB_EMITTER_CONSTANT) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name == "sub_emitter_amount_at_end" && sub_emitter_mode != SUB_EMITTER_AT_END) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } if (property.name.begins_with("orbit_") && !particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -1292,7 +1298,7 @@ void ParticlesMaterial::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING); ADD_GROUP("Angle", ""); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater,degrees"), "set_param", "get_param", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE); ADD_GROUP("Scale", ""); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 64b43f82c6..dfa45cc810 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -207,7 +207,7 @@ void PrimitiveMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces); ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,StandardMaterial3D"), "set_material", "get_material"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces"); } @@ -714,7 +714,7 @@ int BoxMesh::get_subdivide_depth() const { BoxMesh::BoxMesh() {} /** - CylinderMesh + CylinderMesh */ void CylinderMesh::_create_mesh_array(Array &p_arr) const { @@ -866,9 +866,9 @@ void CylinderMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings); ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_top_radius", "get_top_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_bottom_radius", "get_bottom_radius"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater"), "set_height", "get_height"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "top_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_top_radius", "get_top_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bottom_radius", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_bottom_radius", "get_bottom_radius"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings"); } @@ -955,7 +955,7 @@ void PlaneMesh::_create_mesh_array(Array &p_arr) const { u /= (subdivide_w + 1.0); v /= (subdivide_d + 1.0); - points.push_back(Vector3(-x, 0.0, -z)); + points.push_back(Vector3(-x, 0.0, -z) + center_offset); normals.push_back(Vector3(0.0, 1.0, 0.0)); ADD_TANGENT(1.0, 0.0, 0.0, 1.0); uvs.push_back(Vector2(1.0 - u, 1.0 - v)); /* 1.0 - uv to match orientation with Quad */ @@ -993,10 +993,13 @@ void PlaneMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("get_subdivide_width"), &PlaneMesh::get_subdivide_width); ClassDB::bind_method(D_METHOD("set_subdivide_depth", "subdivide"), &PlaneMesh::set_subdivide_depth); ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PlaneMesh::get_subdivide_depth); + ClassDB::bind_method(D_METHOD("set_center_offset", "offset"), &PlaneMesh::set_center_offset); + ClassDB::bind_method(D_METHOD("get_center_offset"), &PlaneMesh::get_center_offset); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_width", "get_subdivide_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_subdivide_depth", "get_subdivide_depth"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } void PlaneMesh::set_size(const Size2 &p_size) { @@ -1026,6 +1029,15 @@ int PlaneMesh::get_subdivide_depth() const { return subdivide_d; } +void PlaneMesh::set_center_offset(const Vector3 p_offset) { + center_offset = p_offset; + _request_update(); +} + +Vector3 PlaneMesh::get_center_offset() const { + return center_offset; +} + PlaneMesh::PlaneMesh() {} /** @@ -1326,10 +1338,10 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { Vector2 _size = Vector2(size.x / 2.0f, size.y / 2.0f); Vector3 quad_faces[4] = { - Vector3(-_size.x, -_size.y, 0), - Vector3(-_size.x, _size.y, 0), - Vector3(_size.x, _size.y, 0), - Vector3(_size.x, -_size.y, 0), + Vector3(-_size.x, -_size.y, 0) + center_offset, + Vector3(-_size.x, _size.y, 0) + center_offset, + Vector3(_size.x, _size.y, 0) + center_offset, + Vector3(_size.x, -_size.y, 0) + center_offset, }; static const int indices[6] = { @@ -1365,7 +1377,11 @@ void QuadMesh::_create_mesh_array(Array &p_arr) const { void QuadMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &QuadMesh::set_size); ClassDB::bind_method(D_METHOD("get_size"), &QuadMesh::get_size); + ClassDB::bind_method(D_METHOD("set_center_offset", "center_offset"), &QuadMesh::set_center_offset); + ClassDB::bind_method(D_METHOD("get_center_offset"), &QuadMesh::get_center_offset); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_offset"), "set_center_offset", "get_center_offset"); } QuadMesh::QuadMesh() { @@ -1381,6 +1397,15 @@ Size2 QuadMesh::get_size() const { return size; } +void QuadMesh::set_center_offset(Vector3 p_center_offset) { + center_offset = p_center_offset; + _request_update(); +} + +Vector3 QuadMesh::get_center_offset() const { + return center_offset; +} + /** SphereMesh */ @@ -1607,10 +1632,10 @@ int TubeTrailMesh::get_builtin_bind_pose_count() const { return sections + 1; } -Transform TubeTrailMesh::get_builtin_bind_pose(int p_index) const { +Transform3D TubeTrailMesh::get_builtin_bind_pose(int p_index) const { float depth = section_length * sections; - Transform xform; + Transform3D xform; xform.origin.y = depth / 2.0 - section_length * float(p_index); xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y @@ -1931,10 +1956,10 @@ int RibbonTrailMesh::get_builtin_bind_pose_count() const { return sections + 1; } -Transform RibbonTrailMesh::get_builtin_bind_pose(int p_index) const { +Transform3D RibbonTrailMesh::get_builtin_bind_pose(int p_index) const { float depth = section_length * sections; - Transform xform; + Transform3D xform; xform.origin.y = depth / 2.0 - section_length * float(p_index); xform.origin.y = -xform.origin.y; //bind is an inverse transform, so negate y diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index ec5806489e..a3de34d3e3 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -211,6 +211,7 @@ private: Size2 size = Size2(2.0, 2.0); int subdivide_w = 0; int subdivide_d = 0; + Vector3 center_offset; protected: static void _bind_methods(); @@ -226,6 +227,9 @@ public: void set_subdivide_depth(const int p_divisions); int get_subdivide_depth() const; + void set_center_offset(const Vector3 p_offset); + Vector3 get_center_offset() const; + PlaneMesh(); }; @@ -274,6 +278,7 @@ class QuadMesh : public PrimitiveMesh { private: Size2 size = Size2(1.0, 1.0); + Vector3 center_offset; protected: static void _bind_methods(); @@ -284,6 +289,9 @@ public: void set_size(const Size2 &p_size); Size2 get_size() const; + + void set_center_offset(const Vector3 p_offset); + Vector3 get_center_offset() const; }; /** @@ -374,7 +382,7 @@ public: Ref<Curve> get_curve() const; virtual int get_builtin_bind_pose_count() const override; - virtual Transform get_builtin_bind_pose(int p_index) const override; + virtual Transform3D get_builtin_bind_pose(int p_index) const override; TubeTrailMesh(); }; @@ -424,7 +432,7 @@ public: Ref<Curve> get_curve() const; virtual int get_builtin_bind_pose_count() const override; - virtual Transform get_builtin_bind_pose(int p_index) const override; + virtual Transform3D get_builtin_bind_pose(int p_index) const override; RibbonTrailMesh(); }; diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index dc4c6dc2d7..17ce0b34ac 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -37,6 +37,26 @@ void RectangleShape2D::_update_shape() { emit_changed(); } +#ifndef DISABLE_DEPRECATED +bool RectangleShape2D::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "extents") { // Compatibility with Godot 3.x. + // Convert to `size`, twice as big. + set_size((Vector2)p_value * 2); + return true; + } + return false; +} + +bool RectangleShape2D::_get(const StringName &p_name, Variant &r_property) const { + if (p_name == "extents") { // Compatibility with Godot 3.x. + // Convert to `extents`, half as big. + r_property = size / 2; + return true; + } + return false; +} +#endif // DISABLE_DEPRECATED + void RectangleShape2D::set_size(const Vector2 &p_size) { size = p_size; _update_shape(); diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h index 8d747c86af..f1e8be4c5b 100644 --- a/scene/resources/rectangle_shape_2d.h +++ b/scene/resources/rectangle_shape_2d.h @@ -41,6 +41,10 @@ class RectangleShape2D : public Shape2D { protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_property) const; +#endif // DISABLE_DEPRECATED public: void set_size(const Vector2 &p_size); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 2414704a57..ee61e64ed3 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -31,14 +31,14 @@ #include "resource_format_text.h" #include "core/config/project_settings.h" +#include "core/io/dir_access.h" #include "core/io/resource_format_binary.h" -#include "core/os/dir_access.h" #include "core/version.h" //version 2: changed names for basis, aabb, Vectors, etc. #define FORMAT_VERSION 2 -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "core/version.h" #define _printerr() ERR_PRINT(String(res_path + ":" + itos(lines) + " - Parse Error: " + error_text).utf8().get_data()); @@ -65,7 +65,7 @@ Error ResourceLoaderText::_parse_sub_resource_dummy(DummyReadData *p_data, Varia if (!p_data->resource_map.has(index)) { Ref<DummyResource> dr; - dr.instance(); + dr.instantiate(); dr->set_subindex(index); p_data->resource_map[index] = dr; p_data->resource_set.insert(dr); @@ -183,7 +183,7 @@ Error ResourceLoaderText::_parse_ext_resource(VariantParser::Stream *p_stream, R Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourceParser &parser) { Ref<PackedScene> packed_scene; - packed_scene.instance(); + packed_scene.instantiate(); while (true) { if (next_tag.name == "node") { @@ -208,7 +208,7 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars if (next_tag.fields.has("type")) { type = packed_scene->get_state()->add_name(next_tag.fields["type"]); } else { - type = SceneState::TYPE_INSTANCED; //no type? assume this was instanced + type = SceneState::TYPE_INSTANCED; //no type? assume this was instantiated } if (next_tag.fields.has("instance")) { @@ -522,7 +522,7 @@ Error ResourceLoaderText::load() { } else { //create - Object *obj = ClassDB::instance(type); + Object *obj = ClassDB::instantiate(type); if (!obj) { error_text += "Can't create sub resource of type: " + type; _printerr(); @@ -575,6 +575,7 @@ Error ResourceLoaderText::load() { int_resources[id] = res; //always assign int resources if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); + res->set_subindex(id); } if (progress && resources_total > 0) { @@ -603,7 +604,7 @@ Error ResourceLoaderText::load() { } if (!resource.is_valid()) { - Object *obj = ClassDB::instance(res_type); + Object *obj = ClassDB::instantiate(res_type); if (!obj) { error_text += "Can't create sub resource of type: " + res_type; _printerr(); @@ -1021,7 +1022,7 @@ Error ResourceLoaderText::save_as_binary(FileAccess *p_f, const String &p_path) int lindex = dummy_read.external_resources.size(); Ref<DummyResource> dr; - dr.instance(); + dr.instantiate(); dr->set_path("res://dummy" + itos(lindex)); //anything is good to detect it for saving as external dummy_read.external_resources[dr] = lindex; dummy_read.rev_external_resources[index] = dr; diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 2dc683415d..f5d9cca859 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -31,9 +31,9 @@ #ifndef RESOURCE_FORMAT_TEXT_H #define RESOURCE_FORMAT_TEXT_H +#include "core/io/file_access.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/os/file_access.h" #include "core/variant/variant_parser.h" #include "scene/resources/packed_scene.h" diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 77c6199794..f19d08dbb1 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -30,7 +30,7 @@ #include "shader.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "scene/scene_string_names.h" #include "servers/rendering/shader_language.h" #include "servers/rendering_server.h" @@ -167,7 +167,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_origi } Ref<Shader> shader; - shader.instance(); + shader.instantiate(); Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path); @@ -184,7 +184,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_origi } void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const { - p_extensions->push_back("shader"); + p_extensions->push_back("gdshader"); } bool ResourceFormatLoaderShader::handles_type(const String &p_type) const { @@ -193,7 +193,7 @@ bool ResourceFormatLoaderShader::handles_type(const String &p_type) const { String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const { String el = p_path.get_extension().to_lower(); - if (el == "shader") { + if (el == "gdshader") { return "Shader"; } return ""; @@ -224,7 +224,7 @@ Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resourc void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { if (const Shader *shader = Object::cast_to<Shader>(*p_resource)) { if (shader->is_text_shader()) { - p_extensions->push_back("shader"); + p_extensions->push_back("gdshader"); } } } diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp index cb44e059a3..a02a0e5488 100644 --- a/scene/resources/shape_3d.cpp +++ b/scene/resources/shape_3d.cpp @@ -35,7 +35,7 @@ #include "scene/resources/mesh.h" #include "servers/physics_server_3d.h" -void Shape3D::add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform) { +void Shape3D::add_vertices_to_array(Vector<Vector3> &array, const Transform3D &p_xform) { Vector<Vector3> toadd = get_debug_mesh_lines(); if (toadd.size()) { diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h index 0644940fd4..b8e529cd3c 100644 --- a/scene/resources/shape_3d.h +++ b/scene/resources/shape_3d.h @@ -60,7 +60,7 @@ public: /// Returns the radius of a sphere that fully enclose this shape virtual real_t get_enclosing_radius() const = 0; - void add_vertices_to_array(Vector<Vector3> &array, const Transform &p_xform); + void add_vertices_to_array(Vector<Vector3> &array, const Transform3D &p_xform); real_t get_margin() const; void set_margin(real_t p_margin); diff --git a/scene/resources/skeleton_modification_2d.cpp b/scene/resources/skeleton_modification_2d.cpp new file mode 100644 index 0000000000..b52a60006a --- /dev/null +++ b/scene/resources/skeleton_modification_2d.cpp @@ -0,0 +1,253 @@ +/*************************************************************************/ +/* skeleton_modification_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d.h" +#include "scene/2d/skeleton_2d.h" + +#include "scene/2d/collision_object_2d.h" +#include "scene/2d/collision_shape_2d.h" +#include "scene/2d/physical_bone_2d.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif // TOOLS_ENABLED + +/////////////////////////////////////// +// Modification2D +/////////////////////////////////////// + +void SkeletonModification2D::_execute(float p_delta) { + call("_execute", p_delta); + + if (!enabled) { + return; + } +} + +void SkeletonModification2D::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + if (stack) { + is_setup = true; + } else { + WARN_PRINT("Could not setup modification with name " + get_name()); + } + + call("_setup_modification", p_stack); +} + +void SkeletonModification2D::_draw_editor_gizmo() { + call("_draw_editor_gizmo"); +} + +void SkeletonModification2D::set_enabled(bool p_enabled) { + enabled = p_enabled; + +#ifdef TOOLS_ENABLED + if (editor_draw_gizmo) { + if (stack) { + stack->set_editor_gizmos_dirty(true); + } + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2D::get_enabled() { + return enabled; +} + +float SkeletonModification2D::clamp_angle(float p_angle, float p_min_bound, float p_max_bound, bool p_invert) { + // Map to the 0 to 360 range (in radians though) instead of the -180 to 180 range. + if (p_angle < 0) { + p_angle = Math_TAU + p_angle; + } + + // Make min and max in the range of 0 to 360 (in radians), and make sure they are in the right order + if (p_min_bound < 0) { + p_min_bound = Math_TAU + p_min_bound; + } + if (p_max_bound < 0) { + p_max_bound = Math_TAU + p_max_bound; + } + if (p_min_bound > p_max_bound) { + float tmp = p_min_bound; + p_min_bound = p_max_bound; + p_max_bound = tmp; + } + + // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle. + if (p_invert == false) { + if (p_angle < p_min_bound || p_angle > p_max_bound) { + Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); + Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); + Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); + + if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { + p_angle = p_min_bound; + } else { + p_angle = p_max_bound; + } + } + } else { + if (p_angle > p_min_bound && p_angle < p_max_bound) { + Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound)); + Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound)); + Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle)); + + if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) { + p_angle = p_min_bound; + } else { + p_angle = p_max_bound; + } + } + } + return p_angle; +} + +void SkeletonModification2D::editor_draw_angle_constraints(Bone2D *p_operation_bone, float p_min_bound, float p_max_bound, + bool p_constraint_enabled, bool p_constraint_in_localspace, bool p_constraint_inverted) { + if (!p_operation_bone) { + return; + } + + Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4); +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); + } +#endif // TOOLS_ENABLED + + float arc_angle_min = p_min_bound; + float arc_angle_max = p_max_bound; + if (arc_angle_min < 0) { + arc_angle_min = (Math_PI * 2) + arc_angle_min; + } + if (arc_angle_max < 0) { + arc_angle_max = (Math_PI * 2) + arc_angle_max; + } + if (arc_angle_min > arc_angle_max) { + float tmp = arc_angle_min; + arc_angle_min = arc_angle_max; + arc_angle_max = tmp; + } + arc_angle_min += p_operation_bone->get_bone_angle(); + arc_angle_max += p_operation_bone->get_bone_angle(); + + if (p_constraint_enabled) { + if (p_constraint_in_localspace) { + Node *operation_bone_parent = p_operation_bone->get_parent(); + Bone2D *operation_bone_parent_bone = Object::cast_to<Bone2D>(operation_bone_parent); + + if (operation_bone_parent_bone) { + stack->skeleton->draw_set_transform( + stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position()), + operation_bone_parent_bone->get_global_rotation() - stack->skeleton->get_global_rotation()); + } else { + stack->skeleton->draw_set_transform(stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position())); + } + } else { + stack->skeleton->draw_set_transform(stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position())); + } + + if (p_constraint_inverted) { + stack->skeleton->draw_arc(Vector2(0, 0), p_operation_bone->get_length(), + arc_angle_min + (Math_PI * 2), arc_angle_max, 32, bone_ik_color, 1.0); + } else { + stack->skeleton->draw_arc(Vector2(0, 0), p_operation_bone->get_length(), + arc_angle_min, arc_angle_max, 32, bone_ik_color, 1.0); + } + stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(arc_angle_min), Math::sin(arc_angle_min)) * p_operation_bone->get_length(), bone_ik_color, 1.0); + stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(arc_angle_max), Math::sin(arc_angle_max)) * p_operation_bone->get_length(), bone_ik_color, 1.0); + + } else { + stack->skeleton->draw_set_transform(stack->skeleton->get_global_transform().affine_inverse().xform(p_operation_bone->get_global_position())); + stack->skeleton->draw_arc(Vector2(0, 0), p_operation_bone->get_length(), 0, Math_PI * 2, 32, bone_ik_color, 1.0); + stack->skeleton->draw_line(Vector2(0, 0), Vector2(1, 0) * p_operation_bone->get_length(), bone_ik_color, 1.0); + } +} + +Ref<SkeletonModificationStack2D> SkeletonModification2D::get_modification_stack() { + return stack; +} + +void SkeletonModification2D::set_is_setup(bool p_setup) { + is_setup = p_setup; +} + +bool SkeletonModification2D::get_is_setup() const { + return is_setup; +} + +void SkeletonModification2D::set_execution_mode(int p_mode) { + execution_mode = p_mode; +} + +int SkeletonModification2D::get_execution_mode() const { + return execution_mode; +} + +void SkeletonModification2D::set_editor_draw_gizmo(bool p_draw_gizmo) { + editor_draw_gizmo = p_draw_gizmo; +#ifdef TOOLS_ENABLED + if (is_setup) { + if (stack) { + stack->set_editor_gizmos_dirty(true); + } + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2D::get_editor_draw_gizmo() const { + return editor_draw_gizmo; +} + +void SkeletonModification2D::_bind_methods() { + BIND_VMETHOD(MethodInfo("_execute", PropertyInfo(Variant::FLOAT, "delta"))); + BIND_VMETHOD(MethodInfo("_setup_modification", PropertyInfo(Variant::OBJECT, "modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D"))); + BIND_VMETHOD(MethodInfo("_draw_editor_gizmo")); + + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification2D::set_enabled); + ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification2D::get_enabled); + ClassDB::bind_method(D_METHOD("get_modification_stack"), &SkeletonModification2D::get_modification_stack); + ClassDB::bind_method(D_METHOD("set_is_setup", "is_setup"), &SkeletonModification2D::set_is_setup); + ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModification2D::get_is_setup); + ClassDB::bind_method(D_METHOD("set_execution_mode", "execution_mode"), &SkeletonModification2D::set_execution_mode); + ClassDB::bind_method(D_METHOD("get_execution_mode"), &SkeletonModification2D::get_execution_mode); + ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification2D::clamp_angle); + ClassDB::bind_method(D_METHOD("set_editor_draw_gizmo", "draw_gizmo"), &SkeletonModification2D::set_editor_draw_gizmo); + ClassDB::bind_method(D_METHOD("get_editor_draw_gizmo"), &SkeletonModification2D::get_editor_draw_gizmo); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process, physics_process"), "set_execution_mode", "get_execution_mode"); +} + +SkeletonModification2D::SkeletonModification2D() { + stack = nullptr; + is_setup = false; +} diff --git a/scene/resources/skeleton_modification_2d.h b/scene/resources/skeleton_modification_2d.h new file mode 100644 index 0000000000..18633e55cb --- /dev/null +++ b/scene/resources/skeleton_modification_2d.h @@ -0,0 +1,85 @@ +/*************************************************************************/ +/* skeleton_modification_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2D_H +#define SKELETONMODIFICATION2D_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_stack_2d.h" + +/////////////////////////////////////// +// SkeletonModification2D +/////////////////////////////////////// + +class SkeletonModificationStack2D; +class Bone2D; + +class SkeletonModification2D : public Resource { + GDCLASS(SkeletonModification2D, Resource); + friend class Skeleton2D; + friend class Bone2D; + +protected: + static void _bind_methods(); + + SkeletonModificationStack2D *stack; + int execution_mode = 0; // 0 = process + + bool enabled = true; + bool is_setup = false; + + bool _print_execution_error(bool p_condition, String p_message); + +public: + virtual void _execute(float _delta); + virtual void _setup_modification(SkeletonModificationStack2D *p_stack); + virtual void _draw_editor_gizmo(); + + bool editor_draw_gizmo = false; + void set_editor_draw_gizmo(bool p_draw_gizmo); + bool get_editor_draw_gizmo() const; + + void set_enabled(bool p_enabled); + bool get_enabled(); + + Ref<SkeletonModificationStack2D> get_modification_stack(); + void set_is_setup(bool p_setup); + bool get_is_setup() const; + + void set_execution_mode(int p_mode); + int get_execution_mode() const; + + float clamp_angle(float p_angle, float p_min_bound, float p_max_bound, bool p_invert_clamp = false); + void editor_draw_angle_constraints(Bone2D *p_operation_bone, float p_min_bound, float p_max_bound, bool p_constraint_enabled, bool p_constraint_in_localspace, bool p_constraint_inverted); + + SkeletonModification2D(); +}; + +#endif // SKELETONMODIFICATION2D_H diff --git a/scene/resources/skeleton_modification_2d_ccdik.cpp b/scene/resources/skeleton_modification_2d_ccdik.cpp new file mode 100644 index 0000000000..7ea60e584e --- /dev/null +++ b/scene/resources/skeleton_modification_2d_ccdik.cpp @@ -0,0 +1,545 @@ +/*************************************************************************/ +/* skeleton_modification_2d_ccdik.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_ccdik.h" +#include "scene/2d/skeleton_2d.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif // TOOLS_ENABLED + +bool SkeletonModification2DCCDIK::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("joint_data/")) { + int which = path.get_slicec('/', 1).to_int(); + String what = path.get_slicec('/', 2); + ERR_FAIL_INDEX_V(which, ccdik_data_chain.size(), false); + + if (what == "bone2d_node") { + set_ccdik_joint_bone2d_node(which, p_value); + } else if (what == "bone_index") { + set_ccdik_joint_bone_index(which, p_value); + } else if (what == "rotate_from_joint") { + set_ccdik_joint_rotate_from_joint(which, p_value); + } else if (what == "enable_constraint") { + set_ccdik_joint_enable_constraint(which, p_value); + } else if (what == "constraint_angle_min") { + set_ccdik_joint_constraint_angle_min(which, Math::deg2rad(float(p_value))); + } else if (what == "constraint_angle_max") { + set_ccdik_joint_constraint_angle_max(which, Math::deg2rad(float(p_value))); + } else if (what == "constraint_angle_invert") { + set_ccdik_joint_constraint_angle_invert(which, p_value); + } else if (what == "constraint_in_localspace") { + set_ccdik_joint_constraint_in_localspace(which, p_value); + } + +#ifdef TOOLS_ENABLED + if (what.begins_with("editor_draw_gizmo")) { + set_ccdik_joint_editor_draw_gizmo(which, p_value); + } +#endif // TOOLS_ENABLED + + return true; + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor/draw_gizmo")) { + set_editor_draw_gizmo(p_value); + } +#endif // TOOLS_ENABLED + + return true; +} + +bool SkeletonModification2DCCDIK::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("joint_data/")) { + int which = path.get_slicec('/', 1).to_int(); + String what = path.get_slicec('/', 2); + ERR_FAIL_INDEX_V(which, ccdik_data_chain.size(), false); + + if (what == "bone2d_node") { + r_ret = get_ccdik_joint_bone2d_node(which); + } else if (what == "bone_index") { + r_ret = get_ccdik_joint_bone_index(which); + } else if (what == "rotate_from_joint") { + r_ret = get_ccdik_joint_rotate_from_joint(which); + } else if (what == "enable_constraint") { + r_ret = get_ccdik_joint_enable_constraint(which); + } else if (what == "constraint_angle_min") { + r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_min(which)); + } else if (what == "constraint_angle_max") { + r_ret = Math::rad2deg(get_ccdik_joint_constraint_angle_max(which)); + } else if (what == "constraint_angle_invert") { + r_ret = get_ccdik_joint_constraint_angle_invert(which); + } else if (what == "constraint_in_localspace") { + r_ret = get_ccdik_joint_constraint_in_localspace(which); + } + +#ifdef TOOLS_ENABLED + if (what.begins_with("editor_draw_gizmo")) { + r_ret = get_ccdik_joint_editor_draw_gizmo(which); + } +#endif // TOOLS_ENABLED + + return true; + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor/draw_gizmo")) { + r_ret = get_editor_draw_gizmo(); + } +#endif // TOOLS_ENABLED + + return true; +} + +void SkeletonModification2DCCDIK::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < ccdik_data_chain.size(); i++) { + String base_string = "joint_data/" + itos(i) + "/"; + + p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "rotate_from_joint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + if (ccdik_data_chain[i].enable_constraint) { + p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "constraint_angle_min", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "constraint_angle_max", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "constraint_angle_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "constraint_in_localspace", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "editor_draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } +#endif // TOOLS_ENABLED + } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } +#endif // TOOLS_ENABLED +} + +void SkeletonModification2DCCDIK::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + if (!enabled) { + return; + } + + if (target_node_cache.is_null()) { + WARN_PRINT_ONCE("Target cache is out of date. Attempting to update..."); + update_target_cache(); + return; + } + if (tip_node_cache.is_null()) { + WARN_PRINT_ONCE("Tip cache is out of date. Attempting to update..."); + update_tip_cache(); + return; + } + + Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache)); + if (!target || !target->is_inside_tree()) { + ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!"); + return; + } + + Node2D *tip = Object::cast_to<Node2D>(ObjectDB::get_instance(tip_node_cache)); + if (!tip || !tip->is_inside_tree()) { + ERR_PRINT_ONCE("Tip node is not in the scene tree. Cannot execute modification!"); + return; + } + + for (int i = 0; i < ccdik_data_chain.size(); i++) { + _execute_ccdik_joint(i, target, tip); + } +} + +void SkeletonModification2DCCDIK::_execute_ccdik_joint(int p_joint_idx, Node2D *p_target, Node2D *p_tip) { + CCDIK_Joint_Data2D ccdik_data = ccdik_data_chain[p_joint_idx]; + if (ccdik_data.bone_idx < 0 || ccdik_data.bone_idx > stack->skeleton->get_bone_count()) { + ERR_PRINT_ONCE("2D CCDIK joint: bone index not found!"); + return; + } + + Bone2D *operation_bone = stack->skeleton->get_bone(ccdik_data.bone_idx); + Transform2D operation_transform = operation_bone->get_global_transform(); + + if (ccdik_data.rotate_from_joint) { + // To rotate from the joint, simply look at the target! + operation_transform.set_rotation( + operation_transform.looking_at(p_target->get_global_transform().get_origin()).get_rotation() - operation_bone->get_bone_angle()); + } else { + // How to rotate from the tip: get the difference of rotation needed from the tip to the target, from the perspective of the joint. + // Because we are only using the offset, we do not need to account for the bone angle of the Bone2D node. + float joint_to_tip = operation_transform.get_origin().angle_to_point(p_tip->get_global_transform().get_origin()); + float joint_to_target = operation_transform.get_origin().angle_to_point(p_target->get_global_transform().get_origin()); + operation_transform.set_rotation( + operation_transform.get_rotation() + (joint_to_target - joint_to_tip)); + } + + // Reset scale + operation_transform.set_scale(operation_bone->get_global_transform().get_scale()); + + // Apply constraints in globalspace: + if (ccdik_data.enable_constraint && !ccdik_data.constraint_in_localspace) { + operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angle_invert)); + } + + // Convert from a global transform to a delta and then apply the delta to the local transform. + operation_bone->set_global_transform(operation_transform); + operation_transform = operation_bone->get_transform(); + + // Apply constraints in localspace: + if (ccdik_data.enable_constraint && ccdik_data.constraint_in_localspace) { + operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angle_invert)); + } + + // Set the local pose override, and to make sure child bones are also updated, set the transform of the bone. + stack->skeleton->set_bone_local_pose_override(ccdik_data.bone_idx, operation_transform, stack->strength, true); + operation_bone->set_transform(operation_transform); + operation_bone->notification(operation_bone->NOTIFICATION_TRANSFORM_CHANGED); +} + +void SkeletonModification2DCCDIK::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack != nullptr) { + is_setup = true; + update_target_cache(); + update_tip_cache(); + } +} + +void SkeletonModification2DCCDIK::_draw_editor_gizmo() { + if (!enabled || !is_setup) { + return; + } + + for (int i = 0; i < ccdik_data_chain.size(); i++) { + if (!ccdik_data_chain[i].editor_draw_gizmo) { + continue; + } + + Bone2D *operation_bone = stack->skeleton->get_bone(ccdik_data_chain[i].bone_idx); + editor_draw_angle_constraints(operation_bone, ccdik_data_chain[i].constraint_angle_min, ccdik_data_chain[i].constraint_angle_max, + ccdik_data_chain[i].enable_constraint, ccdik_data_chain[i].constraint_in_localspace, ccdik_data_chain[i].constraint_angle_invert); + } +} + +void SkeletonModification2DCCDIK::update_target_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!"); + return; + } + + target_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(target_node)) { + Node *node = stack->skeleton->get_node(target_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update target cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update target cache: node is not in the scene tree!"); + target_node_cache = node->get_instance_id(); + } + } + } +} + +void SkeletonModification2DCCDIK::update_tip_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update tip cache: modification is not properly setup!"); + return; + } + + tip_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(tip_node)) { + Node *node = stack->skeleton->get_node(tip_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update tip cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update tip cache: node is not in the scene tree!"); + tip_node_cache = node->get_instance_id(); + } + } + } +} + +void SkeletonModification2DCCDIK::ccdik_joint_update_bone2d_cache(int p_joint_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "Cannot update bone2d cache: joint index out of range!"); + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update CCDIK Bone2D cache: modification is not properly setup!"); + return; + } + + ccdik_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(ccdik_data_chain[p_joint_idx].bone2d_node)) { + Node *node = stack->skeleton->get_node(ccdik_data_chain[p_joint_idx].bone2d_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update CCDIK joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update CCDIK joint " + itos(p_joint_idx) + " Bone2D cache: node is not in the scene tree!"); + ccdik_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id(); + + Bone2D *bone = Object::cast_to<Bone2D>(node); + if (bone) { + ccdik_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton(); + } else { + ERR_FAIL_MSG("CCDIK joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!"); + } + } + } + } +} + +void SkeletonModification2DCCDIK::set_target_node(const NodePath &p_target_node) { + target_node = p_target_node; + update_target_cache(); +} + +NodePath SkeletonModification2DCCDIK::get_target_node() const { + return target_node; +} + +void SkeletonModification2DCCDIK::set_tip_node(const NodePath &p_tip_node) { + tip_node = p_tip_node; + update_tip_cache(); +} + +NodePath SkeletonModification2DCCDIK::get_tip_node() const { + return tip_node; +} + +void SkeletonModification2DCCDIK::set_ccdik_data_chain_length(int p_length) { + ccdik_data_chain.resize(p_length); + notify_property_list_changed(); +} + +int SkeletonModification2DCCDIK::get_ccdik_data_chain_length() { + return ccdik_data_chain.size(); +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].bone2d_node = p_target_node; + ccdik_joint_update_bone2d_cache(p_joint_idx); + + notify_property_list_changed(); +} + +NodePath SkeletonModification2DCCDIK::get_ccdik_joint_bone2d_node(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), NodePath(), "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].bone2d_node; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCCDIK joint out of range!"); + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (is_setup) { + if (stack->skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + ccdik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + ccdik_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id(); + ccdik_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx)); + } else { + WARN_PRINT("Cannot verify the CCDIK joint " + itos(p_joint_idx) + " bone index for this modification..."); + ccdik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + } + } else { + WARN_PRINT("Cannot verify the CCDIK joint " + itos(p_joint_idx) + " bone index for this modification..."); + ccdik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + } + + notify_property_list_changed(); +} + +int SkeletonModification2DCCDIK::get_ccdik_joint_bone_index(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), -1, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].bone_idx; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_rotate_from_joint(int p_joint_idx, bool p_rotate_from_joint) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].rotate_from_joint = p_rotate_from_joint; +} + +bool SkeletonModification2DCCDIK::get_ccdik_joint_rotate_from_joint(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].rotate_from_joint; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_constraint) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].enable_constraint = p_constraint; + notify_property_list_changed(); + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DCCDIK::get_ccdik_joint_enable_constraint(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].enable_constraint; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_min(int p_joint_idx, float p_angle_min) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].constraint_angle_min = p_angle_min; + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +float SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_min(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), 0.0, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].constraint_angle_min; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_max(int p_joint_idx, float p_angle_max) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].constraint_angle_max = p_angle_max; + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +float SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_max(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), 0.0, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].constraint_angle_max; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_invert(int p_joint_idx, bool p_invert) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].constraint_angle_invert = p_invert; + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_invert(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].constraint_angle_invert; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_constraint_in_localspace(int p_joint_idx, bool p_constraint_in_localspace) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].constraint_in_localspace = p_constraint_in_localspace; + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DCCDIK::get_ccdik_joint_constraint_in_localspace(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].constraint_in_localspace; +} + +void SkeletonModification2DCCDIK::set_ccdik_joint_editor_draw_gizmo(int p_joint_idx, bool p_draw_gizmo) { + ERR_FAIL_INDEX_MSG(p_joint_idx, ccdik_data_chain.size(), "CCDIK joint out of range!"); + ccdik_data_chain.write[p_joint_idx].editor_draw_gizmo = p_draw_gizmo; + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DCCDIK::get_ccdik_joint_editor_draw_gizmo(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, ccdik_data_chain.size(), false, "CCDIK joint out of range!"); + return ccdik_data_chain[p_joint_idx].editor_draw_gizmo; +} + +void SkeletonModification2DCCDIK::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DCCDIK::set_target_node); + ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DCCDIK::get_target_node); + ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification2DCCDIK::set_tip_node); + ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification2DCCDIK::get_tip_node); + + ClassDB::bind_method(D_METHOD("set_ccdik_data_chain_length", "length"), &SkeletonModification2DCCDIK::set_ccdik_data_chain_length); + ClassDB::bind_method(D_METHOD("get_ccdik_data_chain_length"), &SkeletonModification2DCCDIK::get_ccdik_data_chain_length); + + ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone2d_node", "joint_idx", "bone2d_nodepath"), &SkeletonModification2DCCDIK::set_ccdik_joint_bone2d_node); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone2d_node", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_bone2d_node); + ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DCCDIK::set_ccdik_joint_bone_index); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_index", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_bone_index); + ClassDB::bind_method(D_METHOD("set_ccdik_joint_rotate_from_joint", "joint_idx", "rotate_from_joint"), &SkeletonModification2DCCDIK::set_ccdik_joint_rotate_from_joint); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_rotate_from_joint", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_rotate_from_joint); + ClassDB::bind_method(D_METHOD("set_ccdik_joint_enable_constraint", "joint_idx", "enable_constraint"), &SkeletonModification2DCCDIK::set_ccdik_joint_enable_constraint); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_enable_constraint", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_enable_constraint); + ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_min", "joint_idx", "angle_min"), &SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_min); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_min", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_min); + ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_max", "joint_idx", "angle_max"), &SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_max); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_max", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_max); + ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_invert", "joint_idx", "invert"), &SkeletonModification2DCCDIK::set_ccdik_joint_constraint_angle_invert); + ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_invert", "joint_idx"), &SkeletonModification2DCCDIK::get_ccdik_joint_constraint_angle_invert); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "tip_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_tip_node", "get_tip_node"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "ccdik_data_chain_length", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_ccdik_data_chain_length", "get_ccdik_data_chain_length"); +} + +SkeletonModification2DCCDIK::SkeletonModification2DCCDIK() { + stack = nullptr; + is_setup = false; + enabled = true; + editor_draw_gizmo = true; +} + +SkeletonModification2DCCDIK::~SkeletonModification2DCCDIK() { +} diff --git a/scene/resources/skeleton_modification_2d_ccdik.h b/scene/resources/skeleton_modification_2d_ccdik.h new file mode 100644 index 0000000000..dc48291f62 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_ccdik.h @@ -0,0 +1,116 @@ +/*************************************************************************/ +/* skeleton_modification_2d_ccdik.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2DCCDIK_H +#define SKELETONMODIFICATION2DCCDIK_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModification2DCCDIK +/////////////////////////////////////// + +class SkeletonModification2DCCDIK : public SkeletonModification2D { + GDCLASS(SkeletonModification2DCCDIK, SkeletonModification2D); + +private: + struct CCDIK_Joint_Data2D { + int bone_idx = -1; + NodePath bone2d_node; + ObjectID bone2d_node_cache; + bool rotate_from_joint = false; + + bool enable_constraint = false; + float constraint_angle_min = 0; + float constraint_angle_max = (2.0 * Math_PI); + bool constraint_angle_invert = false; + bool constraint_in_localspace = true; + + bool editor_draw_gizmo = true; + }; + + Vector<CCDIK_Joint_Data2D> ccdik_data_chain; + + NodePath target_node; + ObjectID target_node_cache; + void update_target_cache(); + + NodePath tip_node; + ObjectID tip_node_cache; + void update_tip_cache(); + + void ccdik_joint_update_bone2d_cache(int p_joint_idx); + void _execute_ccdik_joint(int p_joint_idx, Node2D *p_target, Node2D *p_tip); + +protected: + static void _bind_methods(); + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + void _draw_editor_gizmo() override; + + void set_target_node(const NodePath &p_target_node); + NodePath get_target_node() const; + void set_tip_node(const NodePath &p_tip_node); + NodePath get_tip_node() const; + + int get_ccdik_data_chain_length(); + void set_ccdik_data_chain_length(int p_new_length); + + void set_ccdik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node); + NodePath get_ccdik_joint_bone2d_node(int p_joint_idx) const; + void set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx); + int get_ccdik_joint_bone_index(int p_joint_idx) const; + + void set_ccdik_joint_rotate_from_joint(int p_joint_idx, bool p_rotate_from_joint); + bool get_ccdik_joint_rotate_from_joint(int p_joint_idx) const; + void set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_constraint); + bool get_ccdik_joint_enable_constraint(int p_joint_idx) const; + void set_ccdik_joint_constraint_angle_min(int p_joint_idx, float p_angle_min); + float get_ccdik_joint_constraint_angle_min(int p_joint_idx) const; + void set_ccdik_joint_constraint_angle_max(int p_joint_idx, float p_angle_max); + float get_ccdik_joint_constraint_angle_max(int p_joint_idx) const; + void set_ccdik_joint_constraint_angle_invert(int p_joint_idx, bool p_invert); + bool get_ccdik_joint_constraint_angle_invert(int p_joint_idx) const; + void set_ccdik_joint_constraint_in_localspace(int p_joint_idx, bool p_constraint_in_localspace); + bool get_ccdik_joint_constraint_in_localspace(int p_joint_idx) const; + void set_ccdik_joint_editor_draw_gizmo(int p_joint_idx, bool p_draw_gizmo); + bool get_ccdik_joint_editor_draw_gizmo(int p_joint_idx) const; + + SkeletonModification2DCCDIK(); + ~SkeletonModification2DCCDIK(); +}; + +#endif // SKELETONMODIFICATION2DCCDIK_H diff --git a/scene/resources/skeleton_modification_2d_fabrik.cpp b/scene/resources/skeleton_modification_2d_fabrik.cpp new file mode 100644 index 0000000000..aef852f7e4 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_fabrik.cpp @@ -0,0 +1,444 @@ +/*************************************************************************/ +/* skeleton_modification_2d_fabrik.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_fabrik.h" +#include "scene/2d/skeleton_2d.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif // TOOLS_ENABLED + +bool SkeletonModification2DFABRIK::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("joint_data/")) { + int which = path.get_slicec('/', 1).to_int(); + String what = path.get_slicec('/', 2); + ERR_FAIL_INDEX_V(which, fabrik_data_chain.size(), false); + + if (what == "bone2d_node") { + set_fabrik_joint_bone2d_node(which, p_value); + } else if (what == "bone_index") { + set_fabrik_joint_bone_index(which, p_value); + } else if (what == "magnet_position") { + set_fabrik_joint_magnet_position(which, p_value); + } else if (what == "use_target_rotation") { + set_fabrik_joint_use_target_rotation(which, p_value); + } + } + + return true; +} + +bool SkeletonModification2DFABRIK::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("joint_data/")) { + int which = path.get_slicec('/', 1).to_int(); + String what = path.get_slicec('/', 2); + ERR_FAIL_INDEX_V(which, fabrik_data_chain.size(), false); + + if (what == "bone2d_node") { + r_ret = get_fabrik_joint_bone2d_node(which); + } else if (what == "bone_index") { + r_ret = get_fabrik_joint_bone_index(which); + } else if (what == "magnet_position") { + r_ret = get_fabrik_joint_magnet_position(which); + } else if (what == "use_target_rotation") { + r_ret = get_fabrik_joint_use_target_rotation(which); + } + return true; + } + return true; +} + +void SkeletonModification2DFABRIK::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < fabrik_data_chain.size(); i++) { + String base_string = "joint_data/" + itos(i) + "/"; + + p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT)); + + if (i > 0) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, base_string + "magnet_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } + if (i == fabrik_data_chain.size() - 1) { + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_target_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } + } +} + +void SkeletonModification2DFABRIK::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + if (!enabled) { + return; + } + + if (target_node_cache.is_null()) { + WARN_PRINT_ONCE("Target cache is out of date. Attempting to update..."); + update_target_cache(); + return; + } + + if (fabrik_data_chain.size() <= 1) { + ERR_PRINT_ONCE("FABRIK requires at least two joints to operate! Cannot execute modification!"); + return; + } + + Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache)); + if (!target || !target->is_inside_tree()) { + ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!"); + return; + } + target_global_pose = target->get_global_transform(); + + if (fabrik_data_chain[0].bone2d_node_cache.is_null() && !fabrik_data_chain[0].bone2d_node.is_empty()) { + fabrik_joint_update_bone2d_cache(0); + WARN_PRINT("Bone2D cache for origin joint is out of date. Updating..."); + } + + Bone2D *origin_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[0].bone2d_node_cache)); + if (!origin_bone2d_node || !origin_bone2d_node->is_inside_tree()) { + ERR_PRINT_ONCE("Origin joint's Bone2D node is not in the scene tree. Cannot execute modification!"); + return; + } + + origin_global_pose = origin_bone2d_node->get_global_transform(); + + if (fabrik_transform_chain.size() != fabrik_data_chain.size()) { + fabrik_transform_chain.resize(fabrik_data_chain.size()); + } + + for (int i = 0; i < fabrik_data_chain.size(); i++) { + // Update the transform chain + if (fabrik_data_chain[i].bone2d_node_cache.is_null() && !fabrik_data_chain[i].bone2d_node.is_empty()) { + WARN_PRINT_ONCE("Bone2D cache for joint " + itos(i) + " is out of date.. Attempting to update..."); + fabrik_joint_update_bone2d_cache(i); + } + Bone2D *joint_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache)); + if (!joint_bone2d_node) { + ERR_PRINT_ONCE("FABRIK Joint " + itos(i) + " does not have a Bone2D node set! Cannot execute modification!"); + return; + } + fabrik_transform_chain.write[i] = joint_bone2d_node->get_global_transform(); + + // Apply magnet positions + if (i == 0) { + continue; // The origin cannot use a magnet position! + } else { + Transform2D joint_trans = fabrik_transform_chain[i]; + joint_trans.set_origin(joint_trans.get_origin() + fabrik_data_chain[i].magnet_position); + fabrik_transform_chain.write[i] = joint_trans; + } + } + + Bone2D *final_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[fabrik_data_chain.size() - 1].bone2d_node_cache)); + float final_bone2d_angle = final_bone2d_node->get_global_transform().get_rotation(); + if (fabrik_data_chain[fabrik_data_chain.size() - 1].use_target_rotation) { + final_bone2d_angle = target_global_pose.get_rotation(); + } + Vector2 final_bone2d_direction = Vector2(Math::cos(final_bone2d_angle), Math::sin(final_bone2d_angle)); + float final_bone2d_length = final_bone2d_node->get_length() * MIN(final_bone2d_node->get_global_scale().x, final_bone2d_node->get_global_scale().y); + float target_distance = (final_bone2d_node->get_global_transform().get_origin() + (final_bone2d_direction * final_bone2d_length)).distance_to(target->get_global_transform().get_origin()); + chain_iterations = 0; + + while (target_distance > chain_tolarance) { + chain_backwards(); + chain_forwards(); + + final_bone2d_angle = final_bone2d_node->get_global_transform().get_rotation(); + if (fabrik_data_chain[fabrik_data_chain.size() - 1].use_target_rotation) { + final_bone2d_angle = target_global_pose.get_rotation(); + } + final_bone2d_direction = Vector2(Math::cos(final_bone2d_angle), Math::sin(final_bone2d_angle)); + target_distance = (final_bone2d_node->get_global_transform().get_origin() + (final_bone2d_direction * final_bone2d_length)).distance_to(target->get_global_transform().get_origin()); + + chain_iterations += 1; + if (chain_iterations >= chain_max_iterations) { + break; + } + } + + // Apply all of the saved transforms to the Bone2D nodes + for (int i = 0; i < fabrik_data_chain.size(); i++) { + Bone2D *joint_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache)); + if (!joint_bone2d_node) { + ERR_PRINT_ONCE("FABRIK Joint " + itos(i) + " does not have a Bone2D node set!"); + continue; + } + Transform2D chain_trans = fabrik_transform_chain[i]; + + // Apply rotation + if (i + 1 < fabrik_data_chain.size()) { + chain_trans = chain_trans.looking_at(fabrik_transform_chain[i + 1].get_origin()); + } else { + if (fabrik_data_chain[i].use_target_rotation) { + chain_trans.set_rotation(target_global_pose.get_rotation()); + } else { + chain_trans = chain_trans.looking_at(target_global_pose.get_origin()); + } + } + // Adjust for the bone angle + chain_trans.set_rotation(chain_trans.get_rotation() - joint_bone2d_node->get_bone_angle()); + + // Reset scale + chain_trans.set_scale(joint_bone2d_node->get_global_transform().get_scale()); + + // Apply to the bone, and to the override + joint_bone2d_node->set_global_transform(chain_trans); + stack->skeleton->set_bone_local_pose_override(fabrik_data_chain[i].bone_idx, joint_bone2d_node->get_transform(), stack->strength, true); + } +} + +void SkeletonModification2DFABRIK::chain_backwards() { + int final_joint_index = fabrik_data_chain.size() - 1; + Bone2D *final_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[final_joint_index].bone2d_node_cache)); + Transform2D final_bone2d_trans = fabrik_transform_chain[final_joint_index]; + + // Set the rotation of the tip bone + final_bone2d_trans = final_bone2d_trans.looking_at(target_global_pose.get_origin()); + + // Set the position of the tip bone + float final_bone2d_angle = final_bone2d_trans.get_rotation(); + if (fabrik_data_chain[final_joint_index].use_target_rotation) { + final_bone2d_angle = target_global_pose.get_rotation(); + } + Vector2 final_bone2d_direction = Vector2(Math::cos(final_bone2d_angle), Math::sin(final_bone2d_angle)); + float final_bone2d_length = final_bone2d_node->get_length() * MIN(final_bone2d_node->get_global_scale().x, final_bone2d_node->get_global_scale().y); + final_bone2d_trans.set_origin(target_global_pose.get_origin() - (final_bone2d_direction * final_bone2d_length)); + + // Save the transform + fabrik_transform_chain.write[final_joint_index] = final_bone2d_trans; + + int i = final_joint_index; + while (i >= 1) { + Transform2D previous_pose = fabrik_transform_chain[i]; + i -= 1; + Bone2D *current_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache)); + Transform2D current_pose = fabrik_transform_chain[i]; + + float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y); + float length = current_bone2d_node_length / (previous_pose.get_origin() - current_pose.get_origin()).length(); + Vector2 finish_position = previous_pose.get_origin().lerp(current_pose.get_origin(), length); + current_pose.set_origin(finish_position); + + // Save the transform + fabrik_transform_chain.write[i] = current_pose; + } +} + +void SkeletonModification2DFABRIK::chain_forwards() { + Transform2D origin_bone2d_trans = fabrik_transform_chain[0]; + origin_bone2d_trans.set_origin(origin_global_pose.get_origin()); + // Save the position + fabrik_transform_chain.write[0] = origin_bone2d_trans; + + for (int i = 0; i < fabrik_data_chain.size() - 1; i++) { + Bone2D *current_bone2d_node = Object::cast_to<Bone2D>(ObjectDB::get_instance(fabrik_data_chain[i].bone2d_node_cache)); + Transform2D current_pose = fabrik_transform_chain[i]; + Transform2D next_pose = fabrik_transform_chain[i + 1]; + + float current_bone2d_node_length = current_bone2d_node->get_length() * MIN(current_bone2d_node->get_global_scale().x, current_bone2d_node->get_global_scale().y); + float length = current_bone2d_node_length / (current_pose.get_origin() - next_pose.get_origin()).length(); + Vector2 finish_position = current_pose.get_origin().lerp(next_pose.get_origin(), length); + current_pose.set_origin(finish_position); + + // Apply to the bone + fabrik_transform_chain.write[i + 1] = current_pose; + } +} + +void SkeletonModification2DFABRIK::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack != nullptr) { + is_setup = true; + update_target_cache(); + } +} + +void SkeletonModification2DFABRIK::update_target_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!"); + return; + } + + target_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(target_node)) { + Node *node = stack->skeleton->get_node(target_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update target cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update target cache: node is not in scene tree!"); + target_node_cache = node->get_instance_id(); + } + } + } +} + +void SkeletonModification2DFABRIK::fabrik_joint_update_bone2d_cache(int p_joint_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "Cannot update bone2d cache: joint index out of range!"); + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update FABRIK Bone2D cache: modification is not properly setup!"); + return; + } + + fabrik_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(fabrik_data_chain[p_joint_idx].bone2d_node)) { + Node *node = stack->skeleton->get_node(fabrik_data_chain[p_joint_idx].bone2d_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update FABRIK joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update FABRIK joint " + itos(p_joint_idx) + " Bone2D cache: node is not in scene tree!"); + fabrik_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id(); + + Bone2D *bone = Object::cast_to<Bone2D>(node); + if (bone) { + fabrik_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton(); + } else { + ERR_FAIL_MSG("FABRIK joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!"); + } + } + } + } +} + +void SkeletonModification2DFABRIK::set_target_node(const NodePath &p_target_node) { + target_node = p_target_node; + update_target_cache(); +} + +NodePath SkeletonModification2DFABRIK::get_target_node() const { + return target_node; +} + +void SkeletonModification2DFABRIK::set_fabrik_data_chain_length(int p_length) { + fabrik_data_chain.resize(p_length); + notify_property_list_changed(); +} + +int SkeletonModification2DFABRIK::get_fabrik_data_chain_length() { + return fabrik_data_chain.size(); +} + +void SkeletonModification2DFABRIK::set_fabrik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) { + ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!"); + fabrik_data_chain.write[p_joint_idx].bone2d_node = p_target_node; + fabrik_joint_update_bone2d_cache(p_joint_idx); + + notify_property_list_changed(); +} + +NodePath SkeletonModification2DFABRIK::get_fabrik_joint_bone2d_node(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), NodePath(), "FABRIK joint out of range!"); + return fabrik_data_chain[p_joint_idx].bone2d_node; +} + +void SkeletonModification2DFABRIK::set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!"); + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (is_setup) { + if (stack->skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + fabrik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + fabrik_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id(); + fabrik_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx)); + } else { + WARN_PRINT("Cannot verify the FABRIK joint " + itos(p_joint_idx) + " bone index for this modification..."); + fabrik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + } + } else { + WARN_PRINT("Cannot verify the FABRIK joint " + itos(p_joint_idx) + " bone index for this modification..."); + fabrik_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + } + + notify_property_list_changed(); +} + +int SkeletonModification2DFABRIK::get_fabrik_joint_bone_index(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), -1, "FABRIK joint out of range!"); + return fabrik_data_chain[p_joint_idx].bone_idx; +} + +void SkeletonModification2DFABRIK::set_fabrik_joint_magnet_position(int p_joint_idx, Vector2 p_magnet_position) { + ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!"); + fabrik_data_chain.write[p_joint_idx].magnet_position = p_magnet_position; +} + +Vector2 SkeletonModification2DFABRIK::get_fabrik_joint_magnet_position(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), Vector2(), "FABRIK joint out of range!"); + return fabrik_data_chain[p_joint_idx].magnet_position; +} + +void SkeletonModification2DFABRIK::set_fabrik_joint_use_target_rotation(int p_joint_idx, bool p_use_target_rotation) { + ERR_FAIL_INDEX_MSG(p_joint_idx, fabrik_data_chain.size(), "FABRIK joint out of range!"); + fabrik_data_chain.write[p_joint_idx].use_target_rotation = p_use_target_rotation; +} + +bool SkeletonModification2DFABRIK::get_fabrik_joint_use_target_rotation(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, fabrik_data_chain.size(), false, "FABRIK joint out of range!"); + return fabrik_data_chain[p_joint_idx].use_target_rotation; +} + +void SkeletonModification2DFABRIK::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DFABRIK::set_target_node); + ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DFABRIK::get_target_node); + + ClassDB::bind_method(D_METHOD("set_fabrik_data_chain_length", "length"), &SkeletonModification2DFABRIK::set_fabrik_data_chain_length); + ClassDB::bind_method(D_METHOD("get_fabrik_data_chain_length"), &SkeletonModification2DFABRIK::get_fabrik_data_chain_length); + + ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone2d_node", "joint_idx", "bone2d_nodepath"), &SkeletonModification2DFABRIK::set_fabrik_joint_bone2d_node); + ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone2d_node", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_bone2d_node); + ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DFABRIK::set_fabrik_joint_bone_index); + ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_index", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_bone_index); + ClassDB::bind_method(D_METHOD("set_fabrik_joint_magnet_position", "joint_idx", "magnet_position"), &SkeletonModification2DFABRIK::set_fabrik_joint_magnet_position); + ClassDB::bind_method(D_METHOD("get_fabrik_joint_magnet_position", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_magnet_position); + ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_target_rotation", "joint_idx", "use_target_rotation"), &SkeletonModification2DFABRIK::set_fabrik_joint_use_target_rotation); + ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_target_rotation", "joint_idx"), &SkeletonModification2DFABRIK::get_fabrik_joint_use_target_rotation); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "fabrik_data_chain_length", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_fabrik_data_chain_length", "get_fabrik_data_chain_length"); +} + +SkeletonModification2DFABRIK::SkeletonModification2DFABRIK() { + stack = nullptr; + is_setup = false; + enabled = true; + editor_draw_gizmo = false; +} + +SkeletonModification2DFABRIK::~SkeletonModification2DFABRIK() { +} diff --git a/scene/resources/skeleton_modification_2d_fabrik.h b/scene/resources/skeleton_modification_2d_fabrik.h new file mode 100644 index 0000000000..79e0106e26 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_fabrik.h @@ -0,0 +1,108 @@ +/*************************************************************************/ +/* skeleton_modification_2d_fabrik.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2DFABRIK_H +#define SKELETONMODIFICATION2DFABRIK_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModification2DFABRIK +/////////////////////////////////////// + +class SkeletonModification2DFABRIK : public SkeletonModification2D { + GDCLASS(SkeletonModification2DFABRIK, SkeletonModification2D); + +private: + struct FABRIK_Joint_Data2D { + int bone_idx = -1; + NodePath bone2d_node; + ObjectID bone2d_node_cache; + + Vector2 magnet_position = Vector2(0, 0); + bool use_target_rotation = false; + + bool editor_draw_gizmo = true; + }; + + Vector<FABRIK_Joint_Data2D> fabrik_data_chain; + + // Unlike in 3D, we need a vector of Transform2D objects to perform FABRIK. + // This is because FABRIK (unlike CCDIK) needs to operate on transforms that are NOT + // affected by each other, making the transforms stored in Bone2D unusable, as well as those in Skeleton2D. + // For this reason, this modification stores a vector of Transform2Ds used for the calculations, which are then applied at the end. + Vector<Transform2D> fabrik_transform_chain; + + NodePath target_node; + ObjectID target_node_cache; + void update_target_cache(); + + float chain_tolarance = 0.01; + int chain_max_iterations = 10; + int chain_iterations = 0; + Transform2D target_global_pose = Transform2D(); + Transform2D origin_global_pose = Transform2D(); + + void fabrik_joint_update_bone2d_cache(int p_joint_idx); + void chain_backwards(); + void chain_forwards(); + +protected: + static void _bind_methods(); + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + + void set_target_node(const NodePath &p_target_node); + NodePath get_target_node() const; + + int get_fabrik_data_chain_length(); + void set_fabrik_data_chain_length(int p_new_length); + + void set_fabrik_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node); + NodePath get_fabrik_joint_bone2d_node(int p_joint_idx) const; + void set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx); + int get_fabrik_joint_bone_index(int p_joint_idx) const; + + void set_fabrik_joint_magnet_position(int p_joint_idx, Vector2 p_magnet_position); + Vector2 get_fabrik_joint_magnet_position(int p_joint_idx) const; + void set_fabrik_joint_use_target_rotation(int p_joint_idx, bool p_use_target_rotation); + bool get_fabrik_joint_use_target_rotation(int p_joint_idx) const; + + SkeletonModification2DFABRIK(); + ~SkeletonModification2DFABRIK(); +}; + +#endif // SKELETONMODIFICATION2DFABRIK_H diff --git a/scene/resources/skeleton_modification_2d_jiggle.cpp b/scene/resources/skeleton_modification_2d_jiggle.cpp new file mode 100644 index 0000000000..2547083336 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_jiggle.cpp @@ -0,0 +1,564 @@ +/*************************************************************************/ +/* skeleton_modification_2d_jiggle.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_jiggle.h" +#include "scene/2d/skeleton_2d.h" + +bool SkeletonModification2DJiggle::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("joint_data/")) { + int which = path.get_slicec('/', 1).to_int(); + String what = path.get_slicec('/', 2); + ERR_FAIL_INDEX_V(which, jiggle_data_chain.size(), false); + + if (what == "bone2d_node") { + set_jiggle_joint_bone2d_node(which, p_value); + } else if (what == "bone_index") { + set_jiggle_joint_bone_index(which, p_value); + } else if (what == "override_defaults") { + set_jiggle_joint_override(which, p_value); + } else if (what == "stiffness") { + set_jiggle_joint_stiffness(which, p_value); + } else if (what == "mass") { + set_jiggle_joint_mass(which, p_value); + } else if (what == "damping") { + set_jiggle_joint_damping(which, p_value); + } else if (what == "use_gravity") { + set_jiggle_joint_use_gravity(which, p_value); + } else if (what == "gravity") { + set_jiggle_joint_gravity(which, p_value); + } + return true; + } else { + if (path == "use_colliders") { + set_use_colliders(p_value); + } else if (path == "collision_mask") { + set_collision_mask(p_value); + } + } + return true; +} + +bool SkeletonModification2DJiggle::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("joint_data/")) { + int which = path.get_slicec('/', 1).to_int(); + String what = path.get_slicec('/', 2); + ERR_FAIL_INDEX_V(which, jiggle_data_chain.size(), false); + + if (what == "bone2d_node") { + r_ret = get_jiggle_joint_bone2d_node(which); + } else if (what == "bone_index") { + r_ret = get_jiggle_joint_bone_index(which); + } else if (what == "override_defaults") { + r_ret = get_jiggle_joint_override(which); + } else if (what == "stiffness") { + r_ret = get_jiggle_joint_stiffness(which); + } else if (what == "mass") { + r_ret = get_jiggle_joint_mass(which); + } else if (what == "damping") { + r_ret = get_jiggle_joint_damping(which); + } else if (what == "use_gravity") { + r_ret = get_jiggle_joint_use_gravity(which); + } else if (what == "gravity") { + r_ret = get_jiggle_joint_gravity(which); + } + return true; + } else { + if (path == "use_colliders") { + r_ret = get_use_colliders(); + } else if (path == "collision_mask") { + r_ret = get_collision_mask(); + } + } + return true; +} + +void SkeletonModification2DJiggle::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::BOOL, "use_colliders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + if (use_colliders) { + p_list->push_back(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS, "", PROPERTY_USAGE_DEFAULT)); + } + + for (int i = 0; i < jiggle_data_chain.size(); i++) { + String base_string = "joint_data/" + itos(i) + "/"; + + p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "override_defaults", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + + if (jiggle_data_chain[i].override_defaults) { + p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "stiffness", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "mass", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + if (jiggle_data_chain[i].use_gravity) { + p_list->push_back(PropertyInfo(Variant::VECTOR2, base_string + "gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } + } + } +} + +void SkeletonModification2DJiggle::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + if (!enabled) { + return; + } + if (target_node_cache.is_null()) { + WARN_PRINT_ONCE("Target cache is out of date. Attempting to update..."); + update_target_cache(); + return; + } + Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache)); + if (!target || !target->is_inside_tree()) { + ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!"); + return; + } + + for (int i = 0; i < jiggle_data_chain.size(); i++) { + _execute_jiggle_joint(i, target, p_delta); + } +} + +void SkeletonModification2DJiggle::_execute_jiggle_joint(int p_joint_idx, Node2D *p_target, float p_delta) { + // Adopted from: https://wiki.unity3d.com/index.php/JiggleBone + // With modifications by TwistedTwigleg. + + if (jiggle_data_chain[p_joint_idx].bone_idx <= -1 || jiggle_data_chain[p_joint_idx].bone_idx > stack->skeleton->get_bone_count()) { + ERR_PRINT_ONCE("Jiggle joint " + itos(p_joint_idx) + " bone index is invalid. Cannot execute modification on joint..."); + return; + } + + if (jiggle_data_chain[p_joint_idx].bone2d_node_cache.is_null() && !jiggle_data_chain[p_joint_idx].bone2d_node.is_empty()) { + WARN_PRINT_ONCE("Bone2D cache for joint " + itos(p_joint_idx) + " is out of date. Updating..."); + jiggle_joint_update_bone2d_cache(p_joint_idx); + } + + Bone2D *operation_bone = stack->skeleton->get_bone(jiggle_data_chain[p_joint_idx].bone_idx); + if (!operation_bone) { + ERR_PRINT_ONCE("Jiggle joint " + itos(p_joint_idx) + " does not have a Bone2D node or it cannot be found!"); + return; + } + + Transform2D operation_bone_trans = operation_bone->get_global_transform(); + Vector2 target_position = p_target->get_global_transform().get_origin(); + + jiggle_data_chain.write[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta; + + if (jiggle_data_chain[p_joint_idx].use_gravity) { + jiggle_data_chain.write[p_joint_idx].force += jiggle_data_chain[p_joint_idx].gravity * p_delta; + } + + jiggle_data_chain.write[p_joint_idx].acceleration = jiggle_data_chain[p_joint_idx].force / jiggle_data_chain[p_joint_idx].mass; + jiggle_data_chain.write[p_joint_idx].velocity += jiggle_data_chain[p_joint_idx].acceleration * (1 - jiggle_data_chain[p_joint_idx].damping); + + jiggle_data_chain.write[p_joint_idx].dynamic_position += jiggle_data_chain[p_joint_idx].velocity + jiggle_data_chain[p_joint_idx].force; + jiggle_data_chain.write[p_joint_idx].dynamic_position += operation_bone_trans.get_origin() - jiggle_data_chain[p_joint_idx].last_position; + jiggle_data_chain.write[p_joint_idx].last_position = operation_bone_trans.get_origin(); + + // Collision detection/response + if (use_colliders) { + if (execution_mode == SkeletonModificationStack2D::EXECUTION_MODE::execution_mode_physics_process) { + Ref<World2D> world_2d = stack->skeleton->get_world_2d(); + ERR_FAIL_COND(world_2d.is_null()); + PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space()); + PhysicsDirectSpaceState2D::RayResult ray_result; + + // Add exception support? + bool ray_hit = space_state->intersect_ray(operation_bone_trans.get_origin(), jiggle_data_chain[p_joint_idx].dynamic_position, + ray_result, Set<RID>(), collision_mask); + + if (ray_hit) { + jiggle_data_chain.write[p_joint_idx].dynamic_position = jiggle_data_chain[p_joint_idx].last_noncollision_position; + jiggle_data_chain.write[p_joint_idx].acceleration = Vector2(0, 0); + jiggle_data_chain.write[p_joint_idx].velocity = Vector2(0, 0); + } else { + jiggle_data_chain.write[p_joint_idx].last_noncollision_position = jiggle_data_chain[p_joint_idx].dynamic_position; + } + } else { + WARN_PRINT_ONCE("Jiggle 2D modifier: You cannot detect colliders without the stack mode being set to _physics_process!"); + } + } + + // Rotate the bone using the dynamic position! + operation_bone_trans = operation_bone_trans.looking_at(jiggle_data_chain[p_joint_idx].dynamic_position); + operation_bone_trans.set_rotation(operation_bone_trans.get_rotation() - operation_bone->get_bone_angle()); + + // Reset scale + operation_bone_trans.set_scale(operation_bone->get_global_transform().get_scale()); + + operation_bone->set_global_transform(operation_bone_trans); + stack->skeleton->set_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx, operation_bone->get_transform(), stack->strength, true); +} + +void SkeletonModification2DJiggle::_update_jiggle_joint_data() { + for (int i = 0; i < jiggle_data_chain.size(); i++) { + if (!jiggle_data_chain[i].override_defaults) { + set_jiggle_joint_stiffness(i, stiffness); + set_jiggle_joint_mass(i, mass); + set_jiggle_joint_damping(i, damping); + set_jiggle_joint_use_gravity(i, use_gravity); + set_jiggle_joint_gravity(i, gravity); + } + } +} + +void SkeletonModification2DJiggle::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack) { + is_setup = true; + + if (stack->skeleton) { + for (int i = 0; i < jiggle_data_chain.size(); i++) { + int bone_idx = jiggle_data_chain[i].bone_idx; + if (bone_idx > 0 && bone_idx < stack->skeleton->get_bone_count()) { + Bone2D *bone2d_node = stack->skeleton->get_bone(bone_idx); + jiggle_data_chain.write[i].dynamic_position = bone2d_node->get_global_transform().get_origin(); + } + } + } + + update_target_cache(); + } +} + +void SkeletonModification2DJiggle::update_target_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!"); + return; + } + + target_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(target_node)) { + Node *node = stack->skeleton->get_node(target_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update target cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update target cache: node is not in scene tree!"); + target_node_cache = node->get_instance_id(); + } + } + } +} + +void SkeletonModification2DJiggle::jiggle_joint_update_bone2d_cache(int p_joint_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Cannot update bone2d cache: joint index out of range!"); + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update Jiggle " + itos(p_joint_idx) + " Bone2D cache: modification is not properly setup!"); + return; + } + + jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(jiggle_data_chain[p_joint_idx].bone2d_node)) { + Node *node = stack->skeleton->get_node(jiggle_data_chain[p_joint_idx].bone2d_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: node is not in scene tree!"); + jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = node->get_instance_id(); + + Bone2D *bone = Object::cast_to<Bone2D>(node); + if (bone) { + jiggle_data_chain.write[p_joint_idx].bone_idx = bone->get_index_in_skeleton(); + } else { + ERR_FAIL_MSG("Jiggle joint " + itos(p_joint_idx) + " Bone2D cache: Nodepath to Bone2D is not a Bone2D node!"); + } + } + } + } +} + +void SkeletonModification2DJiggle::set_target_node(const NodePath &p_target_node) { + target_node = p_target_node; + update_target_cache(); +} + +NodePath SkeletonModification2DJiggle::get_target_node() const { + return target_node; +} + +void SkeletonModification2DJiggle::set_stiffness(float p_stiffness) { + ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!"); + stiffness = p_stiffness; + _update_jiggle_joint_data(); +} + +float SkeletonModification2DJiggle::get_stiffness() const { + return stiffness; +} + +void SkeletonModification2DJiggle::set_mass(float p_mass) { + ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!"); + mass = p_mass; + _update_jiggle_joint_data(); +} + +float SkeletonModification2DJiggle::get_mass() const { + return mass; +} + +void SkeletonModification2DJiggle::set_damping(float p_damping) { + ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!"); + ERR_FAIL_COND_MSG(p_damping > 1, "Damping cannot be more than one!"); + damping = p_damping; + _update_jiggle_joint_data(); +} + +float SkeletonModification2DJiggle::get_damping() const { + return damping; +} + +void SkeletonModification2DJiggle::set_use_gravity(bool p_use_gravity) { + use_gravity = p_use_gravity; + _update_jiggle_joint_data(); +} + +bool SkeletonModification2DJiggle::get_use_gravity() const { + return use_gravity; +} + +void SkeletonModification2DJiggle::set_gravity(Vector2 p_gravity) { + gravity = p_gravity; + _update_jiggle_joint_data(); +} + +Vector2 SkeletonModification2DJiggle::get_gravity() const { + return gravity; +} + +void SkeletonModification2DJiggle::set_use_colliders(bool p_use_colliders) { + use_colliders = p_use_colliders; + notify_property_list_changed(); +} + +bool SkeletonModification2DJiggle::get_use_colliders() const { + return use_colliders; +} + +void SkeletonModification2DJiggle::set_collision_mask(int p_mask) { + collision_mask = p_mask; +} + +int SkeletonModification2DJiggle::get_collision_mask() const { + return collision_mask; +} + +// Jiggle joint data functions +int SkeletonModification2DJiggle::get_jiggle_data_chain_length() { + return jiggle_data_chain.size(); +} + +void SkeletonModification2DJiggle::set_jiggle_data_chain_length(int p_length) { + ERR_FAIL_COND(p_length < 0); + jiggle_data_chain.resize(p_length); + notify_property_list_changed(); +} + +void SkeletonModification2DJiggle::set_jiggle_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node) { + ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Jiggle joint out of range!"); + jiggle_data_chain.write[p_joint_idx].bone2d_node = p_target_node; + jiggle_joint_update_bone2d_cache(p_joint_idx); + + notify_property_list_changed(); +} + +NodePath SkeletonModification2DJiggle::get_jiggle_joint_bone2d_node(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, jiggle_data_chain.size(), NodePath(), "Jiggle joint out of range!"); + return jiggle_data_chain[p_joint_idx].bone2d_node; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, jiggle_data_chain.size(), "Jiggle joint out of range!"); + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (is_setup) { + if (stack->skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + jiggle_data_chain.write[p_joint_idx].bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id(); + jiggle_data_chain.write[p_joint_idx].bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx)); + } else { + WARN_PRINT("Cannot verify the Jiggle joint " + itos(p_joint_idx) + " bone index for this modification..."); + jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + } + } else { + WARN_PRINT("Cannot verify the Jiggle joint " + itos(p_joint_idx) + " bone index for this modification..."); + jiggle_data_chain.write[p_joint_idx].bone_idx = p_bone_idx; + } + + notify_property_list_changed(); +} + +int SkeletonModification2DJiggle::get_jiggle_joint_bone_index(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, jiggle_data_chain.size(), -1, "Jiggle joint out of range!"); + return jiggle_data_chain[p_joint_idx].bone_idx; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_override(int p_joint_idx, bool p_override) { + ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size()); + jiggle_data_chain.write[p_joint_idx].override_defaults = p_override; + _update_jiggle_joint_data(); + notify_property_list_changed(); +} + +bool SkeletonModification2DJiggle::get_jiggle_joint_override(int p_joint_idx) const { + ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), false); + return jiggle_data_chain[p_joint_idx].override_defaults; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_stiffness(int p_joint_idx, float p_stiffness) { + ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!"); + ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size()); + jiggle_data_chain.write[p_joint_idx].stiffness = p_stiffness; +} + +float SkeletonModification2DJiggle::get_jiggle_joint_stiffness(int p_joint_idx) const { + ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1); + return jiggle_data_chain[p_joint_idx].stiffness; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_mass(int p_joint_idx, float p_mass) { + ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!"); + ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size()); + jiggle_data_chain.write[p_joint_idx].mass = p_mass; +} + +float SkeletonModification2DJiggle::get_jiggle_joint_mass(int p_joint_idx) const { + ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1); + return jiggle_data_chain[p_joint_idx].mass; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_damping(int p_joint_idx, float p_damping) { + ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!"); + ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size()); + jiggle_data_chain.write[p_joint_idx].damping = p_damping; +} + +float SkeletonModification2DJiggle::get_jiggle_joint_damping(int p_joint_idx) const { + ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), -1); + return jiggle_data_chain[p_joint_idx].damping; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity) { + ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size()); + jiggle_data_chain.write[p_joint_idx].use_gravity = p_use_gravity; + notify_property_list_changed(); +} + +bool SkeletonModification2DJiggle::get_jiggle_joint_use_gravity(int p_joint_idx) const { + ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), false); + return jiggle_data_chain[p_joint_idx].use_gravity; +} + +void SkeletonModification2DJiggle::set_jiggle_joint_gravity(int p_joint_idx, Vector2 p_gravity) { + ERR_FAIL_INDEX(p_joint_idx, jiggle_data_chain.size()); + jiggle_data_chain.write[p_joint_idx].gravity = p_gravity; +} + +Vector2 SkeletonModification2DJiggle::get_jiggle_joint_gravity(int p_joint_idx) const { + ERR_FAIL_INDEX_V(p_joint_idx, jiggle_data_chain.size(), Vector2(0, 0)); + return jiggle_data_chain[p_joint_idx].gravity; +} + +void SkeletonModification2DJiggle::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DJiggle::set_target_node); + ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DJiggle::get_target_node); + + ClassDB::bind_method(D_METHOD("set_jiggle_data_chain_length", "length"), &SkeletonModification2DJiggle::set_jiggle_data_chain_length); + ClassDB::bind_method(D_METHOD("get_jiggle_data_chain_length"), &SkeletonModification2DJiggle::get_jiggle_data_chain_length); + + ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &SkeletonModification2DJiggle::set_stiffness); + ClassDB::bind_method(D_METHOD("get_stiffness"), &SkeletonModification2DJiggle::get_stiffness); + ClassDB::bind_method(D_METHOD("set_mass", "mass"), &SkeletonModification2DJiggle::set_mass); + ClassDB::bind_method(D_METHOD("get_mass"), &SkeletonModification2DJiggle::get_mass); + ClassDB::bind_method(D_METHOD("set_damping", "damping"), &SkeletonModification2DJiggle::set_damping); + ClassDB::bind_method(D_METHOD("get_damping"), &SkeletonModification2DJiggle::get_damping); + ClassDB::bind_method(D_METHOD("set_use_gravity", "use_gravity"), &SkeletonModification2DJiggle::set_use_gravity); + ClassDB::bind_method(D_METHOD("get_use_gravity"), &SkeletonModification2DJiggle::get_use_gravity); + ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &SkeletonModification2DJiggle::set_gravity); + ClassDB::bind_method(D_METHOD("get_gravity"), &SkeletonModification2DJiggle::get_gravity); + + ClassDB::bind_method(D_METHOD("set_use_colliders", "use_colliders"), &SkeletonModification2DJiggle::set_use_colliders); + ClassDB::bind_method(D_METHOD("get_use_colliders"), &SkeletonModification2DJiggle::get_use_colliders); + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SkeletonModification2DJiggle::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &SkeletonModification2DJiggle::get_collision_mask); + + // Jiggle joint data functions + ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone2d_node", "joint_idx", "bone2d_node"), &SkeletonModification2DJiggle::set_jiggle_joint_bone2d_node); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone2d_node", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_bone2d_node); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification2DJiggle::set_jiggle_joint_bone_index); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_index", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_bone_index); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_override", "joint_idx", "override"), &SkeletonModification2DJiggle::set_jiggle_joint_override); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_override", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_override); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_stiffness", "joint_idx", "stiffness"), &SkeletonModification2DJiggle::set_jiggle_joint_stiffness); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_stiffness", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_stiffness); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_mass", "joint_idx", "mass"), &SkeletonModification2DJiggle::set_jiggle_joint_mass); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_mass", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_mass); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_damping", "joint_idx", "damping"), &SkeletonModification2DJiggle::set_jiggle_joint_damping); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_damping", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_damping); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_use_gravity", "joint_idx", "use_gravity"), &SkeletonModification2DJiggle::set_jiggle_joint_use_gravity); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_use_gravity", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_use_gravity); + ClassDB::bind_method(D_METHOD("set_jiggle_joint_gravity", "joint_idx", "gravity"), &SkeletonModification2DJiggle::set_jiggle_joint_gravity); + ClassDB::bind_method(D_METHOD("get_jiggle_joint_gravity", "joint_idx"), &SkeletonModification2DJiggle::get_jiggle_joint_gravity); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "jiggle_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_jiggle_data_chain_length", "get_jiggle_data_chain_length"); + ADD_GROUP("Default Joint Settings", ""); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness"), "set_stiffness", "get_stiffness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01"), "set_damping", "get_damping"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gravity"), "set_use_gravity", "get_use_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity"), "set_gravity", "get_gravity"); + ADD_GROUP("", ""); +} + +SkeletonModification2DJiggle::SkeletonModification2DJiggle() { + stack = nullptr; + is_setup = false; + jiggle_data_chain = Vector<Jiggle_Joint_Data2D>(); + stiffness = 3; + mass = 0.75; + damping = 0.75; + use_gravity = false; + gravity = Vector2(0, 6.0); + enabled = true; + editor_draw_gizmo = false; // Nothing to really show in a gizmo right now. +} + +SkeletonModification2DJiggle::~SkeletonModification2DJiggle() { +} diff --git a/scene/resources/skeleton_modification_2d_jiggle.h b/scene/resources/skeleton_modification_2d_jiggle.h new file mode 100644 index 0000000000..e24038a1db --- /dev/null +++ b/scene/resources/skeleton_modification_2d_jiggle.h @@ -0,0 +1,139 @@ +/*************************************************************************/ +/* skeleton_modification_2d_jiggle.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2DJIGGLE_H +#define SKELETONMODIFICATION2DJIGGLE_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModification2DJIGGLE +/////////////////////////////////////// + +class SkeletonModification2DJiggle : public SkeletonModification2D { + GDCLASS(SkeletonModification2DJiggle, SkeletonModification2D); + +private: + struct Jiggle_Joint_Data2D { + int bone_idx = -1; + NodePath bone2d_node; + ObjectID bone2d_node_cache; + + bool override_defaults = false; + float stiffness = 3; + float mass = 0.75; + float damping = 0.75; + bool use_gravity = false; + Vector2 gravity = Vector2(0, 6.0); + + Vector2 force = Vector2(0, 0); + Vector2 acceleration = Vector2(0, 0); + Vector2 velocity = Vector2(0, 0); + Vector2 last_position = Vector2(0, 0); + Vector2 dynamic_position = Vector2(0, 0); + + Vector2 last_noncollision_position = Vector2(0, 0); + }; + + Vector<Jiggle_Joint_Data2D> jiggle_data_chain; + + NodePath target_node; + ObjectID target_node_cache; + void update_target_cache(); + + float stiffness = 3; + float mass = 0.75; + float damping = 0.75; + bool use_gravity = false; + Vector2 gravity = Vector2(0, 6); + + bool use_colliders = false; + uint32_t collision_mask = 1; + + void jiggle_joint_update_bone2d_cache(int p_joint_idx); + void _execute_jiggle_joint(int p_joint_idx, Node2D *p_target, float p_delta); + void _update_jiggle_joint_data(); + +protected: + static void _bind_methods(); + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + + void set_target_node(const NodePath &p_target_node); + NodePath get_target_node() const; + + void set_stiffness(float p_stiffness); + float get_stiffness() const; + void set_mass(float p_mass); + float get_mass() const; + void set_damping(float p_damping); + float get_damping() const; + void set_use_gravity(bool p_use_gravity); + bool get_use_gravity() const; + void set_gravity(Vector2 p_gravity); + Vector2 get_gravity() const; + + void set_use_colliders(bool p_use_colliders); + bool get_use_colliders() const; + void set_collision_mask(int p_mask); + int get_collision_mask() const; + + int get_jiggle_data_chain_length(); + void set_jiggle_data_chain_length(int p_new_length); + + void set_jiggle_joint_bone2d_node(int p_joint_idx, const NodePath &p_target_node); + NodePath get_jiggle_joint_bone2d_node(int p_joint_idx) const; + void set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx); + int get_jiggle_joint_bone_index(int p_joint_idx) const; + + void set_jiggle_joint_override(int p_joint_idx, bool p_override); + bool get_jiggle_joint_override(int p_joint_idx) const; + void set_jiggle_joint_stiffness(int p_joint_idx, float p_stiffness); + float get_jiggle_joint_stiffness(int p_joint_idx) const; + void set_jiggle_joint_mass(int p_joint_idx, float p_mass); + float get_jiggle_joint_mass(int p_joint_idx) const; + void set_jiggle_joint_damping(int p_joint_idx, float p_damping); + float get_jiggle_joint_damping(int p_joint_idx) const; + void set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity); + bool get_jiggle_joint_use_gravity(int p_joint_idx) const; + void set_jiggle_joint_gravity(int p_joint_idx, Vector2 p_gravity); + Vector2 get_jiggle_joint_gravity(int p_joint_idx) const; + + SkeletonModification2DJiggle(); + ~SkeletonModification2DJiggle(); +}; + +#endif // SKELETONMODIFICATION2DJIGGLE_H diff --git a/scene/resources/skeleton_modification_2d_lookat.cpp b/scene/resources/skeleton_modification_2d_lookat.cpp new file mode 100644 index 0000000000..fd5c8c7cc2 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_lookat.cpp @@ -0,0 +1,407 @@ +/*************************************************************************/ +/* skeleton_modification_2d_lookat.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_lookat.h" +#include "scene/2d/skeleton_2d.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif // TOOLS_ENABLED + +bool SkeletonModification2DLookAt::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("enable_constraint")) { + set_enable_constraint(p_value); + } else if (path.begins_with("constraint_angle_min")) { + set_constraint_angle_min(Math::deg2rad(float(p_value))); + } else if (path.begins_with("constraint_angle_max")) { + set_constraint_angle_max(Math::deg2rad(float(p_value))); + } else if (path.begins_with("constraint_angle_invert")) { + set_constraint_angle_invert(p_value); + } else if (path.begins_with("constraint_in_localspace")) { + set_constraint_in_localspace(p_value); + } else if (path.begins_with("additional_rotation")) { + set_additional_rotation(Math::deg2rad(float(p_value))); + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor/draw_gizmo")) { + set_editor_draw_gizmo(p_value); + } +#endif // TOOLS_ENABLED + + return true; +} + +bool SkeletonModification2DLookAt::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("enable_constraint")) { + r_ret = get_enable_constraint(); + } else if (path.begins_with("constraint_angle_min")) { + r_ret = Math::rad2deg(get_constraint_angle_min()); + } else if (path.begins_with("constraint_angle_max")) { + r_ret = Math::rad2deg(get_constraint_angle_max()); + } else if (path.begins_with("constraint_angle_invert")) { + r_ret = get_constraint_angle_invert(); + } else if (path.begins_with("constraint_in_localspace")) { + r_ret = get_constraint_in_localspace(); + } else if (path.begins_with("additional_rotation")) { + r_ret = Math::rad2deg(get_additional_rotation()); + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor/draw_gizmo")) { + r_ret = get_editor_draw_gizmo(); + } +#endif // TOOLS_ENABLED + + return true; +} + +void SkeletonModification2DLookAt::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::BOOL, "enable_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + if (enable_constraint) { + p_list->push_back(PropertyInfo(Variant::FLOAT, "constraint_angle_min", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::FLOAT, "constraint_angle_max", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, "constraint_angle_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, "constraint_in_localspace", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } + p_list->push_back(PropertyInfo(Variant::FLOAT, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } +#endif // TOOLS_ENABLED +} + +void SkeletonModification2DLookAt::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + if (!enabled) { + return; + } + + if (target_node_cache.is_null()) { + WARN_PRINT_ONCE("Target cache is out of date. Attempting to update..."); + update_target_cache(); + return; + } + + if (bone2d_node_cache.is_null() && !bone2d_node.is_empty()) { + update_bone2d_cache(); + WARN_PRINT_ONCE("Bone2D node cache is out of date. Attempting to update..."); + return; + } + + if (target_node_reference == nullptr) { + target_node_reference = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache)); + } + if (!target_node_reference || !target_node_reference->is_inside_tree()) { + ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!"); + return; + } + if (bone_idx <= -1) { + ERR_PRINT_ONCE("Bone index is invalid. Cannot execute modification!"); + return; + } + + Bone2D *operation_bone = stack->skeleton->get_bone(bone_idx); + if (operation_bone == nullptr) { + ERR_PRINT_ONCE("bone_idx for modification does not point to a valid bone! Cannot execute modification"); + return; + } + + Transform2D operation_transform = operation_bone->get_global_transform(); + Transform2D target_trans = target_node_reference->get_global_transform(); + + // Look at the target! + operation_transform = operation_transform.looking_at(target_trans.get_origin()); + // Apply whatever scale it had prior to looking_at + operation_transform.set_scale(operation_bone->get_global_transform().get_scale()); + + // Account for the direction the bone faces in: + operation_transform.set_rotation(operation_transform.get_rotation() - operation_bone->get_bone_angle()); + + // Apply additional rotation + operation_transform.set_rotation(operation_transform.get_rotation() + additional_rotation); + + // Apply constraints in globalspace: + if (enable_constraint && !constraint_in_localspace) { + operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), constraint_angle_min, constraint_angle_max, constraint_angle_invert)); + } + + // Convert from a global transform to a local transform via the Bone2D node + operation_bone->set_global_transform(operation_transform); + operation_transform = operation_bone->get_transform(); + + // Apply constraints in localspace: + if (enable_constraint && constraint_in_localspace) { + operation_transform.set_rotation(clamp_angle(operation_transform.get_rotation(), constraint_angle_min, constraint_angle_max, constraint_angle_invert)); + } + + // Set the local pose override, and to make sure child bones are also updated, set the transform of the bone. + stack->skeleton->set_bone_local_pose_override(bone_idx, operation_transform, stack->strength, true); + operation_bone->set_transform(operation_transform); +} + +void SkeletonModification2DLookAt::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack != nullptr) { + is_setup = true; + update_target_cache(); + update_bone2d_cache(); + } +} + +void SkeletonModification2DLookAt::_draw_editor_gizmo() { + if (!enabled || !is_setup) { + return; + } + + Bone2D *operation_bone = stack->skeleton->get_bone(bone_idx); + editor_draw_angle_constraints(operation_bone, constraint_angle_min, constraint_angle_max, + enable_constraint, constraint_in_localspace, constraint_angle_invert); +} + +void SkeletonModification2DLookAt::update_bone2d_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update Bone2D cache: modification is not properly setup!"); + return; + } + + bone2d_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(bone2d_node)) { + Node *node = stack->skeleton->get_node(bone2d_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update Bone2D cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update Bone2D cache: node is not in the scene tree!"); + bone2d_node_cache = node->get_instance_id(); + + Bone2D *bone = Object::cast_to<Bone2D>(node); + if (bone) { + bone_idx = bone->get_index_in_skeleton(); + } else { + ERR_FAIL_MSG("Error Bone2D cache: Nodepath to Bone2D is not a Bone2D node!"); + } + + // Set this to null so we update it + target_node_reference = nullptr; + } + } + } +} + +void SkeletonModification2DLookAt::set_bone2d_node(const NodePath &p_target_node) { + bone2d_node = p_target_node; + update_bone2d_cache(); +} + +NodePath SkeletonModification2DLookAt::get_bone2d_node() const { + return bone2d_node; +} + +int SkeletonModification2DLookAt::get_bone_index() const { + return bone_idx; +} + +void SkeletonModification2DLookAt::set_bone_index(int p_bone_idx) { + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (is_setup) { + if (stack->skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + bone_idx = p_bone_idx; + bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id(); + bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx)); + } else { + WARN_PRINT("Cannot verify the bone index for this modification..."); + bone_idx = p_bone_idx; + } + } else { + WARN_PRINT("Cannot verify the bone index for this modification..."); + bone_idx = p_bone_idx; + } + + notify_property_list_changed(); +} + +void SkeletonModification2DLookAt::update_target_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!"); + return; + } + + target_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(target_node)) { + Node *node = stack->skeleton->get_node(target_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update target cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update target cache: node is not in the scene tree!"); + target_node_cache = node->get_instance_id(); + } + } + } +} + +void SkeletonModification2DLookAt::set_target_node(const NodePath &p_target_node) { + target_node = p_target_node; + update_target_cache(); +} + +NodePath SkeletonModification2DLookAt::get_target_node() const { + return target_node; +} + +float SkeletonModification2DLookAt::get_additional_rotation() const { + return additional_rotation; +} + +void SkeletonModification2DLookAt::set_additional_rotation(float p_rotation) { + additional_rotation = p_rotation; +} + +void SkeletonModification2DLookAt::set_enable_constraint(bool p_constraint) { + enable_constraint = p_constraint; + notify_property_list_changed(); +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DLookAt::get_enable_constraint() const { + return enable_constraint; +} + +void SkeletonModification2DLookAt::set_constraint_angle_min(float p_angle_min) { + constraint_angle_min = p_angle_min; +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +float SkeletonModification2DLookAt::get_constraint_angle_min() const { + return constraint_angle_min; +} + +void SkeletonModification2DLookAt::set_constraint_angle_max(float p_angle_max) { + constraint_angle_max = p_angle_max; +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +float SkeletonModification2DLookAt::get_constraint_angle_max() const { + return constraint_angle_max; +} + +void SkeletonModification2DLookAt::set_constraint_angle_invert(bool p_invert) { + constraint_angle_invert = p_invert; +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DLookAt::get_constraint_angle_invert() const { + return constraint_angle_invert; +} + +void SkeletonModification2DLookAt::set_constraint_in_localspace(bool p_constraint_in_localspace) { + constraint_in_localspace = p_constraint_in_localspace; +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DLookAt::get_constraint_in_localspace() const { + return constraint_in_localspace; +} + +void SkeletonModification2DLookAt::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_bone2d_node", "bone2d_nodepath"), &SkeletonModification2DLookAt::set_bone2d_node); + ClassDB::bind_method(D_METHOD("get_bone2d_node"), &SkeletonModification2DLookAt::get_bone2d_node); + ClassDB::bind_method(D_METHOD("set_bone_index", "bone_idx"), &SkeletonModification2DLookAt::set_bone_index); + ClassDB::bind_method(D_METHOD("get_bone_index"), &SkeletonModification2DLookAt::get_bone_index); + + ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DLookAt::set_target_node); + ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DLookAt::get_target_node); + + ClassDB::bind_method(D_METHOD("set_additional_rotation", "rotation"), &SkeletonModification2DLookAt::set_additional_rotation); + ClassDB::bind_method(D_METHOD("get_additional_rotation"), &SkeletonModification2DLookAt::get_additional_rotation); + + ClassDB::bind_method(D_METHOD("set_enable_constraint", "enable_constraint"), &SkeletonModification2DLookAt::set_enable_constraint); + ClassDB::bind_method(D_METHOD("get_enable_constraint"), &SkeletonModification2DLookAt::get_enable_constraint); + ClassDB::bind_method(D_METHOD("set_constraint_angle_min", "angle_min"), &SkeletonModification2DLookAt::set_constraint_angle_min); + ClassDB::bind_method(D_METHOD("get_constraint_angle_min"), &SkeletonModification2DLookAt::get_constraint_angle_min); + ClassDB::bind_method(D_METHOD("set_constraint_angle_max", "angle_max"), &SkeletonModification2DLookAt::set_constraint_angle_max); + ClassDB::bind_method(D_METHOD("get_constraint_angle_max"), &SkeletonModification2DLookAt::get_constraint_angle_max); + ClassDB::bind_method(D_METHOD("set_constraint_angle_invert", "invert"), &SkeletonModification2DLookAt::set_constraint_angle_invert); + ClassDB::bind_method(D_METHOD("get_constraint_angle_invert"), &SkeletonModification2DLookAt::get_constraint_angle_invert); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_index"), "set_bone_index", "get_bone_index"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D"), "set_bone2d_node", "get_bone2d_node"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); +} + +SkeletonModification2DLookAt::SkeletonModification2DLookAt() { + stack = nullptr; + is_setup = false; + bone_idx = -1; + additional_rotation = 0; + enable_constraint = false; + constraint_angle_min = 0; + constraint_angle_max = Math_PI * 2; + constraint_angle_invert = false; + enabled = true; + + editor_draw_gizmo = true; +} + +SkeletonModification2DLookAt::~SkeletonModification2DLookAt() { +} diff --git a/scene/resources/skeleton_modification_2d_lookat.h b/scene/resources/skeleton_modification_2d_lookat.h new file mode 100644 index 0000000000..6aff30b826 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_lookat.h @@ -0,0 +1,100 @@ +/*************************************************************************/ +/* skeleton_modification_2d_lookat.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2DLOOKAT_H +#define SKELETONMODIFICATION2DLOOKAT_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModification2DLookAt +/////////////////////////////////////// + +class SkeletonModification2DLookAt : public SkeletonModification2D { + GDCLASS(SkeletonModification2DLookAt, SkeletonModification2D); + +private: + int bone_idx = -1; + NodePath bone2d_node; + ObjectID bone2d_node_cache; + + NodePath target_node; + ObjectID target_node_cache; + Node2D *target_node_reference = nullptr; + + float additional_rotation = 0; + bool enable_constraint = false; + float constraint_angle_min = 0; + float constraint_angle_max = (2.0 * Math_PI); + bool constraint_angle_invert = false; + bool constraint_in_localspace = true; + + void update_bone2d_cache(); + void update_target_cache(); + +protected: + static void _bind_methods(); + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + void _draw_editor_gizmo() override; + + void set_bone2d_node(const NodePath &p_target_node); + NodePath get_bone2d_node() const; + void set_bone_index(int p_idx); + int get_bone_index() const; + + void set_target_node(const NodePath &p_target_node); + NodePath get_target_node() const; + + void set_additional_rotation(float p_rotation); + float get_additional_rotation() const; + + void set_enable_constraint(bool p_constraint); + bool get_enable_constraint() const; + void set_constraint_angle_min(float p_angle_min); + float get_constraint_angle_min() const; + void set_constraint_angle_max(float p_angle_max); + float get_constraint_angle_max() const; + void set_constraint_angle_invert(bool p_invert); + bool get_constraint_angle_invert() const; + void set_constraint_in_localspace(bool p_constraint_in_localspace); + bool get_constraint_in_localspace() const; + + SkeletonModification2DLookAt(); + ~SkeletonModification2DLookAt(); +}; + +#endif // SKELETONMODIFICATION2DLOOKAT_H diff --git a/scene/resources/skeleton_modification_2d_physicalbones.cpp b/scene/resources/skeleton_modification_2d_physicalbones.cpp new file mode 100644 index 0000000000..9dedb93f36 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_physicalbones.cpp @@ -0,0 +1,297 @@ +/*************************************************************************/ +/* skeleton_modification_2d_physicalbones.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_physicalbones.h" +#include "scene/2d/physical_bone_2d.h" +#include "scene/2d/skeleton_2d.h" + +bool SkeletonModification2DPhysicalBones::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + +#ifdef TOOLS_ENABLED + // Exposes a way to fetch the PhysicalBone2D nodes from the Godot editor. + if (is_setup) { + if (Engine::get_singleton()->is_editor_hint()) { + if (path.begins_with("fetch_bones")) { + fetch_physical_bones(); + notify_property_list_changed(); + return true; + } + } + } +#endif //TOOLS_ENABLED + + if (path.begins_with("joint_")) { + int which = path.get_slicec('_', 1).to_int(); + String what = path.get_slicec('_', 2); + ERR_FAIL_INDEX_V(which, physical_bone_chain.size(), false); + + if (what == "nodepath") { + set_physical_bone_node(which, p_value); + } + return true; + } + return true; +} + +bool SkeletonModification2DPhysicalBones::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + if (path.begins_with("fetch_bones")) { + return true; // Do nothing! + } + } +#endif //TOOLS_ENABLED + + if (path.begins_with("joint_")) { + int which = path.get_slicec('_', 1).to_int(); + String what = path.get_slicec('_', 2); + ERR_FAIL_INDEX_V(which, physical_bone_chain.size(), false); + + if (what == "nodepath") { + r_ret = get_physical_bone_node(which); + } + return true; + } + return true; +} + +void SkeletonModification2DPhysicalBones::_get_property_list(List<PropertyInfo> *p_list) const { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "fetch_bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } +#endif //TOOLS_ENABLED + + for (int i = 0; i < physical_bone_chain.size(); i++) { + String base_string = "joint_" + itos(i) + "_"; + + p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicalBone2D", PROPERTY_USAGE_DEFAULT)); + } +} + +void SkeletonModification2DPhysicalBones::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + if (!enabled) { + return; + } + + if (_simulation_state_dirty) { + _update_simulation_state(); + } + + for (int i = 0; i < physical_bone_chain.size(); i++) { + PhysicalBone_Data2D bone_data = physical_bone_chain[i]; + if (bone_data.physical_bone_node_cache.is_null()) { + WARN_PRINT_ONCE("PhysicalBone2D cache " + itos(i) + " is out of date. Attempting to update..."); + _physical_bone_update_cache(i); + continue; + } + + PhysicalBone2D *physical_bone = Object::cast_to<PhysicalBone2D>(ObjectDB::get_instance(bone_data.physical_bone_node_cache)); + if (!physical_bone) { + ERR_PRINT_ONCE("PhysicalBone2D not found at index " + itos(i) + "!"); + return; + } + if (physical_bone->get_bone2d_index() < 0 || physical_bone->get_bone2d_index() > stack->skeleton->get_bone_count()) { + ERR_PRINT_ONCE("PhysicalBone2D at index " + itos(i) + " has invalid Bone2D!"); + return; + } + Bone2D *bone_2d = stack->skeleton->get_bone(physical_bone->get_bone2d_index()); + + if (physical_bone->get_simulate_physics() && !physical_bone->get_follow_bone_when_simulating()) { + bone_2d->set_global_transform(physical_bone->get_global_transform()); + stack->skeleton->set_bone_local_pose_override(physical_bone->get_bone2d_index(), bone_2d->get_transform(), stack->strength, true); + } + } +} + +void SkeletonModification2DPhysicalBones::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack) { + is_setup = true; + + if (stack->skeleton) { + for (int i = 0; i < physical_bone_chain.size(); i++) { + _physical_bone_update_cache(i); + } + } + } +} + +void SkeletonModification2DPhysicalBones::_physical_bone_update_cache(int p_joint_idx) { + ERR_FAIL_INDEX_MSG(p_joint_idx, physical_bone_chain.size(), "Cannot update PhysicalBone2D cache: joint index out of range!"); + if (!is_setup || !stack) { + if (!stack) { + ERR_PRINT_ONCE("Cannot update PhysicalBone2D cache: modification is not properly setup!"); + } + return; + } + + physical_bone_chain.write[p_joint_idx].physical_bone_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(physical_bone_chain[p_joint_idx].physical_bone_node)) { + Node *node = stack->skeleton->get_node(physical_bone_chain[p_joint_idx].physical_bone_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update Physical Bone2D " + itos(p_joint_idx) + " cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update Physical Bone2D " + itos(p_joint_idx) + " cache: node is not in scene tree!"); + physical_bone_chain.write[p_joint_idx].physical_bone_node_cache = node->get_instance_id(); + } + } + } +} + +int SkeletonModification2DPhysicalBones::get_physical_bone_chain_length() { + return physical_bone_chain.size(); +} + +void SkeletonModification2DPhysicalBones::set_physical_bone_chain_length(int p_length) { + ERR_FAIL_COND(p_length < 0); + physical_bone_chain.resize(p_length); + notify_property_list_changed(); +} + +void SkeletonModification2DPhysicalBones::fetch_physical_bones() { + ERR_FAIL_COND_MSG(!stack, "No modification stack found! Cannot fetch physical bones!"); + ERR_FAIL_COND_MSG(!stack->skeleton, "No skeleton found! Cannot fetch physical bones!"); + + physical_bone_chain.clear(); + + List<Node *> node_queue = List<Node *>(); + node_queue.push_back(stack->skeleton); + + while (node_queue.size() > 0) { + Node *node_to_process = node_queue[0]; + node_queue.pop_front(); + + if (node_to_process != nullptr) { + PhysicalBone2D *potential_bone = Object::cast_to<PhysicalBone2D>(node_to_process); + if (potential_bone) { + PhysicalBone_Data2D new_data = PhysicalBone_Data2D(); + new_data.physical_bone_node = stack->skeleton->get_path_to(potential_bone); + new_data.physical_bone_node_cache = potential_bone->get_instance_id(); + physical_bone_chain.push_back(new_data); + } + for (int i = 0; i < node_to_process->get_child_count(); i++) { + node_queue.push_back(node_to_process->get_child(i)); + } + } + } +} + +void SkeletonModification2DPhysicalBones::start_simulation(const TypedArray<StringName> &p_bones) { + _simulation_state_dirty = true; + _simulation_state_dirty_names = p_bones; + _simulation_state_dirty_process = true; + + if (is_setup) { + _update_simulation_state(); + } +} + +void SkeletonModification2DPhysicalBones::stop_simulation(const TypedArray<StringName> &p_bones) { + _simulation_state_dirty = true; + _simulation_state_dirty_names = p_bones; + _simulation_state_dirty_process = false; + + if (is_setup) { + _update_simulation_state(); + } +} + +void SkeletonModification2DPhysicalBones::_update_simulation_state() { + if (!_simulation_state_dirty) { + return; + } + _simulation_state_dirty = false; + + if (_simulation_state_dirty_names.size() <= 0) { + for (int i = 0; i < physical_bone_chain.size(); i++) { + PhysicalBone2D *physical_bone = Object::cast_to<PhysicalBone2D>(stack->skeleton->get_node(physical_bone_chain[i].physical_bone_node)); + if (!physical_bone) { + continue; + } + + physical_bone->set_simulate_physics(_simulation_state_dirty_process); + } + } else { + for (int i = 0; i < physical_bone_chain.size(); i++) { + PhysicalBone2D *physical_bone = Object::cast_to<PhysicalBone2D>(ObjectDB::get_instance(physical_bone_chain[i].physical_bone_node_cache)); + if (!physical_bone) { + continue; + } + if (_simulation_state_dirty_names.has(physical_bone->get_name())) { + physical_bone->set_simulate_physics(_simulation_state_dirty_process); + } + } + } +} + +void SkeletonModification2DPhysicalBones::set_physical_bone_node(int p_joint_idx, const NodePath &p_nodepath) { + ERR_FAIL_INDEX_MSG(p_joint_idx, physical_bone_chain.size(), "Joint index out of range!"); + physical_bone_chain.write[p_joint_idx].physical_bone_node = p_nodepath; + _physical_bone_update_cache(p_joint_idx); +} + +NodePath SkeletonModification2DPhysicalBones::get_physical_bone_node(int p_joint_idx) const { + ERR_FAIL_INDEX_V_MSG(p_joint_idx, physical_bone_chain.size(), NodePath(), "Joint index out of range!"); + return physical_bone_chain[p_joint_idx].physical_bone_node; +} + +void SkeletonModification2DPhysicalBones::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_physical_bone_chain_length", "length"), &SkeletonModification2DPhysicalBones::set_physical_bone_chain_length); + ClassDB::bind_method(D_METHOD("get_physical_bone_chain_length"), &SkeletonModification2DPhysicalBones::get_physical_bone_chain_length); + + ClassDB::bind_method(D_METHOD("set_physical_bone_node", "joint_idx", "physicalbone2d_node"), &SkeletonModification2DPhysicalBones::set_physical_bone_node); + ClassDB::bind_method(D_METHOD("get_physical_bone_node", "joint_idx"), &SkeletonModification2DPhysicalBones::get_physical_bone_node); + + ClassDB::bind_method(D_METHOD("fetch_physical_bones"), &SkeletonModification2DPhysicalBones::fetch_physical_bones); + ClassDB::bind_method(D_METHOD("start_simulation", "bones"), &SkeletonModification2DPhysicalBones::start_simulation, DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("stop_simulation", "bones"), &SkeletonModification2DPhysicalBones::stop_simulation, DEFVAL(Array())); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "physical_bone_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_physical_bone_chain_length", "get_physical_bone_chain_length"); +} + +SkeletonModification2DPhysicalBones::SkeletonModification2DPhysicalBones() { + stack = nullptr; + is_setup = false; + physical_bone_chain = Vector<PhysicalBone_Data2D>(); + enabled = true; + editor_draw_gizmo = false; // Nothing to really show in a gizmo right now. +} + +SkeletonModification2DPhysicalBones::~SkeletonModification2DPhysicalBones() { +} diff --git a/scene/resources/skeleton_modification_2d_physicalbones.h b/scene/resources/skeleton_modification_2d_physicalbones.h new file mode 100644 index 0000000000..cdf6a5f570 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_physicalbones.h @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* skeleton_modification_2d_physicalbones.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2DPHYSICALBONES_H +#define SKELETONMODIFICATION2DPHYSICALBONES_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModification2DJIGGLE +/////////////////////////////////////// + +class SkeletonModification2DPhysicalBones : public SkeletonModification2D { + GDCLASS(SkeletonModification2DPhysicalBones, SkeletonModification2D); + +private: + struct PhysicalBone_Data2D { + NodePath physical_bone_node; + ObjectID physical_bone_node_cache; + }; + Vector<PhysicalBone_Data2D> physical_bone_chain; + + void _physical_bone_update_cache(int p_joint_idx); + + bool _simulation_state_dirty = false; + TypedArray<StringName> _simulation_state_dirty_names; + bool _simulation_state_dirty_process; + void _update_simulation_state(); + +protected: + static void _bind_methods(); + bool _get(const StringName &p_path, Variant &r_ret) const; + bool _set(const StringName &p_path, const Variant &p_value); + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + + int get_physical_bone_chain_length(); + void set_physical_bone_chain_length(int p_new_length); + + void set_physical_bone_node(int p_joint_idx, const NodePath &p_path); + NodePath get_physical_bone_node(int p_joint_idx) const; + + void fetch_physical_bones(); + void start_simulation(const TypedArray<StringName> &p_bones); + void stop_simulation(const TypedArray<StringName> &p_bones); + + SkeletonModification2DPhysicalBones(); + ~SkeletonModification2DPhysicalBones(); +}; + +#endif // SKELETONMODIFICATION2DPHYSICALBONES_H diff --git a/scene/resources/skeleton_modification_2d_stackholder.cpp b/scene/resources/skeleton_modification_2d_stackholder.cpp new file mode 100644 index 0000000000..9436092cd9 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_stackholder.cpp @@ -0,0 +1,131 @@ +/*************************************************************************/ +/* skeleton_modification_2d_stackholder.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_stackholder.h" +#include "scene/2d/skeleton_2d.h" + +bool SkeletonModification2DStackHolder::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path == "held_modification_stack") { + set_held_modification_stack(p_value); + } + +#ifdef TOOLS_ENABLED + if (path == "editor/draw_gizmo") { + set_editor_draw_gizmo(p_value); + } +#endif // TOOLS_ENABLED + + return true; +} + +bool SkeletonModification2DStackHolder::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path == "held_modification_stack") { + r_ret = get_held_modification_stack(); + } + +#ifdef TOOLS_ENABLED + if (path == "editor/draw_gizmo") { + r_ret = get_editor_draw_gizmo(); + } +#endif // TOOLS_ENABLED + + return true; +} + +void SkeletonModification2DStackHolder::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } +#endif // TOOLS_ENABLED +} + +void SkeletonModification2DStackHolder::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + + if (held_modification_stack.is_valid()) { + held_modification_stack->execute(p_delta, execution_mode); + } +} + +void SkeletonModification2DStackHolder::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack != nullptr) { + is_setup = true; + + if (held_modification_stack.is_valid()) { + held_modification_stack->set_skeleton(stack->get_skeleton()); + held_modification_stack->setup(); + } + } +} + +void SkeletonModification2DStackHolder::_draw_editor_gizmo() { + if (stack) { + if (held_modification_stack.is_valid()) { + held_modification_stack->draw_editor_gizmos(); + } + } +} + +void SkeletonModification2DStackHolder::set_held_modification_stack(Ref<SkeletonModificationStack2D> p_held_stack) { + held_modification_stack = p_held_stack; + + if (is_setup && held_modification_stack.is_valid()) { + held_modification_stack->set_skeleton(stack->get_skeleton()); + held_modification_stack->setup(); + } +} + +Ref<SkeletonModificationStack2D> SkeletonModification2DStackHolder::get_held_modification_stack() const { + return held_modification_stack; +} + +void SkeletonModification2DStackHolder::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_held_modification_stack", "held_modification_stack"), &SkeletonModification2DStackHolder::set_held_modification_stack); + ClassDB::bind_method(D_METHOD("get_held_modification_stack"), &SkeletonModification2DStackHolder::get_held_modification_stack); +} + +SkeletonModification2DStackHolder::SkeletonModification2DStackHolder() { + stack = nullptr; + is_setup = false; + enabled = true; +} + +SkeletonModification2DStackHolder::~SkeletonModification2DStackHolder() { +} diff --git a/scene/3d/immediate_geometry_3d.h b/scene/resources/skeleton_modification_2d_stackholder.h index ee4938d9f7..9cc38e3942 100644 --- a/scene/3d/immediate_geometry_3d.h +++ b/scene/resources/skeleton_modification_2d_stackholder.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* immediate_geometry_3d.h */ +/* skeleton_modification_2d_stackholder.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,45 +28,37 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef IMMEDIATE_GEOMETRY_3D_H -#define IMMEDIATE_GEOMETRY_3D_H +#ifndef SKELETONMODIFICATION2DSTACKHOLDER_H +#define SKELETONMODIFICATION2DSTACKHOLDER_H -#include "scene/3d/visual_instance_3d.h" -#include "scene/resources/mesh.h" +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" -class ImmediateGeometry3D : public GeometryInstance3D { - GDCLASS(ImmediateGeometry3D, GeometryInstance3D); +/////////////////////////////////////// +// SkeletonModification2DJIGGLE +/////////////////////////////////////// - RID im; - //a list of textures drawn need to be kept, to avoid references - // in RenderingServer from becoming invalid if the texture is no longer used - List<Ref<Texture2D>> cached_textures; - bool empty = true; - AABB aabb; +class SkeletonModification2DStackHolder : public SkeletonModification2D { + GDCLASS(SkeletonModification2DStackHolder, SkeletonModification2D); protected: static void _bind_methods(); + bool _get(const StringName &p_path, Variant &r_ret) const; + bool _set(const StringName &p_path, const Variant &p_value); + void _get_property_list(List<PropertyInfo> *p_list) const; public: - void begin(Mesh::PrimitiveType p_primitive, const Ref<Texture2D> &p_texture = Ref<Texture2D>()); - void set_normal(const Vector3 &p_normal); - void set_tangent(const Plane &p_tangent); - void set_color(const Color &p_color); - void set_uv(const Vector2 &p_uv); - void set_uv2(const Vector2 &p_uv2); + Ref<SkeletonModificationStack2D> held_modification_stack; - void add_vertex(const Vector3 &p_vertex); + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + void _draw_editor_gizmo() override; - void end(); - void clear(); + void set_held_modification_stack(Ref<SkeletonModificationStack2D> p_held_stack); + Ref<SkeletonModificationStack2D> get_held_modification_stack() const; - void add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv = true); - - virtual AABB get_aabb() const override; - virtual Vector<Face3> get_faces(uint32_t p_usage_flags) const override; - - ImmediateGeometry3D(); - ~ImmediateGeometry3D(); + SkeletonModification2DStackHolder(); + ~SkeletonModification2DStackHolder(); }; -#endif // IMMEDIATE_GEOMETRY_H +#endif // SKELETONMODIFICATION2DSTACKHOLDER_H diff --git a/scene/resources/skeleton_modification_2d_twoboneik.cpp b/scene/resources/skeleton_modification_2d_twoboneik.cpp new file mode 100644 index 0000000000..0a91290015 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_twoboneik.cpp @@ -0,0 +1,481 @@ +/*************************************************************************/ +/* skeleton_modification_2d_twoboneik.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_2d_twoboneik.h" +#include "scene/2d/skeleton_2d.h" + +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif // TOOLS_ENABLED + +bool SkeletonModification2DTwoBoneIK::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path == "joint_one_bone_idx") { + set_joint_one_bone_idx(p_value); + } else if (path == "joint_one_bone2d_node") { + set_joint_one_bone2d_node(p_value); + } else if (path == "joint_two_bone_idx") { + set_joint_two_bone_idx(p_value); + } else if (path == "joint_two_bone2d_node") { + set_joint_two_bone2d_node(p_value); + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor/draw_gizmo")) { + set_editor_draw_gizmo(p_value); + } else if (path.begins_with("editor/draw_min_max")) { + set_editor_draw_min_max(p_value); + } +#endif // TOOLS_ENABLED + + return true; +} + +bool SkeletonModification2DTwoBoneIK::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path == "joint_one_bone_idx") { + r_ret = get_joint_one_bone_idx(); + } else if (path == "joint_one_bone2d_node") { + r_ret = get_joint_one_bone2d_node(); + } else if (path == "joint_two_bone_idx") { + r_ret = get_joint_two_bone_idx(); + } else if (path == "joint_two_bone2d_node") { + r_ret = get_joint_two_bone2d_node(); + } + +#ifdef TOOLS_ENABLED + if (path.begins_with("editor/draw_gizmo")) { + r_ret = get_editor_draw_gizmo(); + } else if (path.begins_with("editor/draw_min_max")) { + r_ret = get_editor_draw_min_max(); + } +#endif // TOOLS_ENABLED + + return true; +} + +void SkeletonModification2DTwoBoneIK::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::INT, "joint_one_bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, "joint_one_bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT)); + + p_list->push_back(PropertyInfo(Variant::INT, "joint_two_bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::NODE_PATH, "joint_two_bone2d_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Bone2D", PROPERTY_USAGE_DEFAULT)); + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_gizmo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + p_list->push_back(PropertyInfo(Variant::BOOL, "editor/draw_min_max", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT)); + } +#endif // TOOLS_ENABLED +} + +void SkeletonModification2DTwoBoneIK::_execute(float p_delta) { + ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr, + "Modification is not setup and therefore cannot execute!"); + if (!enabled) { + return; + } + + if (target_node_cache.is_null()) { + WARN_PRINT_ONCE("Target cache is out of date. Attempting to update..."); + update_target_cache(); + return; + } + + if (joint_one_bone2d_node_cache.is_null() && !joint_one_bone2d_node.is_empty()) { + WARN_PRINT_ONCE("Joint one Bone2D node cache is out of date. Attempting to update..."); + update_joint_one_bone2d_cache(); + } + if (joint_two_bone2d_node_cache.is_null() && !joint_two_bone2d_node.is_empty()) { + WARN_PRINT_ONCE("Joint two Bone2D node cache is out of date. Attempting to update..."); + update_joint_two_bone2d_cache(); + } + + Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache)); + if (!target || !target->is_inside_tree()) { + ERR_PRINT_ONCE("Target node is not in the scene tree. Cannot execute modification!"); + return; + } + + Bone2D *joint_one_bone = stack->skeleton->get_bone(joint_one_bone_idx); + if (joint_one_bone == nullptr) { + ERR_PRINT_ONCE("Joint one bone_idx does not point to a valid bone! Cannot execute modification!"); + return; + } + + Bone2D *joint_two_bone = stack->skeleton->get_bone(joint_two_bone_idx); + if (joint_two_bone == nullptr) { + ERR_PRINT_ONCE("Joint two bone_idx does not point to a valid bone! Cannot execute modification!"); + return; + } + + // Adopted from the links below: + // http://theorangeduck.com/page/simple-two-joint + // https://www.alanzucconi.com/2018/05/02/ik-2d-2/ + // With modifications by TwistedTwigleg + Vector2 target_difference = target->get_global_transform().get_origin() - joint_one_bone->get_global_transform().get_origin(); + float joint_one_to_target = target_difference.length(); + float angle_atan = Math::atan2(target_difference.y, target_difference.x); + + float bone_one_length = joint_one_bone->get_length() * MIN(joint_one_bone->get_global_scale().x, joint_one_bone->get_global_scale().y); + float bone_two_length = joint_two_bone->get_length() * MIN(joint_two_bone->get_global_scale().x, joint_two_bone->get_global_scale().y); + bool override_angles_due_to_out_of_range = false; + + if (joint_one_to_target < target_minimum_distance) { + joint_one_to_target = target_minimum_distance; + } + if (joint_one_to_target > target_maximum_distance && target_maximum_distance > 0.0) { + joint_one_to_target = target_maximum_distance; + } + + if (bone_one_length + bone_two_length < joint_one_to_target) { + override_angles_due_to_out_of_range = true; + } + + if (!override_angles_due_to_out_of_range) { + float angle_0 = Math::acos(((joint_one_to_target * joint_one_to_target) + (bone_one_length * bone_one_length) - (bone_two_length * bone_two_length)) / (2.0 * joint_one_to_target * bone_one_length)); + float angle_1 = Math::acos(((bone_two_length * bone_two_length) + (bone_one_length * bone_one_length) - (joint_one_to_target * joint_one_to_target)) / (2.0 * bone_two_length * bone_one_length)); + + if (flip_bend_direction) { + angle_0 = -angle_0; + angle_1 = -angle_1; + } + + if (isnan(angle_0) || isnan(angle_1)) { + // We cannot solve for this angle! Do nothing to avoid setting the rotation (and scale) to NaN. + } else { + joint_one_bone->set_global_rotation(angle_atan - angle_0 - joint_one_bone->get_bone_angle()); + joint_two_bone->set_rotation(-Math_PI - angle_1 - joint_two_bone->get_bone_angle() + joint_one_bone->get_bone_angle()); + } + } else { + joint_one_bone->set_global_rotation(angle_atan - joint_one_bone->get_bone_angle()); + joint_two_bone->set_global_rotation(angle_atan - joint_two_bone->get_bone_angle()); + } + + stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, joint_one_bone->get_transform(), stack->strength, true); + stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, joint_two_bone->get_transform(), stack->strength, true); +} + +void SkeletonModification2DTwoBoneIK::_setup_modification(SkeletonModificationStack2D *p_stack) { + stack = p_stack; + + if (stack) { + is_setup = true; + update_target_cache(); + update_joint_one_bone2d_cache(); + update_joint_two_bone2d_cache(); + } +} + +void SkeletonModification2DTwoBoneIK::_draw_editor_gizmo() { + if (!enabled || !is_setup) { + return; + } + + Bone2D *operation_bone_one = stack->skeleton->get_bone(joint_one_bone_idx); + if (!operation_bone_one) { + return; + } + stack->skeleton->draw_set_transform( + stack->skeleton->get_global_transform().affine_inverse().xform(operation_bone_one->get_global_position()), + operation_bone_one->get_global_rotation() - stack->skeleton->get_global_rotation()); + + Color bone_ik_color = Color(1.0, 0.65, 0.0, 0.4); +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); + } +#endif // TOOLS_ENABLED + + if (flip_bend_direction) { + float angle = -(Math_PI * 0.5) + operation_bone_one->get_bone_angle(); + stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(angle), sin(angle)) * (operation_bone_one->get_length() * 0.5), bone_ik_color, 2.0); + } else { + float angle = (Math_PI * 0.5) + operation_bone_one->get_bone_angle(); + stack->skeleton->draw_line(Vector2(0, 0), Vector2(Math::cos(angle), sin(angle)) * (operation_bone_one->get_length() * 0.5), bone_ik_color, 2.0); + } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + if (editor_draw_min_max) { + if (target_maximum_distance != 0.0 || target_minimum_distance != 0.0) { + Vector2 target_direction = Vector2(0, 1); + if (target_node_cache.is_valid()) { + stack->skeleton->draw_set_transform(Vector2(0, 0), 0.0); + Node2D *target = Object::cast_to<Node2D>(ObjectDB::get_instance(target_node_cache)); + target_direction = operation_bone_one->get_global_position().direction_to(target->get_global_position()); + } + + stack->skeleton->draw_circle(target_direction * target_minimum_distance, 8, bone_ik_color); + stack->skeleton->draw_circle(target_direction * target_maximum_distance, 8, bone_ik_color); + stack->skeleton->draw_line(target_direction * target_minimum_distance, target_direction * target_maximum_distance, bone_ik_color, 2.0); + } + } + } +#endif // TOOLS_ENABLED +} + +void SkeletonModification2DTwoBoneIK::update_target_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update target cache: modification is not properly setup!"); + return; + } + + target_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(target_node)) { + Node *node = stack->skeleton->get_node(target_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update target cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update target cache: node is not in the scene tree!"); + target_node_cache = node->get_instance_id(); + } + } + } +} + +void SkeletonModification2DTwoBoneIK::update_joint_one_bone2d_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update joint one Bone2D cache: modification is not properly setup!"); + return; + } + + joint_one_bone2d_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(joint_one_bone2d_node)) { + Node *node = stack->skeleton->get_node(joint_one_bone2d_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update update joint one Bone2D cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update update joint one Bone2D cache: node is not in the scene tree!"); + joint_one_bone2d_node_cache = node->get_instance_id(); + + Bone2D *bone = Object::cast_to<Bone2D>(node); + if (bone) { + joint_one_bone_idx = bone->get_index_in_skeleton(); + } else { + ERR_FAIL_MSG("update joint one Bone2D cache: Nodepath to Bone2D is not a Bone2D node!"); + } + } + } + } +} + +void SkeletonModification2DTwoBoneIK::update_joint_two_bone2d_cache() { + if (!is_setup || !stack) { + ERR_PRINT_ONCE("Cannot update joint two Bone2D cache: modification is not properly setup!"); + return; + } + + joint_two_bone2d_node_cache = ObjectID(); + if (stack->skeleton) { + if (stack->skeleton->is_inside_tree()) { + if (stack->skeleton->has_node(joint_two_bone2d_node)) { + Node *node = stack->skeleton->get_node(joint_two_bone2d_node); + ERR_FAIL_COND_MSG(!node || stack->skeleton == node, + "Cannot update update joint two Bone2D cache: node is this modification's skeleton or cannot be found!"); + ERR_FAIL_COND_MSG(!node->is_inside_tree(), + "Cannot update update joint two Bone2D cache: node is not in scene tree!"); + joint_two_bone2d_node_cache = node->get_instance_id(); + + Bone2D *bone = Object::cast_to<Bone2D>(node); + if (bone) { + joint_two_bone_idx = bone->get_index_in_skeleton(); + } else { + ERR_FAIL_MSG("update joint two Bone2D cache: Nodepath to Bone2D is not a Bone2D node!"); + } + } + } + } +} + +void SkeletonModification2DTwoBoneIK::set_target_node(const NodePath &p_target_node) { + target_node = p_target_node; + update_target_cache(); +} + +NodePath SkeletonModification2DTwoBoneIK::get_target_node() const { + return target_node; +} + +void SkeletonModification2DTwoBoneIK::set_joint_one_bone2d_node(const NodePath &p_target_node) { + joint_one_bone2d_node = p_target_node; + update_joint_one_bone2d_cache(); + notify_property_list_changed(); +} + +void SkeletonModification2DTwoBoneIK::set_target_minimum_distance(float p_distance) { + ERR_FAIL_COND_MSG(p_distance < 0, "Target minimum distance cannot be less than zero!"); + target_minimum_distance = p_distance; +} + +float SkeletonModification2DTwoBoneIK::get_target_minimum_distance() const { + return target_minimum_distance; +} + +void SkeletonModification2DTwoBoneIK::set_target_maximum_distance(float p_distance) { + ERR_FAIL_COND_MSG(p_distance < 0, "Target maximum distance cannot be less than zero!"); + target_maximum_distance = p_distance; +} + +float SkeletonModification2DTwoBoneIK::get_target_maximum_distance() const { + return target_maximum_distance; +} + +void SkeletonModification2DTwoBoneIK::set_flip_bend_direction(bool p_flip_direction) { + flip_bend_direction = p_flip_direction; + +#ifdef TOOLS_ENABLED + if (stack && is_setup) { + stack->set_editor_gizmos_dirty(true); + } +#endif // TOOLS_ENABLED +} + +bool SkeletonModification2DTwoBoneIK::get_flip_bend_direction() const { + return flip_bend_direction; +} + +NodePath SkeletonModification2DTwoBoneIK::get_joint_one_bone2d_node() const { + return joint_one_bone2d_node; +} + +void SkeletonModification2DTwoBoneIK::set_joint_two_bone2d_node(const NodePath &p_target_node) { + joint_two_bone2d_node = p_target_node; + update_joint_two_bone2d_cache(); + notify_property_list_changed(); +} + +NodePath SkeletonModification2DTwoBoneIK::get_joint_two_bone2d_node() const { + return joint_two_bone2d_node; +} + +void SkeletonModification2DTwoBoneIK::set_joint_one_bone_idx(int p_bone_idx) { + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (is_setup) { + if (stack->skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + joint_one_bone_idx = p_bone_idx; + joint_one_bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id(); + joint_one_bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx)); + } else { + WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint one..."); + joint_one_bone_idx = p_bone_idx; + } + } else { + WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint one..."); + joint_one_bone_idx = p_bone_idx; + } + + notify_property_list_changed(); +} + +int SkeletonModification2DTwoBoneIK::get_joint_one_bone_idx() const { + return joint_one_bone_idx; +} + +void SkeletonModification2DTwoBoneIK::set_joint_two_bone_idx(int p_bone_idx) { + ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!"); + + if (is_setup) { + if (stack->skeleton) { + ERR_FAIL_INDEX_MSG(p_bone_idx, stack->skeleton->get_bone_count(), "Passed-in Bone index is out of range!"); + joint_two_bone_idx = p_bone_idx; + joint_two_bone2d_node_cache = stack->skeleton->get_bone(p_bone_idx)->get_instance_id(); + joint_two_bone2d_node = stack->skeleton->get_path_to(stack->skeleton->get_bone(p_bone_idx)); + } else { + WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint two..."); + joint_two_bone_idx = p_bone_idx; + } + } else { + WARN_PRINT("TwoBoneIK: Cannot verify the joint bone index for joint two..."); + joint_two_bone_idx = p_bone_idx; + } + + notify_property_list_changed(); +} + +int SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx() const { + return joint_two_bone_idx; +} + +#ifdef TOOLS_ENABLED +void SkeletonModification2DTwoBoneIK::set_editor_draw_min_max(bool p_draw) { + editor_draw_min_max = p_draw; +} + +bool SkeletonModification2DTwoBoneIK::get_editor_draw_min_max() const { + return editor_draw_min_max; +} +#endif // TOOLS_ENABLED + +void SkeletonModification2DTwoBoneIK::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification2DTwoBoneIK::set_target_node); + ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification2DTwoBoneIK::get_target_node); + + ClassDB::bind_method(D_METHOD("set_target_minimum_distance", "minimum_distance"), &SkeletonModification2DTwoBoneIK::set_target_minimum_distance); + ClassDB::bind_method(D_METHOD("get_target_minimum_distance"), &SkeletonModification2DTwoBoneIK::get_target_minimum_distance); + ClassDB::bind_method(D_METHOD("set_target_maximum_distance", "maximum_distance"), &SkeletonModification2DTwoBoneIK::set_target_maximum_distance); + ClassDB::bind_method(D_METHOD("get_target_maximum_distance"), &SkeletonModification2DTwoBoneIK::get_target_maximum_distance); + ClassDB::bind_method(D_METHOD("set_flip_bend_direction", "flip_direction"), &SkeletonModification2DTwoBoneIK::set_flip_bend_direction); + ClassDB::bind_method(D_METHOD("get_flip_bend_direction"), &SkeletonModification2DTwoBoneIK::get_flip_bend_direction); + + ClassDB::bind_method(D_METHOD("set_joint_one_bone2d_node", "bone2d_node"), &SkeletonModification2DTwoBoneIK::set_joint_one_bone2d_node); + ClassDB::bind_method(D_METHOD("get_joint_one_bone2d_node"), &SkeletonModification2DTwoBoneIK::get_joint_one_bone2d_node); + ClassDB::bind_method(D_METHOD("set_joint_one_bone_idx", "bone_idx"), &SkeletonModification2DTwoBoneIK::set_joint_one_bone_idx); + ClassDB::bind_method(D_METHOD("get_joint_one_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_one_bone_idx); + + ClassDB::bind_method(D_METHOD("set_joint_two_bone2d_node", "bone2d_node"), &SkeletonModification2DTwoBoneIK::set_joint_two_bone2d_node); + ClassDB::bind_method(D_METHOD("get_joint_two_bone2d_node"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone2d_node); + ClassDB::bind_method(D_METHOD("set_joint_two_bone_idx", "bone_idx"), &SkeletonModification2DTwoBoneIK::set_joint_two_bone_idx); + ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification2DTwoBoneIK::get_joint_two_bone_idx); + + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node2D"), "set_target_node", "get_target_node"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_minimum_distance", PROPERTY_HINT_RANGE, "0, 100000000, 0.01"), "set_target_minimum_distance", "get_target_minimum_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_maximum_distance", PROPERTY_HINT_NONE, "0, 100000000, 0.01"), "set_target_maximum_distance", "get_target_maximum_distance"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_bend_direction", PROPERTY_HINT_NONE, ""), "set_flip_bend_direction", "get_flip_bend_direction"); + ADD_GROUP("", ""); +} + +SkeletonModification2DTwoBoneIK::SkeletonModification2DTwoBoneIK() { + stack = nullptr; + is_setup = false; + enabled = true; + editor_draw_gizmo = true; +} + +SkeletonModification2DTwoBoneIK::~SkeletonModification2DTwoBoneIK() { +} diff --git a/scene/resources/skeleton_modification_2d_twoboneik.h b/scene/resources/skeleton_modification_2d_twoboneik.h new file mode 100644 index 0000000000..c7e545a488 --- /dev/null +++ b/scene/resources/skeleton_modification_2d_twoboneik.h @@ -0,0 +1,107 @@ +/*************************************************************************/ +/* skeleton_modification_2d_twoboneik.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATION2DTWOBONEIK_H +#define SKELETONMODIFICATION2DTWOBONEIK_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModification2DJIGGLE +/////////////////////////////////////// + +class SkeletonModification2DTwoBoneIK : public SkeletonModification2D { + GDCLASS(SkeletonModification2DTwoBoneIK, SkeletonModification2D); + +private: + NodePath target_node; + ObjectID target_node_cache; + float target_minimum_distance = 0; + float target_maximum_distance = 0; + bool flip_bend_direction = false; + + NodePath joint_one_bone2d_node; + ObjectID joint_one_bone2d_node_cache; + int joint_one_bone_idx = -1; + + NodePath joint_two_bone2d_node; + ObjectID joint_two_bone2d_node_cache; + int joint_two_bone_idx = -1; + +#ifdef TOOLS_ENABLED + bool editor_draw_min_max = false; +#endif // TOOLS_ENABLED + + void update_target_cache(); + void update_joint_one_bone2d_cache(); + void update_joint_two_bone2d_cache(); + +protected: + static void _bind_methods(); + bool _get(const StringName &p_path, Variant &r_ret) const; + bool _set(const StringName &p_path, const Variant &p_value); + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void _execute(float p_delta) override; + void _setup_modification(SkeletonModificationStack2D *p_stack) override; + void _draw_editor_gizmo() override; + + void set_target_node(const NodePath &p_target_node); + NodePath get_target_node() const; + + void set_target_minimum_distance(float p_minimum_distance); + float get_target_minimum_distance() const; + void set_target_maximum_distance(float p_maximum_distance); + float get_target_maximum_distance() const; + void set_flip_bend_direction(bool p_flip_direction); + bool get_flip_bend_direction() const; + + void set_joint_one_bone2d_node(const NodePath &p_node); + NodePath get_joint_one_bone2d_node() const; + void set_joint_one_bone_idx(int p_bone_idx); + int get_joint_one_bone_idx() const; + + void set_joint_two_bone2d_node(const NodePath &p_node); + NodePath get_joint_two_bone2d_node() const; + void set_joint_two_bone_idx(int p_bone_idx); + int get_joint_two_bone_idx() const; + +#ifdef TOOLS_ENABLED + void set_editor_draw_min_max(bool p_draw); + bool get_editor_draw_min_max() const; +#endif // TOOLS_ENABLED + + SkeletonModification2DTwoBoneIK(); + ~SkeletonModification2DTwoBoneIK(); +}; + +#endif // SKELETONMODIFICATION2DTWOBONEIK_H diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp new file mode 100644 index 0000000000..72c1c330ef --- /dev/null +++ b/scene/resources/skeleton_modification_stack_2d.cpp @@ -0,0 +1,269 @@ +/*************************************************************************/ +/* skeleton_modification_stack_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "skeleton_modification_stack_2d.h" +#include "scene/2d/skeleton_2d.h" + +void SkeletonModificationStack2D::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < modifications.size(); i++) { + p_list->push_back( + PropertyInfo(Variant::OBJECT, "modifications/" + itos(i), + PROPERTY_HINT_RESOURCE_TYPE, + "SkeletonModification2D", + PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + } +} + +bool SkeletonModificationStack2D::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (path.begins_with("modifications/")) { + int mod_idx = path.get_slicec('/', 1).to_int(); + set_modification(mod_idx, p_value); + return true; + } + return true; +} + +bool SkeletonModificationStack2D::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (path.begins_with("modifications/")) { + int mod_idx = path.get_slicec('/', 1).to_int(); + r_ret = get_modification(mod_idx); + return true; + } + return true; +} + +void SkeletonModificationStack2D::setup() { + if (is_setup) { + return; + } + + if (skeleton != nullptr) { + is_setup = true; + for (int i = 0; i < modifications.size(); i++) { + if (!modifications[i].is_valid()) { + continue; + } + modifications.get(i)->_setup_modification(this); + } + +#ifdef TOOLS_ENABLED + set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED + + } else { + WARN_PRINT("Cannot setup SkeletonModificationStack2D: no Skeleton2D set!"); + } +} + +void SkeletonModificationStack2D::execute(float p_delta, int p_execution_mode) { + ERR_FAIL_COND_MSG(!is_setup || skeleton == nullptr || is_queued_for_deletion(), + "Modification stack is not properly setup and therefore cannot execute!"); + + if (!skeleton->is_inside_tree()) { + ERR_PRINT_ONCE("Skeleton is not inside SceneTree! Cannot execute modification!"); + return; + } + + if (!enabled) { + return; + } + + for (int i = 0; i < modifications.size(); i++) { + if (!modifications[i].is_valid()) { + continue; + } + + if (modifications[i]->get_execution_mode() == p_execution_mode) { + modifications.get(i)->_execute(p_delta); + } + } +} + +void SkeletonModificationStack2D::draw_editor_gizmos() { + if (!is_setup) { + return; + } + + if (editor_gizmo_dirty) { + for (int i = 0; i < modifications.size(); i++) { + if (!modifications[i].is_valid()) { + continue; + } + + if (modifications[i]->editor_draw_gizmo) { + modifications.get(i)->_draw_editor_gizmo(); + } + } + skeleton->draw_set_transform(Vector2(0, 0)); + editor_gizmo_dirty = false; + } +} + +void SkeletonModificationStack2D::set_editor_gizmos_dirty(bool p_dirty) { + if (!is_setup) { + return; + } + + if (!editor_gizmo_dirty && p_dirty) { + editor_gizmo_dirty = p_dirty; + if (skeleton) { + skeleton->update(); + } + } else { + editor_gizmo_dirty = p_dirty; + } +} + +void SkeletonModificationStack2D::enable_all_modifications(bool p_enabled) { + for (int i = 0; i < modifications.size(); i++) { + if (!modifications[i].is_valid()) { + continue; + } + modifications.get(i)->set_enabled(p_enabled); + } +} + +Ref<SkeletonModification2D> SkeletonModificationStack2D::get_modification(int p_mod_idx) const { + ERR_FAIL_INDEX_V(p_mod_idx, modifications.size(), nullptr); + return modifications[p_mod_idx]; +} + +void SkeletonModificationStack2D::add_modification(Ref<SkeletonModification2D> p_mod) { + ERR_FAIL_COND(!p_mod.is_valid()); + + p_mod->_setup_modification(this); + modifications.push_back(p_mod); + +#ifdef TOOLS_ENABLED + set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED +} + +void SkeletonModificationStack2D::delete_modification(int p_mod_idx) { + ERR_FAIL_INDEX(p_mod_idx, modifications.size()); + modifications.remove(p_mod_idx); + +#ifdef TOOLS_ENABLED + set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED +} + +void SkeletonModificationStack2D::set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod) { + ERR_FAIL_INDEX(p_mod_idx, modifications.size()); + + if (p_mod == nullptr) { + modifications.insert(p_mod_idx, nullptr); + } else { + p_mod->_setup_modification(this); + modifications.insert(p_mod_idx, p_mod); + } + +#ifdef TOOLS_ENABLED + set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED +} + +void SkeletonModificationStack2D::set_modification_count(int p_count) { + modifications.resize(p_count); + notify_property_list_changed(); + +#ifdef TOOLS_ENABLED + set_editor_gizmos_dirty(true); +#endif // TOOLS_ENABLED +} + +int SkeletonModificationStack2D::get_modification_count() const { + return modifications.size(); +} + +void SkeletonModificationStack2D::set_skeleton(Skeleton2D *p_skeleton) { + skeleton = p_skeleton; +} + +Skeleton2D *SkeletonModificationStack2D::get_skeleton() const { + return skeleton; +} + +bool SkeletonModificationStack2D::get_is_setup() const { + return is_setup; +} + +void SkeletonModificationStack2D::set_enabled(bool p_enabled) { + enabled = p_enabled; +} + +bool SkeletonModificationStack2D::get_enabled() const { + return enabled; +} + +void SkeletonModificationStack2D::set_strength(float p_strength) { + ERR_FAIL_COND_MSG(p_strength < 0, "Strength cannot be less than zero!"); + ERR_FAIL_COND_MSG(p_strength > 1, "Strength cannot be more than one!"); + strength = p_strength; +} + +float SkeletonModificationStack2D::get_strength() const { + return strength; +} + +void SkeletonModificationStack2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("setup"), &SkeletonModificationStack2D::setup); + ClassDB::bind_method(D_METHOD("execute", "delta", "execution_mode"), &SkeletonModificationStack2D::execute); + + ClassDB::bind_method(D_METHOD("enable_all_modifications", "enabled"), &SkeletonModificationStack2D::enable_all_modifications); + ClassDB::bind_method(D_METHOD("get_modification", "mod_idx"), &SkeletonModificationStack2D::get_modification); + ClassDB::bind_method(D_METHOD("add_modification", "modification"), &SkeletonModificationStack2D::add_modification); + ClassDB::bind_method(D_METHOD("delete_modification", "mod_idx"), &SkeletonModificationStack2D::delete_modification); + ClassDB::bind_method(D_METHOD("set_modification", "mod_idx", "modification"), &SkeletonModificationStack2D::set_modification); + + ClassDB::bind_method(D_METHOD("set_modification_count"), &SkeletonModificationStack2D::set_modification_count); + ClassDB::bind_method(D_METHOD("get_modification_count"), &SkeletonModificationStack2D::get_modification_count); + + ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModificationStack2D::get_is_setup); + + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModificationStack2D::set_enabled); + ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModificationStack2D::get_enabled); + + ClassDB::bind_method(D_METHOD("set_strength", "strength"), &SkeletonModificationStack2D::set_strength); + ClassDB::bind_method(D_METHOD("get_strength"), &SkeletonModificationStack2D::get_strength); + + ClassDB::bind_method(D_METHOD("get_skeleton"), &SkeletonModificationStack2D::get_skeleton); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1"), "set_modification_count", "get_modification_count"); +} + +SkeletonModificationStack2D::SkeletonModificationStack2D() { +} diff --git a/scene/resources/skeleton_modification_stack_2d.h b/scene/resources/skeleton_modification_stack_2d.h new file mode 100644 index 0000000000..58855701a1 --- /dev/null +++ b/scene/resources/skeleton_modification_stack_2d.h @@ -0,0 +1,99 @@ +/*************************************************************************/ +/* skeleton_modification_stack_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef SKELETONMODIFICATIONSTACK2D_H +#define SKELETONMODIFICATIONSTACK2D_H + +#include "scene/2d/skeleton_2d.h" +#include "scene/resources/skeleton_modification_2d.h" + +/////////////////////////////////////// +// SkeletonModificationStack2D +/////////////////////////////////////// + +class Skeleton2D; +class SkeletonModification2D; +class Bone2D; + +class SkeletonModificationStack2D : public Resource { + GDCLASS(SkeletonModificationStack2D, Resource); + friend class Skeleton2D; + friend class SkeletonModification2D; + +protected: + static void _bind_methods(); + void _get_property_list(List<PropertyInfo> *p_list) const; + bool _set(const StringName &p_path, const Variant &p_value); + bool _get(const StringName &p_path, Variant &r_ret) const; + +public: + Skeleton2D *skeleton = nullptr; + bool is_setup = false; + bool enabled = false; + float strength = 1.0; + + enum EXECUTION_MODE { + execution_mode_process, + execution_mode_physics_process + }; + + Vector<Ref<SkeletonModification2D>> modifications = Vector<Ref<SkeletonModification2D>>(); + + void setup(); + void execute(float p_delta, int p_execution_mode); + + bool editor_gizmo_dirty = false; + void draw_editor_gizmos(); + void set_editor_gizmos_dirty(bool p_dirty); + + void enable_all_modifications(bool p_enable); + Ref<SkeletonModification2D> get_modification(int p_mod_idx) const; + void add_modification(Ref<SkeletonModification2D> p_mod); + void delete_modification(int p_mod_idx); + void set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod); + + void set_modification_count(int p_count); + int get_modification_count() const; + + void set_skeleton(Skeleton2D *p_skeleton); + Skeleton2D *get_skeleton() const; + + bool get_is_setup() const; + + void set_enabled(bool p_enabled); + bool get_enabled() const; + + void set_strength(float p_strength); + float get_strength() const; + + SkeletonModificationStack2D(); +}; + +#endif // SKELETONMODIFICATION2D_H diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp index fee8fdbde2..710612ae05 100644 --- a/scene/resources/skin.cpp +++ b/scene/resources/skin.cpp @@ -38,14 +38,14 @@ void Skin::set_bind_count(int p_size) { emit_changed(); } -void Skin::add_bind(int p_bone, const Transform &p_pose) { +void Skin::add_bind(int p_bone, const Transform3D &p_pose) { uint32_t index = bind_count; set_bind_count(bind_count + 1); set_bind_bone(index, p_bone); set_bind_pose(index, p_pose); } -void Skin::add_named_bind(const String &p_name, const Transform &p_pose) { +void Skin::add_named_bind(const String &p_name, const Transform3D &p_pose) { uint32_t index = bind_count; set_bind_count(bind_count + 1); set_bind_name(index, p_name); @@ -68,7 +68,7 @@ void Skin::set_bind_bone(int p_index, int p_bone) { emit_changed(); } -void Skin::set_bind_pose(int p_index, const Transform &p_pose) { +void Skin::set_bind_pose(int p_index, const Transform3D &p_pose) { ERR_FAIL_INDEX(p_index, bind_count); binds_ptr[p_index].pose = p_pose; emit_changed(); @@ -134,7 +134,7 @@ void Skin::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < get_bind_count(); i++) { p_list->push_back(PropertyInfo(Variant::STRING_NAME, "bind/" + itos(i) + "/name")); p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater", get_bind_name(i) != StringName() ? PROPERTY_USAGE_NOEDITOR : PROPERTY_USAGE_DEFAULT)); - p_list->push_back(PropertyInfo(Variant::TRANSFORM, "bind/" + itos(i) + "/pose")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, "bind/" + itos(i) + "/pose")); } } diff --git a/scene/resources/skin.h b/scene/resources/skin.h index f5d64f96aa..6857bf743a 100644 --- a/scene/resources/skin.h +++ b/scene/resources/skin.h @@ -39,7 +39,7 @@ class Skin : public Resource { struct Bind { int bone = -1; StringName name; - Transform pose; + Transform3D pose; }; Vector<Bind> binds; @@ -59,11 +59,11 @@ public: void set_bind_count(int p_size); inline int get_bind_count() const { return bind_count; } - void add_bind(int p_bone, const Transform &p_pose); - void add_named_bind(const String &p_name, const Transform &p_pose); + void add_bind(int p_bone, const Transform3D &p_pose); + void add_named_bind(const String &p_name, const Transform3D &p_pose); void set_bind_bone(int p_index, int p_bone); - void set_bind_pose(int p_index, const Transform &p_pose); + void set_bind_pose(int p_index, const Transform3D &p_pose); void set_bind_name(int p_index, const StringName &p_name); inline int get_bind_bone(int p_index) const { @@ -80,9 +80,9 @@ public: return binds_ptr[p_index].name; } - inline Transform get_bind_pose(int p_index) const { + inline Transform3D get_bind_pose(int p_index) const { #ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(p_index, bind_count, Transform()); + ERR_FAIL_INDEX_V(p_index, bind_count, Transform3D()); #endif return binds_ptr[p_index].pose; } diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 9d79c22159..89b3336118 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -270,7 +270,8 @@ ProceduralSkyMaterial::~ProceduralSkyMaterial() { void PanoramaSkyMaterial::set_panorama(const Ref<Texture2D> &p_panorama) { panorama = p_panorama; - RS::get_singleton()->material_set_param(_get_material(), "source_panorama", panorama); + RID tex_rid = p_panorama.is_valid() ? p_panorama->get_rid() : RID(); + RS::get_singleton()->material_set_param(_get_material(), "source_panorama", tex_rid); } Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const { @@ -411,7 +412,8 @@ float PhysicalSkyMaterial::get_dither_strength() const { void PhysicalSkyMaterial::set_night_sky(const Ref<Texture2D> &p_night_sky) { night_sky = p_night_sky; - RS::get_singleton()->material_set_param(_get_material(), "night_sky", night_sky); + RID tex_rid = p_night_sky.is_valid() ? p_night_sky->get_rid() : RID(); + RS::get_singleton()->material_set_param(_get_material(), "night_sky", tex_rid); } Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const { diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp index 90c702081b..df80084c5c 100644 --- a/scene/resources/sprite_frames.cpp +++ b/scene/resources/sprite_frames.cpp @@ -228,7 +228,7 @@ void SpriteFrames::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames); ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "_set_frames", "_get_frames"); //compatibility ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations); ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 2159f1bc97..87371224e0 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -121,7 +121,6 @@ void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) { } else { region_rect = Rect2(Point2(), texture->get_size()); } - emit_signal("texture_changed"); emit_changed(); } @@ -285,8 +284,6 @@ void StyleBoxTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_v_axis_stretch_mode", "mode"), &StyleBoxTexture::set_v_axis_stretch_mode); ClassDB::bind_method(D_METHOD("get_v_axis_stretch_mode"), &StyleBoxTexture::get_v_axis_stretch_mode); - ADD_SIGNAL(MethodInfo("texture_changed")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); ADD_GROUP("Margin", "margin_"); diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index f2143e683d..9f8c35b668 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -370,13 +370,13 @@ Array SurfaceTool::commit_to_arrays() { for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { const Vertex &v = vertex_array[idx]; - w[idx + 0] = v.tangent.x; - w[idx + 1] = v.tangent.y; - w[idx + 2] = v.tangent.z; + w[idx * 4 + 0] = v.tangent.x; + w[idx * 4 + 1] = v.tangent.y; + w[idx * 4 + 2] = v.tangent.z; //float d = v.tangent.dot(v.binormal,v.normal); float d = v.binormal.dot(v.normal.cross(v.tangent)); - w[idx + 3] = d < 0 ? -1 : 1; + w[idx * 4 + 3] = d < 0 ? -1 : 1; } a[i] = array; @@ -537,12 +537,16 @@ Array SurfaceTool::commit_to_arrays() { int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4; Vector<int> array; array.resize(varr_len * count); + array.fill(0); int *w = array.ptrw(); for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { const Vertex &v = vertex_array[idx]; - ERR_CONTINUE(v.bones.size() != count); + if (v.bones.size() > count) { + ERR_PRINT_ONCE(vformat("Invalid bones size %d vs count %d", v.bones.size(), count)); + continue; + } for (int j = 0; j < count; j++) { w[idx * count + j] = v.bones[j]; @@ -557,12 +561,16 @@ Array SurfaceTool::commit_to_arrays() { int count = skin_weights == SKIN_8_WEIGHTS ? 8 : 4; array.resize(varr_len * count); + array.fill(0.0f); float *w = array.ptrw(); for (uint32_t idx = 0; idx < vertex_array.size(); idx++) { const Vertex &v = vertex_array[idx]; - ERR_CONTINUE(v.weights.size() != count); + if (v.weights.size() > count) { + ERR_PRINT_ONCE(vformat("Invalid weight size %d vs count %d", v.weights.size(), count)); + continue; + } for (int j = 0; j < count; j++) { w[idx * count + j] = v.weights[j]; @@ -599,7 +607,7 @@ Ref<ArrayMesh> SurfaceTool::commit(const Ref<ArrayMesh> &p_existing, uint32_t p_ if (p_existing.is_valid()) { mesh = p_existing; } else { - mesh.instance(); + mesh.instantiate(); } int varr_len = vertex_array.size(); @@ -857,7 +865,7 @@ void SurfaceTool::create_from_blend_shape(const Ref<Mesh> &p_existing, int p_sur _create_list_from_arrays(arr[shape_idx], &vertex_array, &index_array, format); } -void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform) { +void SurfaceTool::append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform3D &p_xform) { ERR_FAIL_NULL_MSG(p_existing, "First argument in SurfaceTool::append_from() must be a valid object of type Mesh"); if (vertex_array.size() == 0) { diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index f5f3a95b14..bde6702759 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -35,8 +35,8 @@ #include "scene/resources/mesh.h" #include "thirdparty/misc/mikktspace.h" -class SurfaceTool : public Reference { - GDCLASS(SurfaceTool, Reference); +class SurfaceTool : public RefCounted { + GDCLASS(SurfaceTool, RefCounted); public: struct Vertex { @@ -186,7 +186,7 @@ public: Array commit_to_arrays(); void create_from(const Ref<Mesh> &p_existing, int p_surface); void create_from_blend_shape(const Ref<Mesh> &p_existing, int p_surface, const String &p_blend_shape_name); - void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform &p_xform); + void append_from(const Ref<Mesh> &p_existing, int p_surface, const Transform3D &p_xform); Ref<ArrayMesh> commit(const Ref<ArrayMesh> &p_existing = Ref<ArrayMesh>(), uint32_t p_flags = 0); SurfaceTool(); diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp index 564c65adb9..33bb0a83e9 100644 --- a/scene/resources/text_file.cpp +++ b/scene/resources/text_file.cpp @@ -30,7 +30,7 @@ #include "text_file.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" bool TextFile::has_text() const { return text != ""; diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h index 74d4f2c32c..1b5c1a3123 100644 --- a/scene/resources/text_line.h +++ b/scene/resources/text_line.h @@ -36,8 +36,8 @@ /*************************************************************************/ -class TextLine : public Reference { - GDCLASS(TextLine, Reference); +class TextLine : public RefCounted { + GDCLASS(TextLine, RefCounted); RID rid; int spacing_top = 0; diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index 4396b07130..a34e745090 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -36,8 +36,8 @@ /*************************************************************************/ -class TextParagraph : public Reference { - GDCLASS(TextParagraph, Reference); +class TextParagraph : public RefCounted { + GDCLASS(TextParagraph, RefCounted); RID dropcap_rid; int dropcap_lines = 0; diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 4475179431..98997e482a 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -88,7 +88,7 @@ void ImageTexture::reload_from_file() { } Ref<Image> img; - img.instance(); + img.instantiate(); if (ImageLoader::load_image(path, img) == OK) { create_from_image(img); @@ -138,7 +138,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) { } Ref<Image> img; - img.instance(); + img.instantiate(); Error err = ImageLoader::load_image(path, img); ERR_FAIL_COND_MSG(err != OK, "Cannot load image from path '" + path + "'."); @@ -173,7 +173,7 @@ Image::Format ImageTexture::get_format() const { return format; } -void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { +void ImageTexture::update(const Ref<Image> &p_image) { ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image"); ERR_FAIL_COND_MSG(texture.is_null(), "Texture is not initialized."); ERR_FAIL_COND_MSG(p_image->get_width() != w || p_image->get_height() != h, @@ -183,11 +183,7 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { ERR_FAIL_COND_MSG(mipmaps != p_image->has_mipmaps(), "The new image mipmaps configuration must match the texture's image mipmaps configuration"); - if (p_immediate) { - RenderingServer::get_singleton()->texture_2d_update_immediate(texture, p_image); - } else { - RenderingServer::get_singleton()->texture_2d_update(texture, p_image); - } + RenderingServer::get_singleton()->texture_2d_update(texture, p_image); notify_property_list_changed(); emit_changed(); @@ -258,7 +254,7 @@ bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { decom->decompress(); img = decom; } - alpha_cache.instance(); + alpha_cache.instantiate(); alpha_cache->create_from_image_alpha(img); } } @@ -305,7 +301,7 @@ void ImageTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("create_from_image", "image"), &ImageTexture::create_from_image); ClassDB::bind_method(D_METHOD("get_format"), &ImageTexture::get_format); - ClassDB::bind_method(D_METHOD("update", "image", "immediate"), &ImageTexture::update, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("update", "image"), &ImageTexture::update); ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override); ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook); } @@ -327,7 +323,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit uint32_t mipmaps = f->get_32(); Image::Format format = Image::Format(f->get_32()); - if (data_format == DATA_FORMAT_LOSSLESS || data_format == DATA_FORMAT_LOSSY || data_format == DATA_FORMAT_BASIS_UNIVERSAL) { + if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) { //look for a PNG or WEBP file inside int sw = w; @@ -360,10 +356,10 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit Ref<Image> img; if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) { img = Image::basis_universal_unpacker(pv); - } else if (data_format == DATA_FORMAT_LOSSLESS) { - img = Image::lossless_unpacker(pv); + } else if (data_format == DATA_FORMAT_PNG) { + img = Image::png_unpacker(pv); } else { - img = Image::lossy_unpacker(pv); + img = Image::webp_unpacker(pv); } if (img.is_null() || img->is_empty()) { @@ -390,7 +386,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit //print_line("mipmap read total: " + itos(mipmap_images.size())); Ref<Image> image; - image.instance(); + image.instantiate(); if (mipmap_images.size() == 1) { //only one image (which will most likely be the case anyway for this format) @@ -442,7 +438,7 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit } Ref<Image> image; - image.instance(); + image.instantiate(); image->create(tw, th, mipmaps - i ? true : false, format, data); @@ -553,7 +549,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &r_width, int &r_hei Error StreamTexture2D::load(const String &p_path) { int lw, lh; Ref<Image> image; - image.instance(); + image.instantiate(); bool request_3d; bool request_normal; @@ -679,7 +675,7 @@ bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const { img = decom; } - alpha_cache.instance(); + alpha_cache.instantiate(); alpha_cache->create_from_image_alpha(img); } } @@ -738,7 +734,7 @@ StreamTexture2D::~StreamTexture2D() { RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTexture2D> st; - st.instance(); + st.instantiate(); Error err = st->load(p_path); if (r_error) { *r_error = err; @@ -1036,7 +1032,7 @@ StreamTexture3D::~StreamTexture3D() { RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTexture3D> st; - st.instance(); + st.instantiate(); Error err = st->load(p_path); if (r_error) { *r_error = err; @@ -1411,14 +1407,26 @@ void CurveTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("set_curve", "curve"), &CurveTexture::set_curve); ClassDB::bind_method(D_METHOD("get_curve"), &CurveTexture::get_curve); + ClassDB::bind_method(D_METHOD("set_texture_mode", "texture_mode"), &CurveTexture::set_texture_mode); + ClassDB::bind_method(D_METHOD("get_texture_mode"), &CurveTexture::get_texture_mode); + ClassDB::bind_method(D_METHOD("_update"), &CurveTexture::_update); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "32,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_mode", PROPERTY_HINT_ENUM, "RGB,Red"), "set_texture_mode", "get_texture_mode"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve"); + + BIND_ENUM_CONSTANT(TEXTURE_MODE_RGB); + BIND_ENUM_CONSTANT(TEXTURE_MODE_RED); } void CurveTexture::set_width(int p_width) { ERR_FAIL_COND(p_width < 32 || p_width > 4096); + + if (_width == p_width) { + return; + } + _width = p_width; _update(); } @@ -1454,7 +1462,7 @@ void CurveTexture::set_curve(Ref<Curve> p_curve) { void CurveTexture::_update() { Vector<uint8_t> data; - data.resize(_width * sizeof(float)); + data.resize(_width * sizeof(float) * (texture_mode == TEXTURE_MODE_RGB ? 3 : 1)); // The array is locked in that scope { @@ -1465,24 +1473,42 @@ void CurveTexture::_update() { Curve &curve = **_curve; for (int i = 0; i < _width; ++i) { float t = i / static_cast<float>(_width); - wd[i] = curve.interpolate_baked(t); + if (texture_mode == TEXTURE_MODE_RGB) { + wd[i * 3 + 0] = curve.interpolate_baked(t); + wd[i * 3 + 1] = wd[i * 3 + 0]; + wd[i * 3 + 2] = wd[i * 3 + 0]; + } else { + wd[i] = curve.interpolate_baked(t); + } } } else { for (int i = 0; i < _width; ++i) { - wd[i] = 0; + if (texture_mode == TEXTURE_MODE_RGB) { + wd[i * 3 + 0] = 0; + wd[i * 3 + 1] = 0; + wd[i * 3 + 2] = 0; + } else { + wd[i] = 0; + } } } } - Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RF, data)); + Ref<Image> image = memnew(Image(_width, 1, false, texture_mode == TEXTURE_MODE_RGB ? Image::FORMAT_RGBF : Image::FORMAT_RF, data)); if (_texture.is_valid()) { - RID new_texture = RS::get_singleton()->texture_2d_create(image); - RS::get_singleton()->texture_replace(_texture, new_texture); + if (_current_texture_mode != texture_mode || _current_width != _width) { + RID new_texture = RS::get_singleton()->texture_2d_create(image); + RS::get_singleton()->texture_replace(_texture, new_texture); + } else { + RS::get_singleton()->texture_2d_update(_texture, image); + } } else { _texture = RS::get_singleton()->texture_2d_create(image); } + _current_texture_mode = texture_mode; + _current_width = _width; emit_changed(); } @@ -1491,6 +1517,17 @@ Ref<Curve> CurveTexture::get_curve() const { return _curve; } +void CurveTexture::set_texture_mode(TextureMode p_mode) { + if (texture_mode == p_mode) { + return; + } + texture_mode = p_mode; + _update(); +} +CurveTexture::TextureMode CurveTexture::get_texture_mode() const { + return texture_mode; +} + RID CurveTexture::get_rid() const { if (!_texture.is_valid()) { _texture = RS::get_singleton()->texture_2d_placeholder_create(); @@ -1508,6 +1545,204 @@ CurveTexture::~CurveTexture() { ////////////////// +void Curve3Texture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_width", "width"), &Curve3Texture::set_width); + + ClassDB::bind_method(D_METHOD("set_curve_x", "curve"), &Curve3Texture::set_curve_x); + ClassDB::bind_method(D_METHOD("get_curve_x"), &Curve3Texture::get_curve_x); + + ClassDB::bind_method(D_METHOD("set_curve_y", "curve"), &Curve3Texture::set_curve_y); + ClassDB::bind_method(D_METHOD("get_curve_y"), &Curve3Texture::get_curve_y); + + ClassDB::bind_method(D_METHOD("set_curve_z", "curve"), &Curve3Texture::set_curve_z); + ClassDB::bind_method(D_METHOD("get_curve_z"), &Curve3Texture::get_curve_z); + + ClassDB::bind_method(D_METHOD("_update"), &Curve3Texture::_update); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_x", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_x", "get_curve_x"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_y", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_y", "get_curve_y"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve_z", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve_z", "get_curve_z"); +} + +void Curve3Texture::set_width(int p_width) { + ERR_FAIL_COND(p_width < 32 || p_width > 4096); + + if (_width == p_width) { + return; + } + + _width = p_width; + _update(); +} + +int Curve3Texture::get_width() const { + return _width; +} + +void Curve3Texture::ensure_default_setup(float p_min, float p_max) { + if (_curve_x.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + curve->set_min_value(p_min); + curve->set_max_value(p_max); + set_curve_x(curve); + } + + if (_curve_y.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + curve->set_min_value(p_min); + curve->set_max_value(p_max); + set_curve_y(curve); + } + + if (_curve_z.is_null()) { + Ref<Curve> curve = Ref<Curve>(memnew(Curve)); + curve->add_point(Vector2(0, 1)); + curve->add_point(Vector2(1, 1)); + curve->set_min_value(p_min); + curve->set_max_value(p_max); + set_curve_z(curve); + } +} + +void Curve3Texture::set_curve_x(Ref<Curve> p_curve) { + if (_curve_x != p_curve) { + if (_curve_x.is_valid()) { + _curve_x->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update)); + } + _curve_x = p_curve; + if (_curve_x.is_valid()) { + _curve_x->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update), varray(), CONNECT_REFERENCE_COUNTED); + } + _update(); + } +} + +void Curve3Texture::set_curve_y(Ref<Curve> p_curve) { + if (_curve_y != p_curve) { + if (_curve_y.is_valid()) { + _curve_y->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update)); + } + _curve_y = p_curve; + if (_curve_y.is_valid()) { + _curve_y->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update), varray(), CONNECT_REFERENCE_COUNTED); + } + _update(); + } +} + +void Curve3Texture::set_curve_z(Ref<Curve> p_curve) { + if (_curve_z != p_curve) { + if (_curve_z.is_valid()) { + _curve_z->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update)); + } + _curve_z = p_curve; + if (_curve_z.is_valid()) { + _curve_z->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &Curve3Texture::_update), varray(), CONNECT_REFERENCE_COUNTED); + } + _update(); + } +} + +void Curve3Texture::_update() { + Vector<uint8_t> data; + data.resize(_width * sizeof(float) * 3); + + // The array is locked in that scope + { + uint8_t *wd8 = data.ptrw(); + float *wd = (float *)wd8; + + if (_curve_x.is_valid()) { + Curve &curve_x = **_curve_x; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + wd[i * 3 + 0] = curve_x.interpolate_baked(t); + } + + } else { + for (int i = 0; i < _width; ++i) { + wd[i * 3 + 0] = 0; + } + } + + if (_curve_y.is_valid()) { + Curve &curve_y = **_curve_y; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + wd[i * 3 + 1] = curve_y.interpolate_baked(t); + } + + } else { + for (int i = 0; i < _width; ++i) { + wd[i * 3 + 1] = 0; + } + } + + if (_curve_z.is_valid()) { + Curve &curve_z = **_curve_z; + for (int i = 0; i < _width; ++i) { + float t = i / static_cast<float>(_width); + wd[i * 3 + 2] = curve_z.interpolate_baked(t); + } + + } else { + for (int i = 0; i < _width; ++i) { + wd[i * 3 + 2] = 0; + } + } + } + + Ref<Image> image = memnew(Image(_width, 1, false, Image::FORMAT_RGBF, data)); + + if (_texture.is_valid()) { + if (_current_width != _width) { + RID new_texture = RS::get_singleton()->texture_2d_create(image); + RS::get_singleton()->texture_replace(_texture, new_texture); + } else { + RS::get_singleton()->texture_2d_update(_texture, image); + } + } else { + _texture = RS::get_singleton()->texture_2d_create(image); + } + _current_width = _width; + + emit_changed(); +} + +Ref<Curve> Curve3Texture::get_curve_x() const { + return _curve_x; +} + +Ref<Curve> Curve3Texture::get_curve_y() const { + return _curve_y; +} + +Ref<Curve> Curve3Texture::get_curve_z() const { + return _curve_z; +} + +RID Curve3Texture::get_rid() const { + if (!_texture.is_valid()) { + _texture = RS::get_singleton()->texture_2d_placeholder_create(); + } + return _texture; +} + +Curve3Texture::Curve3Texture() {} + +Curve3Texture::~Curve3Texture() { + if (_texture.is_valid()) { + RS::get_singleton()->free(_texture); + } +} + +////////////////// + GradientTexture::GradientTexture() { _queue_update(); } @@ -1527,7 +1762,7 @@ void GradientTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("_update"), &GradientTexture::_update); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gradient", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_gradient", "get_gradient"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,4096"), "set_width", "get_width"); } void GradientTexture::set_gradient(Ref<Gradient> p_gradient) { @@ -1595,6 +1830,7 @@ void GradientTexture::_update() { } void GradientTexture::set_width(int p_width) { + ERR_FAIL_COND(p_width <= 0); width = p_width; _queue_update(); } @@ -1876,7 +2112,7 @@ void AnimatedTexture::_validate_property(PropertyInfo &property) const { if (prop.begins_with("frame_")) { int frame = prop.get_slicec('/', 0).get_slicec('_', 1).to_int(); if (frame >= frame_count) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } @@ -1904,7 +2140,7 @@ void AnimatedTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay); ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", 0), "set_current_frame", "get_current_frame"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "oneshot"), "set_oneshot", "get_oneshot"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps"); @@ -2257,15 +2493,15 @@ RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const S Ref<StreamTextureLayered> st; if (p_path.get_extension().to_lower() == "stexarray") { Ref<StreamTexture2DArray> s; - s.instance(); + s.instantiate(); st = s; } else if (p_path.get_extension().to_lower() == "scube") { Ref<StreamCubemap> s; - s.instance(); + s.instantiate(); st = s; } else if (p_path.get_extension().to_lower() == "scubearray") { Ref<StreamCubemapArray> s; - s.instance(); + s.instantiate(); st = s; } else { if (r_error) { diff --git a/scene/resources/texture.h b/scene/resources/texture.h index df8c00f8ff..73390039cb 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -31,10 +31,10 @@ #ifndef TEXTURE_H #define TEXTURE_H +#include "core/io/file_access.h" #include "core/io/resource.h" #include "core/io/resource_loader.h" #include "core/math/rect2.h" -#include "core/os/file_access.h" #include "core/os/mutex.h" #include "core/os/rw_lock.h" #include "core/os/thread_safe.h" @@ -107,7 +107,7 @@ public: Image::Format get_format() const; - void update(const Ref<Image> &p_image, bool p_immediate = false); + void update(const Ref<Image> &p_image); Ref<Image> get_image() const override; int get_width() const override; @@ -136,8 +136,8 @@ class StreamTexture2D : public Texture2D { public: enum DataFormat { DATA_FORMAT_IMAGE, - DATA_FORMAT_LOSSLESS, - DATA_FORMAT_LOSSY, + DATA_FORMAT_PNG, + DATA_FORMAT_WEBP, DATA_FORMAT_BASIS_UNIVERSAL, }; @@ -146,9 +146,6 @@ public: }; enum FormatBits { - FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1, - FORMAT_BIT_LOSSLESS = 1 << 20, - FORMAT_BIT_LOSSY = 1 << 21, FORMAT_BIT_STREAM = 1 << 22, FORMAT_BIT_HAS_MIPMAPS = 1 << 23, FORMAT_BIT_DETECT_3D = 1 << 24, @@ -389,8 +386,8 @@ class StreamTextureLayered : public TextureLayered { public: enum DataFormat { DATA_FORMAT_IMAGE, - DATA_FORMAT_LOSSLESS, - DATA_FORMAT_LOSSY, + DATA_FORMAT_PNG, + DATA_FORMAT_WEBP, DATA_FORMAT_BASIS_UNIVERSAL, }; @@ -399,9 +396,6 @@ public: }; enum FormatBits { - FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1, - FORMAT_BIT_LOSSLESS = 1 << 20, - FORMAT_BIT_LOSSY = 1 << 21, FORMAT_BIT_STREAM = 1 << 22, FORMAT_BIT_HAS_MIPMAPS = 1 << 23, }; @@ -532,8 +526,8 @@ class StreamTexture3D : public Texture3D { public: enum DataFormat { DATA_FORMAT_IMAGE, - DATA_FORMAT_LOSSLESS, - DATA_FORMAT_LOSSY, + DATA_FORMAT_PNG, + DATA_FORMAT_WEBP, DATA_FORMAT_BASIS_UNIVERSAL, }; @@ -542,9 +536,6 @@ public: }; enum FormatBits { - FORMAT_MASK_IMAGE_FORMAT = (1 << 20) - 1, - FORMAT_BIT_LOSSLESS = 1 << 20, - FORMAT_BIT_LOSSY = 1 << 21, FORMAT_BIT_STREAM = 1 << 22, FORMAT_BIT_HAS_MIPMAPS = 1 << 23, }; @@ -595,11 +586,19 @@ public: class CurveTexture : public Texture2D { GDCLASS(CurveTexture, Texture2D); RES_BASE_EXTENSION("curvetex") +public: + enum TextureMode { + TEXTURE_MODE_RGB, + TEXTURE_MODE_RED, + }; private: mutable RID _texture; Ref<Curve> _curve; int _width = 2048; + int _current_width = 0; + TextureMode texture_mode = TEXTURE_MODE_RGB; + TextureMode _current_texture_mode = TEXTURE_MODE_RGB; void _update(); @@ -610,6 +609,9 @@ public: void set_width(int p_width); int get_width() const override; + void set_texture_mode(TextureMode p_mode); + TextureMode get_texture_mode() const; + void ensure_default_setup(float p_min = 0, float p_max = 1); void set_curve(Ref<Curve> p_curve); @@ -623,18 +625,49 @@ public: CurveTexture(); ~CurveTexture(); }; -/* - enum CubeMapSide { - CUBEMAP_LEFT, - CUBEMAP_RIGHT, - CUBEMAP_BOTTOM, - CUBEMAP_TOP, - CUBEMAP_FRONT, - CUBEMAP_BACK, - }; -*/ -//VARIANT_ENUM_CAST( Texture::CubeMapSide ); +VARIANT_ENUM_CAST(CurveTexture::TextureMode) + +class Curve3Texture : public Texture2D { + GDCLASS(Curve3Texture, Texture2D); + RES_BASE_EXTENSION("curvetex") + +private: + mutable RID _texture; + Ref<Curve> _curve_x; + Ref<Curve> _curve_y; + Ref<Curve> _curve_z; + int _width = 2048; + int _current_width = 0; + + void _update(); + +protected: + static void _bind_methods(); + +public: + void set_width(int p_width); + int get_width() const override; + + void ensure_default_setup(float p_min = 0, float p_max = 1); + + void set_curve_x(Ref<Curve> p_curve); + Ref<Curve> get_curve_x() const; + + void set_curve_y(Ref<Curve> p_curve); + Ref<Curve> get_curve_y() const; + + void set_curve_z(Ref<Curve> p_curve); + Ref<Curve> get_curve_z() const; + + virtual RID get_rid() const override; + + virtual int get_height() const override { return 1; } + virtual bool has_alpha() const override { return false; } + + Curve3Texture(); + ~Curve3Texture(); +}; class GradientTexture : public Texture2D { GDCLASS(GradientTexture, Texture2D); diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 786a96501a..89ac033207 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -29,10 +29,15 @@ /*************************************************************************/ #include "theme.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/string/print_string.h" void Theme::_emit_theme_changed() { + if (no_change_propagation) { + return; + } + + notify_property_list_changed(); emit_changed(); } @@ -415,8 +420,7 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) { default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } Ref<Font> Theme::get_default_theme_font() const { @@ -430,8 +434,7 @@ void Theme::set_default_theme_font_size(int p_font_size) { default_theme_font_size = p_font_size; - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } int Theme::get_default_theme_font_size() const { @@ -478,8 +481,6 @@ void Theme::set_default_font_size(int p_font_size) { } void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon) { - bool new_value = !icon_map.has(p_theme_type) || !icon_map[p_theme_type].has(p_name); - if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) { icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } @@ -490,10 +491,7 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, c icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - if (new_value) { - notify_property_list_changed(); - emit_changed(); - } + _emit_theme_changed(); } Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const { @@ -520,8 +518,7 @@ void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name, icon_map[p_theme_type][p_name] = icon_map[p_theme_type][p_old_name]; icon_map[p_theme_type].erase(p_old_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) { @@ -534,8 +531,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) icon_map[p_theme_type].erase(p_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -553,6 +549,9 @@ void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) con } void Theme::add_icon_type(const StringName &p_theme_type) { + if (icon_map.has(p_theme_type)) { + return; + } icon_map[p_theme_type] = HashMap<StringName, Ref<Texture2D>>(); } @@ -566,8 +565,6 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const { } void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) { - bool new_value = !style_map.has(p_theme_type) || !style_map[p_theme_type].has(p_name); - if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) { style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } @@ -578,10 +575,7 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_typ style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - if (new_value) { - notify_property_list_changed(); - } - emit_changed(); + _emit_theme_changed(); } Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const { @@ -608,8 +602,7 @@ void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_na style_map[p_theme_type][p_name] = style_map[p_theme_type][p_old_name]; style_map[p_theme_type].erase(p_old_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) { @@ -622,8 +615,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t style_map[p_theme_type].erase(p_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -641,6 +633,9 @@ void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) } void Theme::add_stylebox_type(const StringName &p_theme_type) { + if (style_map.has(p_theme_type)) { + return; + } style_map[p_theme_type] = HashMap<StringName, Ref<StyleBox>>(); } @@ -654,8 +649,6 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const { } void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) { - bool new_value = !font_map.has(p_theme_type) || !font_map[p_theme_type].has(p_name); - if (font_map[p_theme_type][p_name].is_valid()) { font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed)); } @@ -666,10 +659,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - if (new_value) { - notify_property_list_changed(); - emit_changed(); - } + _emit_theme_changed(); } Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const { @@ -698,8 +688,7 @@ void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, font_map[p_theme_type][p_name] = font_map[p_theme_type][p_old_name]; font_map[p_theme_type].erase(p_old_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) { @@ -711,8 +700,8 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) } font_map[p_theme_type].erase(p_name); - notify_property_list_changed(); - emit_changed(); + + _emit_theme_changed(); } void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -730,6 +719,9 @@ void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) con } void Theme::add_font_type(const StringName &p_theme_type) { + if (font_map.has(p_theme_type)) { + return; + } font_map[p_theme_type] = HashMap<StringName, Ref<Font>>(); } @@ -743,14 +735,9 @@ void Theme::get_font_type_list(List<StringName> *p_list) const { } void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) { - bool new_value = !font_size_map.has(p_theme_type) || !font_size_map[p_theme_type].has(p_name); - font_size_map[p_theme_type][p_name] = p_font_size; - if (new_value) { - notify_property_list_changed(); - emit_changed(); - } + _emit_theme_changed(); } int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const { @@ -779,8 +766,7 @@ void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_n font_size_map[p_theme_type][p_name] = font_size_map[p_theme_type][p_old_name]; font_size_map[p_theme_type].erase(p_old_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) { @@ -788,8 +774,8 @@ void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_ ERR_FAIL_COND_MSG(!font_size_map[p_theme_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist."); font_size_map[p_theme_type].erase(p_name); - notify_property_list_changed(); - emit_changed(); + + _emit_theme_changed(); } void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -807,6 +793,9 @@ void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list } void Theme::add_font_size_type(const StringName &p_theme_type) { + if (font_size_map.has(p_theme_type)) { + return; + } font_size_map[p_theme_type] = HashMap<StringName, int>(); } @@ -820,14 +809,9 @@ void Theme::get_font_size_type_list(List<StringName> *p_list) const { } void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) { - bool new_value = !color_map.has(p_theme_type) || !color_map[p_theme_type].has(p_name); - color_map[p_theme_type][p_name] = p_color; - if (new_value) { - notify_property_list_changed(); - emit_changed(); - } + _emit_theme_changed(); } Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const { @@ -854,8 +838,7 @@ void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, color_map[p_theme_type][p_name] = color_map[p_theme_type][p_old_name]; color_map[p_theme_type].erase(p_old_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) { @@ -863,8 +846,8 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type ERR_FAIL_COND_MSG(!color_map[p_theme_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist."); color_map[p_theme_type].erase(p_name); - notify_property_list_changed(); - emit_changed(); + + _emit_theme_changed(); } void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -882,6 +865,9 @@ void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) co } void Theme::add_color_type(const StringName &p_theme_type) { + if (color_map.has(p_theme_type)) { + return; + } color_map[p_theme_type] = HashMap<StringName, Color>(); } @@ -895,13 +881,9 @@ void Theme::get_color_type_list(List<StringName> *p_list) const { } void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) { - bool new_value = !constant_map.has(p_theme_type) || !constant_map[p_theme_type].has(p_name); constant_map[p_theme_type][p_name] = p_constant; - if (new_value) { - notify_property_list_changed(); - emit_changed(); - } + _emit_theme_changed(); } int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const { @@ -928,8 +910,7 @@ void Theme::rename_constant(const StringName &p_old_name, const StringName &p_na constant_map[p_theme_type][p_name] = constant_map[p_theme_type][p_old_name]; constant_map[p_theme_type].erase(p_old_name); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) { @@ -937,8 +918,8 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_t ERR_FAIL_COND_MSG(!constant_map[p_theme_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist."); constant_map[p_theme_type].erase(p_name); - notify_property_list_changed(); - emit_changed(); + + _emit_theme_changed(); } void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const { @@ -956,6 +937,9 @@ void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) } void Theme::add_constant_type(const StringName &p_theme_type) { + if (constant_map.has(p_theme_type)) { + return; + } constant_map[p_theme_type] = HashMap<StringName, int>(); } @@ -1199,8 +1183,17 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l } } +void Theme::_freeze_change_propagation() { + no_change_propagation = true; +} + +void Theme::_unfreeze_and_propagate_changes() { + no_change_propagation = false; + _emit_theme_changed(); +} + void Theme::clear() { - //these need disconnecting + // These items need disconnecting. { const StringName *K = nullptr; while ((K = icon_map.next(K))) { @@ -1246,8 +1239,7 @@ void Theme::clear() { color_map.clear(); constant_map.clear(); - notify_property_list_changed(); - emit_changed(); + _emit_theme_changed(); } void Theme::copy_default_theme() { @@ -1261,6 +1253,8 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { return; } + _freeze_change_propagation(); + // These items need reconnecting, so add them normally. { const StringName *K = nullptr; @@ -1297,8 +1291,7 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { color_map = p_other->color_map; constant_map = p_other->constant_map; - notify_property_list_changed(); - emit_changed(); + _unfreeze_and_propagate_changes(); } void Theme::get_type_list(List<StringName> *p_list) const { diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 4de1f065e1..fe64fd7290 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -41,6 +41,12 @@ class Theme : public Resource { GDCLASS(Theme, Resource); RES_BASE_EXTENSION("theme"); +#ifdef TOOLS_ENABLED + friend class ThemeItemImportTree; + friend class ThemeItemEditorDialog; + friend class ThemeTypeEditor; +#endif + public: enum DataType { DATA_TYPE_COLOR, @@ -53,6 +59,8 @@ public: }; private: + bool no_change_propagation = false; + void _emit_theme_changed(); HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map; @@ -96,6 +104,9 @@ protected: static void _bind_methods(); + void _freeze_change_propagation(); + void _unfreeze_and_propagate_changes(); + virtual void reset_state() override; public: diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 2c2c8ea0e8..deee22f05f 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -30,7 +30,10 @@ #include "tile_set.h" +#include "core/core_string_names.h" #include "core/math/geometry_2d.h" +#include "core/templates/local_vector.h" + #include "scene/2d/navigation_region_2d.h" #include "scene/gui/control.h" #include "scene/resources/convex_polygon_shape_2d.h" @@ -38,6 +41,25 @@ /////////////////////////////// TileSet ////////////////////////////////////// +const char *TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[] = { + "right_side", + "right_corner", + "bottom_right_side", + "bottom_right_corner", + "bottom_side", + "bottom_corner", + "bottom_left_side", + "bottom_left_corner", + "left_side", + "left_corner", + "top_left_side", + "top_left_corner", + "top_side", + "top_corner", + "top_right_side", + "top_right_corner" +}; + // --- Plugins --- Vector<TileSetPlugin *> TileSet::get_tile_set_atlas_plugins() const { return tile_set_plugins_vector; @@ -51,6 +73,8 @@ void TileSet::set_tile_shape(TileSet::TileShape p_shape) { E_source->get()->notify_tile_data_properties_should_change(); } + terrain_bits_meshes_dirty = true; + tile_meshes_dirty = true; emit_changed(); } TileSet::TileShape TileSet::get_tile_shape() const { @@ -72,6 +96,8 @@ void TileSet::set_tile_offset_axis(TileSet::TileOffsetAxis p_alignment) { E_source->get()->notify_tile_data_properties_should_change(); } + terrain_bits_meshes_dirty = true; + tile_meshes_dirty = true; emit_changed(); } TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const { @@ -81,20 +107,14 @@ TileSet::TileOffsetAxis TileSet::get_tile_offset_axis() const { void TileSet::set_tile_size(Size2i p_size) { ERR_FAIL_COND(p_size.x < 1 || p_size.y < 1); tile_size = p_size; + terrain_bits_meshes_dirty = true; + tile_meshes_dirty = true; emit_changed(); } Size2i TileSet::get_tile_size() const { return tile_size; } -void TileSet::set_tile_skew(Vector2 p_skew) { - emit_changed(); - tile_skew = p_skew; -} -Vector2 TileSet::get_tile_skew() const { - return tile_skew; -} - int TileSet::get_next_source_id() const { return next_source_id; } @@ -117,7 +137,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source p_tile_set_source->set_tile_set(this); _compute_next_source_id(); - sources[new_source_id]->connect("changed", callable_mp(this, &TileSet::_source_changed)); + sources[new_source_id]->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileSet::_source_changed)); emit_changed(); @@ -127,7 +147,7 @@ int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source void TileSet::remove_source(int p_source_id) { ERR_FAIL_COND_MSG(!sources.has(p_source_id), vformat("Cannot remove TileSet atlas source. No tileset atlas source with id %d.", p_source_id)); - sources[p_source_id]->disconnect("changed", callable_mp(this, &TileSet::_source_changed)); + sources[p_source_id]->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileSet::_source_changed)); sources[p_source_id]->set_tile_set(nullptr); sources.erase(p_source_id); @@ -240,80 +260,6 @@ bool TileSet::get_occlusion_layer_sdf_collision(int p_layer_index) const { return occlusion_layers[p_layer_index].sdf_collision; } -void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { - // TODO: optimize this with 2D meshes when they work again. - if (get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) { - if (p_filled && p_texture.is_valid()) { - p_canvas_item->draw_texture_rect(p_texture, p_region, false, p_color); - } else { - p_canvas_item->draw_rect(p_region, p_color, p_filled); - } - } else { - float overlap = 0.0; - switch (get_tile_shape()) { - case TileSet::TILE_SHAPE_ISOMETRIC: - overlap = 0.5; - break; - case TileSet::TILE_SHAPE_HEXAGON: - overlap = 0.25; - break; - case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: - overlap = 0.0; - break; - default: - break; - } - - Vector<Vector2> uvs; - uvs.append(Vector2(0.5, 0.0)); - uvs.append(Vector2(0.0, overlap)); - uvs.append(Vector2(0.0, 1.0 - overlap)); - uvs.append(Vector2(0.5, 1.0)); - uvs.append(Vector2(1.0, 1.0 - overlap)); - uvs.append(Vector2(1.0, overlap)); - uvs.append(Vector2(0.5, 0.0)); - if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < uvs.size(); i++) { - uvs.write[i] = Vector2(uvs[i].y, uvs[i].x); - } - } - - Vector<Vector2> points; - for (int i = 0; i < uvs.size(); i++) { - points.append(p_region.position + uvs[i] * p_region.size); - } - - if (p_filled) { - // This does hurt performances a lot. We should use a mesh if possible instead. - p_canvas_item->draw_colored_polygon(points, p_color, uvs, p_texture); - - // Should improve performances, but does not work as draw_primitive does not work with textures :/ : - /*for (int i = 0; i < 6; i += 3) { - Vector<Vector2> quad; - quad.append(points[i]); - quad.append(points[(i + 1) % points.size()]); - quad.append(points[(i + 2) % points.size()]); - quad.append(points[(i + 3) % points.size()]); - - Vector<Vector2> uv_quad; - uv_quad.append(uvs[i]); - uv_quad.append(uvs[(i + 1) % uvs.size()]); - uv_quad.append(uvs[(i + 2) % uvs.size()]); - uv_quad.append(uvs[(i + 3) % uvs.size()]); - - p_control->draw_primitive(quad, Vector<Color>(), uv_quad, p_texture); - }*/ - - } else { - // This does hurt performances a lot. We should use a mesh if possible instead. - // tile_shape_grid->draw_polyline(points, p_color); - for (int i = 0; i < points.size() - 1; i++) { - p_canvas_item->draw_line(points[i], points[i + 1], p_color); - } - } - } -} - // Physics void TileSet::set_physics_layers_count(int p_physics_layers_count) { ERR_FAIL_COND(p_physics_layers_count < 0); @@ -459,14 +405,9 @@ Color TileSet::get_terrain_color(int p_terrain_set, int p_terrain_index) const { return terrain_sets[p_terrain_set].terrains[p_terrain_index].color; } -bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const { - if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) { - return false; - } - - TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set); +bool TileSet::is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const { if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_SIDE || @@ -474,7 +415,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER || @@ -483,7 +424,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh } } } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE || @@ -491,7 +432,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_LEFT_CORNER || @@ -501,7 +442,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh } } else { if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || @@ -511,7 +452,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || @@ -522,7 +463,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh } } } else { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_SIDES) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_SIDE || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE || @@ -532,7 +473,7 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return true; } } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + if (p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES || p_terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { if (p_peering_bit == TileSet::CELL_NEIGHBOR_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER || p_peering_bit == TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER || @@ -547,6 +488,15 @@ bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeigh return false; } +bool TileSet::is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const { + if (p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count()) { + return false; + } + + TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set); + return is_valid_peering_bit_for_mode(terrain_mode, p_peering_bit); +} + // Navigation void TileSet::set_navigation_layers_count(int p_navigation_layers_count) { ERR_FAIL_COND(p_navigation_layers_count < 0); @@ -657,9 +607,926 @@ Variant::Type TileSet::get_custom_data_type(int p_layer_id) const { return custom_data_layers[p_layer_id].type; } +Vector<Vector2> TileSet::get_tile_shape_polygon() { + Vector<Vector2> points; + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + points.append(Vector2(0.0, 0.0)); + points.append(Vector2(1.0, 0.0)); + points.append(Vector2(1.0, 1.0)); + points.append(Vector2(0.0, 1.0)); + } else { + float overlap = 0.0; + switch (tile_shape) { + case TileSet::TILE_SHAPE_ISOMETRIC: + overlap = 0.5; + break; + case TileSet::TILE_SHAPE_HEXAGON: + overlap = 0.25; + break; + case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: + overlap = 0.0; + break; + default: + break; + } + + points.append(Vector2(0.5, 0.0)); + points.append(Vector2(0.0, overlap)); + points.append(Vector2(0.0, 1.0 - overlap)); + points.append(Vector2(0.5, 1.0)); + points.append(Vector2(1.0, 1.0 - overlap)); + points.append(Vector2(1.0, overlap)); + points.append(Vector2(0.5, 0.0)); + if (get_tile_offset_axis() == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < points.size(); i++) { + points.write[i] = Vector2(points[i].y, points[i].x); + } + } + } + for (int i = 0; i < points.size(); i++) { + points.write[i] = points[i] * tile_size - tile_size / 2; + } + return points; +} + +void TileSet::draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled, Ref<Texture2D> p_texture) { + if (tile_meshes_dirty) { + Vector<Vector2> uvs = get_tile_shape_polygon(); + for (int i = 0; i < uvs.size(); i++) { + uvs.write[i] = (uvs[i] + tile_size / 2) / tile_size; + } + + Vector<Color> colors; + colors.resize(uvs.size()); + colors.fill(Color(1.0, 1.0, 1.0, 1.0)); + + // Filled mesh. + tile_filled_mesh->clear_surfaces(); + Array a; + a.resize(Mesh::ARRAY_MAX); + a[Mesh::ARRAY_VERTEX] = uvs; + a[Mesh::ARRAY_TEX_UV] = uvs; + a[Mesh::ARRAY_COLOR] = colors; + a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(uvs); + tile_filled_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + + // Lines mesh. + tile_lines_mesh->clear_surfaces(); + a.clear(); + a.resize(Mesh::ARRAY_MAX); + // Add the first point again when drawing lines. + uvs.push_back(uvs[0]); + colors.push_back(colors[0]); + a[Mesh::ARRAY_VERTEX] = uvs; + a[Mesh::ARRAY_COLOR] = colors; + tile_lines_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINE_STRIP, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + + tile_meshes_dirty = false; + } + + Transform2D xform; + xform.scale(p_region.size); + xform.set_origin(p_region.get_position()); + if (p_filled) { + p_canvas_item->draw_mesh(tile_filled_mesh, p_texture, xform, p_color); + } else { + p_canvas_item->draw_mesh(tile_lines_mesh, Ref<Texture2D>(), xform, p_color); + } +} + +Vector<Point2> TileSet::get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit) { + ERR_FAIL_COND_V(p_terrain_set < 0 || p_terrain_set >= get_terrain_sets_count(), Vector<Point2>()); + + TileSet::TerrainMode terrain_mode = get_terrain_set_mode(p_terrain_set); + + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + return _get_square_corner_or_side_terrain_bit_polygon(tile_size, p_bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + return _get_square_corner_terrain_bit_polygon(tile_size, p_bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + return _get_square_side_terrain_bit_polygon(tile_size, p_bit); + } + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + return _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, p_bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + return _get_isometric_corner_terrain_bit_polygon(tile_size, p_bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + return _get_isometric_side_terrain_bit_polygon(tile_size, p_bit); + } + } else { + float overlap = 0.0; + switch (tile_shape) { + case TileSet::TILE_SHAPE_HEXAGON: + overlap = 0.25; + break; + case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: + overlap = 0.0; + break; + default: + break; + } + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + return _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + return _get_half_offset_corner_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + return _get_half_offset_side_terrain_bit_polygon(tile_size, p_bit, overlap, tile_offset_axis); + } + } +} + +#define TERRAIN_ALPHA 0.6 + +void TileSet::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data) { + ERR_FAIL_COND(!p_tile_data); + + if (terrain_bits_meshes_dirty) { + // Recompute the meshes. + terrain_bits_meshes.clear(); + + for (int terrain_mode_index = 0; terrain_mode_index < 3; terrain_mode_index++) { + TerrainMode terrain_mode = TerrainMode(terrain_mode_index); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + CellNeighbor bit = CellNeighbor(i); + + if (is_valid_peering_bit_for_mode(terrain_mode, bit)) { + Vector<Vector2> polygon; + if (tile_shape == TileSet::TILE_SHAPE_SQUARE) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + polygon = _get_square_corner_or_side_terrain_bit_polygon(tile_size, bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + polygon = _get_square_corner_terrain_bit_polygon(tile_size, bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + polygon = _get_square_side_terrain_bit_polygon(tile_size, bit); + } + } else if (tile_shape == TileSet::TILE_SHAPE_ISOMETRIC) { + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + polygon = _get_isometric_corner_or_side_terrain_bit_polygon(tile_size, bit); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + polygon = _get_isometric_corner_terrain_bit_polygon(tile_size, bit); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + polygon = _get_isometric_side_terrain_bit_polygon(tile_size, bit); + } + } else { + float overlap = 0.0; + switch (tile_shape) { + case TileSet::TILE_SHAPE_HEXAGON: + overlap = 0.25; + break; + case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: + overlap = 0.0; + break; + default: + break; + } + if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { + polygon = _get_half_offset_corner_or_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis); + } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { + polygon = _get_half_offset_corner_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis); + } else { // TileData::TERRAIN_MODE_MATCH_SIDES + polygon = _get_half_offset_side_terrain_bit_polygon(tile_size, bit, overlap, tile_offset_axis); + } + } + + Ref<ArrayMesh> mesh; + mesh.instantiate(); + Vector<Vector2> uvs; + uvs.resize(polygon.size()); + Vector<Color> colors; + colors.resize(polygon.size()); + colors.fill(Color(1.0, 1.0, 1.0, 1.0)); + Array a; + a.resize(Mesh::ARRAY_MAX); + a[Mesh::ARRAY_VERTEX] = polygon; + a[Mesh::ARRAY_TEX_UV] = uvs; + a[Mesh::ARRAY_COLOR] = colors; + a[Mesh::ARRAY_INDEX] = Geometry2D::triangulate_polygon(polygon); + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, a, Array(), Dictionary(), Mesh::ARRAY_FLAG_USE_2D_VERTICES); + terrain_bits_meshes[terrain_mode][bit] = mesh; + } + } + } + terrain_bits_meshes_dirty = false; + } + + int terrain_set = p_tile_data->get_terrain_set(); + if (terrain_set < 0) { + return; + } + TileSet::TerrainMode terrain_mode = get_terrain_set_mode(terrain_set); + + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + CellNeighbor bit = CellNeighbor(i); + if (is_valid_peering_bit_terrain(terrain_set, bit)) { + int terrain_id = p_tile_data->get_peering_bit_terrain(bit); + if (terrain_id >= 0) { + Color color = get_terrain_color(terrain_set, terrain_id); + color.a = TERRAIN_ALPHA; + p_canvas_item->draw_mesh(terrain_bits_meshes[terrain_mode][bit], Ref<Texture2D>(), Transform2D(), color); + } + } + } + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); +} + +Vector<Vector<Ref<Texture2D>>> TileSet::generate_terrains_icons(Size2i p_size) { + // Counts the number of matching terrain tiles and find the best matching icon. + struct Count { + int count = 0; + float probability = 0.0; + Ref<Texture2D> texture; + Rect2i region; + }; + Vector<Vector<Ref<Texture2D>>> output; + LocalVector<LocalVector<Count>> counts; + output.resize(get_terrain_sets_count()); + counts.resize(get_terrain_sets_count()); + for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) { + output.write[terrain_set].resize(get_terrains_count(terrain_set)); + counts[terrain_set].resize(get_terrains_count(terrain_set)); + } + + for (int source_index = 0; source_index < get_source_count(); source_index++) { + int source_id = get_source_id(source_index); + Ref<TileSetSource> source = get_source(source_id); + + Ref<TileSetAtlasSource> atlas_source = source; + if (atlas_source.is_valid()) { + for (int tile_index = 0; tile_index < source->get_tiles_count(); tile_index++) { + Vector2i tile_id = source->get_tile_id(tile_index); + for (int alternative_index = 0; alternative_index < source->get_alternative_tiles_count(tile_id); alternative_index++) { + int alternative_id = source->get_alternative_tile_id(tile_id, alternative_index); + + TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(tile_id, alternative_id)); + int terrain_set = tile_data->get_terrain_set(); + if (terrain_set >= 0) { + ERR_FAIL_INDEX_V(terrain_set, get_terrain_sets_count(), Vector<Vector<Ref<Texture2D>>>()); + + LocalVector<int> bit_counts; + bit_counts.resize(get_terrains_count(terrain_set)); + for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) { + bit_counts[terrain] = 0; + } + for (int terrain_bit = 0; terrain_bit < TileSet::CELL_NEIGHBOR_MAX; terrain_bit++) { + TileSet::CellNeighbor cell_neighbor = TileSet::CellNeighbor(terrain_bit); + if (is_valid_peering_bit_terrain(terrain_set, cell_neighbor)) { + int terrain = tile_data->get_peering_bit_terrain(cell_neighbor); + if (terrain >= 0) { + bit_counts[terrain] += 1; + } + } + } + + for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) { + if ((bit_counts[terrain] > counts[terrain_set][terrain].count) || (bit_counts[terrain] == counts[terrain_set][terrain].count && tile_data->get_probability() > counts[terrain_set][terrain].probability)) { + counts[terrain_set][terrain].count = bit_counts[terrain]; + counts[terrain_set][terrain].probability = tile_data->get_probability(); + counts[terrain_set][terrain].texture = atlas_source->get_texture(); + counts[terrain_set][terrain].region = atlas_source->get_tile_texture_region(tile_id); + } + } + } + } + } + } + } + + // Generate the icons. + for (int terrain_set = 0; terrain_set < get_terrain_sets_count(); terrain_set++) { + for (int terrain = 0; terrain < get_terrains_count(terrain_set); terrain++) { + Ref<Image> image; + image.instantiate(); + if (counts[terrain_set][terrain].count > 0) { + // Get the best tile. + Ref<Texture2D> texture = counts[terrain_set][terrain].texture; + Rect2 region = counts[terrain_set][terrain].region; + image->create(region.size.x, region.size.y, false, Image::FORMAT_RGBA8); + image->blit_rect(texture->get_image(), region, Point2()); + image->resize(p_size.x, p_size.y, Image::INTERPOLATE_NEAREST); + } else { + image->create(1, 1, false, Image::FORMAT_RGBA8); + image->set_pixel(0, 0, get_terrain_color(terrain_set, terrain)); + } + Ref<ImageTexture> icon; + icon.instantiate(); + icon->create_from_image(image); + icon->set_size_override(p_size); + + output.write[terrain_set].write[terrain] = icon; + } + } + return output; +} + void TileSet::_source_changed() { emit_changed(); - notify_property_list_changed(); +} + +Vector<Point2> TileSet::_get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Rect2 bit_rect; + bit_rect.size = Vector2(p_size) / 3; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + bit_rect.position = Vector2(1, -1); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + bit_rect.position = Vector2(1, 1); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + bit_rect.position = Vector2(-1, 1); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + bit_rect.position = Vector2(-3, 1); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + bit_rect.position = Vector2(-3, -1); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + bit_rect.position = Vector2(-3, -3); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + bit_rect.position = Vector2(-1, -3); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + bit_rect.position = Vector2(1, -3); + break; + default: + break; + } + bit_rect.position *= Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + polygon.push_back(bit_rect.position); + polygon.push_back(Vector2(bit_rect.get_end().x, bit_rect.position.y)); + polygon.push_back(bit_rect.get_end()); + polygon.push_back(Vector2(bit_rect.position.x, bit_rect.get_end().y)); + return polygon; +} + +Vector<Point2> TileSet::_get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(3, 3) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(1, 1) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(-3, 3) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-1, 1) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(-3, -3) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-1, -1) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(3, -3) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(1, -1) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + polygon.push_back(Vector2(1, -1) * unit); + polygon.push_back(Vector2(3, -3) * unit); + polygon.push_back(Vector2(3, 3) * unit); + polygon.push_back(Vector2(1, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + polygon.push_back(Vector2(-1, 1) * unit); + polygon.push_back(Vector2(-3, 3) * unit); + polygon.push_back(Vector2(3, 3) * unit); + polygon.push_back(Vector2(1, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + polygon.push_back(Vector2(-1, -1) * unit); + polygon.push_back(Vector2(-3, -3) * unit); + polygon.push_back(Vector2(-3, 3) * unit); + polygon.push_back(Vector2(-1, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + polygon.push_back(Vector2(-1, -1) * unit); + polygon.push_back(Vector2(-3, -3) * unit); + polygon.push_back(Vector2(3, -3) * unit); + polygon.push_back(Vector2(1, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(2, -1) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(2, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(Vector2(0, 1) * unit); + polygon.push_back(Vector2(1, 2) * unit); + polygon.push_back(Vector2(2, 1) * unit); + polygon.push_back(Vector2(1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(Vector2(0, 1) * unit); + polygon.push_back(Vector2(-1, 2) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(1, 2) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(Vector2(0, 1) * unit); + polygon.push_back(Vector2(-1, 2) * unit); + polygon.push_back(Vector2(-2, 1) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-2, -1) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-2, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(Vector2(0, -1) * unit); + polygon.push_back(Vector2(-1, -2) * unit); + polygon.push_back(Vector2(-2, -1) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(Vector2(0, -1) * unit); + polygon.push_back(Vector2(-1, -2) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(1, -2) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(Vector2(0, -1) * unit); + polygon.push_back(Vector2(1, -2) * unit); + polygon.push_back(Vector2(2, -1) * unit); + polygon.push_back(Vector2(1, 0) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(Vector2(0.5, -0.5) * unit); + polygon.push_back(Vector2(1.5, -1.5) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(1.5, 1.5) * unit); + polygon.push_back(Vector2(0.5, 0.5) * unit); + polygon.push_back(Vector2(1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(Vector2(-0.5, 0.5) * unit); + polygon.push_back(Vector2(-1.5, 1.5) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(1.5, 1.5) * unit); + polygon.push_back(Vector2(0.5, 0.5) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(Vector2(-0.5, -0.5) * unit); + polygon.push_back(Vector2(-1.5, -1.5) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(-1.5, 1.5) * unit); + polygon.push_back(Vector2(-0.5, 0.5) * unit); + polygon.push_back(Vector2(-1, 0) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(Vector2(-0.5, -0.5) * unit); + polygon.push_back(Vector2(-1.5, -1.5) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(1.5, -1.5) * unit); + polygon.push_back(Vector2(0.5, -0.5) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit) { + Vector2 unit = Vector2(p_size) / 6.0; + Vector<Vector2> polygon; + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(0, 3) * unit); + polygon.push_back(Vector2(0, 1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(Vector2(-1, 0) * unit); + polygon.push_back(Vector2(-3, 0) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(Vector2(1, 0) * unit); + polygon.push_back(Vector2(3, 0) * unit); + polygon.push_back(Vector2(0, -3) * unit); + polygon.push_back(Vector2(0, -1) * unit); + break; + default: + break; + } + return polygon; +} + +Vector<Point2> TileSet::_get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { + Vector<Vector2> point_list; + point_list.push_back(Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(1, 3.0 - p_overlap * 2.0)); + point_list.push_back(Vector2(0, 3)); + point_list.push_back(Vector2(-1, 3.0 - p_overlap * 2.0)); + point_list.push_back(Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + point_list.push_back(Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(-1, -(3.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(0, -3)); + point_list.push_back(Vector2(1, -(3.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); + point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); + + Vector2 unit = Vector2(p_size) / 6.0; + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = point_list[i] * unit; + } + + Vector<Vector2> polygon; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + polygon.push_back(point_list[17]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[11]); + polygon.push_back(point_list[12]); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(point_list[12]); + polygon.push_back(point_list[13]); + polygon.push_back(point_list[14]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[14]); + polygon.push_back(point_list[15]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[15]); + polygon.push_back(point_list[16]); + polygon.push_back(point_list[17]); + break; + default: + break; + } + } else { + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); + } + } + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + polygon.push_back(point_list[17]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[15]); + polygon.push_back(point_list[16]); + polygon.push_back(point_list[17]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[14]); + polygon.push_back(point_list[15]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(point_list[12]); + polygon.push_back(point_list[13]); + polygon.push_back(point_list[14]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[11]); + polygon.push_back(point_list[12]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + default: + break; + } + } + + int half_polygon_size = polygon.size(); + for (int i = 0; i < half_polygon_size; i++) { + polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); + } + + return polygon; +} + +Vector<Point2> TileSet::_get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { + Vector<Vector2> point_list; + point_list.push_back(Vector2(3, 0)); + point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(0, 3)); + point_list.push_back(Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-3, 0)); + point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(0, -3)); + point_list.push_back(Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); + point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); + + Vector2 unit = Vector2(p_size) / 6.0; + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = point_list[i] * unit; + } + + Vector<Vector2> polygon; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_TOP_CORNER: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + polygon.push_back(point_list[0]); + break; + default: + break; + } + } else { + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); + } + } + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: + polygon.push_back(point_list[10]); + polygon.push_back(point_list[11]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_CORNER: + polygon.push_back(point_list[8]); + polygon.push_back(point_list[9]); + polygon.push_back(point_list[10]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: + polygon.push_back(point_list[6]); + polygon.push_back(point_list[7]); + polygon.push_back(point_list[8]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + polygon.push_back(point_list[6]); + break; + default: + break; + } + } + + int half_polygon_size = polygon.size(); + for (int i = 0; i < half_polygon_size; i++) { + polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); + } + + return polygon; +} + +Vector<Point2> TileSet::_get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { + Vector<Vector2> point_list; + point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(0, 3)); + point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); + point_list.push_back(Vector2(0, -3)); + point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); + + Vector2 unit = Vector2(p_size) / 6.0; + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = point_list[i] * unit; + } + + Vector<Vector2> polygon; + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + case TileSet::CELL_NEIGHBOR_LEFT_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + default: + break; + } + } else { + if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { + for (int i = 0; i < point_list.size(); i++) { + point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); + } + } + switch (p_bit) { + case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: + polygon.push_back(point_list[0]); + polygon.push_back(point_list[1]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: + polygon.push_back(point_list[5]); + polygon.push_back(point_list[0]); + break; + case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: + polygon.push_back(point_list[4]); + polygon.push_back(point_list[5]); + break; + case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: + polygon.push_back(point_list[3]); + polygon.push_back(point_list[4]); + break; + case TileSet::CELL_NEIGHBOR_TOP_SIDE: + polygon.push_back(point_list[2]); + polygon.push_back(point_list[3]); + break; + case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: + polygon.push_back(point_list[1]); + polygon.push_back(point_list[2]); + break; + default: + break; + } + } + + int half_polygon_size = polygon.size(); + for (int i = 0; i < half_polygon_size; i++) { + polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); + } + + return polygon; } void TileSet::reset_state() { @@ -747,12 +1614,18 @@ void TileSet::compatibility_conversion() { for (int k = 0; k < ctd->shapes.size(); k++) { CompatibilityShapeData csd = ctd->shapes[k]; if (csd.autotile_coords == coords) { - tile_data->set_collision_shapes_count(0, tile_data->get_collision_shapes_count(0) + 1); - int index = tile_data->get_collision_shapes_count(0) - 1; - tile_data->set_collision_shape_one_way(0, index, csd.one_way); - tile_data->set_collision_shape_one_way_margin(0, index, csd.one_way_margin); - tile_data->set_collision_shape_shape(0, index, csd.shape); - // Ignores transform for now. + Ref<ConvexPolygonShape2D> convex_shape = csd.shape; // Only ConvexPolygonShape2D are supported, which is the default type used by the 3.x editor + if (convex_shape.is_valid()) { + Vector<Vector2> polygon = convex_shape->get_points(); + for (int point_index = 0; point_index < polygon.size(); point_index++) { + polygon.write[point_index] = csd.transform.xform(polygon[point_index]); + } + tile_data->set_collision_polygons_count(0, tile_data->get_collision_polygons_count(0) + 1); + int index = tile_data->get_collision_polygons_count(0) - 1; + tile_data->set_collision_polygon_one_way(0, index, csd.one_way); + tile_data->set_collision_polygon_one_way_margin(0, index, csd.one_way_margin); + tile_data->set_collision_polygon_points(0, index, polygon); + } } } @@ -801,7 +1674,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { #ifndef DISABLE_DEPRECATED // TODO: THIS IS HOW WE CHECK IF WE HAVE A DEPRECATED RESOURCE // This should be moved to a dedicated conversion system - if (components.size() >= 1 && components[0].is_valid_integer()) { + if (components.size() >= 1 && components[0].is_valid_int()) { int id = components[0].to_int(); // Get or create the compatibility object @@ -966,7 +1839,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { #endif // DISABLE_DEPRECATED // This is now a new property. - if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) { + if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) { // Occlusion layers. int index = components[0].trim_prefix("occlusion_layer_").to_int(); ERR_FAIL_COND_V(index < 0, false); @@ -985,7 +1858,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { set_occlusion_layer_sdf_collision(index, p_value); return true; } - } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) { // Physics layers. int index = components[0].trim_prefix("physics_layer_").to_int(); ERR_FAIL_COND_V(index < 0, false); @@ -1012,7 +1885,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { set_physics_layer_physics_material(index, physics_material); return true; } - } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer()) { + } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int()) { // Terrains. int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int(); ERR_FAIL_COND_V(terrain_set_index < 0, false); @@ -1029,7 +1902,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { } set_terrains_count(terrain_set_index, p_value); return true; - } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_integer()) { + } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_int()) { int terrain_index = components[1].trim_prefix("terrain_").to_int(); ERR_FAIL_COND_V(terrain_index < 0, false); if (components[2] == "name") { @@ -1054,7 +1927,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { return true; } } - } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) { // Navigation layers. int index = components[0].trim_prefix("navigation_layer_").to_int(); ERR_FAIL_COND_V(index < 0, false); @@ -1066,7 +1939,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { set_navigation_layer_layers(index, p_value); return true; } - } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int()) { // Custom data layers. int index = components[0].trim_prefix("custom_data_layer_").to_int(); ERR_FAIL_COND_V(index < 0, false); @@ -1085,7 +1958,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { set_custom_data_type(index, Variant::Type(int(p_value))); return true; } - } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_integer()) { + } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) { // Create source only if it does not exists. int source_id = components[1].to_int(); @@ -1105,7 +1978,7 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) { bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); - if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) { + if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) { // Occlusion layers. int index = components[0].trim_prefix("occlusion_layer_").to_int(); if (index < 0 || index >= occlusion_layers.size()) { @@ -1118,7 +1991,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_occlusion_layer_sdf_collision(index); return true; } - } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) { // Physics layers. int index = components[0].trim_prefix("physics_layer_").to_int(); if (index < 0 || index >= physics_layers.size()) { @@ -1134,7 +2007,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_physics_layer_physics_material(index); return true; } - } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_integer()) { + } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int()) { // Terrains. int terrain_set_index = components[0].trim_prefix("terrain_set_").to_int(); if (terrain_set_index < 0 || terrain_set_index >= terrain_sets.size()) { @@ -1146,7 +2019,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { } else if (components[1] == "terrains_count") { r_ret = get_terrains_count(terrain_set_index); return true; - } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_integer()) { + } else if (components.size() >= 3 && components[1].begins_with("terrain_") && components[1].trim_prefix("terrain_").is_valid_int()) { int terrain_index = components[1].trim_prefix("terrain_").to_int(); if (terrain_index < 0 || terrain_index >= terrain_sets[terrain_set_index].terrains.size()) { return false; @@ -1159,7 +2032,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { return true; } } - } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) { // navigation layers. int index = components[0].trim_prefix("navigation_layer_").to_int(); if (index < 0 || index >= navigation_layers.size()) { @@ -1169,7 +2042,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_navigation_layer_layers(index); return true; } - } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("custom_data_layer_") && components[0].trim_prefix("custom_data_layer_").is_valid_int()) { // Custom data layers. int index = components[0].trim_prefix("custom_data_layer_").to_int(); if (index < 0 || index >= custom_data_layers.size()) { @@ -1182,7 +2055,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_custom_data_type(index); return true; } - } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_integer()) { + } else if (components.size() == 2 && components[0] == "sources" && components[1].is_valid_int()) { // Atlases data. int source_id = components[1].to_int(); @@ -1287,14 +2160,11 @@ void TileSet::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tile_offset_axis"), &TileSet::get_tile_offset_axis); ClassDB::bind_method(D_METHOD("set_tile_size", "size"), &TileSet::set_tile_size); ClassDB::bind_method(D_METHOD("get_tile_size"), &TileSet::get_tile_size); - ClassDB::bind_method(D_METHOD("set_tile_skew", "skew"), &TileSet::set_tile_skew); - ClassDB::bind_method(D_METHOD("get_tile_skew"), &TileSet::get_tile_skew); ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_shape", PROPERTY_HINT_ENUM, "Square,Isometric,Half-Offset Square,Hexagon"), "set_tile_shape", "get_tile_shape"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_layout", PROPERTY_HINT_ENUM, "Stacked,Stacked Offset,Stairs Right,Stairs Down,Diamond Right,Diamond Down"), "set_tile_layout", "get_tile_layout"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tile_offset_axis", PROPERTY_HINT_ENUM, "Horizontal Offset,Vertical Offset"), "set_tile_offset_axis", "get_tile_offset_axis"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_size"), "set_tile_size", "get_tile_size"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "tile_skew"), "set_tile_skew", "get_tile_skew"); // Rendering. ClassDB::bind_method(D_METHOD("set_uv_clipping", "uv_clipping"), &TileSet::set_uv_clipping); @@ -1375,22 +2245,22 @@ void TileSet::_bind_methods() { BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_HORIZONTAL); BIND_ENUM_CONSTANT(TILE_OFFSET_AXIS_VERTICAL); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_RIGHT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_RIGHT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_LEFT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_LEFT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_CORNER); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - BIND_ENUM_CONSTANT(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_RIGHT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_LEFT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_LEFT_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_CORNER); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_SIDE); + BIND_ENUM_CONSTANT(CELL_NEIGHBOR_TOP_RIGHT_CORNER); BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS_AND_SIDES); BIND_ENUM_CONSTANT(TERRAIN_MODE_MATCH_CORNERS); @@ -1398,10 +2268,13 @@ void TileSet::_bind_methods() { } TileSet::TileSet() { - // Instanciatie and list all plugins. + // Instantiate the tile meshes. + tile_lines_mesh.instantiate(); + tile_filled_mesh.instantiate(); + + // Instanciate and list all plugins. tile_set_plugins_vector.append(memnew(TileSetPluginAtlasRendering)); tile_set_plugins_vector.append(memnew(TileSetPluginAtlasPhysics)); - tile_set_plugins_vector.append(memnew(TileSetPluginAtlasTerrain)); tile_set_plugins_vector.append(memnew(TileSetPluginAtlasNavigation)); tile_set_plugins_vector.append(memnew(TileSetPluginScenesCollections)); } @@ -1534,7 +2407,7 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) // Compute the vector2i if we have coordinates. Vector<String> coords_split = components[0].split(":"); Vector2i coords = TileSetSource::INVALID_ATLAS_COORDS; - if (coords_split.size() == 2 && coords_split[0].is_valid_integer() && coords_split[1].is_valid_integer()) { + if (coords_split.size() == 2 && coords_split[0].is_valid_int() && coords_split[1].is_valid_int()) { coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int()); } @@ -1550,7 +2423,7 @@ bool TileSetAtlasSource::_set(const StringName &p_name, const Variant &p_value) move_tile_in_atlas(coords, coords, p_value); } else if (components[1] == "next_alternative_id") { tiles[coords].next_alternative_id = p_value; - } else if (components[1].is_valid_integer()) { + } else if (components[1].is_valid_int()) { int alternative_id = components[1].to_int(); if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE) { // Create the alternative if needed ? @@ -1584,7 +2457,7 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const { // Properties. Vector<String> coords_split = components[0].split(":"); - if (coords_split.size() == 2 && coords_split[0].is_valid_integer() && coords_split[1].is_valid_integer()) { + if (coords_split.size() == 2 && coords_split[0].is_valid_int() && coords_split[1].is_valid_int()) { Vector2i coords = Vector2i(coords_split[0].to_int(), coords_split[1].to_int()); if (tiles.has(coords)) { if (components.size() >= 2) { @@ -1595,7 +2468,7 @@ bool TileSetAtlasSource::_get(const StringName &p_name, Variant &r_ret) const { } else if (components[1] == "next_alternative_id") { r_ret = tiles[coords].next_alternative_id; return true; - } else if (components[1].is_valid_integer()) { + } else if (components[1].is_valid_int()) { int alternative_id = components[1].to_int(); if (alternative_id != TileSetSource::INVALID_TILE_ALTERNATIVE && tiles[coords].alternatives.has(alternative_id)) { if (components.size() >= 3) { @@ -2160,7 +3033,7 @@ int TileSetScenesCollectionSource::get_next_scene_tile_id() const { bool TileSetScenesCollectionSource::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); - if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_integer()) { + if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_int()) { int scene_id = components[1].to_int(); if (components.size() >= 3 && components[2] == "scene") { if (has_scene_tile_id(scene_id)) { @@ -2184,7 +3057,7 @@ bool TileSetScenesCollectionSource::_set(const StringName &p_name, const Variant bool TileSetScenesCollectionSource::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); - if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_integer() && scenes.has(components[1].to_int())) { + if (components.size() >= 2 && components[0] == "scenes" && components[1].is_valid_int() && scenes.has(components[1].to_int())) { if (components.size() >= 3 && components[2] == "scene") { r_ret = scenes[components[1].to_int()].scene; return true; @@ -2237,16 +3110,14 @@ void TileSetScenesCollectionSource::_bind_methods() { void TileData::set_tile_set(const TileSet *p_tile_set) { tile_set = p_tile_set; - if (tile_set) { - occluders.resize(tile_set->get_occlusion_layers_count()); - physics.resize(tile_set->get_physics_layers_count()); - navigation.resize(tile_set->get_navigation_layers_count()); - custom_data.resize(tile_set->get_custom_data_layers_count()); - } - notify_property_list_changed(); + notify_tile_data_properties_should_change(); } void TileData::notify_tile_data_properties_should_change() { + if (!tile_set) { + return; + } + occluders.resize(tile_set->get_occlusion_layers_count()); physics.resize(tile_set->get_physics_layers_count()); for (int bit_index = 0; bit_index < 16; bit_index++) { @@ -2373,76 +3244,112 @@ Ref<OccluderPolygon2D> TileData::get_occluder(int p_layer_id) const { } // Physics -int TileData::get_collision_shapes_count(int p_layer_id) const { +int TileData::get_collision_polygons_count(int p_layer_id) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); - return physics[p_layer_id].shapes.size(); + return physics[p_layer_id].polygons.size(); } -void TileData::set_collision_shapes_count(int p_layer_id, int p_shapes_count) { +void TileData::set_collision_polygons_count(int p_layer_id, int p_polygons_count) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_COND(p_shapes_count < 0); - physics.write[p_layer_id].shapes.resize(p_shapes_count); + ERR_FAIL_COND(p_polygons_count < 0); + physics.write[p_layer_id].polygons.resize(p_polygons_count); notify_property_list_changed(); emit_signal("changed"); } -void TileData::add_collision_shape(int p_layer_id) { +void TileData::add_collision_polygon(int p_layer_id) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - physics.write[p_layer_id].shapes.push_back(PhysicsLayerTileData::ShapeTileData()); + physics.write[p_layer_id].polygons.push_back(PhysicsLayerTileData::PolygonShapeTileData()); emit_signal("changed"); } -void TileData::remove_collision_shape(int p_layer_id, int p_shape_index) { +void TileData::remove_collision_polygon(int p_layer_id, int p_polygon_index) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.remove(p_shape_index); + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + physics.write[p_layer_id].polygons.remove(p_polygon_index); emit_signal("changed"); } -void TileData::set_collision_shape_shape(int p_layer_id, int p_shape_index, Ref<Shape2D> p_shape) { +void TileData::set_collision_polygon_points(int p_layer_id, int p_polygon_index, Vector<Vector2> p_polygon) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.write[p_shape_index].shape = p_shape; + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + ERR_FAIL_COND_MSG(p_polygon.size() != 0 && p_polygon.size() < 3, "Invalid polygon. Needs either 0 or more than 3 points."); + + if (p_polygon.is_empty()) { + physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.clear(); + } else { + // Decompose into convex shapes. + Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(p_polygon); + ERR_FAIL_COND_MSG(decomp.is_empty(), "Could not decompose the polygon into convex shapes."); + + physics.write[p_layer_id].polygons.write[p_polygon_index].shapes.resize(decomp.size()); + for (int i = 0; i < decomp.size(); i++) { + Ref<ConvexPolygonShape2D> shape; + shape.instantiate(); + shape->set_points(decomp[i]); + physics.write[p_layer_id].polygons.write[p_polygon_index].shapes[i] = shape; + } + } + physics.write[p_layer_id].polygons.write[p_polygon_index].polygon = p_polygon; emit_signal("changed"); } -Ref<Shape2D> TileData::get_collision_shape_shape(int p_layer_id, int p_shape_index) const { - ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Ref<Shape2D>()); - ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), Ref<Shape2D>()); - return physics[p_layer_id].shapes[p_shape_index].shape; +Vector<Vector2> TileData::get_collision_polygon_points(int p_layer_id, int p_polygon_index) const { + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), Vector<Vector2>()); + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Vector<Vector2>()); + return physics[p_layer_id].polygons[p_polygon_index].polygon; } -void TileData::set_collision_shape_one_way(int p_layer_id, int p_shape_index, bool p_one_way) { +void TileData::set_collision_polygon_one_way(int p_layer_id, int p_polygon_index, bool p_one_way) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.write[p_shape_index].one_way = p_one_way; + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + physics.write[p_layer_id].polygons.write[p_polygon_index].one_way = p_one_way; emit_signal("changed"); } -bool TileData::is_collision_shape_one_way(int p_layer_id, int p_shape_index) const { +bool TileData::is_collision_polygon_one_way(int p_layer_id, int p_polygon_index) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), false); - ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), false); - return physics[p_layer_id].shapes[p_shape_index].one_way; + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), false); + return physics[p_layer_id].polygons[p_polygon_index].one_way; } -void TileData::set_collision_shape_one_way_margin(int p_layer_id, int p_shape_index, float p_one_way_margin) { +void TileData::set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin) { ERR_FAIL_INDEX(p_layer_id, physics.size()); - ERR_FAIL_INDEX(p_shape_index, physics[p_layer_id].shapes.size()); - physics.write[p_layer_id].shapes.write[p_shape_index].one_way_margin = p_one_way_margin; + ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size()); + physics.write[p_layer_id].polygons.write[p_polygon_index].one_way_margin = p_one_way_margin; emit_signal("changed"); } -float TileData::get_collision_shape_one_way_margin(int p_layer_id, int p_shape_index) const { +float TileData::get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const { ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0.0); - ERR_FAIL_INDEX_V(p_shape_index, physics[p_layer_id].shapes.size(), 0.0); - return physics[p_layer_id].shapes[p_shape_index].one_way_margin; + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0.0); + return physics[p_layer_id].polygons[p_polygon_index].one_way_margin; +} + +int TileData::get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const { + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), 0); + return physics[p_layer_id].polygons[p_polygon_index].shapes.size(); +} + +Ref<ConvexPolygonShape2D> TileData::get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const { + ERR_FAIL_INDEX_V(p_layer_id, physics.size(), 0); + ERR_FAIL_INDEX_V(p_polygon_index, physics[p_layer_id].polygons.size(), Ref<ConvexPolygonShape2D>()); + ERR_FAIL_INDEX_V(shape_index, (int)physics[p_layer_id].polygons[shape_index].shapes.size(), Ref<ConvexPolygonShape2D>()); + return physics[p_layer_id].polygons[shape_index].shapes[shape_index]; } // Terrain void TileData::set_terrain_set(int p_terrain_set) { ERR_FAIL_COND(p_terrain_set < -1); + if (p_terrain_set == terrain_set) { + return; + } if (tile_set) { ERR_FAIL_COND(p_terrain_set >= tile_set->get_terrain_sets_count()); + for (int i = 0; i < 16; i++) { + terrain_peering_bits[i] = -1; + } } terrain_set = p_terrain_set; notify_property_list_changed(); @@ -2454,6 +3361,7 @@ int TileData::get_terrain_set() const { } void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int p_terrain_index) { + ERR_FAIL_COND(terrain_set < 0); ERR_FAIL_COND(p_terrain_index < -1); if (tile_set) { ERR_FAIL_COND(p_terrain_index >= tile_set->get_terrains_count(terrain_set)); @@ -2464,6 +3372,7 @@ void TileData::set_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit, int } int TileData::get_peering_bit_terrain(TileSet::CellNeighbor p_peering_bit) const { + ERR_FAIL_COND_V(!is_valid_peering_bit_terrain(p_peering_bit), -1); return terrain_peering_bits[p_peering_bit]; } @@ -2487,7 +3396,7 @@ Ref<NavigationPolygon> TileData::get_navigation_polygon(int p_layer_id) const { // Misc void TileData::set_probability(float p_probability) { - ERR_FAIL_COND(p_probability <= 0.0); + ERR_FAIL_COND(p_probability < 0.0); probability = p_probability; emit_signal("changed"); } @@ -2524,7 +3433,7 @@ Variant TileData::get_custom_data_by_layer_id(int p_layer_id) const { bool TileData::_set(const StringName &p_name, const Variant &p_value) { Vector<String> components = String(p_name).split("/", true, 2); - if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) { + if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) { // Occlusion layers. int layer_index = components[0].trim_prefix("occlusion_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); @@ -2544,11 +3453,11 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { set_occluder(layer_index, polygon); return true; } - } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) { + } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) { // Physics layers. int layer_index = components[0].trim_prefix("physics_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); - if (components.size() == 2 && components[1] == "shapes_count") { + if (components.size() == 2 && components[1] == "polygons_count") { if (p_value.get_type() != Variant::INT) { return false; } @@ -2560,13 +3469,13 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { physics.resize(layer_index + 1); } } - set_collision_shapes_count(layer_index, p_value); + set_collision_polygons_count(layer_index, p_value); return true; - } else if (components.size() == 3 && components[1].begins_with("shape_") && components[1].trim_prefix("shape_").is_valid_integer()) { - int shape_index = components[1].trim_prefix("shape_").to_int(); - ERR_FAIL_COND_V(shape_index < 0, false); + } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) { + int polygon_index = components[1].trim_prefix("polygon_").to_int(); + ERR_FAIL_COND_V(polygon_index < 0, false); - if (components[2] == "shape" || components[2] == "one_way" || components[2] == "one_way_margin") { + if (components[2] == "points" || components[2] == "one_way" || components[2] == "one_way_margin") { if (layer_index >= physics.size()) { if (tile_set) { return false; @@ -2575,23 +3484,23 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { } } - if (shape_index >= physics[layer_index].shapes.size()) { - physics.write[layer_index].shapes.resize(shape_index + 1); + if (polygon_index >= physics[layer_index].polygons.size()) { + physics.write[layer_index].polygons.resize(polygon_index + 1); } } - if (components[2] == "shape") { - Ref<Shape2D> shape = p_value; - set_collision_shape_shape(layer_index, shape_index, shape); + if (components[2] == "points") { + Vector<Vector2> polygon = p_value; + set_collision_polygon_points(layer_index, polygon_index, polygon); return true; } else if (components[2] == "one_way") { - set_collision_shape_one_way(layer_index, shape_index, p_value); + set_collision_polygon_one_way(layer_index, polygon_index, p_value); return true; } else if (components[2] == "one_way_margin") { - set_collision_shape_one_way_margin(layer_index, shape_index, p_value); + set_collision_polygon_one_way_margin(layer_index, polygon_index, p_value); return true; } } - } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) { + } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) { // Navigation layers. int layer_index = components[0].trim_prefix("navigation_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); @@ -2613,43 +3522,15 @@ bool TileData::_set(const StringName &p_name, const Variant &p_value) { } } else if (components.size() == 2 && components[0] == "terrains_peering_bit") { // Terrains. - if (components[1] == "right_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE, p_value); - } else if (components[1] == "right_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER, p_value); - } else if (components[1] == "bottom_right_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, p_value); - } else if (components[1] == "bottom_right_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, p_value); - } else if (components[1] == "bottom_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, p_value); - } else if (components[1] == "bottom_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, p_value); - } else if (components[1] == "bottom_left_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, p_value); - } else if (components[1] == "bottom_left_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, p_value); - } else if (components[1] == "left_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE, p_value); - } else if (components[1] == "left_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER, p_value); - } else if (components[1] == "top_left_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, p_value); - } else if (components[1] == "top_left_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, p_value); - } else if (components[1] == "top_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE, p_value); - } else if (components[1] == "top_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER, p_value); - } else if (components[1] == "top_right_side") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, p_value); - } else if (components[1] == "top_right_corner") { - set_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, p_value); - } else { - return false; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) { + set_peering_bit_terrain(bit, p_value); + return true; + } } - return true; - } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_integer()) { + return false; + } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) { // Custom data layers. int layer_index = components[0].trim_prefix("custom_data_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); @@ -2673,7 +3554,7 @@ bool TileData::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (tile_set) { - if (components.size() == 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_integer()) { + if (components.size() == 2 && components[0].begins_with("occlusion_layer") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) { // Occlusion layers. int layer_index = components[0].trim_prefix("occlusion_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); @@ -2684,72 +3565,43 @@ bool TileData::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_occluder(layer_index); return true; } - } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_integer()) { + } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) { // Physics layers. int layer_index = components[0].trim_prefix("physics_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); if (layer_index >= physics.size()) { return false; } - if (components.size() == 2 && components[1] == "shapes_count") { - r_ret = get_collision_shapes_count(layer_index); + if (components.size() == 2 && components[1] == "polygons_count") { + r_ret = get_collision_polygons_count(layer_index); return true; - } else if (components.size() == 3 && components[1].begins_with("shape_") && components[1].trim_prefix("shape_").is_valid_integer()) { - int shape_index = components[1].trim_prefix("shape_").to_int(); - ERR_FAIL_COND_V(shape_index < 0, false); - if (shape_index >= physics[layer_index].shapes.size()) { + } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) { + int polygon_index = components[1].trim_prefix("polygon_").to_int(); + ERR_FAIL_COND_V(polygon_index < 0, false); + if (polygon_index >= physics[layer_index].polygons.size()) { return false; } - if (components[2] == "shape") { - r_ret = get_collision_shape_shape(layer_index, shape_index); + if (components[2] == "points") { + r_ret = get_collision_polygon_points(layer_index, polygon_index); return true; } else if (components[2] == "one_way") { - r_ret = is_collision_shape_one_way(layer_index, shape_index); + r_ret = is_collision_polygon_one_way(layer_index, polygon_index); return true; } else if (components[2] == "one_way_margin") { - r_ret = get_collision_shape_one_way_margin(layer_index, shape_index); + r_ret = get_collision_polygon_one_way_margin(layer_index, polygon_index); return true; } } } else if (components.size() == 2 && components[0] == "terrains_peering_bit") { // Terrains. - if (components[1] == "right_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_RIGHT_SIDE]; - } else if (components[1] == "right_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_RIGHT_CORNER]; - } else if (components[1] == "bottom_right_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE]; - } else if (components[1] == "bottom_right_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER]; - } else if (components[1] == "bottom_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_SIDE]; - } else if (components[1] == "bottom_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_CORNER]; - } else if (components[1] == "bottom_left_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE]; - } else if (components[1] == "bottom_left_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER]; - } else if (components[1] == "left_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_LEFT_SIDE]; - } else if (components[1] == "left_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_LEFT_CORNER]; - } else if (components[1] == "top_left_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE]; - } else if (components[1] == "top_left_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER]; - } else if (components[1] == "top_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_SIDE]; - } else if (components[1] == "top_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_CORNER]; - } else if (components[1] == "top_right_side") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE]; - } else if (components[1] == "top_right_corner") { - r_ret = terrain_peering_bits[TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER]; - } else { - return false; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + if (components[1] == TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]) { + r_ret = terrain_peering_bits[i]; + return true; + } } - return true; - } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_integer()) { + return false; + } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) { // Occlusion layers. int layer_index = components[0].trim_prefix("navigation_layer_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); @@ -2760,7 +3612,7 @@ bool TileData::_get(const StringName &p_name, Variant &r_ret) const { r_ret = get_navigation_polygon(layer_index); return true; } - } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_integer()) { + } else if (components.size() == 1 && components[0].begins_with("custom_data_") && components[0].trim_prefix("custom_data_").is_valid_int()) { // Custom data layers. int layer_index = components[0].trim_prefix("custom_data_").to_int(); ERR_FAIL_COND_V(layer_index < 0, false); @@ -2793,26 +3645,26 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { // Physics layers. p_list->push_back(PropertyInfo(Variant::NIL, "Physics", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); for (int i = 0; i < physics.size(); i++) { - p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/shapes_count", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); + p_list->push_back(PropertyInfo(Variant::INT, vformat("physics_layer_%d/polygons_count", i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); - for (int j = 0; j < physics[i].shapes.size(); j++) { - // physics_layer_%d/shapes_count - property_info = PropertyInfo(Variant::OBJECT, vformat("physics_layer_%d/shape_%d/shape", i, j), PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_DEFAULT); - if (!physics[i].shapes[j].shape.is_valid()) { + for (int j = 0; j < physics[i].polygons.size(); j++) { + // physics_layer_%d/points + property_info = PropertyInfo(Variant::ARRAY, vformat("physics_layer_%d/polygon_%d/points", i, j), PROPERTY_HINT_ARRAY_TYPE, "Vector2", PROPERTY_USAGE_DEFAULT); + if (physics[i].polygons[j].polygon.is_empty()) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); - // physics_layer_%d/shape_%d/one_way - property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/shape_%d/one_way", i, j)); - if (physics[i].shapes[j].one_way == false) { + // physics_layer_%d/polygon_%d/one_way + property_info = PropertyInfo(Variant::BOOL, vformat("physics_layer_%d/polygon_%d/one_way", i, j)); + if (physics[i].polygons[j].one_way == false) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); - // physics_layer_%d/shape_%d/one_way_margin - property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/shape_%d/one_way_margin", i, j)); - if (physics[i].shapes[j].one_way_margin == 1.0) { + // physics_layer_%d/polygon_%d/one_way_margin + property_info = PropertyInfo(Variant::FLOAT, vformat("physics_layer_%d/polygon_%d/one_way_margin", i, j)); + if (physics[i].polygons[j].one_way_margin == 1.0) { property_info.usage ^= PROPERTY_USAGE_STORAGE; } p_list->push_back(property_info); @@ -2822,117 +3674,15 @@ void TileData::_get_property_list(List<PropertyInfo> *p_list) const { // Terrain data if (terrain_set >= 0) { p_list->push_back(PropertyInfo(Variant::NIL, "Terrains", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/right_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/right_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_RIGHT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_right_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_right_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_left_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/bottom_left_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/left_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/left_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_LEFT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_left_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_left_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_right_side"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; - } - p_list->push_back(property_info); - } - if (is_valid_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER)) { - property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/top_right_corner"); - if (get_peering_bit_terrain(TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER) == -1) { - property_info.usage ^= PROPERTY_USAGE_STORAGE; + for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) { + TileSet::CellNeighbor bit = TileSet::CellNeighbor(i); + if (is_valid_peering_bit_terrain(bit)) { + property_info = PropertyInfo(Variant::INT, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i])); + if (get_peering_bit_terrain(bit) == -1) { + property_info.usage ^= PROPERTY_USAGE_STORAGE; + } + p_list->push_back(property_info); } - p_list->push_back(property_info); } } @@ -2984,16 +3734,16 @@ void TileData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_occluder", "layer_id"), &TileData::get_occluder); // Physics. - ClassDB::bind_method(D_METHOD("get_collision_shapes_count", "layer_id"), &TileData::get_collision_shapes_count); - ClassDB::bind_method(D_METHOD("set_collision_shapes_count", "layer_id", "shapes_count"), &TileData::set_collision_shapes_count); - ClassDB::bind_method(D_METHOD("add_collision_shape", "layer_id"), &TileData::add_collision_shape); - ClassDB::bind_method(D_METHOD("remove_collision_shape", "layer_id", "shape_index"), &TileData::remove_collision_shape); - ClassDB::bind_method(D_METHOD("set_collision_shape_shape", "layer_id", "shape_index", "shape"), &TileData::set_collision_shape_shape); - ClassDB::bind_method(D_METHOD("get_collision_shape_shape", "layer_id", "shape_index"), &TileData::get_collision_shape_shape); - ClassDB::bind_method(D_METHOD("set_collision_shape_one_way", "layer_id", "shape_index", "one_way"), &TileData::set_collision_shape_one_way); - ClassDB::bind_method(D_METHOD("is_collision_shape_one_way", "layer_id", "shape_index"), &TileData::is_collision_shape_one_way); - ClassDB::bind_method(D_METHOD("set_collision_shape_one_way_margin", "layer_id", "shape_index", "one_way_margin"), &TileData::set_collision_shape_one_way_margin); - ClassDB::bind_method(D_METHOD("get_collision_shape_one_way_margin", "layer_id", "shape_index"), &TileData::get_collision_shape_one_way_margin); + ClassDB::bind_method(D_METHOD("get_collision_polygons_count", "layer_id"), &TileData::get_collision_polygons_count); + ClassDB::bind_method(D_METHOD("set_collision_polygons_count", "layer_id", "polygons_count"), &TileData::set_collision_polygons_count); + ClassDB::bind_method(D_METHOD("add_collision_polygon", "layer_id"), &TileData::add_collision_polygon); + ClassDB::bind_method(D_METHOD("remove_collision_polygon", "layer_id", "polygon_index"), &TileData::remove_collision_polygon); + ClassDB::bind_method(D_METHOD("set_collision_polygon_points", "layer_id", "polygon_index", "polygon"), &TileData::set_collision_polygon_points); + ClassDB::bind_method(D_METHOD("get_collision_polygon_points", "layer_id", "polygon_index"), &TileData::get_collision_polygon_points); + ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way", "layer_id", "polygon_index", "one_way"), &TileData::set_collision_polygon_one_way); + ClassDB::bind_method(D_METHOD("is_collision_polygon_one_way", "layer_id", "polygon_index"), &TileData::is_collision_polygon_one_way); + ClassDB::bind_method(D_METHOD("set_collision_polygon_one_way_margin", "layer_id", "polygon_index", "one_way_margin"), &TileData::set_collision_polygon_one_way_margin); + ClassDB::bind_method(D_METHOD("get_collision_polygon_one_way_margin", "layer_id", "polygon_index"), &TileData::get_collision_polygon_one_way_margin); // Terrain ClassDB::bind_method(D_METHOD("set_terrain_set", "terrain_set"), &TileData::set_terrain_set); @@ -3032,805 +3782,6 @@ void TileData::_bind_methods() { ADD_SIGNAL(MethodInfo("changed")); } - -/////////////////////////////// TileSetPluginAtlasTerrain ////////////////////////////////////// - -// --- PLUGINS --- -void TileSetPluginAtlasTerrain::_draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - Rect2 bit_rect; - bit_rect.size = Vector2(p_size) / 3; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - bit_rect.position = Vector2(1, -1); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - bit_rect.position = Vector2(1, 1); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - bit_rect.position = Vector2(-1, 1); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - bit_rect.position = Vector2(-3, 1); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - bit_rect.position = Vector2(-3, -1); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - bit_rect.position = Vector2(-3, -3); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - bit_rect.position = Vector2(-1, -3); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - bit_rect.position = Vector2(1, -3); - break; - default: - break; - } - bit_rect.position *= Vector2(p_size) / 6.0; - p_canvas_item->draw_rect(bit_rect, p_color); -} - -void TileSetPluginAtlasTerrain::_draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(3, 3) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(1, 1) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(-3, 3) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-1, 1) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(-3, -3) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-1, -1) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(3, -3) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(1, -1) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - polygon.push_back(Vector2(1, -1) * unit); - polygon.push_back(Vector2(3, -3) * unit); - polygon.push_back(Vector2(3, 3) * unit); - polygon.push_back(Vector2(1, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - polygon.push_back(Vector2(-1, 1) * unit); - polygon.push_back(Vector2(-3, 3) * unit); - polygon.push_back(Vector2(3, 3) * unit); - polygon.push_back(Vector2(1, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - polygon.push_back(Vector2(-1, -1) * unit); - polygon.push_back(Vector2(-3, -3) * unit); - polygon.push_back(Vector2(-3, 3) * unit); - polygon.push_back(Vector2(-1, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - polygon.push_back(Vector2(-1, -1) * unit); - polygon.push_back(Vector2(-3, -3) * unit); - polygon.push_back(Vector2(3, -3) * unit); - polygon.push_back(Vector2(1, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(2, -1) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(2, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(Vector2(0, 1) * unit); - polygon.push_back(Vector2(1, 2) * unit); - polygon.push_back(Vector2(2, 1) * unit); - polygon.push_back(Vector2(1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(Vector2(0, 1) * unit); - polygon.push_back(Vector2(-1, 2) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(1, 2) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(Vector2(0, 1) * unit); - polygon.push_back(Vector2(-1, 2) * unit); - polygon.push_back(Vector2(-2, 1) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-2, -1) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-2, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(Vector2(0, -1) * unit); - polygon.push_back(Vector2(-1, -2) * unit); - polygon.push_back(Vector2(-2, -1) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(Vector2(0, -1) * unit); - polygon.push_back(Vector2(-1, -2) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(1, -2) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(Vector2(0, -1) * unit); - polygon.push_back(Vector2(1, -2) * unit); - polygon.push_back(Vector2(2, -1) * unit); - polygon.push_back(Vector2(1, 0) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(Vector2(0.5, -0.5) * unit); - polygon.push_back(Vector2(1.5, -1.5) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(1.5, 1.5) * unit); - polygon.push_back(Vector2(0.5, 0.5) * unit); - polygon.push_back(Vector2(1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(Vector2(-0.5, 0.5) * unit); - polygon.push_back(Vector2(-1.5, 1.5) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(1.5, 1.5) * unit); - polygon.push_back(Vector2(0.5, 0.5) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(Vector2(-0.5, -0.5) * unit); - polygon.push_back(Vector2(-1.5, -1.5) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(-1.5, 1.5) * unit); - polygon.push_back(Vector2(-0.5, 0.5) * unit); - polygon.push_back(Vector2(-1, 0) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(Vector2(-0.5, -0.5) * unit); - polygon.push_back(Vector2(-1.5, -1.5) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(1.5, -1.5) * unit); - polygon.push_back(Vector2(0.5, -0.5) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit) { - PackedColorArray color_array; - color_array.push_back(p_color); - - Vector2 unit = Vector2(p_size) / 6.0; - PackedVector2Array polygon; - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(0, 3) * unit); - polygon.push_back(Vector2(0, 1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(Vector2(-1, 0) * unit); - polygon.push_back(Vector2(-3, 0) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(Vector2(1, 0) * unit); - polygon.push_back(Vector2(3, 0) * unit); - polygon.push_back(Vector2(0, -3) * unit); - polygon.push_back(Vector2(0, -1) * unit); - break; - default: - break; - } - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { - PackedColorArray color_array; - color_array.push_back(p_color); - - PackedVector2Array point_list; - point_list.push_back(Vector2(3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(1, 3.0 - p_overlap * 2.0)); - point_list.push_back(Vector2(0, 3)); - point_list.push_back(Vector2(-1, 3.0 - p_overlap * 2.0)); - point_list.push_back(Vector2(-2, 3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-3, (3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - point_list.push_back(Vector2(-3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(-1, -(3.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(0, -3)); - point_list.push_back(Vector2(1, -(3.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(2, -3.0 * (1.0 - (p_overlap * 2.0) * 2.0 / 3.0))); - point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(3, -(3.0 * (1.0 - p_overlap * 2.0)) / 2.0)); - - Vector2 unit = Vector2(p_size) / 6.0; - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = point_list[i] * unit; - } - - PackedVector2Array polygon; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - polygon.push_back(point_list[17]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[11]); - polygon.push_back(point_list[12]); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(point_list[12]); - polygon.push_back(point_list[13]); - polygon.push_back(point_list[14]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[14]); - polygon.push_back(point_list[15]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[15]); - polygon.push_back(point_list[16]); - polygon.push_back(point_list[17]); - break; - default: - break; - } - } else { - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); - } - } - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - polygon.push_back(point_list[17]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[15]); - polygon.push_back(point_list[16]); - polygon.push_back(point_list[17]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[14]); - polygon.push_back(point_list[15]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(point_list[12]); - polygon.push_back(point_list[13]); - polygon.push_back(point_list[14]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[11]); - polygon.push_back(point_list[12]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - default: - break; - } - } - - int half_polygon_size = polygon.size(); - for (int i = 0; i < half_polygon_size; i++) { - polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); - } - - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { - PackedColorArray color_array; - color_array.push_back(p_color); - - PackedVector2Array point_list; - point_list.push_back(Vector2(3, 0)); - point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(0, 3)); - point_list.push_back(Vector2(-1.5, (3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-3, 0)); - point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(0, -3)); - point_list.push_back(Vector2(1.5, -(3.0 * (1.0 - p_overlap * 2.0) + 3.0) / 2.0)); - point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); - - Vector2 unit = Vector2(p_size) / 6.0; - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = point_list[i] * unit; - } - - PackedVector2Array polygon; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_CORNER: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_TOP_CORNER: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - polygon.push_back(point_list[0]); - break; - default: - break; - } - } else { - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); - } - } - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_CORNER: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER: - polygon.push_back(point_list[10]); - polygon.push_back(point_list[11]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_CORNER: - polygon.push_back(point_list[8]); - polygon.push_back(point_list[9]); - polygon.push_back(point_list[10]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER: - polygon.push_back(point_list[6]); - polygon.push_back(point_list[7]); - polygon.push_back(point_list[8]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - polygon.push_back(point_list[6]); - break; - default: - break; - } - } - - int half_polygon_size = polygon.size(); - for (int i = 0; i < half_polygon_size; i++) { - polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); - } - - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -void TileSetPluginAtlasTerrain::_draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis) { - PackedColorArray color_array; - color_array.push_back(p_color); - - PackedVector2Array point_list; - point_list.push_back(Vector2(3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(0, 3)); - point_list.push_back(Vector2(-3, 3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(-3, -3.0 * (1.0 - p_overlap * 2.0))); - point_list.push_back(Vector2(0, -3)); - point_list.push_back(Vector2(3, -3.0 * (1.0 - p_overlap * 2.0))); - - Vector2 unit = Vector2(p_size) / 6.0; - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = point_list[i] * unit; - } - - PackedVector2Array polygon; - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_RIGHT_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - case TileSet::CELL_NEIGHBOR_LEFT_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - default: - break; - } - } else { - if (p_offset_axis == TileSet::TILE_OFFSET_AXIS_VERTICAL) { - for (int i = 0; i < point_list.size(); i++) { - point_list.write[i] = Vector2(point_list[i].y, point_list[i].x); - } - } - switch (p_bit) { - case TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE: - polygon.push_back(point_list[0]); - polygon.push_back(point_list[1]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_SIDE: - polygon.push_back(point_list[5]); - polygon.push_back(point_list[0]); - break; - case TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE: - polygon.push_back(point_list[4]); - polygon.push_back(point_list[5]); - break; - case TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE: - polygon.push_back(point_list[3]); - polygon.push_back(point_list[4]); - break; - case TileSet::CELL_NEIGHBOR_TOP_SIDE: - polygon.push_back(point_list[2]); - polygon.push_back(point_list[3]); - break; - case TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE: - polygon.push_back(point_list[1]); - polygon.push_back(point_list[2]); - break; - default: - break; - } - } - - int half_polygon_size = polygon.size(); - for (int i = 0; i < half_polygon_size; i++) { - polygon.push_back(polygon[half_polygon_size - 1 - i] / 3.0); - } - - if (!polygon.is_empty()) { - p_canvas_item->draw_polygon(polygon, color_array); - } -} - -#define TERRAIN_ALPHA 0.8 - -#define DRAW_TERRAIN_BIT(f, bit) \ - { \ - int terrain_id = p_tile_data->get_peering_bit_terrain((bit)); \ - if (terrain_id >= 0) { \ - Color color = p_tile_set->get_terrain_color(terrain_set, terrain_id); \ - color.a = TERRAIN_ALPHA; \ - f(p_canvas_item, color, size, (bit)); \ - } \ - } - -#define DRAW_HALF_OFFSET_TERRAIN_BIT(f, bit, overlap, half_offset_axis) \ - { \ - int terrain_id = p_tile_data->get_peering_bit_terrain((bit)); \ - if (terrain_id >= 0) { \ - Color color = p_tile_set->get_terrain_color(terrain_set, terrain_id); \ - color.a = TERRAIN_ALPHA; \ - f(p_canvas_item, color, size, (bit), overlap, half_offset_axis); \ - } \ - } - -void TileSetPluginAtlasTerrain::draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data) { - ERR_FAIL_COND(!p_tile_set); - ERR_FAIL_COND(!p_tile_data); - - int terrain_set = p_tile_data->get_terrain_set(); - if (terrain_set < 0) { - return; - } - TileSet::TerrainMode terrain_mode = p_tile_set->get_terrain_set_mode(terrain_set); - - TileSet::TileShape shape = p_tile_set->get_tile_shape(); - Vector2i size = p_tile_set->get_tile_size(); - - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); - if (shape == TileSet::TILE_SHAPE_SQUARE) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE); - DRAW_TERRAIN_BIT(_draw_square_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER); - } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_square_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER); - } else { // TileData::TERRAIN_MODE_MATCH_SIDES - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE); - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_square_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE); - } - } else if (shape == TileSet::TILE_SHAPE_ISOMETRIC) { - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER); - DRAW_TERRAIN_BIT(_draw_isometric_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER); - } else { // TileData::TERRAIN_MODE_MATCH_SIDES - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE); - DRAW_TERRAIN_BIT(_draw_isometric_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE); - } - } else { - TileSet::TileOffsetAxis offset_axis = p_tile_set->get_tile_offset_axis(); - float overlap = 0.0; - switch (p_tile_set->get_tile_shape()) { - case TileSet::TILE_SHAPE_HEXAGON: - overlap = 0.25; - break; - case TileSet::TILE_SHAPE_HALF_OFFSET_SQUARE: - overlap = 0.0; - break; - default: - break; - } - if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS_AND_SIDES) { - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - } else { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_or_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - } - } else if (terrain_mode == TileSet::TERRAIN_MODE_MATCH_CORNERS) { - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - } else { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_CORNER, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_corner_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_CORNER, overlap, offset_axis); - } - } else { // TileData::TERRAIN_MODE_MATCH_SIDES - if (offset_axis == TileSet::TILE_OFFSET_AXIS_HORIZONTAL) { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - } else { - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_RIGHT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_BOTTOM_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_LEFT_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_SIDE, overlap, offset_axis); - DRAW_HALF_OFFSET_TERRAIN_BIT(_draw_half_offset_side_terrain_bit, TileSet::CELL_NEIGHBOR_TOP_RIGHT_SIDE, overlap, offset_axis); - } - } - } - RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); -} - /////////////////////////////// TileSetPluginAtlasRendering ////////////////////////////////////// void TileSetPluginAtlasRendering::tilemap_notification(TileMap *p_tile_map, int p_what) { @@ -3870,8 +3821,8 @@ void TileSetPluginAtlasRendering::tilemap_notification(TileMap *p_tile_map, int } break; case CanvasItem::NOTIFICATION_DRAW: { Ref<TileSet> tile_set = p_tile_map->get_tileset(); - if (tile_set.is_valid()) { - RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(p_tile_map->get_canvas_item(), tile_set->is_y_sorting()); + if (tile_set.is_valid() || p_tile_map->is_y_sort_enabled()) { + RenderingServer::get_singleton()->canvas_item_set_sort_children_by_y(p_tile_map->get_canvas_item(), tile_set->is_y_sorting() || p_tile_map->is_y_sort_enabled()); } } break; } @@ -4216,15 +4167,17 @@ void TileSetPluginAtlasPhysics::update_dirty_quadrants(TileMap *p_tile_map, Self for (int body_index = 0; body_index < q.bodies.size(); body_index++) { // Add the shapes again. - for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(body_index); shape_index++) { - bool one_way_collision = tile_data->is_collision_shape_one_way(body_index, shape_index); - float one_way_collision_margin = tile_data->get_collision_shape_one_way_margin(body_index, shape_index); - Ref<Shape2D> shape = tile_data->get_collision_shape_shape(body_index, shape_index); - if (shape.is_valid()) { + for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) { + bool one_way_collision = tile_data->is_collision_polygon_one_way(body_index, polygon_index); + float one_way_collision_margin = tile_data->get_collision_polygon_one_way_margin(body_index, polygon_index); + + int shapes_count = tile_data->get_collision_polygon_shapes_count(body_index, polygon_index); + for (int shape_index = 0; shape_index < shapes_count; shape_index++) { Transform2D xform = Transform2D(); xform.set_origin(p_tile_map->map_to_world(E_cell->get()) - quadrant_pos); // Add decomposed convex shapes. + Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(body_index, polygon_index, shape_index); ps->body_add_shape(q.bodies[body_index], shape->get_rid(), xform); ps->body_set_shape_metadata(q.bodies[body_index], shape_index, E_cell->get()); ps->body_set_shape_as_one_way_collision(q.bodies[body_index], shape_index, one_way_collision, one_way_collision_margin); @@ -4341,11 +4294,13 @@ void TileSetPluginAtlasPhysics::draw_quadrant_debug(TileMap *p_tile_map, TileMap TileData *tile_data = Object::cast_to<TileData>(atlas_source->get_tile_data(c.get_atlas_coords(), c.alternative_tile)); for (int body_index = 0; body_index < p_quadrant->bodies.size(); body_index++) { - for (int shape_index = 0; shape_index < tile_data->get_collision_shapes_count(body_index); shape_index++) { - // Draw the debug shape. - Ref<Shape2D> shape = tile_data->get_collision_shape_shape(body_index, shape_index); - if (shape.is_valid()) { - shape->draw(p_quadrant->debug_canvas_item, debug_collision_color); + for (int polygon_index = 0; polygon_index < tile_data->get_collision_polygons_count(body_index); polygon_index++) { + // Draw the debug polygon. + Vector<Vector2> polygon = tile_data->get_collision_polygon_points(body_index, polygon_index); + if (polygon.size() >= 3) { + Vector<Color> color; + color.push_back(debug_collision_color); + rs->canvas_item_add_polygon(p_quadrant->debug_canvas_item, polygon, color); } } } @@ -4585,7 +4540,7 @@ void TileSetPluginScenesCollections::update_dirty_quadrants(TileMap *p_tile_map, if (scenes_collection_source) { Ref<PackedScene> packed_scene = scenes_collection_source->get_scene_tile_scene(c.alternative_tile); if (packed_scene.is_valid()) { - Node *scene = packed_scene->instance(); + Node *scene = packed_scene->instantiate(); p_tile_map->add_child(scene); Control *scene_as_control = Object::cast_to<Control>(scene); Node2D *scene_as_node2d = Object::cast_to<Node2D>(scene); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 6cf4198f30..dbf6dbabe6 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -33,19 +33,18 @@ #include "core/io/resource.h" #include "core/object/object.h" +#include "core/templates/local_vector.h" #include "scene/2d/light_occluder_2d.h" #include "scene/2d/navigation_region_2d.h" #include "scene/main/canvas_item.h" +#include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" #include "scene/resources/packed_scene.h" #include "scene/resources/physics_material.h" #include "scene/resources/shape_2d.h" #ifndef DISABLE_DEPRECATED -#include "scene/2d/light_occluder_2d.h" -#include "scene/2d/navigation_region_2d.h" #include "scene/resources/shader.h" -#include "scene/resources/shape_2d.h" #include "scene/resources/texture.h" #endif @@ -60,7 +59,6 @@ class TileSetPlugin; class TileSetPluginAtlasRendering; class TileSetPluginAtlasPhysics; class TileSetPluginAtlasNavigation; -class TileSetPluginAtlasTerrain; class TileSet : public Resource { GDCLASS(TileSet, Resource); @@ -138,6 +136,8 @@ public: CELL_NEIGHBOR_MAX, }; + static const char *CELL_NEIGHBOR_ENUM_TO_TEXT[]; + enum TerrainMode { TERRAIN_MODE_MATCH_CORNERS_AND_SIDES = 0, TERRAIN_MODE_MATCH_CORNERS, @@ -194,6 +194,10 @@ private: }; Vector<OcclusionLayer> occlusion_layers; + Ref<ArrayMesh> tile_lines_mesh; + Ref<ArrayMesh> tile_filled_mesh; + bool tile_meshes_dirty = true; + // Physics struct PhysicsLayer { uint32_t collision_layer = 1; @@ -213,6 +217,9 @@ private: }; Vector<TerrainSet> terrain_sets; + Map<TerrainMode, Map<CellNeighbor, Ref<ArrayMesh>>> terrain_bits_meshes; + bool terrain_bits_meshes_dirty = true; + // Navigation struct Navigationlayer { uint32_t layers = 1; @@ -239,6 +246,19 @@ private: void _compute_next_source_id(); void _source_changed(); + // Helpers + Vector<Point2> _get_square_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_square_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_square_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + + Vector<Point2> _get_isometric_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_isometric_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + Vector<Point2> _get_isometric_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit); + + Vector<Point2> _get_half_offset_corner_or_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); + Vector<Point2> _get_half_offset_corner_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); + Vector<Point2> _get_half_offset_side_terrain_bit_polygon(Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); + protected: static void _bind_methods(); @@ -257,8 +277,6 @@ public: TileOffsetAxis get_tile_offset_axis() const; void set_tile_size(Size2i p_size); Size2i get_tile_size() const; - void set_tile_skew(Vector2 p_skew); - Vector2 get_tile_skew() const; // -- Sources management -- int get_next_source_id() const; @@ -305,6 +323,7 @@ public: String get_terrain_name(int p_terrain_set, int p_terrain_index) const; void set_terrain_color(int p_terrain_set, int p_terrain_index, Color p_color); Color get_terrain_color(int p_terrain_set, int p_terrain_index) const; + bool is_valid_peering_bit_for_mode(TileSet::TerrainMode p_terrain_mode, TileSet::CellNeighbor p_peering_bit) const; bool is_valid_peering_bit_terrain(int p_terrain_set, TileSet::CellNeighbor p_peering_bit) const; // Navigation @@ -323,8 +342,14 @@ public: Variant::Type get_custom_data_type(int p_layer_id) const; // Helpers + Vector<Vector2> get_tile_shape_polygon(); void draw_tile_shape(CanvasItem *p_canvas_item, Rect2 p_region, Color p_color, bool p_filled = false, Ref<Texture2D> p_texture = Ref<Texture2D>()); + Vector<Point2> get_terrain_bit_polygon(int p_terrain_set, TileSet::CellNeighbor p_bit); + void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, const TileData *p_tile_data); + Vector<Vector<Ref<Texture2D>>> generate_terrains_icons(Size2i p_size); + + // Resource management virtual void reset_state() override; TileSet(); @@ -509,13 +534,14 @@ private: // Physics struct PhysicsLayerTileData { - struct ShapeTileData { - Ref<Shape2D> shape = Ref<Shape2D>(); + struct PolygonShapeTileData { + LocalVector<Vector2> polygon; + LocalVector<Ref<ConvexPolygonShape2D>> shapes; bool one_way = false; float one_way_margin = 1.0; }; - Vector<ShapeTileData> shapes; + Vector<PolygonShapeTileData> polygons; }; Vector<PhysicsLayerTileData> physics; // TODO add support for areas. @@ -570,16 +596,18 @@ public: Ref<OccluderPolygon2D> get_occluder(int p_layer_id) const; // Physics - int get_collision_shapes_count(int p_layer_id) const; - void set_collision_shapes_count(int p_layer_id, int p_shapes_count); - void add_collision_shape(int p_layer_id); - void remove_collision_shape(int p_layer_id, int p_shape_index); - void set_collision_shape_shape(int p_layer_id, int p_shape_index, Ref<Shape2D> p_shape); - Ref<Shape2D> get_collision_shape_shape(int p_layer_id, int p_shape_index) const; - void set_collision_shape_one_way(int p_layer_id, int p_shape_index, bool p_one_way); - bool is_collision_shape_one_way(int p_layer_id, int p_shape_index) const; - void set_collision_shape_one_way_margin(int p_layer_id, int p_shape_index, float p_one_way_margin); - float get_collision_shape_one_way_margin(int p_layer_id, int p_shape_index) const; + int get_collision_polygons_count(int p_layer_id) const; + void set_collision_polygons_count(int p_layer_id, int p_shapes_count); + void add_collision_polygon(int p_layer_id); + void remove_collision_polygon(int p_layer_id, int p_polygon_index); + void set_collision_polygon_points(int p_layer_id, int p_polygon_index, Vector<Vector2> p_polygon); + Vector<Vector2> get_collision_polygon_points(int p_layer_id, int p_polygon_index) const; + void set_collision_polygon_one_way(int p_layer_id, int p_polygon_index, bool p_one_way); + bool is_collision_polygon_one_way(int p_layer_id, int p_polygon_index) const; + void set_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index, float p_one_way_margin); + float get_collision_polygon_one_way_margin(int p_layer_id, int p_polygon_index) const; + int get_collision_polygon_shapes_count(int p_layer_id, int p_polygon_index) const; + Ref<ConvexPolygonShape2D> get_collision_polygon_shape(int p_layer_id, int p_polygon_index, int shape_index) const; // Terrain void set_terrain_set(int p_terrain_id); @@ -637,26 +665,6 @@ public: static void draw_tile(RID p_canvas_item, Vector2i p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, Vector2i p_atlas_coords, int p_alternative_tile, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0)); }; -class TileSetPluginAtlasTerrain : public TileSetPlugin { - GDCLASS(TileSetPluginAtlasTerrain, TileSetPlugin); - -private: - static void _draw_square_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_square_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_square_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - - static void _draw_isometric_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_isometric_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - static void _draw_isometric_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit); - - static void _draw_half_offset_corner_or_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); - static void _draw_half_offset_corner_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); - static void _draw_half_offset_side_terrain_bit(CanvasItem *p_canvas_item, Color p_color, Vector2i p_size, TileSet::CellNeighbor p_bit, float p_overlap, TileSet::TileOffsetAxis p_offset_axis); - -public: - static void draw_terrains(CanvasItem *p_canvas_item, Transform2D p_transform, TileSet *p_tile_set, const TileData *p_tile_data); -}; - class TileSetPluginAtlasPhysics : public TileSetPlugin { GDCLASS(TileSetPluginAtlasPhysics, TileSetPlugin); diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index f37b1a3e8e..36a1c206c8 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -33,6 +33,7 @@ #include "core/templates/vmap.h" #include "servers/rendering/shader_types.h" #include "visual_shader_nodes.h" +#include "visual_shader_particle_nodes.h" #include "visual_shader_sdf_nodes.h" bool VisualShaderNode::is_simple_decl() const { @@ -60,6 +61,20 @@ Variant VisualShaderNode::get_input_port_default_value(int p_port) const { return Variant(); } +void VisualShaderNode::remove_input_port_default_value(int p_port) { + if (default_input_values.has(p_port)) { + default_input_values.erase(p_port); + emit_changed(); + } +} + +void VisualShaderNode::clear_default_input_values() { + if (!default_input_values.is_empty()) { + default_input_values.clear(); + emit_changed(); + } +} + bool VisualShaderNode::is_port_separator(int p_index) const { return false; } @@ -220,6 +235,9 @@ void VisualShaderNode::_bind_methods() { ClassDB::bind_method(D_METHOD("set_input_port_default_value", "port", "value"), &VisualShaderNode::set_input_port_default_value); ClassDB::bind_method(D_METHOD("get_input_port_default_value", "port"), &VisualShaderNode::get_input_port_default_value); + ClassDB::bind_method(D_METHOD("remove_input_port_default_value", "port"), &VisualShaderNode::remove_input_port_default_value); + ClassDB::bind_method(D_METHOD("clear_default_input_values"), &VisualShaderNode::clear_default_input_values); + ClassDB::bind_method(D_METHOD("set_default_input_values", "values"), &VisualShaderNode::set_default_input_values); ClassDB::bind_method(D_METHOD("get_default_input_values"), &VisualShaderNode::get_default_input_values); @@ -373,6 +391,18 @@ void VisualShaderNodeCustom::set_default_input_values(const Array &p_values) { } } +void VisualShaderNodeCustom::remove_input_port_default_value(int p_port) { + if (!is_initialized) { + VisualShaderNode::remove_input_port_default_value(p_port); + } +} + +void VisualShaderNodeCustom::clear_default_input_values() { + if (!is_initialized) { + VisualShaderNode::clear_default_input_values(); + } +} + void VisualShaderNodeCustom::_set_input_port_default_value(int p_port, const Variant &p_value) { VisualShaderNode::set_input_port_default_value(p_port, p_value); } @@ -587,7 +617,7 @@ void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_c if (g->nodes[p_id].node->get_class_name() == p_new_class) { return; } - VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(p_new_class)); + VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(p_new_class)); vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update)); g->nodes[p_id].node = Ref<VisualShaderNode>(vsn); @@ -1050,9 +1080,11 @@ static const char *type_string[VisualShader::TYPE_MAX] = { "vertex", "fragment", "light", - "emit", + "start", "process", - "end", + "collide", + "start_custom", + "process_custom", "sky", }; @@ -1328,7 +1360,8 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui return OK; } - code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n"; + String node_name = "// " + vsnode->get_caption() + ":" + itos(node) + "\n"; + String node_code; Vector<String> input_vars; input_vars.resize(vsnode->get_input_port_count()); @@ -1399,21 +1432,21 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui if (defval.get_type() == Variant::FLOAT) { float val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n"; + node_code += "\tfloat " + inputs[i] + " = " + vformat("%.5f", val) + ";\n"; } else if (defval.get_type() == Variant::INT) { int val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - code += "\tint " + inputs[i] + " = " + itos(val) + ";\n"; + node_code += "\tint " + inputs[i] + " = " + itos(val) + ";\n"; } else if (defval.get_type() == Variant::BOOL) { bool val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - code += "\tbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; + node_code += "\tbool " + inputs[i] + " = " + (val ? "true" : "false") + ";\n"; } else if (defval.get_type() == Variant::VECTOR3) { Vector3 val = defval; inputs[i] = "n_in" + itos(node) + "p" + itos(i); - code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z); - } else if (defval.get_type() == Variant::TRANSFORM) { - Transform val = defval; + node_code += "\tvec3 " + inputs[i] + " = " + vformat("vec3(%.5f, %.5f, %.5f);\n", val.x, val.y, val.z); + } else if (defval.get_type() == Variant::TRANSFORM3D) { + Transform3D val = defval; val.basis.transpose(); inputs[i] = "n_in" + itos(node) + "p" + itos(i); Array values; @@ -1426,7 +1459,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui values.push_back(val.origin.y); values.push_back(val.origin.z); bool err = false; - code += "\tmat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err); + node_code += "\tmat4 " + inputs[i] + " = " + String("mat4(vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 0.0), vec4(%.5f, %.5f, %.5f, 1.0));\n").sprintf(values, &err); } else { //will go empty, node is expected to know what it is doing at this point and handle it } @@ -1514,7 +1547,12 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui } } - code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); + node_code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview); + if (node_code != String()) { + code += node_name; + code += node_code; + code += "\n"; + } for (int i = 0; i < output_count; i++) { bool new_line_inserted = false; @@ -1564,7 +1602,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const String &p_func_name) const { if (!ShaderTypes::get_singleton()->get_functions(p_mode).has(p_func_name)) { if (p_mode == RenderingServer::ShaderMode::SHADER_PARTICLES) { - if (p_func_name == "emit" || p_func_name == "process" || p_func_name == "end") { + if (p_func_name == "start_custom" || p_func_name == "process_custom" || p_func_name == "collide") { return true; } } @@ -1645,11 +1683,12 @@ void VisualShader::_update_shader() const { global_code += "render_mode " + render_mode + ";\n\n"; } - static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "emit", "process", "end", "sky" }; + static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light", "start", "process", "collide", "start_custom", "process_custom", "sky" }; String global_expressions; Set<String> used_uniform_names; List<VisualShaderNodeUniform *> uniforms; + Map<int, List<int>> emitters; for (int i = 0, index = 0; i < TYPE_MAX; i++) { if (!has_func_name(RenderingServer::ShaderMode(shader_mode), func_name[i])) { @@ -1674,6 +1713,19 @@ void VisualShader::_update_shader() const { if (uniform.is_valid()) { uniforms.push_back(uniform.ptr()); } + Ref<VisualShaderNodeParticleEmit> emit_particle = Object::cast_to<VisualShaderNodeParticleEmit>(E->get().node.ptr()); + if (emit_particle.is_valid()) { + if (!emitters.has(i)) { + emitters.insert(i, List<int>()); + } + + for (Map<int, Node>::Element *M = graph[i].nodes.front(); M; M = M->next()) { + if (M->get().node == emit_particle.ptr()) { + emitters[i].push_back(M->key()); + break; + } + } + } } } @@ -1722,6 +1774,13 @@ void VisualShader::_update_shader() const { Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes); ERR_FAIL_COND(err != OK); + if (emitters.has(i)) { + for (List<int>::Element *E = emitters[i].front(); E; E = E->next()) { + err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, func_code, default_tex_params, input_connections, output_connections, E->get(), processed, false, classes); + ERR_FAIL_COND(err != OK); + } + } + if (shader_mode == Shader::MODE_PARTICLES) { code_map.insert(i, func_code); } else { @@ -1730,19 +1789,130 @@ void VisualShader::_update_shader() const { } } + String global_compute_code; + if (shader_mode == Shader::MODE_PARTICLES) { - code += "\nvoid compute() {\n"; - code += "\tif (RESTART) {\n"; - code += code_map[TYPE_EMIT]; - code += "\t} else {\n"; - code += code_map[TYPE_PROCESS]; + bool has_start = !code_map[TYPE_START].is_empty(); + bool has_start_custom = !code_map[TYPE_START_CUSTOM].is_empty(); + bool has_process = !code_map[TYPE_PROCESS].is_empty(); + bool has_process_custom = !code_map[TYPE_PROCESS_CUSTOM].is_empty(); + bool has_collide = !code_map[TYPE_COLLIDE].is_empty(); + + code += "void start() {\n"; + if (has_start || has_start_custom) { + code += "\tuint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; + code += "\tvec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; + code += "\tfloat __radians;\n"; + code += "\tvec3 __vec3_buff1;\n"; + code += "\tvec3 __vec3_buff2;\n"; + code += "\tfloat __scalar_buff1;\n"; + code += "\tfloat __scalar_buff2;\n"; + code += "\tvec3 __ndiff = normalize(__diff);\n\n"; + } + if (has_start) { + code += "\t{\n"; + code += code_map[TYPE_START].replace("\n\t", "\n\t\t"); + code += "\t}\n"; + if (has_start_custom) { + code += "\t\n"; + } + } + if (has_start_custom) { + code += "\t{\n"; + code += code_map[TYPE_START_CUSTOM].replace("\n\t", "\n\t\t"); + code += "\t}\n"; + } + code += "}\n\n"; + code += "void process() {\n"; + if (has_process || has_process_custom || has_collide) { + code += "\tuint __seed = __hash(NUMBER + uint(1) + RANDOM_SEED);\n"; + code += "\tvec3 __vec3_buff1;\n"; + code += "\tvec3 __diff = TRANSFORM[3].xyz - EMISSION_TRANSFORM[3].xyz;\n"; + code += "\tvec3 __ndiff = normalize(__diff);\n\n"; + } + code += "\t{\n"; + String tab = "\t"; + if (has_collide) { + code += "\t\tif (COLLIDED) {\n\n"; + code += code_map[TYPE_COLLIDE].replace("\n\t", "\n\t\t\t"); + if (has_process) { + code += "\t\t} else {\n\n"; + tab += "\t"; + } + } + if (has_process) { + code += code_map[TYPE_PROCESS].replace("\n\t", "\n\t" + tab); + } + if (has_collide) { + code += "\t\t}\n"; + } code += "\t}\n"; - code += "}\n"; + + if (has_process_custom) { + code += "\t{\n\n"; + code += code_map[TYPE_PROCESS_CUSTOM].replace("\n\t", "\n\t\t"); + code += "\t}\n"; + } + + code += "}\n\n"; + + global_compute_code += "float __rand_from_seed(inout uint seed) {\n"; + global_compute_code += "\tint k;\n"; + global_compute_code += "\tint s = int(seed);\n"; + global_compute_code += "\tif (s == 0)\n"; + global_compute_code += "\ts = 305420679;\n"; + global_compute_code += "\tk = s / 127773;\n"; + global_compute_code += "\ts = 16807 * (s - k * 127773) - 2836 * k;\n"; + global_compute_code += "\tif (s < 0)\n"; + global_compute_code += "\t\ts += 2147483647;\n"; + global_compute_code += "\tseed = uint(s);\n"; + global_compute_code += "\treturn float(seed % uint(65536)) / 65535.0;\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "float __rand_from_seed_m1_p1(inout uint seed) {\n"; + global_compute_code += "\treturn __rand_from_seed(seed) * 2.0 - 1.0;\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "float __randf_range(inout uint seed, float from, float to) {\n"; + global_compute_code += "\treturn __rand_from_seed(seed) * (to - from) + from;\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "vec3 __randv_range(inout uint seed, vec3 from, vec3 to) {\n"; + global_compute_code += "\treturn vec3(__randf_range(seed, from.x, to.x), __randf_range(seed, from.y, to.y), __randf_range(seed, from.z, to.z));\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "uint __hash(uint x) {\n"; + global_compute_code += "\tx = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + global_compute_code += "\tx = ((x >> uint(16)) ^ x) * uint(73244475);\n"; + global_compute_code += "\tx = (x >> uint(16)) ^ x;\n"; + global_compute_code += "\treturn x;\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "mat3 __build_rotation_mat3(vec3 axis, float angle) {\n"; + global_compute_code += "\taxis = normalize(axis);\n"; + global_compute_code += "\tfloat s = sin(angle);\n"; + global_compute_code += "\tfloat c = cos(angle);\n"; + global_compute_code += "\tfloat oc = 1.0 - c;\n"; + global_compute_code += "\treturn mat3(vec3(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s), vec3(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s), vec3(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c));\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "mat4 __build_rotation_mat4(vec3 axis, float angle) {\n"; + global_compute_code += "\taxis = normalize(axis);\n"; + global_compute_code += "\tfloat s = sin(angle);\n"; + global_compute_code += "\tfloat c = cos(angle);\n"; + global_compute_code += "\tfloat oc = 1.0 - c;\n"; + global_compute_code += "\treturn mat4(vec4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0), vec4(oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0), vec4(oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0), vec4(0, 0, 0, 1));\n"; + global_compute_code += "}\n\n"; + + global_compute_code += "vec3 __get_random_unit_vec3(inout uint seed) {\n"; + global_compute_code += "\treturn normalize(vec3(__rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed), __rand_from_seed_m1_p1(seed)));\n"; + global_compute_code += "}\n\n"; } //set code secretly global_code += "\n\n"; String final_code = global_code; + final_code += global_compute_code; final_code += global_code_per_node; final_code += global_expressions; String tcode = code; @@ -1833,9 +2003,11 @@ void VisualShader::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_VERTEX); BIND_ENUM_CONSTANT(TYPE_FRAGMENT); BIND_ENUM_CONSTANT(TYPE_LIGHT); - BIND_ENUM_CONSTANT(TYPE_EMIT); + BIND_ENUM_CONSTANT(TYPE_START); BIND_ENUM_CONSTANT(TYPE_PROCESS); - BIND_ENUM_CONSTANT(TYPE_END); + BIND_ENUM_CONSTANT(TYPE_COLLIDE); + BIND_ENUM_CONSTANT(TYPE_START_CUSTOM); + BIND_ENUM_CONSTANT(TYPE_PROCESS_CUSTOM); BIND_ENUM_CONSTANT(TYPE_SKY); BIND_ENUM_CONSTANT(TYPE_MAX); @@ -1846,11 +2018,20 @@ void VisualShader::_bind_methods() { VisualShader::VisualShader() { dirty.set(); for (int i = 0; i < TYPE_MAX; i++) { - Ref<VisualShaderNodeOutput> output; - output.instance(); - output->shader_type = Type(i); - output->shader_mode = shader_mode; - graph[i].nodes[NODE_ID_OUTPUT].node = output; + if (i > (int)TYPE_LIGHT && i < (int)TYPE_SKY) { + Ref<VisualShaderNodeParticleOutput> output; + output.instantiate(); + output->shader_type = Type(i); + output->shader_mode = shader_mode; + graph[i].nodes[NODE_ID_OUTPUT].node = output; + } else { + Ref<VisualShaderNodeOutput> output; + output.instantiate(); + output->shader_type = Type(i); + output->shader_mode = shader_mode; + graph[i].nodes[NODE_ID_OUTPUT].node = output; + } + graph[i].nodes[NODE_ID_OUTPUT].position = Vector2(400, 150); } } @@ -1979,27 +2160,45 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular_shininess", "SPECULAR_SHININESS.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "specular_shininess_alpha", "SPECULAR_SHININESS.a" }, - // Particles, Emit - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles, Start + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles, Start (Custom) + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Particles, Process + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, @@ -2009,20 +2208,39 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = { { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - // Particles, End - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "restart", "float(RESTART ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "active", "float(ACTIVE ? 1.0 : 0.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + // Particles, Process (Custom) + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles, Collide + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "attractor_force", "ATTRACTOR_FORCE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "collision_depth", "COLLISION_DEPTH" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "collision_normal", "COLLISION_NORMAL" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "restart", "RESTART" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "delta", "DELTA" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "lifetime", "LIFETIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR_INT, "index", "INDEX" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_TRANSFORM, "emission_transform", "EMISSION_TRANSFORM" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, // Sky, Sky { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_cubemap_pass", "AT_CUBEMAP_PASS" }, @@ -2098,11 +2316,13 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::preview_ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "screen_uv", "vec3(SCREEN_UV, 0.0)" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, - // Particles, Vertex - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "vec3(1.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "1.0" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "vec3(0.0, 0.0, 1.0)" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + + // Particles + { Shader::MODE_PARTICLES, VisualShader::TYPE_START, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_COLLIDE, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_START_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, + { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS_CUSTOM, VisualShaderNode::PORT_TYPE_SCALAR, "time", "TIME" }, { Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr }, }; @@ -2313,6 +2533,14 @@ Vector<StringName> VisualShaderNodeInput::get_editable_properties() const { return props; } +void VisualShaderNodeInput::set_shader_type(VisualShader::Type p_shader_type) { + shader_type = p_shader_type; +} + +void VisualShaderNodeInput::set_shader_mode(Shader::Mode p_shader_mode) { + shader_mode = p_shader_mode; +} + void VisualShaderNodeInput::_bind_methods() { ClassDB::bind_method(D_METHOD("set_input_name", "name"), &VisualShaderNodeInput::set_input_name); ClassDB::bind_method(D_METHOD("get_input_name"), &VisualShaderNodeInput::get_input_name); @@ -2480,6 +2708,28 @@ VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_ return UniformType::UNIFORM_TYPE_FLOAT; } +VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_port_type_by_index(int p_idx) const { + if (p_idx >= 0 && p_idx < uniforms.size()) { + switch (uniforms[p_idx].type) { + case UniformType::UNIFORM_TYPE_FLOAT: + return PORT_TYPE_SCALAR; + case UniformType::UNIFORM_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case UniformType::UNIFORM_TYPE_SAMPLER: + return PORT_TYPE_SAMPLER; + case UniformType::UNIFORM_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case UniformType::UNIFORM_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + case UniformType::UNIFORM_TYPE_COLOR: + return PORT_TYPE_VECTOR; + default: + break; + } + } + return PORT_TYPE_SCALAR; +} + String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { switch (uniform_type) { case UniformType::UNIFORM_TYPE_FLOAT: @@ -2595,30 +2845,7 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { // Canvas Item, Light { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "light", "LIGHT.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "light_alpha", "LIGHT.a" }, - // Particles, Emit - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_EMIT, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - // Particles, Process - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_PROCESS, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, - // Particles, End - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "velocity", "VELOCITY" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_VECTOR, "custom", "CUSTOM.rgb" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_SCALAR, "custom_alpha", "CUSTOM.a" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_TRANSFORM, "transform", "TRANSFORM" }, - { Shader::MODE_PARTICLES, VisualShader::TYPE_END, VisualShaderNode::PORT_TYPE_BOOLEAN, "active", "ACTIVE" }, + // Sky, Sky { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR" }, { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" }, diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index aa7768751e..880c401b29 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -51,9 +51,11 @@ public: TYPE_VERTEX, TYPE_FRAGMENT, TYPE_LIGHT, - TYPE_EMIT, + TYPE_START, TYPE_PROCESS, - TYPE_END, + TYPE_COLLIDE, + TYPE_START_CUSTOM, + TYPE_PROCESS_CUSTOM, TYPE_SKY, TYPE_MAX }; @@ -230,6 +232,8 @@ public: Variant get_input_port_default_value(int p_port) const; // if NIL (default if node does not set anything) is returned, it means no default value is wanted if disconnected, thus no input var must be supplied (empty string will be supplied) Array get_default_input_values() const; virtual void set_default_input_values(const Array &p_values); + virtual void remove_input_port_default_value(int p_port); + virtual void clear_default_input_values(); virtual int get_output_port_count() const = 0; virtual PortType get_output_port_type(int p_port) const = 0; @@ -305,6 +309,8 @@ protected: virtual void set_input_port_default_value(int p_port, const Variant &p_value) override; virtual void set_default_input_values(const Array &p_values) override; + virtual void remove_input_port_default_value(int p_port) override; + virtual void clear_default_input_values() override; protected: void _set_input_port_default_value(int p_port, const Variant &p_value); @@ -344,6 +350,10 @@ class VisualShaderNodeInput : public VisualShaderNode { String input_name = "[None]"; +public: + void set_shader_type(VisualShader::Type p_shader_type); + void set_shader_mode(Shader::Mode p_shader_mode); + protected: static void _bind_methods(); void _validate_property(PropertyInfo &property) const override; @@ -507,6 +517,7 @@ public: String get_uniform_name_by_index(int p_idx) const; UniformType get_uniform_type_by_name(const String &p_name) const; UniformType get_uniform_type_by_index(int p_idx) const; + PortType get_port_type_by_index(int p_idx) const; virtual Vector<StringName> get_editable_properties() const override; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index e7cc78cb3a..4e73b8db44 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -341,10 +341,10 @@ void VisualShaderNodeVec3Constant::_bind_methods() { VisualShaderNodeVec3Constant::VisualShaderNodeVec3Constant() { } -////////////// Transform +////////////// Transform3D String VisualShaderNodeTransformConstant::get_caption() const { - return "Transform"; + return "Transform3D"; } int VisualShaderNodeTransformConstant::get_input_port_count() const { @@ -372,7 +372,7 @@ String VisualShaderNodeTransformConstant::get_output_port_name(int p_port) const } String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { - Transform t = constant; + Transform3D t = constant; t.basis.transpose(); String code = "\t" + p_output_vars[0] + " = mat4("; @@ -383,12 +383,12 @@ String VisualShaderNodeTransformConstant::generate_code(Shader::Mode p_mode, Vis return code; } -void VisualShaderNodeTransformConstant::set_constant(Transform p_value) { +void VisualShaderNodeTransformConstant::set_constant(Transform3D p_value) { constant = p_value; emit_changed(); } -Transform VisualShaderNodeTransformConstant::get_constant() const { +Transform3D VisualShaderNodeTransformConstant::get_constant() const { return constant; } @@ -402,7 +402,7 @@ void VisualShaderNodeTransformConstant::_bind_methods() { ClassDB::bind_method(D_METHOD("set_constant", "value"), &VisualShaderNodeTransformConstant::set_constant); ClassDB::bind_method(D_METHOD("get_constant"), &VisualShaderNodeTransformConstant::get_constant); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "constant"), "set_constant", "get_constant"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "constant"), "set_constant", "get_constant"); } VisualShaderNodeTransformConstant::VisualShaderNodeTransformConstant() { @@ -805,7 +805,7 @@ void VisualShaderNodeTexture::_bind_methods() { VisualShaderNodeTexture::VisualShaderNodeTexture() { } -////////////// Curve +////////////// CurveTexture String VisualShaderNodeCurveTexture::get_caption() const { return "CurveTexture"; @@ -860,7 +860,7 @@ String VisualShaderNodeCurveTexture::generate_code(Shader::Mode p_mode, VisualSh } String id = make_unique_id(p_type, p_id, "curve"); String code; - code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ", 0.0)).r;\n"; + code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).r;\n"; return code; } @@ -889,6 +889,90 @@ VisualShaderNodeCurveTexture::VisualShaderNodeCurveTexture() { allow_v_resize = false; } +////////////// Curve3Texture + +String VisualShaderNodeCurve3Texture::get_caption() const { + return "Curve3Texture"; +} + +int VisualShaderNodeCurve3Texture::get_input_port_count() const { + return 1; +} + +VisualShaderNodeCurve3Texture::PortType VisualShaderNodeCurve3Texture::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeCurve3Texture::get_input_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeCurve3Texture::get_output_port_count() const { + return 1; +} + +VisualShaderNodeCurve3Texture::PortType VisualShaderNodeCurve3Texture::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeCurve3Texture::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeCurve3Texture::set_texture(Ref<Curve3Texture> p_texture) { + texture = p_texture; + emit_changed(); +} + +Ref<Curve3Texture> VisualShaderNodeCurve3Texture::get_texture() const { + return texture; +} + +Vector<StringName> VisualShaderNodeCurve3Texture::get_editable_properties() const { + Vector<StringName> props; + props.push_back("texture"); + return props; +} + +String VisualShaderNodeCurve3Texture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "curve3d") + ";\n"; +} + +String VisualShaderNodeCurve3Texture::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + if (p_input_vars[0] == String()) { + return "\t" + p_output_vars[0] + " = vec3(0.0);\n"; + } + String id = make_unique_id(p_type, p_id, "curve3d"); + String code; + code += "\t" + p_output_vars[0] + " = texture(" + id + ", vec2(" + p_input_vars[0] + ")).rgb;\n"; + return code; +} + +Vector<VisualShader::DefaultTextureParam> VisualShaderNodeCurve3Texture::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const { + VisualShader::DefaultTextureParam dtp; + dtp.name = make_unique_id(p_type, p_id, "curve3d"); + dtp.param = texture; + Vector<VisualShader::DefaultTextureParam> ret; + ret.push_back(dtp); + return ret; +} + +void VisualShaderNodeCurve3Texture::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_texture", "texture"), &VisualShaderNodeCurve3Texture::set_texture); + ClassDB::bind_method(D_METHOD("get_texture"), &VisualShaderNodeCurve3Texture::get_texture); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Curve3Texture"), "set_texture", "get_texture"); +} + +bool VisualShaderNodeCurve3Texture::is_use_prop_slots() const { + return true; +} + +VisualShaderNodeCurve3Texture::VisualShaderNodeCurve3Texture() { + simple_decl = true; + allow_v_resize = false; +} + ////////////// Sample3D int VisualShaderNodeSample3D::get_input_port_count() const { @@ -1901,8 +1985,8 @@ void VisualShaderNodeTransformMult::_bind_methods() { } VisualShaderNodeTransformMult::VisualShaderNodeTransformMult() { - set_input_port_default_value(0, Transform()); - set_input_port_default_value(1, Transform()); + set_input_port_default_value(0, Transform3D()); + set_input_port_default_value(1, Transform3D()); } ////////////// TransformVec Mult @@ -1975,7 +2059,7 @@ void VisualShaderNodeTransformVecMult::_bind_methods() { } VisualShaderNodeTransformVecMult::VisualShaderNodeTransformVecMult() { - set_input_port_default_value(0, Transform()); + set_input_port_default_value(0, Transform3D()); set_input_port_default_value(1, Vector3()); } @@ -2496,7 +2580,144 @@ void VisualShaderNodeTransformFunc::_bind_methods() { } VisualShaderNodeTransformFunc::VisualShaderNodeTransformFunc() { - set_input_port_default_value(0, Transform()); + set_input_port_default_value(0, Transform3D()); +} + +////////////// UV Func + +String VisualShaderNodeUVFunc::get_caption() const { + return "UVFunc"; +} + +int VisualShaderNodeUVFunc::get_input_port_count() const { + return 3; +} + +VisualShaderNodeUVFunc::PortType VisualShaderNodeUVFunc::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + [[fallthrough]]; // uv + case 1: + return PORT_TYPE_VECTOR; // scale + case 2: + return PORT_TYPE_VECTOR; // offset & pivot + default: + break; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeUVFunc::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "uv"; + case 1: + return "scale"; + case 2: + switch (func) { + case FUNC_PANNING: + return "offset"; + case FUNC_SCALING: + return "pivot"; + case FUNC_MAX: + break; + default: + break; + } + break; + default: + break; + } + return ""; +} + +String VisualShaderNodeUVFunc::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "UV"; + } + return ""; +} + +int VisualShaderNodeUVFunc::get_output_port_count() const { + return 1; +} + +VisualShaderNodeUVFunc::PortType VisualShaderNodeUVFunc::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeUVFunc::get_output_port_name(int p_port) const { + return "uv"; +} + +bool VisualShaderNodeUVFunc::is_show_prop_names() const { + return true; +} + +String VisualShaderNodeUVFunc::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + + String uv; + if (p_input_vars[0].is_empty()) { + uv = "vec3(UV.xy, 0.0)"; + } else { + uv = vformat("%s", p_input_vars[0]); + } + String scale = vformat("%s", p_input_vars[1]); + String offset_pivot = vformat("%s", p_input_vars[2]); + + switch (func) { + case FUNC_PANNING: { + code += vformat("\t%s = fma(%s, %s, %s);\n", p_output_vars[0], offset_pivot, scale, uv); + } break; + case FUNC_SCALING: { + code += vformat("\t%s = fma((%s - %s), %s, %s);\n", p_output_vars[0], uv, offset_pivot, scale, offset_pivot); + } break; + case FUNC_MAX: + break; + } + return code; +} + +void VisualShaderNodeUVFunc::set_function(VisualShaderNodeUVFunc::Function p_func) { + ERR_FAIL_INDEX(int(p_func), FUNC_MAX); + if (func == p_func) { + return; + } + func = p_func; + + if (p_func == FUNC_PANNING) { + set_input_port_default_value(2, Vector3()); // offset + } else { // FUNC_SCALING + set_input_port_default_value(2, Vector3(0.5, 0.5, 0.0)); // pivot + } + emit_changed(); +} + +VisualShaderNodeUVFunc::Function VisualShaderNodeUVFunc::get_function() const { + return func; +} + +Vector<StringName> VisualShaderNodeUVFunc::get_editable_properties() const { + Vector<StringName> props; + props.push_back("function"); + return props; +} + +void VisualShaderNodeUVFunc::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeUVFunc::set_function); + ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeUVFunc::get_function); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Panning,Scaling"), "set_function", "get_function"); + + BIND_ENUM_CONSTANT(FUNC_PANNING); + BIND_ENUM_CONSTANT(FUNC_SCALING); + BIND_ENUM_CONSTANT(FUNC_MAX); +} + +VisualShaderNodeUVFunc::VisualShaderNodeUVFunc() { + set_input_port_default_value(1, Vector3(1.0, 1.0, 0.0)); // scale + set_input_port_default_value(2, Vector3()); // offset } ////////////// Dot Product @@ -2611,7 +2832,7 @@ String VisualShaderNodeDeterminant::generate_code(Shader::Mode p_mode, VisualSha } VisualShaderNodeDeterminant::VisualShaderNodeDeterminant() { - set_input_port_default_value(0, Transform()); + set_input_port_default_value(0, Transform3D()); } ////////////// Scalar Derivative Function @@ -3622,7 +3843,7 @@ String VisualShaderNodeTransformDecompose::generate_code(Shader::Mode p_mode, Vi } VisualShaderNodeTransformDecompose::VisualShaderNodeTransformDecompose() { - set_input_port_default_value(0, Transform()); + set_input_port_default_value(0, Transform3D()); } ////////////// Float Uniform @@ -4308,12 +4529,12 @@ bool VisualShaderNodeTransformUniform::is_default_value_enabled() const { return default_value_enabled; } -void VisualShaderNodeTransformUniform::set_default_value(const Transform &p_value) { +void VisualShaderNodeTransformUniform::set_default_value(const Transform3D &p_value) { default_value = p_value; emit_changed(); } -Transform VisualShaderNodeTransformUniform::get_default_value() const { +Transform3D VisualShaderNodeTransformUniform::get_default_value() const { return default_value; } @@ -4342,7 +4563,7 @@ void VisualShaderNodeTransformUniform::_bind_methods() { ClassDB::bind_method(D_METHOD("get_default_value"), &VisualShaderNodeTransformUniform::get_default_value); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "default_value_enabled"), "set_default_value_enabled", "is_default_value_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "default_value"), "set_default_value", "get_default_value"); } bool VisualShaderNodeTransformUniform::is_show_prop_names() const { @@ -5025,8 +5246,8 @@ void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) { set_input_port_default_value(2, false); break; case OP_TYPE_TRANSFORM: - set_input_port_default_value(1, Transform()); - set_input_port_default_value(2, Transform()); + set_input_port_default_value(1, Transform3D()); + set_input_port_default_value(2, Transform3D()); break; default: break; @@ -5405,8 +5626,8 @@ void VisualShaderNodeCompare::set_comparison_type(ComparisonType p_type) { simple_decl = true; break; case CTYPE_TRANSFORM: - set_input_port_default_value(0, Transform()); - set_input_port_default_value(1, Transform()); + set_input_port_default_value(0, Transform3D()); + set_input_port_default_value(1, Transform3D()); simple_decl = true; break; } diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 1c70459e3b..3ae79723e9 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -209,7 +209,7 @@ public: class VisualShaderNodeTransformConstant : public VisualShaderNodeConstant { GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNodeConstant); - Transform constant; + Transform3D constant; protected: static void _bind_methods(); @@ -227,8 +227,8 @@ public: virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; - void set_constant(Transform p_value); - Transform get_constant() const; + void set_constant(Transform3D p_value); + Transform3D get_constant() const; virtual Vector<StringName> get_editable_properties() const override; @@ -338,6 +338,39 @@ public: /////////////////////////////////////// +class VisualShaderNodeCurve3Texture : public VisualShaderNodeResizableBase { + GDCLASS(VisualShaderNodeCurve3Texture, VisualShaderNodeResizableBase); + Ref<Curve3Texture> texture; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const override; + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_texture(Ref<Curve3Texture> p_value); + Ref<Curve3Texture> get_texture() const; + + virtual Vector<StringName> get_editable_properties() const override; + virtual bool is_use_prop_slots() const override; + + VisualShaderNodeCurve3Texture(); +}; + +/////////////////////////////////////// + class VisualShaderNodeSample3D : public VisualShaderNode { GDCLASS(VisualShaderNodeSample3D, VisualShaderNode); @@ -1019,6 +1052,51 @@ public: VARIANT_ENUM_CAST(VisualShaderNodeTransformFunc::Function) /////////////////////////////////////// +/// UV FUNC +/////////////////////////////////////// + +class VisualShaderNodeUVFunc : public VisualShaderNode { + GDCLASS(VisualShaderNodeUVFunc, VisualShaderNode); + +public: + enum Function { + FUNC_PANNING, + FUNC_SCALING, + FUNC_MAX, + }; + +protected: + Function func = FUNC_PANNING; + + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual String get_input_port_default_hint(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual bool is_show_prop_names() const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_function(Function p_op); + Function get_function() const; + + virtual Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeUVFunc(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeUVFunc::Function) + +/////////////////////////////////////// /// DOT /////////////////////////////////////// @@ -1788,7 +1866,7 @@ class VisualShaderNodeTransformUniform : public VisualShaderNodeUniform { private: bool default_value_enabled = false; - Transform default_value = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); + Transform3D default_value = Transform3D(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0); protected: static void _bind_methods(); @@ -1813,8 +1891,8 @@ public: void set_default_value_enabled(bool p_enabled); bool is_default_value_enabled() const; - void set_default_value(const Transform &p_value); - Transform get_default_value() const; + void set_default_value(const Transform3D &p_value); + Transform3D get_default_value() const; bool is_qualifier_supported(Qualifier p_qual) const override; bool is_convertible_to_constant() const override; diff --git a/scene/resources/visual_shader_particle_nodes.cpp b/scene/resources/visual_shader_particle_nodes.cpp new file mode 100644 index 0000000000..29d583a82a --- /dev/null +++ b/scene/resources/visual_shader_particle_nodes.cpp @@ -0,0 +1,1025 @@ +/*************************************************************************/ +/* visual_shader_particle_nodes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#include "visual_shader_particle_nodes.h" + +// VisualShaderNodeParticleEmitter + +int VisualShaderNodeParticleEmitter::get_output_port_count() const { + return 1; +} + +VisualShaderNodeParticleEmitter::PortType VisualShaderNodeParticleEmitter::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeParticleEmitter::get_output_port_name(int p_port) const { + if (p_port == 0) { + return "position"; + } + return String(); +} + +VisualShaderNodeParticleEmitter::VisualShaderNodeParticleEmitter() { +} + +// VisualShaderNodeParticleSphereEmitter + +String VisualShaderNodeParticleSphereEmitter::get_caption() const { + return "SphereEmitter"; +} + +int VisualShaderNodeParticleSphereEmitter::get_input_port_count() const { + return 2; +} + +VisualShaderNodeParticleSphereEmitter::PortType VisualShaderNodeParticleSphereEmitter::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleSphereEmitter::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "radius"; + } else if (p_port == 1) { + return "inner_radius"; + } + return String(); +} + +String VisualShaderNodeParticleSphereEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code; + code += "vec3 __get_random_point_in_sphere(inout uint seed, float radius, float inner_radius) {\n"; + code += "\treturn __get_random_unit_vec3(seed) * __randf_range(seed, inner_radius, radius);\n"; + code += "}\n\n"; + return code; +} + +String VisualShaderNodeParticleSphereEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + code += "\t" + p_output_vars[0] + " = __get_random_point_in_sphere(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; + return code; +} + +VisualShaderNodeParticleSphereEmitter::VisualShaderNodeParticleSphereEmitter() { + set_input_port_default_value(0, 10.0); + set_input_port_default_value(1, 0.0); +} + +// VisualShaderNodeParticleBoxEmitter + +String VisualShaderNodeParticleBoxEmitter::get_caption() const { + return "BoxEmitter"; +} + +int VisualShaderNodeParticleBoxEmitter::get_input_port_count() const { + return 1; +} + +VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleBoxEmitter::get_input_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleBoxEmitter::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "extents"; + } + return String(); +} + +String VisualShaderNodeParticleBoxEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code; + code += "vec3 __get_random_point_in_box(inout uint seed, vec3 extents) {\n"; + code += "\tvec3 half_extents = extents / 2.0;\n"; + code += "\treturn vec3(__randf_range(seed, -half_extents.x, half_extents.x), __randf_range(seed, -half_extents.y, half_extents.y), __randf_range(seed, -half_extents.z, half_extents.z));\n"; + code += "}\n\n"; + return code; +} + +String VisualShaderNodeParticleBoxEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + code += "\t" + p_output_vars[0] + " = __get_random_point_in_box(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ");\n"; + return code; +} + +VisualShaderNodeParticleBoxEmitter::VisualShaderNodeParticleBoxEmitter() { + set_input_port_default_value(0, Vector3(1.0, 1.0, 1.0)); +} + +// VisualShaderNodeParticleRingEmitter + +String VisualShaderNodeParticleRingEmitter::get_caption() const { + return "RingEmitter"; +} + +int VisualShaderNodeParticleRingEmitter::get_input_port_count() const { + return 3; +} + +VisualShaderNodeParticleRingEmitter::PortType VisualShaderNodeParticleRingEmitter::get_input_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleRingEmitter::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "radius"; + } else if (p_port == 1) { + return "inner_radius"; + } else if (p_port == 2) { + return "height"; + } + return String(); +} + +String VisualShaderNodeParticleRingEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + String code; + code += "vec3 __get_random_point_on_ring(inout uint seed, float radius, float inner_radius, float height) {\n"; + code += "\tfloat angle = __rand_from_seed(seed) * PI * 2.0;\n"; + code += "\tvec2 ring = vec2(sin(angle), cos(angle)) * __randf_range(seed, inner_radius, radius);\n"; + code += "\treturn vec3(ring.x, __randf_range(seed, min(0.0, height), max(0.0, height)), ring.y);\n"; + code += "}\n\n"; + return code; +} + +String VisualShaderNodeParticleRingEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + code = "\t" + p_output_vars[0] + " = __get_random_point_on_ring(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ");\n"; + return code; +} + +VisualShaderNodeParticleRingEmitter::VisualShaderNodeParticleRingEmitter() { + set_input_port_default_value(0, 10.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); +} + +// VisualShaderNodeParticleMultiplyByAxisAngle + +void VisualShaderNodeParticleMultiplyByAxisAngle::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_degrees_mode", "enabled"), &VisualShaderNodeParticleMultiplyByAxisAngle::set_degrees_mode); + ClassDB::bind_method(D_METHOD("is_degrees_mode"), &VisualShaderNodeParticleMultiplyByAxisAngle::is_degrees_mode); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "degrees_mode"), "set_degrees_mode", "is_degrees_mode"); +} + +String VisualShaderNodeParticleMultiplyByAxisAngle::get_caption() const { + return "MultiplyByAxisAngle"; +} + +int VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_count() const { + return 3; +} + +VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_type(int p_port) const { + if (p_port == 0 || p_port == 1) { // position, rotation_axis + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; // angle (degrees/radians) +} + +String VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "position"; + } + if (p_port == 1) { + return "axis"; + } + if (p_port == 2) { + if (degrees_mode) { + return "angle (degrees)"; + } else { + return "angle (radians)"; + } + } + return String(); +} + +bool VisualShaderNodeParticleMultiplyByAxisAngle::is_show_prop_names() const { + return true; +} + +int VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_count() const { + return 1; +} + +VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_name(int p_port) const { + return "position"; +} + +String VisualShaderNodeParticleMultiplyByAxisAngle::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + if (degrees_mode) { + code += "\t" + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", radians(" + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ")) * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n"; + } else { + code += "\t" + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ") * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n"; + } + return code; +} + +void VisualShaderNodeParticleMultiplyByAxisAngle::set_degrees_mode(bool p_enabled) { + degrees_mode = p_enabled; + emit_changed(); +} + +bool VisualShaderNodeParticleMultiplyByAxisAngle::is_degrees_mode() const { + return degrees_mode; +} + +Vector<StringName> VisualShaderNodeParticleMultiplyByAxisAngle::get_editable_properties() const { + Vector<StringName> props; + props.push_back("degrees_mode"); + props.push_back("axis_amount"); + return props; +} + +VisualShaderNodeParticleMultiplyByAxisAngle::VisualShaderNodeParticleMultiplyByAxisAngle() { + set_input_port_default_value(1, Vector3(1, 0, 0)); + set_input_port_default_value(2, 0.0); +} + +// VisualShaderNodeParticleConeVelocity + +String VisualShaderNodeParticleConeVelocity::get_caption() const { + return "ConeVelocity"; +} + +int VisualShaderNodeParticleConeVelocity::get_input_port_count() const { + return 2; +} + +VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_input_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_VECTOR; + } else if (p_port == 1) { + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleConeVelocity::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "direction"; + } else if (p_port == 1) { + return "spread(degrees)"; + } + return String(); +} + +int VisualShaderNodeParticleConeVelocity::get_output_port_count() const { + return 1; +} + +VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) const { + if (p_port == 0) { + return "velocity"; + } + return String(); +} + +String VisualShaderNodeParticleConeVelocity::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + code += "\t__radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n"; + code += "\t__scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; + code += "\t__scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n"; + code += "\t__vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n"; + code += "\t__scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n"; + code += "\t__scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n"; + code += "\t__vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n"; + code += "\t__vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n"; + code += "\t__vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n"; + code += "\t" + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n"; + return code; +} + +VisualShaderNodeParticleConeVelocity::VisualShaderNodeParticleConeVelocity() { + set_input_port_default_value(0, Vector3(1, 0, 0)); + set_input_port_default_value(1, 45.0); +} + +// VisualShaderNodeParticleRandomness + +void VisualShaderNodeParticleRandomness::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeParticleRandomness::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeParticleRandomness::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + +Vector<StringName> VisualShaderNodeParticleRandomness::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +String VisualShaderNodeParticleRandomness::get_caption() const { + return "ParticleRandomness"; +} + +int VisualShaderNodeParticleRandomness::get_output_port_count() const { + return 1; +} + +VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_output_port_type(int p_port) const { + if (op_type == OP_TYPE_VECTOR) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleRandomness::get_output_port_name(int p_port) const { + return "random"; +} + +int VisualShaderNodeParticleRandomness::get_input_port_count() const { + return 2; +} + +VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_input_port_type(int p_port) const { + if (op_type == OP_TYPE_VECTOR) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleRandomness::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "min"; + } else if (p_port == 1) { + return "max"; + } + return String(); +} + +String VisualShaderNodeParticleRandomness::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + if (op_type == OP_TYPE_SCALAR) { + code += vformat("\t%s = __randf_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]); + } else if (op_type == OP_TYPE_VECTOR) { + code += vformat("\t%s = __randv_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]); + } + return code; +} + +void VisualShaderNodeParticleRandomness::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (p_op_type != op_type) { + if (p_op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 1.0); + } else { + set_input_port_default_value(0, Vector3(-1.0, -1.0, -1.0)); + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); + } + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeParticleRandomness::OpType VisualShaderNodeParticleRandomness::get_op_type() const { + return op_type; +} + +VisualShaderNodeParticleRandomness::VisualShaderNodeParticleRandomness() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 1.0); +} + +// VisualShaderNodeParticleAccelerator + +void VisualShaderNodeParticleAccelerator::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShaderNodeParticleAccelerator::set_mode); + ClassDB::bind_method(D_METHOD("get_mode"), &VisualShaderNodeParticleAccelerator::get_mode); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Linear,Radial,Tangential"), "set_mode", "get_mode"); + + BIND_ENUM_CONSTANT(MODE_LINEAR); + BIND_ENUM_CONSTANT(MODE_RADIAL) + BIND_ENUM_CONSTANT(MODE_TANGENTIAL); + BIND_ENUM_CONSTANT(MODE_MAX); +} + +Vector<StringName> VisualShaderNodeParticleAccelerator::get_editable_properties() const { + Vector<StringName> props; + props.push_back("mode"); + return props; +} + +String VisualShaderNodeParticleAccelerator::get_caption() const { + return "ParticleAccelerator"; +} + +int VisualShaderNodeParticleAccelerator::get_output_port_count() const { + return 1; +} + +VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeParticleAccelerator::get_output_port_name(int p_port) const { + return String(); +} + +int VisualShaderNodeParticleAccelerator::get_input_port_count() const { + return 3; +} + +VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_input_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_VECTOR; + } else if (p_port == 1) { + return PORT_TYPE_SCALAR; + } else if (p_port == 2) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleAccelerator::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "amount"; + } else if (p_port == 1) { + return "randomness"; + } else if (p_port == 2) { + return "axis"; + } + return String(); +} + +String VisualShaderNodeParticleAccelerator::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + switch (mode) { + case MODE_LINEAR: + code += "\t" + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; + break; + case MODE_RADIAL: + code += "\t" + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n"; + break; + case MODE_TANGENTIAL: + code += "\t__vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n"; + code += "\t" + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n"; + break; + case MODE_MAX: + break; + default: + break; + } + + return code; +} + +void VisualShaderNodeParticleAccelerator::set_mode(Mode p_mode) { + mode = p_mode; + emit_changed(); +} + +VisualShaderNodeParticleAccelerator::Mode VisualShaderNodeParticleAccelerator::get_mode() const { + return mode; +} + +VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() { + set_input_port_default_value(0, Vector3(1, 1, 1)); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, Vector3(0, -9.8, 0)); +} + +// VisualShaderNodeParticleOutput + +String VisualShaderNodeParticleOutput::get_caption() const { + if (shader_type == VisualShader::TYPE_START) { + return "StartOutput"; + } else if (shader_type == VisualShader::TYPE_PROCESS) { + return "ProcessOutput"; + } else if (shader_type == VisualShader::TYPE_COLLIDE) { + return "CollideOutput"; + } else if (shader_type == VisualShader::TYPE_START_CUSTOM) { + return "CustomStartOutput"; + } else if (shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + return "CustomProcessOutput"; + } + return String(); +} + +int VisualShaderNodeParticleOutput::get_input_port_count() const { + if (shader_type == VisualShader::TYPE_START) { + return 8; + } else if (shader_type == VisualShader::TYPE_COLLIDE) { + return 5; + } else if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + return 6; + } else { // TYPE_PROCESS + return 7; + } + return 0; +} + +VisualShaderNodeParticleOutput::PortType VisualShaderNodeParticleOutput::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + return PORT_TYPE_VECTOR; // custom.rgb + } + return PORT_TYPE_BOOLEAN; // active + case 1: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + break; // custom.a (scalar) + } + return PORT_TYPE_VECTOR; // velocity + case 2: + return PORT_TYPE_VECTOR; // color & velocity + case 3: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + return PORT_TYPE_VECTOR; // color + } + break; // alpha (scalar) + case 4: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + break; // alpha + } + if (shader_type == VisualShader::TYPE_PROCESS) { + break; // scale + } + if (shader_type == VisualShader::TYPE_COLLIDE) { + return PORT_TYPE_TRANSFORM; // transform + } + return PORT_TYPE_VECTOR; // position + case 5: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + return PORT_TYPE_TRANSFORM; // transform + } + if (shader_type == VisualShader::TYPE_PROCESS) { + return PORT_TYPE_VECTOR; // rotation_axis + } + break; // scale (scalar) + case 6: + if (shader_type == VisualShader::TYPE_START) { + return PORT_TYPE_VECTOR; // rotation_axis + } + break; + case 7: + break; // angle (scalar) + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleOutput::get_input_port_name(int p_port) const { + String port_name; + switch (p_port) { + case 0: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + port_name = "custom"; + break; + } + port_name = "active"; + break; + case 1: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + port_name = "custom_alpha"; + break; + } + port_name = "velocity"; + break; + case 2: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + port_name = "velocity"; + break; + } + port_name = "color"; + break; + case 3: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + port_name = "color"; + break; + } + port_name = "alpha"; + break; + case 4: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + port_name = "alpha"; + break; + } + if (shader_type == VisualShader::TYPE_PROCESS) { + port_name = "scale"; + break; + } + if (shader_type == VisualShader::TYPE_COLLIDE) { + port_name = "transform"; + break; + } + port_name = "position"; + break; + case 5: + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + port_name = "transform"; + break; + } + if (shader_type == VisualShader::TYPE_PROCESS) { + port_name = "rotation_axis"; + break; + } + port_name = "scale"; + break; + case 6: + if (shader_type == VisualShader::TYPE_PROCESS) { + port_name = "angle_in_radians"; + break; + } + port_name = "rotation_axis"; + break; + case 7: + port_name = "angle_in_radians"; + break; + default: + break; + } + if (!port_name.is_empty()) { + return port_name.capitalize(); + } + return String(); +} + +bool VisualShaderNodeParticleOutput::is_port_separator(int p_index) const { + if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) { + String name = get_input_port_name(p_index); + return bool(name == "Scale"); + } + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + String name = get_input_port_name(p_index); + return bool(name == "Velocity"); + } + return false; +} + +String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + String tab = "\t"; + + if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) { + if (!p_input_vars[0].is_empty()) { // custom.rgb + code += tab + "CUSTOM.rgb = " + p_input_vars[0] + ";\n"; + } + if (!p_input_vars[1].is_empty()) { // custom.a + code += tab + "CUSTOM.a = " + p_input_vars[1] + ";\n"; + } + if (!p_input_vars[2].is_empty()) { // velocity + code += tab + "VELOCITY = " + p_input_vars[2] + ";\n"; + } + if (!p_input_vars[3].is_empty()) { // color.rgb + code += tab + "COLOR.rgb = " + p_input_vars[3] + ";\n"; + } + if (!p_input_vars[4].is_empty()) { // color.a + code += tab + "COLOR.a = " + p_input_vars[4] + ";\n"; + } + if (!p_input_vars[5].is_empty()) { // transform + code += tab + "TRANSFORM = " + p_input_vars[5] + ";\n"; + } + } else { + if (!p_input_vars[0].is_empty()) { // active (begin) + code += tab + "ACTIVE = " + p_input_vars[0] + ";\n"; + code += tab + "if(ACTIVE) {\n"; + tab += "\t"; + } + if (!p_input_vars[1].is_empty()) { // velocity + code += tab + "VELOCITY = " + p_input_vars[1] + ";\n"; + } + if (!p_input_vars[2].is_empty()) { // color + code += tab + "COLOR.rgb = " + p_input_vars[2] + ";\n"; + } + if (!p_input_vars[3].is_empty()) { // alpha + code += tab + "COLOR.a = " + p_input_vars[3] + ";\n"; + } + + // position + if (shader_type == VisualShader::TYPE_START) { + code += tab + "if (RESTART_POSITION) {\n"; + if (!p_input_vars[4].is_empty()) { + code += tab + "\tTRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(" + p_input_vars[4] + ", 1.0));\n"; + } else { + code += tab + "\tTRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n"; + } + code += tab + "\tif (RESTART_VELOCITY) {\n"; + code += tab + "\t\tVELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n"; + code += tab + "\t}\n"; + code += tab + "\tTRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n"; + code += tab + "}\n"; + } else if (shader_type == VisualShader::TYPE_COLLIDE) { // position + if (!p_input_vars[4].is_empty()) { + code += tab + "TRANSFORM = " + p_input_vars[4] + ";\n"; + } + } + + if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) { + int scale = 5; + int rotation_axis = 6; + int rotation = 7; + if (shader_type == VisualShader::TYPE_PROCESS) { + scale = 4; + rotation_axis = 5; + rotation = 6; + } + String op; + if (shader_type == VisualShader::TYPE_START) { + op = "*="; + } else { + op = "="; + } + + if (!p_input_vars[rotation].is_empty()) { // rotation_axis & angle_in_radians + String axis; + if (p_input_vars[rotation_axis].is_empty()) { + axis = "vec3(0, 1, 0)"; + } else { + axis = p_input_vars[rotation_axis]; + } + code += tab + "TRANSFORM " + op + " __build_rotation_mat4(" + axis + ", " + p_input_vars[rotation] + ");\n"; + } + if (!p_input_vars[scale].is_empty()) { // scale + code += tab + "TRANSFORM " + op + " mat4(vec4(" + p_input_vars[scale] + ", 0, 0, 0), vec4(0, " + p_input_vars[scale] + ", 0, 0), vec4(0, 0, " + p_input_vars[scale] + ", 0), vec4(0, 0, 0, 1));\n"; + } + } + if (!p_input_vars[0].is_empty()) { // active (end) + code += "\t}\n"; + } + } + return code; +} + +VisualShaderNodeParticleOutput::VisualShaderNodeParticleOutput() { +} + +// EmitParticle + +Vector<StringName> VisualShaderNodeParticleEmit::get_editable_properties() const { + Vector<StringName> props; + props.push_back("flags"); + return props; +} + +void VisualShaderNodeParticleEmit::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_flags", "flags"), &VisualShaderNodeParticleEmit::set_flags); + ClassDB::bind_method(D_METHOD("get_flags"), &VisualShaderNodeParticleEmit::get_flags); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Position,RotScale,Velocity,Color,Custom"), "set_flags", "get_flags"); + + BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION); + BIND_ENUM_CONSTANT(EMIT_FLAG_ROT_SCALE); + BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY); + BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR); + BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM); +} + +String VisualShaderNodeParticleEmit::get_caption() const { + return "EmitParticle"; +} + +int VisualShaderNodeParticleEmit::get_input_port_count() const { + return 7; +} + +VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_BOOLEAN; + case 1: + return PORT_TYPE_TRANSFORM; + case 2: + return PORT_TYPE_VECTOR; + case 3: + return PORT_TYPE_VECTOR; + case 4: + return PORT_TYPE_SCALAR; + case 5: + return PORT_TYPE_VECTOR; + case 6: + return PORT_TYPE_SCALAR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleEmit::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "condition"; + case 1: + return "transform"; + case 2: + return "velocity"; + case 3: + return "color"; + case 4: + return "alpha"; + case 5: + return "custom"; + case 6: + return "custom_alpha"; + } + return String(); +} + +int VisualShaderNodeParticleEmit::get_output_port_count() const { + return 0; +} + +VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeParticleEmit::get_output_port_name(int p_port) const { + return String(); +} + +void VisualShaderNodeParticleEmit::add_flag(EmitFlags p_flag) { + flags |= p_flag; + emit_changed(); +} + +bool VisualShaderNodeParticleEmit::has_flag(EmitFlags p_flag) const { + return flags & p_flag; +} + +void VisualShaderNodeParticleEmit::set_flags(EmitFlags p_flags) { + flags = (int)p_flags; + emit_changed(); +} + +VisualShaderNodeParticleEmit::EmitFlags VisualShaderNodeParticleEmit::get_flags() const { + return EmitFlags(flags); +} + +bool VisualShaderNodeParticleEmit::is_show_prop_names() const { + return true; +} + +bool VisualShaderNodeParticleEmit::is_generate_input_var(int p_port) const { + if (p_port == 0) { + if (!is_input_port_connected(0)) { + return false; + } + } + return true; +} + +String VisualShaderNodeParticleEmit::get_input_port_default_hint(int p_port) const { + switch (p_port) { + case 1: + return "default"; + case 2: + return "default"; + case 3: + return "default"; + case 4: + return "default"; + case 5: + return "default"; + case 6: + return "default"; + } + return String(); +} + +String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + String tab; + bool default_condition = false; + + if (!is_input_port_connected(0)) { + default_condition = true; + if (get_input_port_default_value(0)) { + tab = "\t"; + } else { + return code; + } + } else { + tab = "\t\t"; + } + + String transform; + if (p_input_vars[1].is_empty()) { + transform = "TRANSFORM"; + } else { + transform = p_input_vars[1]; + } + + String velocity; + if (p_input_vars[2].is_empty()) { + velocity = "VELOCITY"; + } else { + velocity = p_input_vars[2]; + } + + String color; + if (p_input_vars[3].is_empty()) { + color = "COLOR.rgb"; + } else { + color = p_input_vars[3]; + } + + String alpha; + if (p_input_vars[4].is_empty()) { + alpha = "COLOR.a"; + } else { + alpha = p_input_vars[4]; + } + + String custom; + if (p_input_vars[5].is_empty()) { + custom = "CUSTOM.rgb"; + } else { + custom = p_input_vars[5]; + } + + String custom_alpha; + if (p_input_vars[6].is_empty()) { + custom_alpha = "CUSTOM.a"; + } else { + custom_alpha = p_input_vars[6]; + } + + List<String> flags_arr; + + if (has_flag(EmitFlags::EMIT_FLAG_POSITION)) { + flags_arr.push_back("FLAG_EMIT_POSITION"); + } + if (has_flag(EmitFlags::EMIT_FLAG_ROT_SCALE)) { + flags_arr.push_back("FLAG_EMIT_ROT_SCALE"); + } + if (has_flag(EmitFlags::EMIT_FLAG_VELOCITY)) { + flags_arr.push_back("FLAG_EMIT_VELOCITY"); + } + if (has_flag(EmitFlags::EMIT_FLAG_COLOR)) { + flags_arr.push_back("FLAG_EMIT_COLOR"); + } + if (has_flag(EmitFlags::EMIT_FLAG_CUSTOM)) { + flags_arr.push_back("FLAG_EMIT_CUSTOM"); + } + + String flags; + + for (int i = 0; i < flags_arr.size(); i++) { + if (i > 0) { + flags += "|"; + } + flags += flags_arr[i]; + } + + if (flags.is_empty()) { + flags = "uint(0)"; + } + + if (!default_condition) { + code += "\tif (" + p_input_vars[0] + ") {\n"; + } + + code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags + ");\n"; + + if (!default_condition) { + code += "\t}\n"; + } + + return code; +} + +VisualShaderNodeParticleEmit::VisualShaderNodeParticleEmit() { + set_input_port_default_value(0, true); +} diff --git a/scene/resources/visual_shader_particle_nodes.h b/scene/resources/visual_shader_particle_nodes.h new file mode 100644 index 0000000000..ecd187a885 --- /dev/null +++ b/scene/resources/visual_shader_particle_nodes.h @@ -0,0 +1,285 @@ +/*************************************************************************/ +/* visual_shader_particle_nodes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef VISUAL_SHADER_PARTICLE_NODES_H +#define VISUAL_SHADER_PARTICLE_NODES_H + +#include "scene/resources/visual_shader.h" + +// Emit nodes + +class VisualShaderNodeParticleEmitter : public VisualShaderNode { + GDCLASS(VisualShaderNodeParticleEmitter, VisualShaderNode); + +public: + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + VisualShaderNodeParticleEmitter(); +}; + +class VisualShaderNodeParticleSphereEmitter : public VisualShaderNodeParticleEmitter { + GDCLASS(VisualShaderNodeParticleSphereEmitter, VisualShaderNodeParticleEmitter); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeParticleSphereEmitter(); +}; + +class VisualShaderNodeParticleBoxEmitter : public VisualShaderNodeParticleEmitter { + GDCLASS(VisualShaderNodeParticleBoxEmitter, VisualShaderNodeParticleEmitter); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeParticleBoxEmitter(); +}; + +class VisualShaderNodeParticleRingEmitter : public VisualShaderNodeParticleEmitter { + GDCLASS(VisualShaderNodeParticleRingEmitter, VisualShaderNodeParticleEmitter); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeParticleRingEmitter(); +}; + +class VisualShaderNodeParticleMultiplyByAxisAngle : public VisualShaderNode { + GDCLASS(VisualShaderNodeParticleMultiplyByAxisAngle, VisualShaderNode); + bool degrees_mode = true; + +protected: + static void _bind_methods(); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual bool is_show_prop_names() const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_degrees_mode(bool p_enabled); + bool is_degrees_mode() const; + Vector<StringName> get_editable_properties() const override; + + VisualShaderNodeParticleMultiplyByAxisAngle(); +}; + +class VisualShaderNodeParticleConeVelocity : public VisualShaderNode { + GDCLASS(VisualShaderNodeParticleConeVelocity, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeParticleConeVelocity(); +}; + +class VisualShaderNodeParticleRandomness : public VisualShaderNode { + GDCLASS(VisualShaderNodeParticleRandomness, VisualShaderNode); + +public: + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_MAX, + }; + +private: + OpType op_type = OP_TYPE_SCALAR; + +protected: + static void _bind_methods(); + +public: + Vector<StringName> get_editable_properties() const override; + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_op_type(OpType p_type); + OpType get_op_type() const; + + VisualShaderNodeParticleRandomness(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeParticleRandomness::OpType) + +// Process nodes + +class VisualShaderNodeParticleAccelerator : public VisualShaderNodeOutput { + GDCLASS(VisualShaderNodeParticleAccelerator, VisualShaderNodeOutput); + +public: + enum Mode { + MODE_LINEAR, + MODE_RADIAL, + MODE_TANGENTIAL, + MODE_MAX, + }; + +private: + Mode mode = MODE_LINEAR; + +protected: + static void _bind_methods(); + +public: + Vector<StringName> get_editable_properties() const override; + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + void set_mode(Mode p_mode); + Mode get_mode() const; + + VisualShaderNodeParticleAccelerator(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeParticleAccelerator::Mode) + +// Common nodes + +class VisualShaderNodeParticleOutput : public VisualShaderNodeOutput { + GDCLASS(VisualShaderNodeParticleOutput, VisualShaderNodeOutput); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual bool is_port_separator(int p_index) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeParticleOutput(); +}; + +class VisualShaderNodeParticleEmit : public VisualShaderNode { + GDCLASS(VisualShaderNodeParticleEmit, VisualShaderNode); + +public: + enum EmitFlags { + EMIT_FLAG_POSITION = 1, + EMIT_FLAG_ROT_SCALE = 2, + EMIT_FLAG_VELOCITY = 4, + EMIT_FLAG_COLOR = 8, + EMIT_FLAG_CUSTOM = 16, + }; + +protected: + int flags = EMIT_FLAG_POSITION | EMIT_FLAG_ROT_SCALE | EMIT_FLAG_VELOCITY | EMIT_FLAG_COLOR | EMIT_FLAG_CUSTOM; + static void _bind_methods(); + +public: + Vector<StringName> get_editable_properties() const override; + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + void add_flag(EmitFlags p_flag); + bool has_flag(EmitFlags p_flag) const; + + void set_flags(EmitFlags p_flags); + EmitFlags get_flags() const; + + virtual bool is_show_prop_names() const override; + virtual bool is_generate_input_var(int p_port) const override; + virtual String get_input_port_default_hint(int p_port) const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeParticleEmit(); +}; + +VARIANT_ENUM_CAST(VisualShaderNodeParticleEmit::EmitFlags) + +#endif diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 0a0742753f..eceb42ee14 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -32,290 +32,12 @@ #include "core/config/project_settings.h" #include "scene/2d/camera_2d.h" -#include "scene/2d/visibility_notifier_2d.h" +#include "scene/2d/visible_on_screen_notifier_2d.h" #include "scene/main/window.h" #include "servers/navigation_server_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" -struct SpatialIndexer2D { - struct CellRef { - int ref = 0; - - _FORCE_INLINE_ int inc() { - ref++; - return ref; - } - _FORCE_INLINE_ int dec() { - ref--; - return ref; - } - }; - - struct CellKey { - union { - struct { - int32_t x; - int32_t y; - }; - uint64_t key = 0; - }; - - bool operator==(const CellKey &p_key) const { return key == p_key.key; } - _FORCE_INLINE_ bool operator<(const CellKey &p_key) const { - return key < p_key.key; - } - }; - - struct CellData { - Map<VisibilityNotifier2D *, CellRef> notifiers; - }; - - Map<CellKey, CellData> cells; - int cell_size; - - Map<VisibilityNotifier2D *, Rect2> notifiers; - - struct ViewportData { - Map<VisibilityNotifier2D *, uint64_t> notifiers; - Rect2 rect; - }; - - Map<Viewport *, ViewportData> viewports; - - bool changed = false; - - uint64_t pass = 0; - - void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) { - Point2i begin = p_rect.position; - begin /= cell_size; - Point2i end = p_rect.position + p_rect.size; - end /= cell_size; - for (int i = begin.x; i <= end.x; i++) { - for (int j = begin.y; j <= end.y; j++) { - CellKey ck; - ck.x = i; - ck.y = j; - Map<CellKey, CellData>::Element *E = cells.find(ck); - - if (p_add) { - if (!E) { - E = cells.insert(ck, CellData()); - } - E->get().notifiers[p_notifier].inc(); - } else { - ERR_CONTINUE(!E); - if (E->get().notifiers[p_notifier].dec() == 0) { - E->get().notifiers.erase(p_notifier); - if (E->get().notifiers.is_empty()) { - cells.erase(E); - } - } - } - } - } - } - - void _notifier_add(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - ERR_FAIL_COND(notifiers.has(p_notifier)); - notifiers[p_notifier] = p_rect; - _notifier_update_cells(p_notifier, p_rect, true); - changed = true; - } - - void _notifier_update(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - Map<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - if (E->get() == p_rect) { - return; - } - - _notifier_update_cells(p_notifier, p_rect, true); - _notifier_update_cells(p_notifier, E->get(), false); - E->get() = p_rect; - changed = true; - } - - void _notifier_remove(VisibilityNotifier2D *p_notifier) { - Map<VisibilityNotifier2D *, Rect2>::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - _notifier_update_cells(p_notifier, E->get(), false); - notifiers.erase(p_notifier); - - List<Viewport *> removed; - for (Map<Viewport *, ViewportData>::Element *F = viewports.front(); F; F = F->next()) { - Map<VisibilityNotifier2D *, uint64_t>::Element *G = F->get().notifiers.find(p_notifier); - - if (G) { - F->get().notifiers.erase(G); - removed.push_back(F->key()); - } - } - - while (!removed.is_empty()) { - p_notifier->_exit_viewport(removed.front()->get()); - removed.pop_front(); - } - - changed = true; - } - - void _add_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - ERR_FAIL_COND(viewports.has(p_viewport)); - ViewportData vd; - vd.rect = p_rect; - viewports[p_viewport] = vd; - changed = true; - } - - void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - Map<Viewport *, ViewportData>::Element *E = viewports.find(p_viewport); - ERR_FAIL_COND(!E); - if (E->get().rect == p_rect) { - return; - } - E->get().rect = p_rect; - changed = true; - } - - void _remove_viewport(Viewport *p_viewport) { - ERR_FAIL_COND(!viewports.has(p_viewport)); - List<VisibilityNotifier2D *> removed; - for (Map<VisibilityNotifier2D *, uint64_t>::Element *E = viewports[p_viewport].notifiers.front(); E; E = E->next()) { - removed.push_back(E->key()); - } - - while (!removed.is_empty()) { - removed.front()->get()->_exit_viewport(p_viewport); - removed.pop_front(); - } - - viewports.erase(p_viewport); - } - - void _update() { - if (!changed) { - return; - } - - for (Map<Viewport *, ViewportData>::Element *E = viewports.front(); E; E = E->next()) { - Point2i begin = E->get().rect.position; - begin /= cell_size; - Point2i end = E->get().rect.position + E->get().rect.size; - end /= cell_size; - pass++; - List<VisibilityNotifier2D *> added; - List<VisibilityNotifier2D *> removed; - - uint64_t visible_cells = (uint64_t)(end.x - begin.x) * (uint64_t)(end.y - begin.y); - - if (visible_cells > 10000) { - //well you zoomed out a lot, it's your problem. To avoid freezing in the for loops below, we'll manually check cell by cell - - for (Map<CellKey, CellData>::Element *F = cells.front(); F; F = F->next()) { - const CellKey &ck = F->key(); - - if (ck.x < begin.x || ck.x > end.x) { - continue; - } - if (ck.y < begin.y || ck.y > end.y) { - continue; - } - - //notifiers in cell - for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) { - Map<VisibilityNotifier2D *, uint64_t>::Element *H = E->get().notifiers.find(G->key()); - if (!H) { - H = E->get().notifiers.insert(G->key(), pass); - added.push_back(G->key()); - } else { - H->get() = pass; - } - } - } - - } else { - //check cells in grid fashion - for (int i = begin.x; i <= end.x; i++) { - for (int j = begin.y; j <= end.y; j++) { - CellKey ck; - ck.x = i; - ck.y = j; - - Map<CellKey, CellData>::Element *F = cells.find(ck); - if (!F) { - continue; - } - - //notifiers in cell - for (Map<VisibilityNotifier2D *, CellRef>::Element *G = F->get().notifiers.front(); G; G = G->next()) { - Map<VisibilityNotifier2D *, uint64_t>::Element *H = E->get().notifiers.find(G->key()); - if (!H) { - H = E->get().notifiers.insert(G->key(), pass); - added.push_back(G->key()); - } else { - H->get() = pass; - } - } - } - } - } - - for (Map<VisibilityNotifier2D *, uint64_t>::Element *F = E->get().notifiers.front(); F; F = F->next()) { - if (F->get() != pass) { - removed.push_back(F->key()); - } - } - - while (!added.is_empty()) { - added.front()->get()->_enter_viewport(E->key()); - added.pop_front(); - } - - while (!removed.is_empty()) { - E->get().notifiers.erase(removed.front()->get()); - removed.front()->get()->_exit_viewport(E->key()); - removed.pop_front(); - } - } - - changed = false; - } - - SpatialIndexer2D() { - cell_size = GLOBAL_DEF("world/2d/cell_size", 100); - } -}; - -void World2D::_register_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - indexer->_add_viewport(p_viewport, p_rect); -} - -void World2D::_update_viewport(Viewport *p_viewport, const Rect2 &p_rect) { - indexer->_update_viewport(p_viewport, p_rect); -} - -void World2D::_remove_viewport(Viewport *p_viewport) { - indexer->_remove_viewport(p_viewport); -} - -void World2D::_register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - indexer->_notifier_add(p_notifier, p_rect); -} - -void World2D::_update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect) { - indexer->_notifier_update(p_notifier, p_rect); -} - -void World2D::_remove_notifier(VisibilityNotifier2D *p_notifier) { - indexer->_notifier_remove(p_notifier); -} - -void World2D::_update() { - indexer->_update(); -} - RID World2D::get_canvas() const { return canvas; } @@ -328,12 +50,6 @@ RID World2D::get_navigation_map() const { return navigation_map; } -void World2D::get_viewport_list(List<Viewport *> *r_viewports) { - for (Map<Viewport *, SpatialIndexer2D::ViewportData>::Element *E = indexer->viewports.front(); E; E = E->next()) { - r_viewports->push_back(E->key()); - } -} - void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas); ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space); @@ -341,10 +57,10 @@ void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World2D::get_direct_space_state); - ADD_PROPERTY(PropertyInfo(Variant::RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", 0), "", "get_navigation_map"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", 0), "", "get_direct_space_state"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "canvas", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_canvas"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", PROPERTY_USAGE_NONE), "", "get_direct_space_state"); } PhysicsDirectSpaceState2D *World2D::get_direct_space_state() { @@ -369,13 +85,10 @@ World2D::World2D() { NavigationServer2D::get_singleton()->map_set_active(navigation_map, true); NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10)); NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5)); - - indexer = memnew(SpatialIndexer2D); } World2D::~World2D() { RenderingServer::get_singleton()->free(canvas); PhysicsServer2D::get_singleton()->free(space); NavigationServer2D::get_singleton()->free(navigation_map); - memdelete(indexer); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 38abf3d7ad..65f89c8f64 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -35,7 +35,7 @@ #include "core/io/resource.h" #include "servers/physics_server_2d.h" -class VisibilityNotifier2D; +class VisibleOnScreenNotifier2D; class Viewport; struct SpatialIndexer2D; @@ -46,23 +46,15 @@ class World2D : public Resource { RID space; RID navigation_map; - SpatialIndexer2D *indexer; + Set<Viewport *> viewports; protected: static void _bind_methods(); friend class Viewport; - friend class VisibilityNotifier2D; - void _register_viewport(Viewport *p_viewport, const Rect2 &p_rect); - void _update_viewport(Viewport *p_viewport, const Rect2 &p_rect); + void _register_viewport(Viewport *p_viewport); void _remove_viewport(Viewport *p_viewport); - void _register_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect); - void _update_notifier(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect); - void _remove_notifier(VisibilityNotifier2D *p_notifier); - - void _update(); - public: RID get_canvas() const; RID get_space() const; @@ -70,7 +62,7 @@ public: PhysicsDirectSpaceState2D *get_direct_space_state(); - void get_viewport_list(List<Viewport *> *r_viewports); + _FORCE_INLINE_ const Set<Viewport *> &get_viewports() { return viewports; } World2D(); ~World2D(); diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index e811cbf57a..42047f104f 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -33,210 +33,19 @@ #include "core/math/camera_matrix.h" #include "core/math/octree.h" #include "scene/3d/camera_3d.h" -#include "scene/3d/visibility_notifier_3d.h" +#include "scene/3d/visible_on_screen_notifier_3d.h" #include "scene/scene_string_names.h" #include "servers/navigation_server_3d.h" -struct SpatialIndexer { - Octree<VisibilityNotifier3D> octree; - - struct NotifierData { - AABB aabb; - OctreeElementID id; - }; - - Map<VisibilityNotifier3D *, NotifierData> notifiers; - struct CameraData { - Map<VisibilityNotifier3D *, uint64_t> notifiers; - }; - - Map<Camera3D *, CameraData> cameras; - - enum { - VISIBILITY_CULL_MAX = 32768 - }; - - Vector<VisibilityNotifier3D *> cull; - - bool changed; - uint64_t pass; - uint64_t last_frame; - - void _notifier_add(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { - ERR_FAIL_COND(notifiers.has(p_notifier)); - notifiers[p_notifier].aabb = p_rect; - notifiers[p_notifier].id = octree.create(p_notifier, p_rect); - changed = true; - } - - void _notifier_update(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { - Map<VisibilityNotifier3D *, NotifierData>::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - if (E->get().aabb == p_rect) { - return; - } - - E->get().aabb = p_rect; - octree.move(E->get().id, E->get().aabb); - changed = true; - } - - void _notifier_remove(VisibilityNotifier3D *p_notifier) { - Map<VisibilityNotifier3D *, NotifierData>::Element *E = notifiers.find(p_notifier); - ERR_FAIL_COND(!E); - - octree.erase(E->get().id); - notifiers.erase(p_notifier); - - List<Camera3D *> removed; - for (Map<Camera3D *, CameraData>::Element *F = cameras.front(); F; F = F->next()) { - Map<VisibilityNotifier3D *, uint64_t>::Element *G = F->get().notifiers.find(p_notifier); - - if (G) { - F->get().notifiers.erase(G); - removed.push_back(F->key()); - } - } - - while (!removed.is_empty()) { - p_notifier->_exit_camera(removed.front()->get()); - removed.pop_front(); - } - - changed = true; - } - - void _add_camera(Camera3D *p_camera) { - ERR_FAIL_COND(cameras.has(p_camera)); - CameraData vd; - cameras[p_camera] = vd; - changed = true; - } - - void _update_camera(Camera3D *p_camera) { - Map<Camera3D *, CameraData>::Element *E = cameras.find(p_camera); - ERR_FAIL_COND(!E); - changed = true; - } - - void _remove_camera(Camera3D *p_camera) { - ERR_FAIL_COND(!cameras.has(p_camera)); - List<VisibilityNotifier3D *> removed; - for (Map<VisibilityNotifier3D *, uint64_t>::Element *E = cameras[p_camera].notifiers.front(); E; E = E->next()) { - removed.push_back(E->key()); - } - - while (!removed.is_empty()) { - removed.front()->get()->_exit_camera(p_camera); - removed.pop_front(); - } - - cameras.erase(p_camera); - } - - void _update(uint64_t p_frame) { - if (p_frame == last_frame) { - return; - } - last_frame = p_frame; - - if (!changed) { - return; - } - - for (Map<Camera3D *, CameraData>::Element *E = cameras.front(); E; E = E->next()) { - pass++; - - Camera3D *c = E->key(); - - Vector<Plane> planes = c->get_frustum(); - - int culled = octree.cull_convex(planes, cull.ptrw(), cull.size()); - - VisibilityNotifier3D **ptr = cull.ptrw(); - - List<VisibilityNotifier3D *> added; - List<VisibilityNotifier3D *> removed; - - for (int i = 0; i < culled; i++) { - //notifiers in frustum - - Map<VisibilityNotifier3D *, uint64_t>::Element *H = E->get().notifiers.find(ptr[i]); - if (!H) { - E->get().notifiers.insert(ptr[i], pass); - added.push_back(ptr[i]); - } else { - H->get() = pass; - } - } - - for (Map<VisibilityNotifier3D *, uint64_t>::Element *F = E->get().notifiers.front(); F; F = F->next()) { - if (F->get() != pass) { - removed.push_back(F->key()); - } - } - - while (!added.is_empty()) { - added.front()->get()->_enter_camera(E->key()); - added.pop_front(); - } - - while (!removed.is_empty()) { - E->get().notifiers.erase(removed.front()->get()); - removed.front()->get()->_exit_camera(E->key()); - removed.pop_front(); - } - } - changed = false; - } - - SpatialIndexer() { - pass = 0; - last_frame = 0; - changed = false; - cull.resize(VISIBILITY_CULL_MAX); - } -}; - void World3D::_register_camera(Camera3D *p_camera) { #ifndef _3D_DISABLED - indexer->_add_camera(p_camera); -#endif -} - -void World3D::_update_camera(Camera3D *p_camera) { -#ifndef _3D_DISABLED - indexer->_update_camera(p_camera); + cameras.insert(p_camera); #endif } void World3D::_remove_camera(Camera3D *p_camera) { #ifndef _3D_DISABLED - indexer->_remove_camera(p_camera); -#endif -} - -void World3D::_register_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { -#ifndef _3D_DISABLED - indexer->_notifier_add(p_notifier, p_rect); -#endif -} - -void World3D::_update_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect) { -#ifndef _3D_DISABLED - indexer->_notifier_update(p_notifier, p_rect); -#endif -} - -void World3D::_remove_notifier(VisibilityNotifier3D *p_notifier) { -#ifndef _3D_DISABLED - indexer->_notifier_remove(p_notifier); -#endif -} - -void World3D::_update(uint64_t p_frame) { -#ifndef _3D_DISABLED - indexer->_update(p_frame); + cameras.erase(p_camera); #endif } @@ -307,12 +116,6 @@ PhysicsDirectSpaceState3D *World3D::get_direct_space_state() { return PhysicsServer3D::get_singleton()->space_get_direct_state(space); } -void World3D::get_camera_list(List<Camera3D *> *r_cameras) { - for (Map<Camera3D *, SpatialIndexer::CameraData>::Element *E = indexer->cameras.front(); E; E = E->next()) { - r_cameras->push_back(E->key()); - } -} - void World3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space); ClassDB::bind_method(D_METHOD("get_navigation_map"), &World3D::get_navigation_map); @@ -327,10 +130,10 @@ void World3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "camera_effects", PROPERTY_HINT_RESOURCE_TYPE, "CameraEffects"), "set_camera_effects", "get_camera_effects"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", 0), "", "get_navigation_map"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", 0), "", "get_direct_space_state"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_space"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "navigation_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_navigation_map"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "scenario", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "", "get_scenario"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState3D", PROPERTY_USAGE_NONE), "", "get_direct_space_state"); } World3D::World3D() { @@ -349,20 +152,10 @@ World3D::World3D() { NavigationServer3D::get_singleton()->map_set_active(navigation_map, true); NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3)); NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 0.3)); - -#ifdef _3D_DISABLED - indexer = nullptr; -#else - indexer = memnew(SpatialIndexer); -#endif } World3D::~World3D() { PhysicsServer3D::get_singleton()->free(space); RenderingServer::get_singleton()->free(scenario); NavigationServer3D::get_singleton()->free(navigation_map); - -#ifndef _3D_DISABLED - memdelete(indexer); -#endif } diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 4e2717a2bb..2c5be35609 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -38,7 +38,7 @@ #include "servers/rendering_server.h" class Camera3D; -class VisibilityNotifier3D; +class VisibleOnScreenNotifier3D; struct SpatialIndexer; class World3D : public Resource { @@ -48,27 +48,21 @@ private: RID space; RID navigation_map; RID scenario; - SpatialIndexer *indexer; + Ref<Environment> environment; Ref<Environment> fallback_environment; Ref<CameraEffects> camera_effects; + Set<Camera3D *> cameras; + protected: static void _bind_methods(); friend class Camera3D; - friend class VisibilityNotifier3D; void _register_camera(Camera3D *p_camera); - void _update_camera(Camera3D *p_camera); void _remove_camera(Camera3D *p_camera); - void _register_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect); - void _update_notifier(VisibilityNotifier3D *p_notifier, const AABB &p_rect); - void _remove_notifier(VisibilityNotifier3D *p_notifier); - friend class Viewport; - void _update(uint64_t p_frame); - public: RID get_space() const; RID get_navigation_map() const; @@ -83,7 +77,7 @@ public: void set_camera_effects(const Ref<CameraEffects> &p_camera_effects); Ref<CameraEffects> get_camera_effects() const; - void get_camera_list(List<Camera3D *> *r_cameras); + _FORCE_INLINE_ const Set<Camera3D *> &get_cameras() const { return cameras; } PhysicsDirectSpaceState3D *get_direct_space_state(); diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 7575ccd5c3..35f8a506fc 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -103,7 +103,6 @@ SceneStringNames::SceneStringNames() { _update_scroll = StaticCString::create("_update_scroll"); _update_xform = StaticCString::create("_update_xform"); - _clips_input = StaticCString::create("_clips_input"); _structured_text_parser = StaticCString::create("_structured_text_parser"); _proxgroup_add = StaticCString::create("_proxgroup_add"); @@ -144,7 +143,7 @@ SceneStringNames::SceneStringNames() { v_offset = StaticCString::create("v_offset"); transform_pos = StaticCString::create("position"); - transform_rot = StaticCString::create("rotation_degrees"); + transform_rot = StaticCString::create("rotation"); transform_scale = StaticCString::create("scale"); _update_remote = StaticCString::create("_update_remote"); @@ -155,13 +154,13 @@ SceneStringNames::SceneStringNames() { area_entered = StaticCString::create("area_entered"); area_exited = StaticCString::create("area_exited"); - has_point = StaticCString::create("has_point"); + _has_point = StaticCString::create("_has_point"); line_separation = StaticCString::create("line_separation"); - get_drag_data = StaticCString::create("get_drag_data"); - drop_data = StaticCString::create("drop_data"); - can_drop_data = StaticCString::create("can_drop_data"); + _get_drag_data = StaticCString::create("_get_drag_data"); + _drop_data = StaticCString::create("_drop_data"); + _can_drop_data = StaticCString::create("_can_drop_data"); _im_update = StaticCString::create("_im_update"); // Sprite3D @@ -175,6 +174,7 @@ SceneStringNames::SceneStringNames() { _toggled = StaticCString::create("_toggled"); frame_changed = StaticCString::create("frame_changed"); + texture_changed = StaticCString::create("texture_changed"); playback_speed = StaticCString::create("playback/speed"); playback_active = StaticCString::create("playback/active"); diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index a5b489eddc..01865b0d2f 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -129,7 +129,6 @@ public: StringName _update_scroll; StringName _update_xform; - StringName _clips_input; StringName _structured_text_parser; StringName _proxgroup_add; @@ -138,10 +137,10 @@ public: StringName grouped; StringName ungrouped; - StringName has_point; - StringName get_drag_data; - StringName can_drop_data; - StringName drop_data; + StringName _has_point; + StringName _get_drag_data; + StringName _can_drop_data; + StringName _drop_data; StringName screen_entered; StringName screen_exited; @@ -184,6 +183,7 @@ public: StringName _mouse_exit; StringName frame_changed; + StringName texture_changed; StringName playback_speed; StringName playback_active; diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h index 4556db9b93..bea7292b8e 100644 --- a/servers/audio/audio_effect.h +++ b/servers/audio/audio_effect.h @@ -34,8 +34,8 @@ #include "core/io/resource.h" #include "core/math/audio_frame.h" -class AudioEffectInstance : public Reference { - GDCLASS(AudioEffectInstance, Reference); +class AudioEffectInstance : public RefCounted { + GDCLASS(AudioEffectInstance, RefCounted); public: virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) = 0; @@ -46,7 +46,7 @@ class AudioEffect : public Resource { GDCLASS(AudioEffect, Resource); public: - virtual Ref<AudioEffectInstance> instance() = 0; + virtual Ref<AudioEffectInstance> instantiate() = 0; AudioEffect(); }; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index ae07f999ed..aec6932326 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -100,7 +100,7 @@ void AudioStream::_bind_methods() { Ref<AudioStreamPlayback> AudioStreamMicrophone::instance_playback() { Ref<AudioStreamPlaybackMicrophone> playback; - playback.instance(); + playback.instantiate(); playbacks.insert(playback.ptr()); @@ -256,7 +256,7 @@ float AudioStreamRandomPitch::get_random_pitch() const { Ref<AudioStreamPlayback> AudioStreamRandomPitch::instance_playback() { Ref<AudioStreamPlaybackRandomPitch> playback; - playback.instance(); + playback.instantiate(); if (audio_stream.is_valid()) { playback->playback = audio_stream->instance_playback(); } diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 93566783be..0d426f99b2 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -36,8 +36,8 @@ #include "servers/audio/audio_filter_sw.h" #include "servers/audio_server.h" -class AudioStreamPlayback : public Reference { - GDCLASS(AudioStreamPlayback, Reference); +class AudioStreamPlayback : public RefCounted { + GDCLASS(AudioStreamPlayback, RefCounted); public: virtual void start(float p_from_pos = 0.0) = 0; diff --git a/servers/audio/effects/audio_effect_amplify.cpp b/servers/audio/effects/audio_effect_amplify.cpp index c5c1174670..79788d334b 100644 --- a/servers/audio/effects/audio_effect_amplify.cpp +++ b/servers/audio/effects/audio_effect_amplify.cpp @@ -44,9 +44,9 @@ void AudioEffectAmplifyInstance::process(const AudioFrame *p_src_frames, AudioFr mix_volume_db = volume_db; } -Ref<AudioEffectInstance> AudioEffectAmplify::instance() { +Ref<AudioEffectInstance> AudioEffectAmplify::instantiate() { Ref<AudioEffectAmplifyInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectAmplify>(this); ins->mix_volume_db = volume_db; return ins; diff --git a/servers/audio/effects/audio_effect_amplify.h b/servers/audio/effects/audio_effect_amplify.h index 2ece57854c..9d3facc230 100644 --- a/servers/audio/effects/audio_effect_amplify.h +++ b/servers/audio/effects/audio_effect_amplify.h @@ -56,7 +56,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_volume_db(float p_volume); float get_volume_db() const; diff --git a/servers/audio/effects/audio_effect_capture.cpp b/servers/audio/effects/audio_effect_capture.cpp index 78837c7531..065065042e 100644 --- a/servers/audio/effects/audio_effect_capture.cpp +++ b/servers/audio/effects/audio_effect_capture.cpp @@ -73,7 +73,7 @@ void AudioEffectCapture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_buffer_length", "get_buffer_length"); } -Ref<AudioEffectInstance> AudioEffectCapture::instance() { +Ref<AudioEffectInstance> AudioEffectCapture::instantiate() { if (!buffer_initialized) { float target_buffer_size = AudioServer::get_singleton()->get_mix_rate() * buffer_length_seconds; ERR_FAIL_COND_V(target_buffer_size <= 0 || target_buffer_size >= (1 << 27), Ref<AudioEffectInstance>()); @@ -84,7 +84,7 @@ Ref<AudioEffectInstance> AudioEffectCapture::instance() { clear_buffer(); Ref<AudioEffectCaptureInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectCapture>(this); return ins; diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h index 81d4ed6b0f..7f50fc4965 100644 --- a/servers/audio/effects/audio_effect_capture.h +++ b/servers/audio/effects/audio_effect_capture.h @@ -33,7 +33,7 @@ #include "core/config/engine.h" #include "core/math/audio_frame.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/templates/vector.h" #include "servers/audio/audio_effect.h" #include "servers/audio_server.h" @@ -64,7 +64,7 @@ protected: static void _bind_methods(); public: - virtual Ref<AudioEffectInstance> instance() override; + virtual Ref<AudioEffectInstance> instantiate() override; void set_buffer_length(float p_buffer_length_seconds); float get_buffer_length(); diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp index eb2268aa2e..9af3ed30cc 100644 --- a/servers/audio/effects/audio_effect_chorus.cpp +++ b/servers/audio/effects/audio_effect_chorus.cpp @@ -141,9 +141,9 @@ void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames, A buffer_pos += p_frame_count; } -Ref<AudioEffectInstance> AudioEffectChorus::instance() { +Ref<AudioEffectInstance> AudioEffectChorus::instantiate() { Ref<AudioEffectChorusInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectChorus>(this); for (int i = 0; i < 4; i++) { ins->filter_h[i] = AudioFrame(0, 0); @@ -276,7 +276,7 @@ void AudioEffectChorus::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("voice/")) { int voice_idx = property.name.get_slice("/", 1).to_int(); if (voice_idx > voice_count) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } } diff --git a/servers/audio/effects/audio_effect_chorus.h b/servers/audio/effects/audio_effect_chorus.h index f5b023734a..f81bebb0ae 100644 --- a/servers/audio/effects/audio_effect_chorus.h +++ b/servers/audio/effects/audio_effect_chorus.h @@ -128,7 +128,7 @@ public: void set_dry(float amount); float get_dry() const; - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; AudioEffectChorus(); }; diff --git a/servers/audio/effects/audio_effect_compressor.cpp b/servers/audio/effects/audio_effect_compressor.cpp index bb4a90f3d6..cfa2ae6f79 100644 --- a/servers/audio/effects/audio_effect_compressor.cpp +++ b/servers/audio/effects/audio_effect_compressor.cpp @@ -112,9 +112,9 @@ void AudioEffectCompressorInstance::process(const AudioFrame *p_src_frames, Audi } } -Ref<AudioEffectInstance> AudioEffectCompressor::instance() { +Ref<AudioEffectInstance> AudioEffectCompressor::instantiate() { Ref<AudioEffectCompressorInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectCompressor>(this); ins->rundb = 0; ins->runratio = 0; diff --git a/servers/audio/effects/audio_effect_compressor.h b/servers/audio/effects/audio_effect_compressor.h index 33c60680fc..dae4618a64 100644 --- a/servers/audio/effects/audio_effect_compressor.h +++ b/servers/audio/effects/audio_effect_compressor.h @@ -65,7 +65,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_threshold(float p_threshold); float get_threshold() const; diff --git a/servers/audio/effects/audio_effect_delay.cpp b/servers/audio/effects/audio_effect_delay.cpp index ba50eeb0a3..07475e1ed4 100644 --- a/servers/audio/effects/audio_effect_delay.cpp +++ b/servers/audio/effects/audio_effect_delay.cpp @@ -111,9 +111,9 @@ void AudioEffectDelayInstance::_process_chunk(const AudioFrame *p_src_frames, Au } } -Ref<AudioEffectInstance> AudioEffectDelay::instance() { +Ref<AudioEffectInstance> AudioEffectDelay::instantiate() { Ref<AudioEffectDelayInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectDelay>(this); float ring_buffer_max_size = MAX_DELAY_MS + 100; //add 100ms of extra room, just in case diff --git a/servers/audio/effects/audio_effect_delay.h b/servers/audio/effects/audio_effect_delay.h index ff267d5023..50a2233e5f 100644 --- a/servers/audio/effects/audio_effect_delay.h +++ b/servers/audio/effects/audio_effect_delay.h @@ -126,7 +126,7 @@ public: void set_feedback_lowpass(float p_lowpass); float get_feedback_lowpass() const; - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; AudioEffectDelay(); }; diff --git a/servers/audio/effects/audio_effect_distortion.cpp b/servers/audio/effects/audio_effect_distortion.cpp index 5c076ca3fe..188b7a3301 100644 --- a/servers/audio/effects/audio_effect_distortion.cpp +++ b/servers/audio/effects/audio_effect_distortion.cpp @@ -93,9 +93,9 @@ void AudioEffectDistortionInstance::process(const AudioFrame *p_src_frames, Audi } } -Ref<AudioEffectInstance> AudioEffectDistortion::instance() { +Ref<AudioEffectInstance> AudioEffectDistortion::instantiate() { Ref<AudioEffectDistortionInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectDistortion>(this); ins->h[0] = 0; ins->h[1] = 0; diff --git a/servers/audio/effects/audio_effect_distortion.h b/servers/audio/effects/audio_effect_distortion.h index 9da800b79f..3a762f8cf6 100644 --- a/servers/audio/effects/audio_effect_distortion.h +++ b/servers/audio/effects/audio_effect_distortion.h @@ -68,7 +68,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_mode(Mode p_mode); Mode get_mode() const; diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp index 01ac605bd7..e87944b74b 100644 --- a/servers/audio/effects/audio_effect_eq.cpp +++ b/servers/audio/effects/audio_effect_eq.cpp @@ -59,9 +59,9 @@ void AudioEffectEQInstance::process(const AudioFrame *p_src_frames, AudioFrame * } } -Ref<AudioEffectInstance> AudioEffectEQ::instance() { +Ref<AudioEffectInstance> AudioEffectEQ::instantiate() { Ref<AudioEffectEQInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectEQ>(this); ins->gains.resize(eq.get_band_count()); for (int i = 0; i < 2; i++) { diff --git a/servers/audio/effects/audio_effect_eq.h b/servers/audio/effects/audio_effect_eq.h index 38c63a7d4f..b99727d7c0 100644 --- a/servers/audio/effects/audio_effect_eq.h +++ b/servers/audio/effects/audio_effect_eq.h @@ -66,7 +66,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_band_gain_db(int p_band, float p_volume); float get_band_gain_db(int p_band) const; int get_band_count() const; diff --git a/servers/audio/effects/audio_effect_filter.cpp b/servers/audio/effects/audio_effect_filter.cpp index c2d6074825..1db8b1f1b5 100644 --- a/servers/audio/effects/audio_effect_filter.cpp +++ b/servers/audio/effects/audio_effect_filter.cpp @@ -100,9 +100,9 @@ AudioEffectFilterInstance::AudioEffectFilterInstance() { } } -Ref<AudioEffectInstance> AudioEffectFilter::instance() { +Ref<AudioEffectInstance> AudioEffectFilter::instantiate() { Ref<AudioEffectFilterInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectFilter>(this); return ins; diff --git a/servers/audio/effects/audio_effect_filter.h b/servers/audio/effects/audio_effect_filter.h index 9a48ccf70b..1fa3df1570 100644 --- a/servers/audio/effects/audio_effect_filter.h +++ b/servers/audio/effects/audio_effect_filter.h @@ -88,7 +88,7 @@ public: void set_db(FilterDB p_db); FilterDB get_db() const; - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; AudioEffectFilter(AudioFilterSW::Mode p_mode = AudioFilterSW::LOWPASS); }; @@ -100,7 +100,7 @@ class AudioEffectLowPassFilter : public AudioEffectFilter { void _validate_property(PropertyInfo &property) const override { if (property.name == "gain") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -113,7 +113,7 @@ class AudioEffectHighPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectHighPassFilter, AudioEffectFilter); void _validate_property(PropertyInfo &property) const override { if (property.name == "gain") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } @@ -126,7 +126,7 @@ class AudioEffectBandPassFilter : public AudioEffectFilter { GDCLASS(AudioEffectBandPassFilter, AudioEffectFilter); void _validate_property(PropertyInfo &property) const override { if (property.name == "gain") { - property.usage = 0; + property.usage = PROPERTY_USAGE_NONE; } } diff --git a/servers/audio/effects/audio_effect_limiter.cpp b/servers/audio/effects/audio_effect_limiter.cpp index 1a4b01d947..280411641b 100644 --- a/servers/audio/effects/audio_effect_limiter.cpp +++ b/servers/audio/effects/audio_effect_limiter.cpp @@ -67,9 +67,9 @@ void AudioEffectLimiterInstance::process(const AudioFrame *p_src_frames, AudioFr } } -Ref<AudioEffectInstance> AudioEffectLimiter::instance() { +Ref<AudioEffectInstance> AudioEffectLimiter::instantiate() { Ref<AudioEffectLimiterInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectLimiter>(this); return ins; diff --git a/servers/audio/effects/audio_effect_limiter.h b/servers/audio/effects/audio_effect_limiter.h index 8f3092c0e2..d5def670a4 100644 --- a/servers/audio/effects/audio_effect_limiter.h +++ b/servers/audio/effects/audio_effect_limiter.h @@ -71,7 +71,7 @@ public: void set_soft_clip_ratio(float p_soft_clip); float get_soft_clip_ratio() const; - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_volume_db(float p_volume); float get_volume_db() const; diff --git a/servers/audio/effects/audio_effect_panner.cpp b/servers/audio/effects/audio_effect_panner.cpp index 238e979e13..e2062609b9 100644 --- a/servers/audio/effects/audio_effect_panner.cpp +++ b/servers/audio/effects/audio_effect_panner.cpp @@ -40,9 +40,9 @@ void AudioEffectPannerInstance::process(const AudioFrame *p_src_frames, AudioFra } } -Ref<AudioEffectInstance> AudioEffectPanner::instance() { +Ref<AudioEffectInstance> AudioEffectPanner::instantiate() { Ref<AudioEffectPannerInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectPanner>(this); return ins; } diff --git a/servers/audio/effects/audio_effect_panner.h b/servers/audio/effects/audio_effect_panner.h index 0938824c64..d75bcaeb95 100644 --- a/servers/audio/effects/audio_effect_panner.h +++ b/servers/audio/effects/audio_effect_panner.h @@ -54,7 +54,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_pan(float p_cpanume); float get_pan() const; diff --git a/servers/audio/effects/audio_effect_phaser.cpp b/servers/audio/effects/audio_effect_phaser.cpp index 9b70f03a19..c76692eed7 100644 --- a/servers/audio/effects/audio_effect_phaser.cpp +++ b/servers/audio/effects/audio_effect_phaser.cpp @@ -78,9 +78,9 @@ void AudioEffectPhaserInstance::process(const AudioFrame *p_src_frames, AudioFra } } -Ref<AudioEffectInstance> AudioEffectPhaser::instance() { +Ref<AudioEffectInstance> AudioEffectPhaser::instantiate() { Ref<AudioEffectPhaserInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectPhaser>(this); ins->phase = 0; ins->h = AudioFrame(0, 0); diff --git a/servers/audio/effects/audio_effect_phaser.h b/servers/audio/effects/audio_effect_phaser.h index 563927c678..2a0ed64805 100644 --- a/servers/audio/effects/audio_effect_phaser.h +++ b/servers/audio/effects/audio_effect_phaser.h @@ -83,7 +83,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_range_min_hz(float p_hz); float get_range_min_hz() const; diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp index 7b0151b9c1..bfbaeee3f3 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.cpp +++ b/servers/audio/effects/audio_effect_pitch_shift.cpp @@ -298,9 +298,9 @@ void AudioEffectPitchShiftInstance::process(const AudioFrame *p_src_frames, Audi shift_r.PitchShift(base->pitch_scale, p_frame_count, fft_size, base->oversampling, sample_rate, in_r, out_r, 2); } -Ref<AudioEffectInstance> AudioEffectPitchShift::instance() { +Ref<AudioEffectInstance> AudioEffectPitchShift::instantiate() { Ref<AudioEffectPitchShiftInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectPitchShift>(this); static const int fft_sizes[FFT_SIZE_MAX] = { 256, 512, 1024, 2048, 4096 }; ins->fft_size = fft_sizes[fft_size]; diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h index 669943fa43..3ed096cd94 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.h +++ b/servers/audio/effects/audio_effect_pitch_shift.h @@ -109,7 +109,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_pitch_scale(float p_pitch_scale); float get_pitch_scale() const; diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp index 2015ede81f..f71679d30f 100644 --- a/servers/audio/effects/audio_effect_record.cpp +++ b/servers/audio/effects/audio_effect_record.cpp @@ -134,9 +134,9 @@ AudioEffectRecordInstance::~AudioEffectRecordInstance() { finish(); } -Ref<AudioEffectInstance> AudioEffectRecord::instance() { +Ref<AudioEffectInstance> AudioEffectRecord::instantiate() { Ref<AudioEffectRecordInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectRecord>(this); ins->is_recording = false; @@ -269,7 +269,7 @@ Ref<AudioStreamSample> AudioEffectRecord::get_recording() const { } Ref<AudioStreamSample> sample; - sample.instance(); + sample.instantiate(); sample->set_data(dst_data); sample->set_format(dst_format); sample->set_mix_rate(AudioServer::get_singleton()->get_mix_rate()); diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index b97ec43946..1a89821f80 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -31,8 +31,8 @@ #ifndef AUDIOEFFECTRECORD_H #define AUDIOEFFECTRECORD_H +#include "core/io/file_access.h" #include "core/io/marshalls.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "core/os/thread.h" #include "editor/import/resource_importer_wav.h" @@ -96,7 +96,7 @@ protected: static void debug(uint64_t time_diff, int p_frame_count); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_recording_active(bool p_record); bool is_recording_active() const; void set_format(AudioStreamSample::Format p_format); diff --git a/servers/audio/effects/audio_effect_reverb.cpp b/servers/audio/effects/audio_effect_reverb.cpp index b8d812680e..819f906773 100644 --- a/servers/audio/effects/audio_effect_reverb.cpp +++ b/servers/audio/effects/audio_effect_reverb.cpp @@ -79,9 +79,9 @@ AudioEffectReverbInstance::AudioEffectReverbInstance() { reverb[1].set_extra_spread_base(0.000521); //for stereo effect } -Ref<AudioEffectInstance> AudioEffectReverb::instance() { +Ref<AudioEffectInstance> AudioEffectReverb::instantiate() { Ref<AudioEffectReverbInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectReverb>(this); return ins; } diff --git a/servers/audio/effects/audio_effect_reverb.h b/servers/audio/effects/audio_effect_reverb.h index 141ba48e29..d01d1120bd 100644 --- a/servers/audio/effects/audio_effect_reverb.h +++ b/servers/audio/effects/audio_effect_reverb.h @@ -89,7 +89,7 @@ public: float get_wet() const; float get_hpf() const; - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_volume_db(float p_volume); float get_volume_db() const; diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp index 44b7f64d52..6f9e7ac67d 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp @@ -207,9 +207,9 @@ Vector2 AudioEffectSpectrumAnalyzerInstance::get_magnitude_for_frequency_range(f } } -Ref<AudioEffectInstance> AudioEffectSpectrumAnalyzer::instance() { +Ref<AudioEffectInstance> AudioEffectSpectrumAnalyzer::instantiate() { Ref<AudioEffectSpectrumAnalyzerInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectSpectrumAnalyzer>(this); static const int fft_sizes[FFT_SIZE_MAX] = { 256, 512, 1024, 2048, 4096 }; ins->fft_size = fft_sizes[fft_size]; diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.h b/servers/audio/effects/audio_effect_spectrum_analyzer.h index fc275446f0..3c5ae4a5e8 100644 --- a/servers/audio/effects/audio_effect_spectrum_analyzer.h +++ b/servers/audio/effects/audio_effect_spectrum_analyzer.h @@ -90,7 +90,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_buffer_length(float p_seconds); float get_buffer_length() const; void set_tap_back_pos(float p_seconds); diff --git a/servers/audio/effects/audio_effect_stereo_enhance.cpp b/servers/audio/effects/audio_effect_stereo_enhance.cpp index dfdf154aa4..3a016b06b8 100644 --- a/servers/audio/effects/audio_effect_stereo_enhance.cpp +++ b/servers/audio/effects/audio_effect_stereo_enhance.cpp @@ -74,9 +74,9 @@ AudioEffectStereoEnhanceInstance::~AudioEffectStereoEnhanceInstance() { memdelete_arr(delay_ringbuff); } -Ref<AudioEffectInstance> AudioEffectStereoEnhance::instance() { +Ref<AudioEffectInstance> AudioEffectStereoEnhance::instantiate() { Ref<AudioEffectStereoEnhanceInstance> ins; - ins.instance(); + ins.instantiate(); ins->base = Ref<AudioEffectStereoEnhance>(this); diff --git a/servers/audio/effects/audio_effect_stereo_enhance.h b/servers/audio/effects/audio_effect_stereo_enhance.h index f99256470b..e0f9d79a94 100644 --- a/servers/audio/effects/audio_effect_stereo_enhance.h +++ b/servers/audio/effects/audio_effect_stereo_enhance.h @@ -68,7 +68,7 @@ protected: static void _bind_methods(); public: - Ref<AudioEffectInstance> instance() override; + Ref<AudioEffectInstance> instantiate() override; void set_pan_pullout(float p_amount); float get_pan_pullout() const; diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp index d1a05ccf2a..bced2997ce 100644 --- a/servers/audio/effects/audio_stream_generator.cpp +++ b/servers/audio/effects/audio_stream_generator.cpp @@ -48,7 +48,7 @@ float AudioStreamGenerator::get_buffer_length() const { Ref<AudioStreamPlayback> AudioStreamGenerator::instance_playback() { Ref<AudioStreamGeneratorPlayback> playback; - playback.instance(); + playback.instantiate(); playback->generator = this; int target_buffer_size = mix_rate * buffer_len; playback->buffer.resize(nearest_shift(target_buffer_size)); diff --git a/servers/audio/effects/reverb.cpp b/servers/audio/effects/reverb.cpp index 7df2f99f67..1d97de5205 100644 --- a/servers/audio/effects/reverb.cpp +++ b/servers/audio/effects/reverb.cpp @@ -290,7 +290,7 @@ void Reverb::update_parameters() { c.feedback = (room_offset + room_scale); } - float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough) + float auxdmp = params.damp / 2.0 + 0.5; //only half the range (0.5 .. 1.0 is enough) auxdmp *= auxdmp; c.damp = expf(-Math_TAU * auxdmp * 10000 / params.mix_rate); // 0 .. 10khz diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 0e816fd4f8..667087d1ec 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -32,8 +32,8 @@ #include "core/config/project_settings.h" #include "core/debugger/engine_debugger.h" +#include "core/io/file_access.h" #include "core/io/resource_loader.h" -#include "core/os/file_access.h" #include "core/os/os.h" #include "scene/resources/audio_stream_sample.h" #include "servers/audio/audio_driver_dummy.h" @@ -794,7 +794,7 @@ void AudioServer::_update_bus_effects(int p_bus) { for (int i = 0; i < buses[p_bus]->channels.size(); i++) { buses.write[p_bus]->channels.write[i].effect_instances.resize(buses[p_bus]->effects.size()); for (int j = 0; j < buses[p_bus]->effects.size(); j++) { - Ref<AudioEffectInstance> fx = buses.write[p_bus]->effects.write[j].effect->instance(); + Ref<AudioEffectInstance> fx = buses.write[p_bus]->effects.write[j].effect->instantiate(); if (Object::cast_to<AudioEffectCompressorInstance>(*fx)) { Object::cast_to<AudioEffectCompressorInstance>(*fx)->set_current_channel(i); } @@ -813,7 +813,7 @@ void AudioServer::add_bus_effect(int p_bus, const Ref<AudioEffect> &p_effect, in Bus::Effect fx; fx.effect = p_effect; - //fx.instance=p_effect->instance(); + //fx.instance=p_effect->instantiate(); fx.enabled = true; #ifdef DEBUG_ENABLED fx.prof_time = 0; @@ -1188,7 +1188,7 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { Ref<AudioBusLayout> AudioServer::generate_bus_layout() const { Ref<AudioBusLayout> state; - state.instance(); + state.instantiate(); state->buses.resize(buses.size()); diff --git a/servers/camera/camera_feed.h b/servers/camera/camera_feed.h index eb4ef155bc..fac7ae1b2d 100644 --- a/servers/camera/camera_feed.h +++ b/servers/camera/camera_feed.h @@ -43,8 +43,8 @@ camera feeds that can be used as the background for our environment. **/ -class CameraFeed : public Reference { - GDCLASS(CameraFeed, Reference); +class CameraFeed : public RefCounted { + GDCLASS(CameraFeed, RefCounted); public: enum FeedDataType { diff --git a/servers/camera_server.h b/servers/camera_server.h index 97aa8f74ba..7390129df9 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -32,7 +32,7 @@ #define CAMERA_SERVER_H #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/thread_safe.h" #include "core/templates/rid.h" #include "core/variant/variant.h" diff --git a/servers/display_server.cpp b/servers/display_server.cpp index ded4b849ef..be2a813fd1 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -35,7 +35,6 @@ #include "servers/display_server_headless.h" DisplayServer *DisplayServer::singleton = nullptr; -DisplayServer::SwitchVSyncCallbackInThread DisplayServer::switch_vsync_function = nullptr; bool DisplayServer::hidpi_allowed = false; @@ -148,8 +147,8 @@ Point2i DisplayServer::mouse_get_position() const { ERR_FAIL_V_MSG(Point2i(), "Mouse is not supported by this display server."); } -int DisplayServer::mouse_get_button_state() const { - ERR_FAIL_V_MSG(0, "Mouse is not supported by this display server."); +MouseButton DisplayServer::mouse_get_button_state() const { + ERR_FAIL_V_MSG(MOUSE_BUTTON_NONE, "Mouse is not supported by this display server."); } void DisplayServer::clipboard_set(const String &p_text) { @@ -185,7 +184,7 @@ bool DisplayServer::screen_is_kept_on() const { return false; } -DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServer::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Sub-windows not supported by this display server."); } @@ -309,29 +308,13 @@ void DisplayServer::set_icon(const Ref<Image> &p_icon) { WARN_PRINT("Icon not supported by this display server."); } -void DisplayServer::_set_use_vsync(bool p_enable) { - WARN_PRINT("VSync not supported by this display server."); +void DisplayServer::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + WARN_PRINT("Changing the VSync mode is not supported by this display server."); } -void DisplayServer::vsync_set_enabled(bool p_enable) { - vsync_enabled = p_enable; - if (switch_vsync_function) { //if a function was set, use function - switch_vsync_function(p_enable); - } else { //otherwise just call here - _set_use_vsync(p_enable); - } -} - -bool DisplayServer::vsync_is_enabled() const { - return vsync_enabled; -} - -void DisplayServer::vsync_set_use_via_compositor(bool p_enable) { - WARN_PRINT("VSync via compositor not supported by this display server."); -} - -bool DisplayServer::vsync_is_using_via_compositor() const { - return false; +DisplayServer::VSyncMode DisplayServer::window_get_vsync_mode(WindowID p_window) const { + WARN_PRINT("Changing the VSync mode is not supported by this display server."); + return VSyncMode::VSYNC_ENABLED; } void DisplayServer::set_context(Context p_context) { @@ -394,7 +377,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_window_list"), &DisplayServer::get_window_list); ClassDB::bind_method(D_METHOD("get_window_at_screen_position", "position"), &DisplayServer::get_window_at_screen_position); - ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i())); + ClassDB::bind_method(D_METHOD("create_sub_window", "mode", "vsync_mode", "flags", "rect"), &DisplayServer::create_sub_window, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("delete_sub_window", "window_id"), &DisplayServer::delete_sub_window); ClassDB::bind_method(D_METHOD("window_set_title", "title", "window_id"), &DisplayServer::window_set_title, DEFVAL(MAIN_WINDOW_ID)); @@ -441,6 +424,9 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("window_set_ime_active", "active", "window_id"), &DisplayServer::window_set_ime_active, DEFVAL(MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("window_set_ime_position", "position", "window_id"), &DisplayServer::window_set_ime_position, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_set_vsync_mode", "vsync_mode", "window_id"), &DisplayServer::window_set_vsync_mode, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("window_get_vsync_mode", "window_id"), &DisplayServer::window_get_vsync_mode, DEFVAL(MAIN_WINDOW_ID)); + ClassDB::bind_method(D_METHOD("ime_get_selection"), &DisplayServer::ime_get_selection); ClassDB::bind_method(D_METHOD("ime_get_text"), &DisplayServer::ime_get_text); @@ -472,12 +458,6 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events); ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events); - ClassDB::bind_method(D_METHOD("vsync_set_enabled", "enabled"), &DisplayServer::vsync_set_enabled); - ClassDB::bind_method(D_METHOD("vsync_is_enabled"), &DisplayServer::vsync_is_enabled); - - ClassDB::bind_method(D_METHOD("vsync_set_use_via_compositor", "enabled"), &DisplayServer::vsync_set_use_via_compositor); - ClassDB::bind_method(D_METHOD("vsync_is_using_via_compositor"), &DisplayServer::vsync_is_using_via_compositor); - ClassDB::bind_method(D_METHOD("set_native_icon", "filename"), &DisplayServer::set_native_icon); ClassDB::bind_method(D_METHOD("set_icon", "image"), &DisplayServer::set_icon); @@ -561,6 +541,11 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(WINDOW_EVENT_CLOSE_REQUEST); BIND_ENUM_CONSTANT(WINDOW_EVENT_GO_BACK_REQUEST); BIND_ENUM_CONSTANT(WINDOW_EVENT_DPI_CHANGE); + + BIND_ENUM_CONSTANT(VSYNC_DISABLED); + BIND_ENUM_CONSTANT(VSYNC_ENABLED); + BIND_ENUM_CONSTANT(VSYNC_ADAPTIVE); + BIND_ENUM_CONSTANT(VSYNC_MAILBOX); } void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) { @@ -587,9 +572,9 @@ Vector<String> DisplayServer::get_create_function_rendering_drivers(int p_index) return server_create_functions[p_index].get_rendering_drivers_function(); } -DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServer *DisplayServer::create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); - return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_flags, p_resolution, r_error); + return server_create_functions[p_index].create_function(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error); } void DisplayServer::_input_set_mouse_mode(Input::MouseMode p_mode) { diff --git a/servers/display_server.h b/servers/display_server.h index b8201f6fd5..8d289b10fd 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -42,7 +42,6 @@ class DisplayServer : public Object { GDCLASS(DisplayServer, Object) static DisplayServer *singleton; - bool vsync_enabled = true; static bool hidpi_allowed; public: @@ -57,7 +56,16 @@ public: WINDOW_MODE_FULLSCREEN }; - typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, uint32_t, const Size2i &, Error &r_error); + // Keep the VSyncMode enum values in sync with the `display/window/vsync/vsync_mode` + // project setting hint. + enum VSyncMode { + VSYNC_DISABLED, + VSYNC_ENABLED, + VSYNC_ADAPTIVE, + VSYNC_MAILBOX + }; + + typedef DisplayServer *(*CreateFunction)(const String &, WindowMode, VSyncMode, uint32_t, const Size2i &, Error &r_error); typedef Vector<String> (*GetRenderingDriversFunction)(); private: @@ -84,7 +92,6 @@ protected: static int server_create_count; friend class RendererViewport; - virtual void _set_use_vsync(bool p_enable); public: enum Feature { @@ -152,7 +159,7 @@ public: virtual void mouse_warp_to_position(const Point2i &p_to); virtual Point2i mouse_get_position() const; virtual Point2i mouse_get_absolute_position() const; - virtual int mouse_get_button_state() const; + virtual MouseButton mouse_get_button_state() const; virtual void clipboard_set(const String &p_text); virtual String clipboard_get() const; @@ -221,7 +228,7 @@ public: WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS) }; - virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); virtual void show_window(WindowID p_id); virtual void delete_sub_window(WindowID p_id); @@ -272,6 +279,9 @@ public: virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) = 0; virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const = 0; + virtual void window_set_vsync_mode(VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID); + virtual VSyncMode window_get_vsync_mode(WindowID p_window) const; + virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const = 0; virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) = 0; @@ -352,18 +362,6 @@ public: virtual void set_native_icon(const String &p_filename); virtual void set_icon(const Ref<Image> &p_icon); - typedef void (*SwitchVSyncCallbackInThread)(bool); - - static SwitchVSyncCallbackInThread switch_vsync_function; - - void vsync_set_enabled(bool p_enable); - bool vsync_is_enabled() const; - - virtual void vsync_set_use_via_compositor(bool p_enable); - virtual bool vsync_is_using_via_compositor() const; - - //real, actual overridable function to switch vsync, which needs to be called from graphics thread if needed - enum Context { CONTEXT_EDITOR, CONTEXT_PROJECTMAN, @@ -376,7 +374,7 @@ public: static int get_create_function_count(); static const char *get_create_function_name(int p_index); static Vector<String> get_create_function_rendering_drivers(int p_index); - static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create(int p_index, const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); DisplayServer(); ~DisplayServer(); @@ -389,5 +387,6 @@ VARIANT_ENUM_CAST(DisplayServer::ScreenOrientation) VARIANT_ENUM_CAST(DisplayServer::WindowMode) VARIANT_ENUM_CAST(DisplayServer::WindowFlags) VARIANT_ENUM_CAST(DisplayServer::CursorShape) +VARIANT_ENUM_CAST(DisplayServer::VSyncMode) #endif // DISPLAY_SERVER_H diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index 8b386c8d9c..870401b180 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -45,7 +45,7 @@ private: return drivers; } - static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + static DisplayServer *create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { r_error = OK; RasterizerDummy::make_current(); return memnew(DisplayServerHeadless()); diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index 9e32bc209b..ef2635c188 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "servers/navigation_server_2d.h" -#include "core/math/transform.h" #include "core/math/transform_2d.h" +#include "core/math/transform_3d.h" #include "servers/navigation_server_3d.h" /** @@ -129,12 +129,12 @@ static Vector<Vector2> vector_v3_to_v2(const Vector<Vector3> &d) { return nd; } -static Transform trf2_to_trf3(const Transform2D &d) { +static Transform3D trf2_to_trf3(const Transform2D &d) { Vector3 o(v2_to_v3(d.get_origin())); Basis b; b.rotate(Vector3(0, -1, 0), d.get_rotation()); b.scale(v2_to_v3(d.get_scale())); - return Transform(b, o); + return Transform3D(b, o); } static Object *obj_to_obj(Object *d) { diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 420f9c9c18..3aef693ac8 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -106,7 +106,7 @@ public: virtual uint32_t region_get_layers(RID p_region) const = 0; /// Set the global transformation of this region. - virtual void region_set_transform(RID p_region, Transform p_transform) const = 0; + virtual void region_set_transform(RID p_region, Transform3D p_transform) const = 0; /// Set the navigation mesh of this region. virtual void region_set_navmesh(RID p_region, Ref<NavigationMesh> p_nav_mesh) const = 0; diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp index eb9fc0e800..5cc5bae09b 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/area_pair_2d_sw.cpp @@ -33,10 +33,7 @@ bool AreaPair2DSW::setup(real_t p_step) { bool result = false; - - if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) { - result = false; - } else if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) { + if (area->test_collision_mask(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) { result = true; } @@ -113,9 +110,7 @@ AreaPair2DSW::~AreaPair2DSW() { bool Area2Pair2DSW::setup(real_t p_step) { bool result = false; - if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) { - result = false; - } else if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) { + if (area_a->test_collision_mask(area_b) && CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) { result = true; } diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp index f78a487e27..6f244deb1e 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/body_2d_sw.cpp @@ -43,7 +43,7 @@ void Body2DSW::update_inertias() { //update shapes and motions switch (mode) { - case PhysicsServer2D::BODY_MODE_RIGID: { + case PhysicsServer2D::BODY_MODE_DYNAMIC: { if (user_inertia) { _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; break; @@ -87,7 +87,7 @@ void Body2DSW::update_inertias() { _inv_inertia = 0; _inv_mass = 0; } break; - case PhysicsServer2D::BODY_MODE_CHARACTER: { + case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { _inv_inertia = 0; _inv_mass = 1.0 / mass; @@ -204,14 +204,14 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { first_time_kinematic = true; } } break; - case PhysicsServer2D::BODY_MODE_RIGID: { + case PhysicsServer2D::BODY_MODE_DYNAMIC: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; _set_static(false); set_active(true); } break; - case PhysicsServer2D::BODY_MODE_CHARACTER: { + case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _inv_inertia = 0; _set_static(false); @@ -219,7 +219,7 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { angular_velocity = 0; } break; } - if (p_mode == PhysicsServer2D::BODY_MODE_RIGID && _inv_inertia == 0) { + if (p_mode == PhysicsServer2D::BODY_MODE_DYNAMIC && _inv_inertia == 0) { _update_inertia(); } /* @@ -267,25 +267,16 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } break; case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: { - /* - if (mode==PhysicsServer2D::BODY_MODE_STATIC) - break; - */ linear_velocity = p_variant; wakeup(); } break; case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: { - /* - if (mode!=PhysicsServer2D::BODY_MODE_RIGID) - break; - */ angular_velocity = p_variant; wakeup(); } break; case PhysicsServer2D::BODY_STATE_SLEEPING: { - //? if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) { break; } @@ -304,7 +295,7 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } break; case PhysicsServer2D::BODY_STATE_CAN_SLEEP: { can_sleep = p_variant; - if (mode == PhysicsServer2D::BODY_MODE_RIGID && !active && !can_sleep) { + if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) { set_active(true); } @@ -551,7 +542,7 @@ void Body2DSW::wakeup_neighbours() { continue; } Body2DSW *b = n[i]; - if (b->mode != PhysicsServer2D::BODY_MODE_RIGID) { + if (b->mode != PhysicsServer2D::BODY_MODE_DYNAMIC) { continue; } @@ -588,9 +579,7 @@ void Body2DSW::call_queries() { bool Body2DSW::sleep_test(real_t p_step) { if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) { - return true; // - } else if (mode == PhysicsServer2D::BODY_MODE_CHARACTER) { - return !active; // characters and kinematic bodies don't sleep unless asked to sleep + return true; } else if (!can_sleep) { return false; } @@ -623,7 +612,7 @@ Body2DSW::Body2DSW() : active_list(this), inertia_update_list(this), direct_state_query_list(this) { - mode = PhysicsServer2D::BODY_MODE_RIGID; + mode = PhysicsServer2D::BODY_MODE_DYNAMIC; active = true; angular_velocity = 0; biased_angular_velocity = 0; diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index ff31825b83..e5eb374fa3 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -244,11 +244,6 @@ bool BodyPair2DSW::setup(real_t p_step) { } } - if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) { - collided = false; - return false; - } - //use local A coordinates to avoid numerical issues on collision detection offset_B = B->get_transform().get_origin() - A->get_transform().get_origin(); diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index fa87dc1f3f..5d1ef83165 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -47,8 +47,6 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra if (!pending_shape_update_list.in_list()) { PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - // _update_shapes(); - // _shapes_changed(); } void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { @@ -61,8 +59,6 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { if (!pending_shape_update_list.in_list()) { PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - // _update_shapes(); - // _shapes_changed(); } void CollisionObject2DSW::set_shape_metadata(int p_index, const Variant &p_metadata) { @@ -79,11 +75,9 @@ void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_ if (!pending_shape_update_list.in_list()) { PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - // _update_shapes(); - // _shapes_changed(); } -void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) { +void CollisionObject2DSW::set_shape_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, shapes.size()); CollisionObject2DSW::Shape &shape = shapes.write[p_idx]; @@ -103,12 +97,10 @@ void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) { if (!pending_shape_update_list.in_list()) { PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - //_update_shapes(); } else if (!p_disabled && shape.bpid == 0) { if (!pending_shape_update_list.in_list()) { PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - //_update_shapes(); // automatically adds shape with bpid == 0 } } @@ -177,7 +169,6 @@ void CollisionObject2DSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; - if (s.disabled) { continue; } diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index c395e59694..67da758d14 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -118,10 +118,6 @@ public: void set_shape_metadata(int p_index, const Variant &p_metadata); _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); } - _FORCE_INLINE_ bool is_shape_disabled(int p_index) const { - CRASH_BAD_INDEX(p_index, shapes.size()); - return shapes[p_index].disabled; - } _FORCE_INLINE_ Shape2DSW *get_shape(int p_index) const { CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].shape; @@ -147,9 +143,9 @@ public: _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; } _FORCE_INLINE_ Space2DSW *get_space() const { return space; } - void set_shape_as_disabled(int p_idx, bool p_disabled); - _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { - CRASH_BAD_INDEX(p_idx, shapes.size()); + void set_shape_disabled(int p_idx, bool p_disabled); + _FORCE_INLINE_ bool is_shape_disabled(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, shapes.size(), false); return shapes[p_idx].disabled; } diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp index 1c2dca0259..155dda4394 100644 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ b/servers/physics_2d/physics_server_2d_sw.cpp @@ -366,7 +366,7 @@ void PhysicsServer2DSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_ ERR_FAIL_INDEX(p_shape, area->get_shape_count()); FLUSH_QUERY_CHECK(area); - area->set_shape_as_disabled(p_shape, p_disabled); + area->set_shape_disabled(p_shape, p_disabled); } int PhysicsServer2DSW::area_get_shape_count(RID p_area) const { @@ -663,7 +663,7 @@ void PhysicsServer2DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, boo ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); FLUSH_QUERY_CHECK(body); - body->set_shape_as_disabled(p_shape_idx, p_disabled); + body->set_shape_disabled(p_shape_idx, p_disabled); } void PhysicsServer2DSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) { diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/physics_server_2d_sw.h index f1eb78a776..5002bf5fc8 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/physics_server_2d_sw.h @@ -247,8 +247,8 @@ public: virtual void body_set_pickable(RID p_body, bool p_pickable) override; - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; + virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; + virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.08) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override; diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_2d/physics_server_2d_wrap_mt.cpp index 790c87cc44..930b19c2cb 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_2d/physics_server_2d_wrap_mt.cpp @@ -56,7 +56,7 @@ void PhysicsServer2DWrapMT::thread_loop() { step_thread_up.set(); while (!exit.is_set()) { // flush commands one by one, until exit is requested - command_queue.wait_and_flush_one(); + command_queue.wait_and_flush(); } command_queue.flush_all(); // flush all diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_2d/physics_server_2d_wrap_mt.h index c776641699..a8f7ff3393 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_2d/physics_server_2d_wrap_mt.h @@ -253,12 +253,12 @@ public: FUNC2(body_set_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { + bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); } - int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override { + int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.08) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); return physics_2d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); } diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp index 4f12248c3e..4b123b2d46 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/space_2d_sw.cpp @@ -84,10 +84,6 @@ int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, S int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - Shape2DSW *shape = col_obj->get_shape(shape_idx); Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point); @@ -233,10 +229,6 @@ int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Trans const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_margin)) { continue; } @@ -280,10 +272,6 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) { @@ -365,10 +353,6 @@ bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D & int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - cbk.valid_dir = Vector2(); cbk.valid_depth = 0; @@ -460,10 +444,6 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - rcd.valid_dir = Vector2(); rcd.object = col_obj; rcd.shape = shape_idx; @@ -516,8 +496,6 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { keep = false; } else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { keep = false; - } else if (static_cast<Body2DSW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i])) { - keep = false; } if (!keep) { @@ -540,7 +518,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t bool shapes_found = false; for (int i = 0; i < p_body->get_shape_count(); i++) { - if (p_body->is_shape_set_as_disabled(i)) { + if (p_body->is_shape_disabled(i)) { continue; } @@ -592,7 +570,7 @@ int Space2DSW::test_body_ray_separation(Body2DSW *p_body, const Transform2D &p_t int amount = _cull_aabb_for_body(p_body, body_aabb); for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } @@ -732,7 +710,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co bool shapes_found = false; for (int i = 0; i < p_body->get_shape_count(); i++) { - if (p_body->is_shape_set_as_disabled(i)) { + if (p_body->is_shape_disabled(i)) { continue; } @@ -795,7 +773,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co int amount = _cull_aabb_for_body(p_body, body_aabb); for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } @@ -827,7 +805,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); - if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) { + if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) { //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction Vector2 lv = b->get_linear_velocity(); //compute displacement from linear velocity @@ -918,7 +896,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co int amount = _cull_aabb_for_body(p_body, motion_aabb); for (int body_shape_idx = 0; body_shape_idx < p_body->get_shape_count(); body_shape_idx++) { - if (p_body->is_shape_set_as_disabled(body_shape_idx)) { + if (p_body->is_shape_disabled(body_shape_idx)) { continue; } @@ -1060,7 +1038,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); for (int j = from_shape; j < to_shape; j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } @@ -1109,7 +1087,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); - if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_RIGID) { + if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) { //fix for moving platforms (kinematic and dynamic), margin is increased by how much it moved in the given direction Vector2 lv = b->get_linear_velocity(); //compute displacement from linear velocity @@ -1142,6 +1120,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co r_result->collision_local_shape = rcd.best_local_shape; r_result->collision_normal = rcd.best_normal; r_result->collision_point = rcd.best_contact; + r_result->collision_depth = rcd.best_len; + r_result->collision_safe_fraction = safe; + r_result->collision_unsafe_fraction = unsafe; r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object); diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/area_3d_sw.cpp index bb4e0ed752..a9f5c4aec3 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/area_3d_sw.cpp @@ -52,7 +52,7 @@ void Area3DSW::_shapes_changed() { } } -void Area3DSW::set_transform(const Transform &p_transform) { +void Area3DSW::set_transform(const Transform3D &p_transform) { if (!moved_list.in_list() && get_space()) { get_space()->area_add_to_moved_list(&moved_list); } diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/area_3d_sw.h index 8a0a1e963b..12f7545c08 100644 --- a/servers/physics_3d/area_3d_sw.h +++ b/servers/physics_3d/area_3d_sw.h @@ -156,7 +156,7 @@ public: void set_monitorable(bool p_monitorable); _FORCE_INLINE_ bool is_monitorable() const { return monitorable; } - void set_transform(const Transform &p_transform); + void set_transform(const Transform3D &p_transform); void set_space(Space3DSW *p_space); diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp index 2073df7dee..9f93a61909 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/area_pair_3d_sw.cpp @@ -33,10 +33,7 @@ bool AreaPair3DSW::setup(real_t p_step) { bool result = false; - - if (area->is_shape_set_as_disabled(area_shape) || body->is_shape_set_as_disabled(body_shape)) { - result = false; - } else if (area->test_collision_mask(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) { + if (area->test_collision_mask(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) { result = true; } @@ -113,9 +110,7 @@ AreaPair3DSW::~AreaPair3DSW() { bool Area2Pair3DSW::setup(real_t p_step) { bool result = false; - if (area_a->is_shape_set_as_disabled(shape_a) || area_b->is_shape_set_as_disabled(shape_b)) { - result = false; - } else if (area_a->test_collision_mask(area_b) && CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) { + if (area_a->test_collision_mask(area_b) && CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) { result = true; } diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp index e4f9548a61..ea6064cb4c 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/body_3d_sw.cpp @@ -54,7 +54,7 @@ void Body3DSW::update_inertias() { // Update shapes and motions. switch (mode) { - case PhysicsServer3D::BODY_MODE_RIGID: { + case PhysicsServer3D::BODY_MODE_DYNAMIC: { // Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet) real_t total_area = 0; @@ -100,7 +100,7 @@ void Body3DSW::update_inertias() { real_t mass = area * this->mass / total_area; Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix(); - Transform shape_transform = get_shape_transform(i); + Transform3D shape_transform = get_shape_transform(i); Basis shape_basis = shape_transform.basis.orthonormalized(); // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor! @@ -132,7 +132,7 @@ void Body3DSW::update_inertias() { _inv_inertia_tensor.set_zero(); _inv_mass = 0; } break; - case PhysicsServer3D::BODY_MODE_CHARACTER: { + case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { _inv_inertia_tensor.set_zero(); _inv_mass = 1.0 / mass; @@ -239,13 +239,13 @@ void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) { } } break; - case PhysicsServer3D::BODY_MODE_RIGID: { + case PhysicsServer3D::BODY_MODE_DYNAMIC: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _set_static(false); set_active(true); } break; - case PhysicsServer3D::BODY_MODE_CHARACTER: { + case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _set_static(false); set_active(true); @@ -286,7 +286,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va _set_inv_transform(get_transform().affine_inverse()); wakeup_neighbours(); } else { - Transform t = p_variant; + Transform3D t = p_variant; t.orthonormalize(); new_transform = get_transform(); //used as old to compute motion if (new_transform == t) { @@ -299,24 +299,15 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } break; case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: { - /* - if (mode==PhysicsServer3D::BODY_MODE_STATIC) - break; - */ linear_velocity = p_variant; wakeup(); } break; case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: { - /* - if (mode!=PhysicsServer3D::BODY_MODE_RIGID) - break; - */ angular_velocity = p_variant; wakeup(); } break; case PhysicsServer3D::BODY_STATE_SLEEPING: { - //? if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC) { break; } @@ -333,7 +324,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } break; case PhysicsServer3D::BODY_STATE_CAN_SLEEP: { can_sleep = p_variant; - if (mode == PhysicsServer3D::BODY_MODE_RIGID && !active && !can_sleep) { + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) { set_active(true); } @@ -585,7 +576,7 @@ void Body3DSW::integrate_velocities(real_t p_step) { Vector3 total_angular_velocity = angular_velocity + biased_angular_velocity; real_t ang_vel = total_angular_velocity.length(); - Transform transform = get_transform(); + Transform3D transform = get_transform(); if (ang_vel != 0.0) { Vector3 ang_vel_axis = total_angular_velocity / ang_vel; @@ -617,8 +608,8 @@ void Body3DSW::integrate_velocities(real_t p_step) { } /* -void BodySW::simulate_motion(const Transform& p_xform,real_t p_step) { - Transform inv_xform = p_xform.affine_inverse(); +void BodySW::simulate_motion(const Transform3D& p_xform,real_t p_step) { + Transform3D inv_xform = p_xform.affine_inverse(); if (!get_space()) { _set_transform(p_xform); _set_inv_transform(inv_xform); @@ -659,7 +650,7 @@ void Body3DSW::wakeup_neighbours() { continue; } Body3DSW *b = n[i]; - if (b->mode != PhysicsServer3D::BODY_MODE_RIGID) { + if (b->mode != PhysicsServer3D::BODY_MODE_DYNAMIC) { continue; } @@ -693,9 +684,7 @@ void Body3DSW::call_queries() { bool Body3DSW::sleep_test(real_t p_step) { if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC) { - return true; // - } else if (mode == PhysicsServer3D::BODY_MODE_CHARACTER) { - return !active; // characters don't sleep unless asked to sleep + return true; } else if (!can_sleep) { return false; } @@ -723,22 +712,16 @@ void Body3DSW::set_force_integration_callback(const Callable &p_callable, const } } -void Body3DSW::set_kinematic_margin(real_t p_margin) { - kinematic_safe_margin = p_margin; -} - Body3DSW::Body3DSW() : CollisionObject3DSW(TYPE_BODY), active_list(this), inertia_update_list(this), direct_state_query_list(this) { - mode = PhysicsServer3D::BODY_MODE_RIGID; + mode = PhysicsServer3D::BODY_MODE_DYNAMIC; active = true; mass = 1; - kinematic_safe_margin = 0.001; - //_inv_inertia=Transform(); _inv_mass = 1; bounce = 0; friction = 1; diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/body_3d_sw.h index 9afb8cd56f..0fa31c5037 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/body_3d_sw.h @@ -55,7 +55,6 @@ class Body3DSW : public CollisionObject3DSW { uint16_t locked_axis = 0; - real_t kinematic_safe_margin; real_t _inv_mass; Vector3 _inv_inertia; // Relative to the principal axes of inertia @@ -93,7 +92,7 @@ class Body3DSW : public CollisionObject3DSW { bool first_time_kinematic; void _update_inertia(); virtual void _shapes_changed(); - Transform new_transform; + Transform3D new_transform; Map<Constraint3DSW *, int> constraint_map; @@ -144,9 +143,6 @@ class Body3DSW : public CollisionObject3DSW { public: void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant()); - void set_kinematic_margin(real_t p_margin); - _FORCE_INLINE_ real_t get_kinematic_margin() { return kinematic_safe_margin; } - _FORCE_INLINE_ void add_area(Area3DSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { @@ -311,7 +307,7 @@ public: return p_axis.dot(_inv_inertia_tensor.xform_inv(p_axis)); } - //void simulate_motion(const Transform& p_xform,real_t p_step); + //void simulate_motion(const Transform3D& p_xform,real_t p_step); void call_queries(); void wakeup_neighbours(); @@ -390,8 +386,8 @@ public: virtual void set_angular_velocity(const Vector3 &p_velocity) override { body->set_angular_velocity(p_velocity); } virtual Vector3 get_angular_velocity() const override { return body->get_angular_velocity(); } - virtual void set_transform(const Transform &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); } - virtual Transform get_transform() const override { return body->get_transform(); } + virtual void set_transform(const Transform3D &p_transform) override { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); } + virtual Transform3D get_transform() const override { return body->get_transform(); } virtual void add_central_force(const Vector3 &p_force) override { body->add_central_force(p_force); } virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) override { diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp index cdb3da665e..6fc0fa8690 100644 --- a/servers/physics_3d/body_pair_3d_sw.cpp +++ b/servers/physics_3d/body_pair_3d_sw.cpp @@ -161,7 +161,7 @@ void BodyPair3DSW::validate_contacts() { } } -bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B) { +bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform3D &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform3D &p_xform_B) { Vector3 motion = p_A->get_linear_velocity() * p_step; real_t mlen = motion.length(); if (mlen < CMP_EPSILON) { @@ -184,7 +184,7 @@ bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Vector3 from = p_xform_A.xform(s); Vector3 to = from + motion; - Transform from_inv = p_xform_B.affine_inverse(); + Transform3D from_inv = p_xform_B.affine_inverse(); Vector3 local_from = from_inv.xform(from - mnormal * mlen * 0.1); //start from a little inside the bounding box Vector3 local_to = from_inv.xform(to); @@ -230,22 +230,17 @@ bool BodyPair3DSW::setup(real_t p_step) { } } - if (A->is_shape_set_as_disabled(shape_A) || B->is_shape_set_as_disabled(shape_B)) { - collided = false; - return false; - } - offset_B = B->get_transform().get_origin() - A->get_transform().get_origin(); validate_contacts(); const Vector3 &offset_A = A->get_transform().get_origin(); - Transform xform_Au = Transform(A->get_transform().basis, Vector3()); - Transform xform_A = xform_Au * A->get_shape_transform(shape_A); + Transform3D xform_Au = Transform3D(A->get_transform().basis, Vector3()); + Transform3D xform_A = xform_Au * A->get_shape_transform(shape_A); - Transform xform_Bu = B->get_transform(); + Transform3D xform_Bu = B->get_transform(); xform_Bu.origin -= offset_A; - Transform xform_B = xform_Bu * B->get_shape_transform(shape_B); + Transform3D xform_B = xform_Bu * B->get_shape_transform(shape_B); Shape3DSW *shape_A_ptr = A->get_shape(shape_A); Shape3DSW *shape_B_ptr = B->get_shape(shape_B); @@ -571,7 +566,7 @@ void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int void BodySoftBodyPair3DSW::validate_contacts() { // Make sure to erase contacts that are no longer valid. - const Transform &transform_A = body->get_transform(); + const Transform3D &transform_A = body->get_transform(); real_t contact_max_separation = space->get_contact_max_separation(); @@ -607,16 +602,11 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { return false; } - if (body->is_shape_set_as_disabled(body_shape)) { - collided = false; - return false; - } - - const Transform &xform_Au = body->get_transform(); - Transform xform_A = xform_Au * body->get_shape_transform(body_shape); + const Transform3D &xform_Au = body->get_transform(); + Transform3D xform_A = xform_Au * body->get_shape_transform(body_shape); - Transform xform_Bu = soft_body->get_transform(); - Transform xform_B = xform_Bu * soft_body->get_shape_transform(0); + Transform3D xform_Bu = soft_body->get_transform(); + Transform3D xform_B = xform_Bu * soft_body->get_shape_transform(0); validate_contacts(); @@ -647,7 +637,7 @@ bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) { bool do_process = false; - const Transform &transform_A = body->get_transform(); + const Transform3D &transform_A = body->get_transform(); uint32_t contact_count = contacts.size(); for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) { diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h index 3f425ba2d7..976982d1f1 100644 --- a/servers/physics_3d/body_pair_3d_sw.h +++ b/servers/physics_3d/body_pair_3d_sw.h @@ -98,7 +98,7 @@ class BodyPair3DSW : public BodyContact3DSW { void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B); void validate_contacts(); - bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B); + bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform3D &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform3D &p_xform_B); public: virtual bool setup(real_t p_step) override; diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/collision_object_3d_sw.cpp index 459deb1356..24c7d7b85c 100644 --- a/servers/physics_3d/collision_object_3d_sw.cpp +++ b/servers/physics_3d/collision_object_3d_sw.cpp @@ -32,7 +32,7 @@ #include "servers/physics_3d/physics_server_3d_sw.h" #include "space_3d_sw.h" -void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform &p_transform, bool p_disabled) { +void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform3D &p_transform, bool p_disabled) { Shape s; s.shape = p_shape; s.xform = p_transform; @@ -45,8 +45,6 @@ void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform &p_trans if (!pending_shape_update_list.in_list()) { PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - //_update_shapes(); - //_shapes_changed(); } void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) { @@ -58,11 +56,9 @@ void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) { if (!pending_shape_update_list.in_list()) { PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - //_update_shapes(); - //_shapes_changed(); } -void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_transform) { +void CollisionObject3DSW::set_shape_transform(int p_index, const Transform3D &p_transform) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes.write[p_index].xform = p_transform; @@ -70,14 +66,32 @@ void CollisionObject3DSW::set_shape_transform(int p_index, const Transform &p_tr if (!pending_shape_update_list.in_list()) { PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - //_update_shapes(); - //_shapes_changed(); } -void CollisionObject3DSW::set_shape_as_disabled(int p_idx, bool p_enable) { - shapes.write[p_idx].disabled = p_enable; - if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); +void CollisionObject3DSW::set_shape_disabled(int p_idx, bool p_disabled) { + ERR_FAIL_INDEX(p_idx, shapes.size()); + + CollisionObject3DSW::Shape &shape = shapes.write[p_idx]; + if (shape.disabled == p_disabled) { + return; + } + + shape.disabled = p_disabled; + + if (!space) { + return; + } + + if (p_disabled && shape.bpid != 0) { + space->get_broadphase()->remove(shape.bpid); + shape.bpid = 0; + if (!pending_shape_update_list.in_list()) { + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } + } else if (!p_disabled && shape.bpid == 0) { + if (!pending_shape_update_list.in_list()) { + PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + } } } @@ -108,8 +122,6 @@ void CollisionObject3DSW::remove_shape(int p_index) { if (!pending_shape_update_list.in_list()) { PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); } - //_update_shapes(); - //_shapes_changed(); } void CollisionObject3DSW::_set_static(bool p_static) { @@ -146,10 +158,13 @@ void CollisionObject3DSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; + if (s.disabled) { + continue; + } //not quite correct, should compute the next matrix.. AABB shape_aabb = s.shape->get_aabb(); - Transform xform = transform * s.xform; + Transform3D xform = transform * s.xform; shape_aabb = xform.xform(shape_aabb); shape_aabb.grow_by((s.aabb_cache.size.x + s.aabb_cache.size.y) * 0.5 * 0.05); s.aabb_cache = shape_aabb; @@ -173,10 +188,13 @@ void CollisionObject3DSW::_update_shapes_with_motion(const Vector3 &p_motion) { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; + if (s.disabled) { + continue; + } //not quite correct, should compute the next matrix.. AABB shape_aabb = s.shape->get_aabb(); - Transform xform = transform * s.xform; + Transform3D xform = transform * s.xform; shape_aabb = xform.xform(shape_aabb); shape_aabb.merge_with(AABB(shape_aabb.position + p_motion, shape_aabb.size)); //use motion s.aabb_cache = shape_aabb; diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/collision_object_3d_sw.h index 85221b7746..b2b2fa0f50 100644 --- a/servers/physics_3d/collision_object_3d_sw.h +++ b/servers/physics_3d/collision_object_3d_sw.h @@ -60,8 +60,8 @@ private: uint32_t collision_mask; struct Shape { - Transform xform; - Transform xform_inv; + Transform3D xform; + Transform3D xform_inv; BroadPhase3DSW::ID bpid; AABB aabb_cache; //for rayqueries real_t area_cache; @@ -73,8 +73,8 @@ private: Vector<Shape> shapes; Space3DSW *space; - Transform transform; - Transform inv_transform; + Transform3D transform; + Transform3D inv_transform; bool _static; SelfList<CollisionObject3DSW> pending_shape_update_list; @@ -85,7 +85,7 @@ protected: void _update_shapes_with_motion(const Vector3 &p_motion); void _unregister_shapes(); - _FORCE_INLINE_ void _set_transform(const Transform &p_transform, bool p_update_shapes = true) { + _FORCE_INLINE_ void _set_transform(const Transform3D &p_transform, bool p_update_shapes = true) { #ifdef DEBUG_ENABLED ERR_FAIL_COND_MSG(p_transform.origin.length_squared() > MAX_OBJECT_DISTANCE_X2, "Object went too far away (more than '" + itos(MAX_OBJECT_DISTANCE) + "' units from origin)."); @@ -96,7 +96,7 @@ protected: _update_shapes(); } } - _FORCE_INLINE_ void _set_inv_transform(const Transform &p_transform) { inv_transform = p_transform; } + _FORCE_INLINE_ void _set_inv_transform(const Transform3D &p_transform) { inv_transform = p_transform; } void _set_static(bool p_static); virtual void _shapes_changed() = 0; @@ -116,30 +116,41 @@ public: void _shape_changed(); _FORCE_INLINE_ Type get_type() const { return type; } - void add_shape(Shape3DSW *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false); + void add_shape(Shape3DSW *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false); void set_shape(int p_index, Shape3DSW *p_shape); - void set_shape_transform(int p_index, const Transform &p_transform); + void set_shape_transform(int p_index, const Transform3D &p_transform); _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); } - _FORCE_INLINE_ bool is_shape_disabled(int p_index) const { + _FORCE_INLINE_ Shape3DSW *get_shape(int p_index) const { CRASH_BAD_INDEX(p_index, shapes.size()); - return shapes[p_index].disabled; + return shapes[p_index].shape; } - _FORCE_INLINE_ Shape3DSW *get_shape(int p_index) const { return shapes[p_index].shape; } - _FORCE_INLINE_ const Transform &get_shape_transform(int p_index) const { return shapes[p_index].xform; } - _FORCE_INLINE_ const Transform &get_shape_inv_transform(int p_index) const { return shapes[p_index].xform_inv; } - _FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const { return shapes[p_index].aabb_cache; } - _FORCE_INLINE_ real_t get_shape_area(int p_index) const { return shapes[p_index].area_cache; } - - _FORCE_INLINE_ const Transform &get_transform() const { return transform; } - _FORCE_INLINE_ const Transform &get_inv_transform() const { return inv_transform; } + _FORCE_INLINE_ const Transform3D &get_shape_transform(int p_index) const { + CRASH_BAD_INDEX(p_index, shapes.size()); + return shapes[p_index].xform; + } + _FORCE_INLINE_ const Transform3D &get_shape_inv_transform(int p_index) const { + CRASH_BAD_INDEX(p_index, shapes.size()); + return shapes[p_index].xform_inv; + } + _FORCE_INLINE_ const AABB &get_shape_aabb(int p_index) const { + CRASH_BAD_INDEX(p_index, shapes.size()); + return shapes[p_index].aabb_cache; + } + _FORCE_INLINE_ real_t get_shape_area(int p_index) const { + CRASH_BAD_INDEX(p_index, shapes.size()); + return shapes[p_index].area_cache; + } + + _FORCE_INLINE_ const Transform3D &get_transform() const { return transform; } + _FORCE_INLINE_ const Transform3D &get_inv_transform() const { return inv_transform; } _FORCE_INLINE_ Space3DSW *get_space() const { return space; } _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } - void set_shape_as_disabled(int p_idx, bool p_enable); - _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { - CRASH_BAD_INDEX(p_idx, shapes.size()); + void set_shape_disabled(int p_idx, bool p_disabled); + _FORCE_INLINE_ bool is_shape_disabled(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx, shapes.size(), false); return shapes[p_idx].disabled; } diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/collision_solver_3d_sat.cpp index fcac0587b2..1cfb9ba3ad 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/collision_solver_3d_sat.cpp @@ -608,8 +608,8 @@ template <class ShapeA, class ShapeB, bool withMargin = false> class SeparatorAxisTest { const ShapeA *shape_A; const ShapeB *shape_B; - const Transform *transform_A; - const Transform *transform_B; + const Transform3D *transform_A; + const Transform3D *transform_B; real_t best_depth; Vector3 best_axis; _CollectorCallback *callback; @@ -750,7 +750,7 @@ public: callback->collided = true; } - _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A, const Transform &p_transform_A, const ShapeB *p_shape_B, const Transform &p_transform_B, _CollectorCallback *p_callback, real_t p_margin_A = 0, real_t p_margin_B = 0) { + _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A, const Transform3D &p_transform_A, const ShapeB *p_shape_B, const Transform3D &p_transform_B, _CollectorCallback *p_callback, real_t p_margin_A = 0, real_t p_margin_B = 0) { best_depth = 1e15; shape_A = p_shape_A; shape_B = p_shape_B; @@ -764,10 +764,10 @@ public: /****** SAT TESTS *******/ -typedef void (*CollisionFunc)(const Shape3DSW *, const Transform &, const Shape3DSW *, const Transform &, _CollectorCallback *p_callback, real_t, real_t); +typedef void (*CollisionFunc)(const Shape3DSW *, const Transform3D &, const Shape3DSW *, const Transform3D &, _CollectorCallback *p_callback, real_t, real_t); template <bool withMargin> -static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); const SphereShape3DSW *sphere_B = static_cast<const SphereShape3DSW *>(p_b); @@ -787,7 +787,7 @@ static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform &p_tr } template <bool withMargin> -static void _collision_sphere_box(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_sphere_box(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); const BoxShape3DSW *box_B = static_cast<const BoxShape3DSW *>(p_b); @@ -838,7 +838,7 @@ static void _collision_sphere_box(const Shape3DSW *p_a, const Transform &p_trans } template <bool withMargin> -static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); const CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b); @@ -880,7 +880,7 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform &p_t } template <bool withMargin> -static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); @@ -939,7 +939,7 @@ static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform &p_ } template <bool withMargin> -static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); @@ -999,7 +999,7 @@ static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transfo } template <bool withMargin> -static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_sphere_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); @@ -1024,7 +1024,7 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran n1 *= -1.0; } - if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) { + if (!separator.test_axis(n1.normalized())) { return; } @@ -1035,7 +1035,7 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -1044,7 +1044,7 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform &p_tran } template <bool withMargin> -static void _collision_box_box(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_box_box(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); const BoxShape3DSW *box_B = static_cast<const BoxShape3DSW *>(p_b); @@ -1142,7 +1142,7 @@ static void _collision_box_box(const Shape3DSW *p_a, const Transform &p_transfor } template <bool withMargin> -static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_box_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); const CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b); @@ -1240,7 +1240,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform &p_tran } template <bool withMargin> -static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); @@ -1353,7 +1353,7 @@ static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform &p_tra } template <bool withMargin> -static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); @@ -1468,7 +1468,7 @@ static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform } template <bool withMargin> -static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_box_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); @@ -1493,7 +1493,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -1509,7 +1509,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -1533,7 +1533,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo axis_ab *= -1.0; } - if (!separator.test_axis(axis_ab.normalized(), !face_B->backface_collision)) { + if (!separator.test_axis(axis_ab.normalized())) { return; } @@ -1548,7 +1548,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -1578,7 +1578,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -1591,7 +1591,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform &p_transfo } template <bool withMargin> -static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); const CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b); @@ -1655,7 +1655,7 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform &p_ } template <bool withMargin> -static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); @@ -1717,7 +1717,7 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform &p } template <bool withMargin> -static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); @@ -1781,7 +1781,7 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf } template <bool withMargin> -static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_capsule_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); @@ -1812,7 +1812,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } @@ -1821,7 +1821,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra dir_axis *= -1.0; } - if (!separator.test_axis(dir_axis, !face_B->backface_collision)) { + if (!separator.test_axis(dir_axis)) { return; } @@ -1834,7 +1834,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra n1 *= -1.0; } - if (!separator.test_axis(n1.normalized(), !face_B->backface_collision)) { + if (!separator.test_axis(n1.normalized())) { return; } @@ -1845,7 +1845,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra axis *= -1.0; } - if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) { + if (!separator.test_axis(axis.normalized())) { return; } } @@ -1855,7 +1855,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform &p_tra } template <bool withMargin> -static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); @@ -1909,7 +1909,7 @@ static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform & } template <bool withMargin> -static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); @@ -1926,7 +1926,7 @@ static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Trans } template <bool withMargin> -static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); @@ -1955,7 +1955,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr } // Cylinder end caps. - if (!separator.test_axis(cyl_axis, !face_B->backface_collision)) { + if (!separator.test_axis(cyl_axis)) { return; } @@ -1971,7 +1971,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr axis *= -1.0; } - if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) { + if (!separator.test_axis(axis.normalized())) { return; } } @@ -1984,7 +1984,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -2021,7 +2021,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr axis *= -1.0; } - if (!separator.test_axis(axis.normalized(), !face_B->backface_collision)) { + if (!separator.test_axis(axis.normalized())) { return; } } @@ -2031,7 +2031,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform &p_tr } template <bool withMargin> -static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const ConvexPolygonShape3DSW *convex_polygon_A = static_cast<const ConvexPolygonShape3DSW *>(p_a); const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); @@ -2140,7 +2140,7 @@ static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const } template <bool withMargin> -static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform &p_transform_a, const Shape3DSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { +static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const ConvexPolygonShape3DSW *convex_polygon_A = static_cast<const ConvexPolygonShape3DSW *>(p_a); const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); @@ -2175,7 +2175,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -2192,7 +2192,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -2209,7 +2209,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -2229,7 +2229,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -2248,7 +2248,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform axis *= -1.0; } - if (!separator.test_axis(axis, !face_B->backface_collision)) { + if (!separator.test_axis(axis)) { return; } } @@ -2258,7 +2258,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform separator.generate_contacts(); } -bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) { +bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) { PhysicsServer3D::ShapeType type_A = p_shape_A->get_type(); ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_PLANE, false); @@ -2358,8 +2358,8 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_tr const Shape3DSW *A = p_shape_A; const Shape3DSW *B = p_shape_B; - const Transform *transform_A = &p_transform_A; - const Transform *transform_B = &p_transform_B; + const Transform3D *transform_A = &p_transform_A; + const Transform3D *transform_B = &p_transform_B; real_t margin_A = p_margin_a; real_t margin_B = p_margin_b; diff --git a/servers/physics_3d/collision_solver_3d_sat.h b/servers/physics_3d/collision_solver_3d_sat.h index 97454c0b4a..e50da7b101 100644 --- a/servers/physics_3d/collision_solver_3d_sat.h +++ b/servers/physics_3d/collision_solver_3d_sat.h @@ -33,6 +33,6 @@ #include "collision_solver_3d_sw.h" -bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector3 *r_prev_axis = nullptr, real_t p_margin_a = 0, real_t p_margin_b = 0); +bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector3 *r_prev_axis = nullptr, real_t p_margin_a = 0, real_t p_margin_b = 0); #endif // COLLISION_SOLVER_SAT_H diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/collision_solver_3d_sw.cpp index f655c4626c..67330d497e 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/collision_solver_3d_sw.cpp @@ -37,7 +37,7 @@ #define collision_solver sat_calculate_penetration //#define collision_solver gjk_epa_calculate_penetration -bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { +bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A); if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { return false; @@ -89,14 +89,14 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T return found; } -bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { +bool CollisionSolver3DSW::solve_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { const RayShape3DSW *ray = static_cast<const RayShape3DSW *>(p_shape_A); Vector3 from = p_transform_A.origin; Vector3 to = from + p_transform_A.basis.get_axis(2) * ray->get_length(); Vector3 support_A = to; - Transform ai = p_transform_B.affine_inverse(); + Transform3D ai = p_transform_B.affine_inverse(); from = ai.xform(from); to = ai.xform(to); @@ -146,8 +146,8 @@ struct _SoftBodyQueryInfo { SoftBody3DSW *soft_body = nullptr; const Shape3DSW *shape_A = nullptr; const Shape3DSW *shape_B = nullptr; - Transform transform_A; - Transform node_transform; + Transform3D transform_A; + Transform3D node_transform; _SoftBodyContactCollisionInfo contact_info; #ifdef DEBUG_ENABLED int node_query_count = 0; @@ -160,7 +160,7 @@ bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void * Vector3 node_position = query_cinfo.soft_body->get_node_position(p_node_index); - Transform transform_B; + Transform3D transform_B; transform_B.origin = query_cinfo.node_transform.xform(node_position); query_cinfo.contact_info.node_index = p_node_index; @@ -201,11 +201,11 @@ void CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW #endif } -bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { +bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { const SoftBodyShape3DSW *soft_body_shape_B = static_cast<const SoftBodyShape3DSW *>(p_shape_B); SoftBody3DSW *soft_body = soft_body_shape_B->get_soft_body(); - const Transform &world_to_local = soft_body->get_inv_transform(); + const Transform3D &world_to_local = soft_body->get_inv_transform(); const real_t collision_margin = soft_body->get_collision_margin(); @@ -257,9 +257,9 @@ bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Tran } struct _ConcaveCollisionInfo { - const Transform *transform_A; + const Transform3D *transform_A; const Shape3DSW *shape_A; - const Transform *transform_B; + const Transform3D *transform_B; CollisionSolver3DSW::CallbackResult result_callback; void *userdata; bool swap_result; @@ -285,7 +285,7 @@ void CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex cinfo.collisions++; } -bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) { +bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) { const ConcaveShape3DSW *concave_B = static_cast<const ConcaveShape3DSW *>(p_shape_B); _ConcaveCollisionInfo cinfo; @@ -302,7 +302,7 @@ bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transf cinfo.aabb_tests = 0; - Transform rel_transform = p_transform_A; + Transform3D rel_transform = p_transform_A; rel_transform.origin -= p_transform_B.origin; //quickly compute a local AABB @@ -329,7 +329,7 @@ bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transf return cinfo.collided; } -bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { +bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { PhysicsServer3D::ShapeType type_A = p_shape_A->get_type(); PhysicsServer3D::ShapeType type_B = p_shape_B->get_type(); bool concave_A = p_shape_A->is_concave(); @@ -421,7 +421,7 @@ void CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW cinfo.collisions++; } -bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) { +bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) { const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A); if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { return false; @@ -473,7 +473,7 @@ bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const return collided; } -bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) { +bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) { if (p_shape_A->is_concave()) { return false; } @@ -504,7 +504,7 @@ bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Trans cinfo.aabb_tests = 0; cinfo.tested = false; - Transform rel_transform = p_transform_A; + Transform3D rel_transform = p_transform_A; rel_transform.origin -= p_transform_B.origin; //quickly compute a local AABB diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/collision_solver_3d_sw.h index 34ac2c6d3f..a5dd7d48eb 100644 --- a/servers/physics_3d/collision_solver_3d_sw.h +++ b/servers/physics_3d/collision_solver_3d_sw.h @@ -42,16 +42,16 @@ private: static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); static void soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex); static void concave_callback(void *p_userdata, Shape3DSW *p_convex); - static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); - static bool solve_ray(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); - static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); - static bool solve_concave(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0); + static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0); static void concave_distance_callback(void *p_userdata, Shape3DSW *p_convex); - static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B); + static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B); public: - static bool solve_static(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); - static bool solve_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis = nullptr); + static bool solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); + static bool solve_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis = nullptr); }; #endif // COLLISION_SOLVER__SW_H diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp index 1a8c7f704f..2df991563d 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/servers/physics_3d/gjk_epa.cpp @@ -107,16 +107,16 @@ typedef unsigned char U1; struct MinkowskiDiff { const Shape3DSW* m_shapes[2]; - Transform transform_A; - Transform transform_B; + Transform3D transform_A; + Transform3D transform_B; real_t margin_A = 0.0; real_t margin_B = 0.0; Vector3 (*get_support)(const Shape3DSW*, const Vector3&, real_t); - void Initialize(const Shape3DSW* shape0, const Transform& wtrs0, const real_t margin0, - const Shape3DSW* shape1, const Transform& wtrs1, const real_t margin1) { + void Initialize(const Shape3DSW* shape0, const Transform3D& wtrs0, const real_t margin0, + const Shape3DSW* shape1, const Transform3D& wtrs1, const real_t margin1) { m_shapes[0] = shape0; m_shapes[1] = shape1; transform_A = wtrs0; @@ -862,8 +862,8 @@ struct GJK }; // - static void Initialize( const Shape3DSW* shape0, const Transform& wtrs0, real_t margin0, - const Shape3DSW* shape1, const Transform& wtrs1, real_t margin1, + static void Initialize( const Shape3DSW* shape0, const Transform3D& wtrs0, real_t margin0, + const Shape3DSW* shape1, const Transform3D& wtrs1, real_t margin1, sResults& results, tShape& shape) { @@ -885,10 +885,10 @@ struct GJK // bool Distance( const Shape3DSW* shape0, - const Transform& wtrs0, + const Transform3D& wtrs0, real_t margin0, const Shape3DSW* shape1, - const Transform& wtrs1, + const Transform3D& wtrs1, real_t margin1, const Vector3& guess, sResults& results) @@ -926,10 +926,10 @@ bool Distance( const Shape3DSW* shape0, // bool Penetration( const Shape3DSW* shape0, - const Transform& wtrs0, + const Transform3D& wtrs0, real_t margin0, const Shape3DSW* shape1, - const Transform& wtrs1, + const Transform3D& wtrs1, real_t margin1, const Vector3& guess, sResults& results @@ -993,7 +993,7 @@ bool Penetration( const Shape3DSW* shape0, /* clang-format on */ -bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) { +bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) { GjkEpa2::sResults res; if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) { @@ -1005,7 +1005,7 @@ bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_t return false; } -bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) { +bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) { GjkEpa2::sResults res; if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) { diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h index a7e2e1719e..69e85d2bc0 100644 --- a/servers/physics_3d/gjk_epa.h +++ b/servers/physics_3d/gjk_epa.h @@ -34,7 +34,7 @@ #include "collision_solver_3d_sw.h" #include "shape_3d_sw.h" -bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0); -bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform &p_transform_A, const Shape3DSW *p_shape_B, const Transform &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B); +bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0); +bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B); #endif diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp index e9efddf165..7315e9c709 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp @@ -84,7 +84,7 @@ static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) { return (y < 0.0f) ? -angle : angle; } -ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame) : +ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : Joint3DSW(_arr, 2) { A = rbA; B = rbB; @@ -211,7 +211,7 @@ bool ConeTwistJoint3DSW::setup(real_t p_timestep) { // Twist limits if (m_twistSpan >= real_t(0.)) { Vector3 b2Axis22 = B->get_transform().basis.xform(this->m_rbBFrame.basis.get_axis(1)); - Quat rotationArc = Quat(b2Axis1, b1Axis1); + Quaternion rotationArc = Quaternion(b2Axis1, b1Axis1); Vector3 TwistRef = rotationArc.xform(b2Axis22); real_t twist = atan2fast(TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2)); diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h index b871ea50db..608847352c 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h +++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h @@ -73,8 +73,8 @@ public: JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints real_t m_appliedImpulse; - Transform m_rbAFrame; - Transform m_rbBFrame; + Transform3D m_rbAFrame; + Transform3D m_rbBFrame; real_t m_limitSoftness; real_t m_biasFactor; @@ -107,7 +107,7 @@ public: virtual bool setup(real_t p_step) override; virtual void solve(real_t p_step) override; - ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame); + ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame); void setAngularOnly(bool angularOnly) { m_angularOnly = angularOnly; diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp index 7c504764a7..56aba24b42 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp @@ -219,7 +219,7 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( //////////////////////////// G6DOFTranslationalLimitMotorSW //////////////////////////////////// -Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA) : +Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA) : Joint3DSW(_arr, 2), m_frameInA(frameInA), m_frameInB(frameInB), diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h index 8af76cefc2..d46437e782 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h +++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h @@ -81,7 +81,7 @@ public: //! temp_variables //!@{ - real_t m_currentLimitError; //! How much is violated this limit + real_t m_currentLimitError; //!< How much is violated this limit int m_currentLimit; //!< 0=free, 1=at lo limit, 2=at hi limit real_t m_accumulatedImpulse; //!@} @@ -113,7 +113,7 @@ public: return (m_enableMotor || m_currentLimit != 0); } - //! calculates error + //! calculates error /*! calculates m_currentLimit and m_currentLimitError. */ @@ -185,8 +185,8 @@ protected: //! relative_frames //!@{ - Transform m_frameInA; //!< the constraint space w.r.t body A - Transform m_frameInB; //!< the constraint space w.r.t body B + Transform3D m_frameInA; //!< the constraint space w.r.t body A + Transform3D m_frameInB; //!< the constraint space w.r.t body B //!@} //! Jacobians @@ -209,8 +209,8 @@ protected: //! temporal variables //!@{ real_t m_timeStep; - Transform m_calculatedTransformA; - Transform m_calculatedTransformB; + Transform3D m_calculatedTransformA; + Transform3D m_calculatedTransformB; Vector3 m_calculatedAxisAngleDiff; Vector3 m_calculatedAxis[3]; @@ -233,7 +233,7 @@ protected: void calculateAngleInfo(); public: - Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA); + Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA); virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_6DOF; } @@ -251,7 +251,7 @@ public: /*! \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo. */ - const Transform &getCalculatedTransformA() const { + const Transform3D &getCalculatedTransformA() const { return m_calculatedTransformA; } @@ -259,23 +259,23 @@ public: /*! \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo. */ - const Transform &getCalculatedTransformB() const { + const Transform3D &getCalculatedTransformB() const { return m_calculatedTransformB; } - const Transform &getFrameOffsetA() const { + const Transform3D &getFrameOffsetA() const { return m_frameInA; } - const Transform &getFrameOffsetB() const { + const Transform3D &getFrameOffsetB() const { return m_frameInB; } - Transform &getFrameOffsetA() { + Transform3D &getFrameOffsetA() { return m_frameInA; } - Transform &getFrameOffsetB() { + Transform3D &getFrameOffsetB() { return m_frameInB; } @@ -327,7 +327,7 @@ public: return &m_angularLimits[index]; } - //! Retrieves the limit informacion + //! Retrieves the limit informacion G6DOFTranslationalLimitMotor3DSW *getTranslationalLimitMotor() { return &m_linearLimits; } diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp index bb8858c28a..b928f18231 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp @@ -67,7 +67,7 @@ static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) { } } -HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameA, const Transform &frameB) : +HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameA, const Transform3D &frameB) : Joint3DSW(_arr, 2) { A = rbA; B = rbB; @@ -126,7 +126,7 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo rbAxisA1.y, rbAxisA2.y, axisInA.y, rbAxisA1.z, rbAxisA2.z, axisInA.z); - Quat rotationArc = Quat(axisInA, axisInB); + Quaternion rotationArc = Quaternion(axisInA, axisInB); Vector3 rbAxisB1 = rotationArc.xform(rbAxisA1); Vector3 rbAxisB2 = axisInB.cross(rbAxisB1); diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h index 2100f5de44..22eb2f4660 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.h +++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h @@ -66,8 +66,8 @@ class HingeJoint3DSW : public Joint3DSW { JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints JacobianEntry3DSW m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor - Transform m_rbAFrame; // constraint axii. Assumes z is hinge axis. - Transform m_rbBFrame; + Transform3D m_rbAFrame; // constraint axii. Assumes z is hinge axis. + Transform3D m_rbBFrame; real_t m_motorTargetVelocity; real_t m_maxMotorImpulse; @@ -109,7 +109,7 @@ public: void set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value); bool get_flag(PhysicsServer3D::HingeJointFlag p_flag) const; - HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameA, const Transform &frameB); + HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameA, const Transform3D &frameB); HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB); }; diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/jacobian_entry_3d_sw.h index 2829a5caf7..6afa70c816 100644 --- a/servers/physics_3d/joints/jacobian_entry_3d_sw.h +++ b/servers/physics_3d/joints/jacobian_entry_3d_sw.h @@ -50,7 +50,7 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#include "core/math/transform.h" +#include "core/math/transform_3d.h" class JacobianEntry3DSW { public: diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp index 8bd1951311..db9bdb2986 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp @@ -111,7 +111,7 @@ void SliderJoint3DSW::initParams() { //----------------------------------------------------------------------------- -SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB) : +SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : Joint3DSW(_arr, 2), m_frameInA(frameInA), m_frameInB(frameInB) { diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h index ef5891d0f9..f357bbd67a 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.h +++ b/servers/physics_3d/joints/slider_joint_3d_sw.h @@ -76,8 +76,8 @@ protected: Body3DSW *_arr[2]; }; - Transform m_frameInA; - Transform m_frameInB; + Transform3D m_frameInA; + Transform3D m_frameInB; // linear limits real_t m_lowerLinLimit; @@ -120,8 +120,8 @@ protected: JacobianEntry3DSW m_jacAng[3]; real_t m_timeStep; - Transform m_calculatedTransformA; - Transform m_calculatedTransformB; + Transform3D m_calculatedTransformA; + Transform3D m_calculatedTransformB; Vector3 m_sliderAxis; Vector3 m_realPivotAInW; @@ -152,19 +152,19 @@ protected: public: // constructors - SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB); + SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB); //SliderJointSW(); // overrides // access const Body3DSW *getRigidBodyA() const { return A; } const Body3DSW *getRigidBodyB() const { return B; } - const Transform &getCalculatedTransformA() const { return m_calculatedTransformA; } - const Transform &getCalculatedTransformB() const { return m_calculatedTransformB; } - const Transform &getFrameOffsetA() const { return m_frameInA; } - const Transform &getFrameOffsetB() const { return m_frameInB; } - Transform &getFrameOffsetA() { return m_frameInA; } - Transform &getFrameOffsetB() { return m_frameInB; } + const Transform3D &getCalculatedTransformA() const { return m_calculatedTransformA; } + const Transform3D &getCalculatedTransformB() const { return m_calculatedTransformB; } + const Transform3D &getFrameOffsetA() const { return m_frameInA; } + const Transform3D &getFrameOffsetB() const { return m_frameInB; } + Transform3D &getFrameOffsetA() { return m_frameInA; } + Transform3D &getFrameOffsetB() { return m_frameInB; } real_t getLowerLinLimit() { return m_lowerLinLimit; } void setLowerLinLimit(real_t lowerLimit) { m_lowerLinLimit = lowerLimit; } real_t getUpperLinLimit() { return m_upperLinLimit; } diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp index f3eb1ae48f..f26129a404 100644 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ b/servers/physics_3d/physics_server_3d_sw.cpp @@ -262,7 +262,7 @@ PhysicsServer3D::AreaSpaceOverrideMode PhysicsServer3DSW::area_get_space_overrid return area->get_space_override_mode(); } -void PhysicsServer3DSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) { +void PhysicsServer3DSW::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) { Area3DSW *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -283,7 +283,7 @@ void PhysicsServer3DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) area->set_shape(p_shape_idx, shape); } -void PhysicsServer3DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) { +void PhysicsServer3DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) { Area3DSW *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); @@ -307,9 +307,9 @@ RID PhysicsServer3DSW::area_get_shape(RID p_area, int p_shape_idx) const { return shape->get_self(); } -Transform PhysicsServer3DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const { +Transform3D PhysicsServer3DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const { Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform()); + ERR_FAIL_COND_V(!area, Transform3D()); return area->get_shape_transform(p_shape_idx); } @@ -335,7 +335,7 @@ void PhysicsServer3DSW::area_set_shape_disabled(RID p_area, int p_shape_idx, boo ERR_FAIL_COND(!area); ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count()); FLUSH_QUERY_CHECK(area); - area->set_shape_as_disabled(p_shape_idx, p_disabled); + area->set_shape_disabled(p_shape_idx, p_disabled); } void PhysicsServer3DSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) { @@ -368,7 +368,7 @@ void PhysicsServer3DSW::area_set_param(RID p_area, AreaParameter p_param, const area->set_param(p_param, p_value); }; -void PhysicsServer3DSW::area_set_transform(RID p_area, const Transform &p_transform) { +void PhysicsServer3DSW::area_set_transform(RID p_area, const Transform3D &p_transform) { Area3DSW *area = area_owner.getornull(p_area); ERR_FAIL_COND(!area); area->set_transform(p_transform); @@ -385,9 +385,9 @@ Variant PhysicsServer3DSW::area_get_param(RID p_area, AreaParameter p_param) con return area->get_param(p_param); }; -Transform PhysicsServer3DSW::area_get_transform(RID p_area) const { +Transform3D PhysicsServer3DSW::area_get_transform(RID p_area) const { Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform()); + ERR_FAIL_COND_V(!area, Transform3D()); return area->get_transform(); }; @@ -487,7 +487,7 @@ PhysicsServer3D::BodyMode PhysicsServer3DSW::body_get_mode(RID p_body) const { return body->get_mode(); }; -void PhysicsServer3DSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) { +void PhysicsServer3DSW::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -507,8 +507,7 @@ void PhysicsServer3DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) body->set_shape(p_shape_idx, shape); } - -void PhysicsServer3DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) { +void PhysicsServer3DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -538,12 +537,12 @@ void PhysicsServer3DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, boo ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); FLUSH_QUERY_CHECK(body); - body->set_shape_as_disabled(p_shape_idx, p_disabled); + body->set_shape_disabled(p_shape_idx, p_disabled); } -Transform PhysicsServer3DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const { +Transform3D PhysicsServer3DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const { Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Transform()); + ERR_FAIL_COND_V(!body, Transform3D()); return body->get_shape_transform(p_shape_idx); } @@ -657,19 +656,6 @@ real_t PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) cons return body->get_param(p_param); }; -void PhysicsServer3DSW::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_kinematic_margin(p_margin); -} - -real_t PhysicsServer3DSW::body_get_kinematic_safe_margin(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_kinematic_margin(); -} - void PhysicsServer3DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND(!body); @@ -868,7 +854,7 @@ void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) { body->set_ray_pickable(p_enable); } -bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, MotionResult *r_result, bool p_exclude_raycast_shapes) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -876,10 +862,10 @@ bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform &p_from, co _update_shapes(); - return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, body->get_kinematic_margin(), r_result, p_exclude_raycast_shapes); + return body->get_space()->test_body_motion(body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); } -int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { +int PhysicsServer3DSW::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) { Body3DSW *body = body_owner.getornull(p_body); ERR_FAIL_COND_V(!body, false); ERR_FAIL_COND_V(!body->get_space(), false); @@ -1010,7 +996,7 @@ Variant PhysicsServer3DSW::soft_body_get_state(RID p_body, BodyState p_state) co return soft_body->get_state(p_state); } -void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform &p_transform) { +void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform3D &p_transform) { SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); ERR_FAIL_COND(!soft_body); @@ -1253,7 +1239,7 @@ Vector3 PhysicsServer3DSW::pin_joint_get_local_b(RID p_joint) const { return pin_joint->get_position_b(); } -void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) { +void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_frame_A, RID p_body_B, const Transform3D &p_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); ERR_FAIL_COND(!body_A); @@ -1378,7 +1364,7 @@ PhysicsServer3DSW::JointType PhysicsServer3DSW::joint_get_type(RID p_joint) cons return joint->get_type(); } -void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); ERR_FAIL_COND(!body_A); @@ -1418,7 +1404,7 @@ real_t PhysicsServer3DSW::slider_joint_get_param(RID p_joint, SliderJointParam p return slider_joint->get_param(p_param); } -void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); ERR_FAIL_COND(!body_A); @@ -1458,7 +1444,7 @@ real_t PhysicsServer3DSW::cone_twist_joint_get_param(RID p_joint, ConeTwistJoint return cone_twist_joint->get_param(p_param); } -void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) { +void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { Body3DSW *body_A = body_owner.getornull(p_body_A); ERR_FAIL_COND(!body_A); diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/physics_server_3d_sw.h index 0b42f1d605..57b6385758 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/physics_server_3d_sw.h @@ -130,13 +130,13 @@ public: virtual void area_set_space(RID p_area, RID p_space) override; virtual RID area_get_space(RID p_area) const override; - virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override; + virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override; virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) override; - virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) override; + virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) override; virtual int area_get_shape_count(RID p_area) const override; virtual RID area_get_shape(RID p_area, int p_shape_idx) const override; - virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const override; + virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const override; virtual void area_remove_shape(RID p_area, int p_shape_idx) override; virtual void area_clear_shapes(RID p_area) override; @@ -147,10 +147,10 @@ public: virtual ObjectID area_get_object_instance_id(RID p_area) const override; virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) override; - virtual void area_set_transform(RID p_area, const Transform &p_transform) override; + virtual void area_set_transform(RID p_area, const Transform3D &p_transform) override; virtual Variant area_get_param(RID p_area, AreaParameter p_param) const override; - virtual Transform area_get_transform(RID p_area) const override; + virtual Transform3D area_get_transform(RID p_area) const override; virtual void area_set_ray_pickable(RID p_area, bool p_enable) override; @@ -173,13 +173,13 @@ public: virtual void body_set_mode(RID p_body, BodyMode p_mode) override; virtual BodyMode body_get_mode(RID p_body) const override; - virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) override; + virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) override; virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override; - virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) override; + virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) override; virtual int body_get_shape_count(RID p_body) const override; virtual RID body_get_shape(RID p_body, int p_shape_idx) const override; - virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const override; + virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const override; virtual void body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) override; @@ -204,9 +204,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) override; - virtual real_t body_get_kinematic_safe_margin(RID p_body) const override; - virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; virtual Variant body_get_state(RID p_body, BodyState p_state) const override; @@ -245,8 +242,8 @@ public: virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override; + virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; @@ -273,7 +270,7 @@ public: virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const override; - virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) override; + virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) override; @@ -323,7 +320,7 @@ public: virtual void pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) override; virtual Vector3 pin_joint_get_local_b(RID p_joint) const override; - virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_frame_A, RID p_body_B, const Transform &p_frame_B) override; + virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_frame_A, RID p_body_B, const Transform3D &p_frame_B) override; virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) override; virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) override; @@ -332,17 +329,17 @@ public: virtual void hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) override; virtual bool hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const override; - virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A + virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; //reference frame is A virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) override; virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const override; - virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A + virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; //reference frame is A virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) override; virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const override; - virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) override; //reference frame is A + virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) override; //reference frame is A virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) override; virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const override; diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.cpp b/servers/physics_3d/physics_server_3d_wrap_mt.cpp index f73f67a756..0a89c1a9c9 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.cpp +++ b/servers/physics_3d/physics_server_3d_wrap_mt.cpp @@ -56,7 +56,7 @@ void PhysicsServer3DWrapMT::thread_loop() { step_thread_up = true; while (!exit) { // flush commands one by one, until exit is requested - command_queue.wait_and_flush_one(); + command_queue.wait_and_flush(); } command_queue.flush_all(); // flush all diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_3d/physics_server_3d_wrap_mt.h index 69d0fcf3ed..bda2e30dd1 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.h +++ b/servers/physics_3d/physics_server_3d_wrap_mt.h @@ -142,14 +142,14 @@ public: FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode); FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID); - FUNC4(area_add_shape, RID, RID, const Transform &, bool); + FUNC4(area_add_shape, RID, RID, const Transform3D &, bool); FUNC3(area_set_shape, RID, int, RID); - FUNC3(area_set_shape_transform, RID, int, const Transform &); + FUNC3(area_set_shape_transform, RID, int, const Transform3D &); FUNC3(area_set_shape_disabled, RID, int, bool); FUNC1RC(int, area_get_shape_count, RID); FUNC2RC(RID, area_get_shape, RID, int); - FUNC2RC(Transform, area_get_shape_transform, RID, int); + FUNC2RC(Transform3D, area_get_shape_transform, RID, int); FUNC2(area_remove_shape, RID, int); FUNC1(area_clear_shapes, RID); @@ -157,10 +157,10 @@ public: FUNC1RC(ObjectID, area_get_object_instance_id, RID); FUNC3(area_set_param, RID, AreaParameter, const Variant &); - FUNC2(area_set_transform, RID, const Transform &); + FUNC2(area_set_transform, RID, const Transform3D &); FUNC2RC(Variant, area_get_param, RID, AreaParameter); - FUNC1RC(Transform, area_get_transform, RID); + FUNC1RC(Transform3D, area_get_transform, RID); FUNC2(area_set_collision_mask, RID, uint32_t); FUNC2(area_set_collision_layer, RID, uint32_t); @@ -182,12 +182,12 @@ public: FUNC2(body_set_mode, RID, BodyMode); FUNC1RC(BodyMode, body_get_mode, RID); - FUNC4(body_add_shape, RID, RID, const Transform &, bool); + FUNC4(body_add_shape, RID, RID, const Transform3D &, bool); FUNC3(body_set_shape, RID, int, RID); - FUNC3(body_set_shape_transform, RID, int, const Transform &); + FUNC3(body_set_shape_transform, RID, int, const Transform3D &); FUNC1RC(int, body_get_shape_count, RID); - FUNC2RC(Transform, body_get_shape_transform, RID, int); + FUNC2RC(Transform3D, body_get_shape_transform, RID, int); FUNC2RC(RID, body_get_shape, RID, int); FUNC3(body_set_shape_disabled, RID, int, bool); @@ -213,9 +213,6 @@ public: FUNC3(body_set_param, RID, BodyParameter, real_t); FUNC2RC(real_t, body_get_param, RID, BodyParameter); - FUNC2(body_set_kinematic_safe_margin, RID, real_t); - FUNC1RC(real_t, body_get_kinematic_safe_margin, RID); - FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); @@ -253,12 +250,12 @@ public: FUNC2(body_set_ray_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { + bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); - return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, r_result, p_exclude_raycast_shapes); + return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r_result, p_exclude_raycast_shapes); } - int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override { + int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); return physics_3d_server->body_test_ray_separation(p_body, p_transform, p_infinite_inertia, r_recover_motion, r_results, p_result_max, p_margin); } @@ -293,7 +290,7 @@ public: FUNC3(soft_body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, soft_body_get_state, RID, BodyState); - FUNC2(soft_body_set_transform, RID, const Transform &); + FUNC2(soft_body_set_transform, RID, const Transform3D &); FUNC2(soft_body_set_simulation_precision, RID, int); FUNC1RC(int, soft_body_get_simulation_precision, RID); @@ -341,7 +338,7 @@ public: FUNC2(pin_joint_set_local_b, RID, const Vector3 &) FUNC1RC(Vector3, pin_joint_get_local_b, RID) - FUNC5(joint_make_hinge, RID, RID, const Transform &, RID, const Transform &) + FUNC5(joint_make_hinge, RID, RID, const Transform3D &, RID, const Transform3D &) FUNC7(joint_make_hinge_simple, RID, RID, const Vector3 &, const Vector3 &, RID, const Vector3 &, const Vector3 &) FUNC3(hinge_joint_set_param, RID, HingeJointParam, real_t) @@ -350,17 +347,17 @@ public: FUNC3(hinge_joint_set_flag, RID, HingeJointFlag, bool) FUNC2RC(bool, hinge_joint_get_flag, RID, HingeJointFlag) - FUNC5(joint_make_slider, RID, RID, const Transform &, RID, const Transform &) + FUNC5(joint_make_slider, RID, RID, const Transform3D &, RID, const Transform3D &) FUNC3(slider_joint_set_param, RID, SliderJointParam, real_t) FUNC2RC(real_t, slider_joint_get_param, RID, SliderJointParam) - FUNC5(joint_make_cone_twist, RID, RID, const Transform &, RID, const Transform &) + FUNC5(joint_make_cone_twist, RID, RID, const Transform3D &, RID, const Transform3D &) FUNC3(cone_twist_joint_set_param, RID, ConeTwistJointParam, real_t) FUNC2RC(real_t, cone_twist_joint_get_param, RID, ConeTwistJointParam) - FUNC5(joint_make_generic_6dof, RID, RID, const Transform &, RID, const Transform &) + FUNC5(joint_make_generic_6dof, RID, RID, const Transform3D &, RID, const Transform3D &) FUNC4(generic_6dof_joint_set_param, RID, Vector3::Axis, G6DOFJointAxisParam, real_t) FUNC3RC(real_t, generic_6dof_joint_get_param, RID, Vector3::Axis, G6DOFJointAxisParam) diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/shape_3d_sw.cpp index ca7248993f..2ffab0c923 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/shape_3d_sw.cpp @@ -114,7 +114,7 @@ Plane PlaneShape3DSW::get_plane() const { return plane; } -void PlaneShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void PlaneShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // gibberish, a plane is infinity r_min = -1e7; r_max = 1e7; @@ -174,7 +174,7 @@ bool RayShape3DSW::get_slips_on_slope() const { return slips_on_slope; } -void RayShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void RayShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // don't think this will be even used r_min = 0; r_max = 1; @@ -255,7 +255,7 @@ real_t SphereShape3DSW::get_radius() const { return radius; } -void SphereShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void SphereShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { real_t d = p_normal.dot(p_transform.origin); // figure out scale at point @@ -317,7 +317,7 @@ SphereShape3DSW::SphereShape3DSW() { /********** BOX *************/ -void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // no matter the angle, the box is mirrored anyway Vector3 local_normal = p_transform.basis.xform_inv(p_normal); @@ -507,7 +507,7 @@ BoxShape3DSW::BoxShape3DSW() { /********** CAPSULE *************/ -void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { Vector3 n = p_transform.basis.xform_inv(p_normal).normalized(); real_t h = (n.y > 0) ? height : -height; @@ -674,7 +674,7 @@ CapsuleShape3DSW::CapsuleShape3DSW() { /********** CYLINDER *************/ -void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { Vector3 cylinder_axis = p_transform.basis.get_axis(1).normalized(); real_t axis_dot = cylinder_axis.dot(p_normal); @@ -854,7 +854,7 @@ CylinderShape3DSW::CylinderShape3DSW() { /********** CONVEX POLYGON *************/ -void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { int vertex_count = mesh.vertices.size(); if (vertex_count == 0) { return; @@ -1120,7 +1120,7 @@ ConvexPolygonShape3DSW::ConvexPolygonShape3DSW() { /********** FACE POLYGON *************/ -void FaceShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void FaceShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { for (int i = 0; i < 3; i++) { Vector3 v = p_transform.xform(vertex[i]); real_t d = p_normal.dot(v); @@ -1250,7 +1250,7 @@ Vector<Vector3> ConcavePolygonShape3DSW::get_faces() const { return rfaces; } -void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { int count = vertices.size(); if (count == 0) { r_min = 0; @@ -1647,7 +1647,7 @@ int HeightMapShape3DSW::get_depth() const { return depth; } -void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { +void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { //not very useful, but not very used either p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal, 0), r_min, r_max); } diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/shape_3d_sw.h index 4d2b6ffbed..bc8bd3e695 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/shape_3d_sw.h @@ -86,7 +86,7 @@ public: virtual bool is_concave() const { return false; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const = 0; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const = 0; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0; @@ -130,7 +130,7 @@ public: virtual real_t get_area() const { return Math_INF; } virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_PLANE; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; } @@ -157,7 +157,7 @@ public: virtual real_t get_area() const { return 0.0; } virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_RAY; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; @@ -185,7 +185,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SPHERE; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -210,7 +210,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_BOX; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -239,7 +239,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CAPSULE; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -268,7 +268,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CYLINDER; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -293,7 +293,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -371,7 +371,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -415,7 +415,7 @@ public: virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_HEIGHTMAP; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; virtual Vector3 get_support(const Vector3 &p_normal) const; virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const; virtual bool intersect_point(const Vector3 &p_point) const; @@ -441,7 +441,7 @@ struct FaceShape3DSW : public Shape3DSW { const Vector3 &get_vertex(int p_idx) const { return vertex[p_idx]; } - void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const; + void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const; Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const; bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; @@ -462,11 +462,11 @@ struct MotionShape3DSW : public Shape3DSW { virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; } - void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { + void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { Vector3 cast = p_transform.basis.xform(motion); real_t mina, maxa; real_t minb, maxb; - Transform ofsb = p_transform; + Transform3D ofsb = p_transform; ofsb.origin += cast; shape->project_range(p_normal, p_transform, mina, maxa); shape->project_range(p_normal, ofsb, minb, maxb); diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp index f63a470cbe..63a0fe11ba 100644 --- a/servers/physics_3d/soft_body_3d_sw.cpp +++ b/servers/physics_3d/soft_body_3d_sw.cpp @@ -289,7 +289,7 @@ void SoftBody3DSW::update_link_constants() { } } -void SoftBody3DSW::apply_nodes_transform(const Transform &p_transform) { +void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) { if (soft_mesh.is_null()) { return; } @@ -684,7 +684,7 @@ void SoftBody3DSW::generate_bending_constraints(int p_distance) { // // This function takes in a list of interdependent Links and tries // to maximize the distance between calculation -// of dependent links. This increases the amount of parallelism that can +// of dependent links. This increases the amount of parallelism that can // be exploited by out-of-order instruction processors with large but // (inevitably) finite instruction windows. // diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h index 98e554218b..ac8bcbf0b9 100644 --- a/servers/physics_3d/soft_body_3d_sw.h +++ b/servers/physics_3d/soft_body_3d_sw.h @@ -201,7 +201,7 @@ private: void reset_link_rest_lengths(); void update_link_constants(); - void apply_nodes_transform(const Transform &p_transform); + void apply_nodes_transform(const Transform3D &p_transform); void add_velocity(const Vector3 &p_velocity); @@ -231,7 +231,7 @@ public: SoftBody3DSW *get_soft_body() const { return soft_body; } virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; } - virtual void project_range(const Vector3 &p_normal, const Transform &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; } + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; } virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); } virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; } diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/space_3d_sw.cpp index 2df824b320..eff480396d 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/space_3d_sw.cpp @@ -59,7 +59,7 @@ int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeRe int amount = space->broadphase->cull_point(p_point, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); int cc = 0; - //Transform ai = p_xform.affine_inverse(); + //Transform3D ai = p_xform.affine_inverse(); for (int i = 0; i < amount; i++) { if (cc >= p_result_max) { @@ -79,7 +79,7 @@ int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeRe const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - Transform inv_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + Transform3D inv_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); inv_xform.affine_invert(); if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_point))) { @@ -136,7 +136,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - Transform inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform(); + Transform3D inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform(); Vector3 local_from = inv_xform.xform(begin); Vector3 local_to = inv_xform.xform(end); @@ -146,7 +146,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec Vector3 shape_point, shape_normal; if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) { - Transform xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + Transform3D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); shape_point = xform.xform(shape_point); real_t ld = normal.dot(shape_point); @@ -180,7 +180,7 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec return true; } -int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return 0; } @@ -194,7 +194,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans int cc = 0; - //Transform ai = p_xform.affine_inverse(); + //Transform3D ai = p_xform.affine_inverse(); for (int i = 0; i < amount; i++) { if (cc >= p_result_max) { @@ -214,10 +214,6 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - if (!CollisionSolver3DSW::solve_static(shape, p_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_margin, 0)) { continue; } @@ -239,7 +235,7 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans return cc; } -bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { +bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, false); @@ -252,7 +248,7 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor real_t best_safe = 1; real_t best_unsafe = 1; - Transform xform_inv = p_xform.affine_inverse(); + Transform3D xform_inv = p_xform.affine_inverse(); MotionShape3DSW mshape; mshape.shape = shape; mshape.motion = xform_inv.basis.xform(p_motion); @@ -273,14 +269,10 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - Vector3 point_A, point_B; Vector3 sep_axis = p_motion.normalized(); - Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + Transform3D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? if (CollisionSolver3DSW::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { continue; @@ -348,7 +340,7 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor return true; } -bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { if (p_result_max <= 0) { return false; } @@ -385,10 +377,6 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform &p_ int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - if (CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) { collided = true; } @@ -432,7 +420,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect rd->best_local_shape = rd->local_shape; } -bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); ERR_FAIL_COND_V(!shape, 0); @@ -460,10 +448,6 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform &p_shap int shape_idx = space->intersection_query_subindex_results[i]; - if (col_obj->is_shape_set_as_disabled(shape_idx)) { - continue; - } - rcd.object = col_obj; rcd.shape = shape_idx; bool sc = CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); @@ -508,11 +492,11 @@ Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_ob bool shapes_found = false; for (int i = 0; i < obj->get_shape_count(); i++) { - if (obj->is_shape_set_as_disabled(i)) { + if (obj->is_shape_disabled(i)) { continue; } - Transform shape_xform = obj->get_transform() * obj->get_shape_transform(i); + Transform3D shape_xform = obj->get_transform() * obj->get_shape_transform(i); Shape3DSW *shape = obj->get_shape(i); Vector3 point = shape->get_closest_point_to(shape_xform.affine_inverse().xform(p_point)); @@ -555,8 +539,6 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) { keep = false; } else if (static_cast<Body3DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { keep = false; - } else if (static_cast<Body3DSW *>(intersection_query_results[i])->is_shape_set_as_disabled(intersection_query_subindex_results[i])) { - keep = false; } if (!keep) { @@ -573,13 +555,13 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) { return amount; } -int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { +int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin) { AABB body_aabb; bool shapes_found = false; for (int i = 0; i < p_body->get_shape_count(); i++) { - if (p_body->is_shape_set_as_disabled(i)) { + if (p_body->is_shape_disabled(i)) { continue; } @@ -598,7 +580,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra body_aabb = p_transform.xform(p_body->get_inv_transform().xform(body_aabb)); body_aabb = body_aabb.grow(p_margin); - Transform body_transform = p_transform; + Transform3D body_transform = p_transform; for (int i = 0; i < p_result_max; i++) { //reset results @@ -626,7 +608,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra int amount = _cull_aabb_for_body(p_body, body_aabb); for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } @@ -636,7 +618,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra continue; } - Transform body_shape_xform = body_transform * p_body->get_shape_transform(j); + Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j); for (int i = 0; i < amount; i++) { const CollisionObject3DSW *col_obj = intersection_query_results[i]; @@ -724,7 +706,7 @@ int Space3DSW::test_body_ray_separation(Body3DSW *p_body, const Transform &p_tra return rays_found; } -bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { +bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes) { //give me back regular physics engine logic //this is madness //and most people using this function will think @@ -740,7 +722,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons bool shapes_found = false; for (int i = 0; i < p_body->get_shape_count(); i++) { - if (p_body->is_shape_set_as_disabled(i)) { + if (p_body->is_shape_disabled(i)) { continue; } @@ -768,7 +750,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons real_t motion_length = p_motion.length(); Vector3 motion_normal = p_motion / motion_length; - Transform body_transform = p_from; + Transform3D body_transform = p_from; bool recovered = false; @@ -793,11 +775,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons int amount = _cull_aabb_for_body(p_body, body_aabb); for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } - Transform body_shape_xform = body_transform * p_body->get_shape_transform(j); + Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j); Shape3DSW *body_shape = p_body->get_shape(j); if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) { continue; @@ -807,6 +789,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons const CollisionObject3DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; + if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) { + const Body3DSW *b = static_cast<const Body3DSW *>(col_obj); + if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } + } + if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) { collided = cbk.amount > 0; } @@ -864,18 +853,18 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons int amount = _cull_aabb_for_body(p_body, motion_aabb); for (int j = 0; j < p_body->get_shape_count(); j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } - Transform body_shape_xform = body_transform * p_body->get_shape_transform(j); + Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j); Shape3DSW *body_shape = p_body->get_shape(j); if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) { continue; } - Transform body_shape_xform_inv = body_shape_xform.affine_inverse(); + Transform3D body_shape_xform_inv = body_shape_xform.affine_inverse(); MotionShape3DSW mshape; mshape.shape = body_shape; mshape.motion = body_shape_xform_inv.basis.xform(p_motion); @@ -889,11 +878,18 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons const CollisionObject3DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; + if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) { + const Body3DSW *b = static_cast<const Body3DSW *>(col_obj); + if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } + } + //test initial overlap, does it collide if going all the way? Vector3 point_A, point_B; Vector3 sep_axis = motion_normal; - Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); + Transform3D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? if (CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { continue; @@ -960,7 +956,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons } //it collided, let's get the rest info in unsafe advance - Transform ugt = body_transform; + Transform3D ugt = body_transform; ugt.origin += p_motion * unsafe; _RestCallbackData rcd; @@ -975,11 +971,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); for (int j = from_shape; j < to_shape; j++) { - if (p_body->is_shape_set_as_disabled(j)) { + if (p_body->is_shape_disabled(j)) { continue; } - Transform body_shape_xform = ugt * p_body->get_shape_transform(j); + Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j); Shape3DSW *body_shape = p_body->get_shape(j); if (p_exclude_raycast_shapes && body_shape->get_type() == PhysicsServer3D::SHAPE_RAY) { @@ -994,6 +990,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons const CollisionObject3DSW *col_obj = intersection_query_results[i]; int shape_idx = intersection_query_subindex_results[i]; + if (CollisionObject3DSW::TYPE_BODY == col_obj->get_type()) { + const Body3DSW *b = static_cast<const Body3DSW *>(col_obj); + if (p_infinite_inertia && PhysicsServer3D::BODY_MODE_STATIC != b->get_mode() && PhysicsServer3D::BODY_MODE_KINEMATIC != b->get_mode()) { + continue; + } + } + rcd.object = col_obj; rcd.shape = shape_idx; bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); @@ -1011,6 +1014,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform &p_from, cons r_result->collision_local_shape = rcd.best_local_shape; r_result->collision_normal = rcd.best_normal; r_result->collision_point = rcd.best_contact; + r_result->collision_depth = rcd.best_len; + r_result->collision_safe_fraction = safe; + r_result->collision_unsafe_fraction = unsafe; //r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object); diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/space_3d_sw.h index 3a8f452e54..18e93c90cc 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/space_3d_sw.h @@ -50,10 +50,10 @@ public: virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) override; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; PhysicsDirectSpaceState3DSW(); @@ -203,8 +203,8 @@ public: void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; } uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } - int test_body_ray_separation(Body3DSW *p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); - bool test_body_motion(Body3DSW *p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); + int test_body_ray_separation(Body3DSW *p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, PhysicsServer3D::SeparationResult *r_results, int p_result_max, real_t p_margin); + bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_exclude_raycast_shapes); Space3DSW(); ~Space3DSW(); diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 7c5761cc61..ec0ff57a5e 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -418,37 +418,6 @@ void PhysicsDirectSpaceState2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState2D::_get_rest_info); } -int PhysicsShapeQueryResult2D::get_result_count() const { - return result.size(); -} - -RID PhysicsShapeQueryResult2D::get_result_rid(int p_idx) const { - return result[p_idx].rid; -} - -ObjectID PhysicsShapeQueryResult2D::get_result_object_id(int p_idx) const { - return result[p_idx].collider_id; -} - -Object *PhysicsShapeQueryResult2D::get_result_object(int p_idx) const { - return result[p_idx].collider; -} - -int PhysicsShapeQueryResult2D::get_result_object_shape(int p_idx) const { - return result[p_idx].shape; -} - -PhysicsShapeQueryResult2D::PhysicsShapeQueryResult2D() { -} - -void PhysicsShapeQueryResult2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_result_count"), &PhysicsShapeQueryResult2D::get_result_count); - ClassDB::bind_method(D_METHOD("get_result_rid", "idx"), &PhysicsShapeQueryResult2D::get_result_rid); - ClassDB::bind_method(D_METHOD("get_result_object_id", "idx"), &PhysicsShapeQueryResult2D::get_result_object_id); - ClassDB::bind_method(D_METHOD("get_result_object", "idx"), &PhysicsShapeQueryResult2D::get_result_object); - ClassDB::bind_method(D_METHOD("get_result_object_shape", "idx"), &PhysicsShapeQueryResult2D::get_result_object_shape); -} - /////////////////////////////// Vector2 PhysicsTestMotionResult2D::get_motion() const { @@ -487,6 +456,18 @@ int PhysicsTestMotionResult2D::get_collider_shape() const { return result.collider_shape; } +real_t PhysicsTestMotionResult2D::get_collision_depth() const { + return result.collision_depth; +} + +real_t PhysicsTestMotionResult2D::get_collision_safe_fraction() const { + return result.collision_safe_fraction; +} + +real_t PhysicsTestMotionResult2D::get_collision_unsafe_fraction() const { + return result.collision_unsafe_fraction; +} + void PhysicsTestMotionResult2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult2D::get_motion); ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult2D::get_motion_remainder); @@ -497,6 +478,9 @@ void PhysicsTestMotionResult2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult2D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult2D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult2D::get_collider_shape); + ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult2D::get_collision_depth); + ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult2D::get_collision_safe_fraction); + ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult2D::get_collision_unsafe_fraction); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_remainder"), "", "get_motion_remainder"); @@ -507,12 +491,9 @@ void PhysicsTestMotionResult2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape"); -} - -PhysicsTestMotionResult2D::PhysicsTestMotionResult2D() { - colliding = false; - - result.collider_shape = 0; + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_depth"), "", "get_collision_depth"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_safe_fraction"), "", "get_collision_safe_fraction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_unsafe_fraction"), "", "get_collision_unsafe_fraction"); } /////////////////////////////////////// @@ -715,8 +696,8 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); - BIND_ENUM_CONSTANT(BODY_MODE_RIGID); - BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index f2836961f2..6737aacaf0 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -33,7 +33,7 @@ #include "core/io/resource.h" #include "core/object/class_db.h" -#include "core/object/reference.h" +#include "core/object/ref_counted.h" class PhysicsDirectSpaceState2D; @@ -92,11 +92,9 @@ public: PhysicsDirectBodyState2D(); }; -class PhysicsShapeQueryResult2D; - //used for script -class PhysicsShapeQueryParameters2D : public Reference { - GDCLASS(PhysicsShapeQueryParameters2D, Reference); +class PhysicsShapeQueryParameters2D : public RefCounted { + GDCLASS(PhysicsShapeQueryParameters2D, RefCounted); friend class PhysicsDirectSpaceState2D; RES shape_ref; @@ -164,8 +162,8 @@ public: Vector2 normal; RID rid; ObjectID collider_id; - Object *collider; - int shape; + Object *collider = nullptr; + int shape = 0; Variant metadata; }; @@ -174,8 +172,8 @@ public: struct ShapeResult { RID rid; ObjectID collider_id; - Object *collider; - int shape; + Object *collider = nullptr; + int shape = 0; Variant metadata; }; @@ -193,7 +191,7 @@ public: Vector2 normal; RID rid; ObjectID collider_id; - int shape; + int shape = 0; Vector2 linear_velocity; //velocity at contact point Variant metadata; }; @@ -203,26 +201,6 @@ public: PhysicsDirectSpaceState2D(); }; -class PhysicsShapeQueryResult2D : public Reference { - GDCLASS(PhysicsShapeQueryResult2D, Reference); - - Vector<PhysicsDirectSpaceState2D::ShapeResult> result; - - friend class PhysicsDirectSpaceState2D; - -protected: - static void _bind_methods(); - -public: - int get_result_count() const; - RID get_result_rid(int p_idx) const; - ObjectID get_result_object_id(int p_idx) const; - Object *get_result_object(int p_idx) const; - int get_result_object_shape(int p_idx) const; - - PhysicsShapeQueryResult2D(); -}; - class PhysicsTestMotionResult2D; class PhysicsServer2D : public Object { @@ -370,8 +348,8 @@ public: enum BodyMode { BODY_MODE_STATIC, BODY_MODE_KINEMATIC, - BODY_MODE_RIGID, - BODY_MODE_CHARACTER + BODY_MODE_DYNAMIC, + BODY_MODE_DYNAMIC_LOCKED, }; virtual RID body_create() = 0; @@ -493,20 +471,17 @@ public: Vector2 collision_point; Vector2 collision_normal; Vector2 collider_velocity; - int collision_local_shape; + real_t collision_depth = 0.0; + real_t collision_safe_fraction = 0.0; + real_t collision_unsafe_fraction = 0.0; + int collision_local_shape = 0; ObjectID collider_id; RID collider; - int collider_shape; + int collider_shape = 0; Variant collider_metadata; - - MotionResult() { - collision_local_shape = 0; - collider_shape = 0; - collider_id = ObjectID(); - } }; - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; + virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; struct SeparationResult { real_t collision_depth; @@ -520,7 +495,7 @@ public: Variant collider_metadata; }; - virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0; + virtual int body_test_ray_separation(RID p_body, const Transform2D &p_transform, bool p_infinite_inertia, Vector2 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.08) = 0; /* JOINT API */ @@ -603,11 +578,10 @@ public: ~PhysicsServer2D(); }; -class PhysicsTestMotionResult2D : public Reference { - GDCLASS(PhysicsTestMotionResult2D, Reference); +class PhysicsTestMotionResult2D : public RefCounted { + GDCLASS(PhysicsTestMotionResult2D, RefCounted); PhysicsServer2D::MotionResult result; - bool colliding; friend class PhysicsServer2D; protected: @@ -616,7 +590,6 @@ protected: public: PhysicsServer2D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer2D::MotionResult *>(&result); } - //bool is_colliding() const; Vector2 get_motion() const; Vector2 get_motion_remainder() const; @@ -627,8 +600,9 @@ public: RID get_collider_rid() const; Object *get_collider() const; int get_collider_shape() const; - - PhysicsTestMotionResult2D(); + real_t get_collision_depth() const; + real_t get_collision_safe_fraction() const; + real_t get_collision_unsafe_fraction() const; }; typedef PhysicsServer2D *(*CreatePhysicsServer2DCallback)(); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 80a9bd4c0b..7a0253506c 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -128,7 +128,7 @@ void PhysicsDirectBodyState3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform"), "set_transform", "get_transform"); } PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {} @@ -156,11 +156,11 @@ RID PhysicsShapeQueryParameters3D::get_shape_rid() const { return shape; } -void PhysicsShapeQueryParameters3D::set_transform(const Transform &p_transform) { +void PhysicsShapeQueryParameters3D::set_transform(const Transform3D &p_transform) { transform = p_transform; } -Transform PhysicsShapeQueryParameters3D::get_transform() const { +Transform3D PhysicsShapeQueryParameters3D::get_transform() const { return transform; } @@ -242,7 +242,7 @@ void PhysicsShapeQueryParameters3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); - ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "transform"), "set_transform", "get_transform"); + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform"), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } @@ -365,39 +365,94 @@ void PhysicsDirectSpaceState3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState3D::_get_rest_info); } -int PhysicsShapeQueryResult3D::get_result_count() const { - return result.size(); +/////////////////////////////// + +Vector3 PhysicsTestMotionResult3D::get_motion() const { + return result.motion; +} + +Vector3 PhysicsTestMotionResult3D::get_motion_remainder() const { + return result.remainder; +} + +Vector3 PhysicsTestMotionResult3D::get_collision_point() const { + return result.collision_point; } -RID PhysicsShapeQueryResult3D::get_result_rid(int p_idx) const { - return result[p_idx].rid; +Vector3 PhysicsTestMotionResult3D::get_collision_normal() const { + return result.collision_normal; } -ObjectID PhysicsShapeQueryResult3D::get_result_object_id(int p_idx) const { - return result[p_idx].collider_id; +Vector3 PhysicsTestMotionResult3D::get_collider_velocity() const { + return result.collider_velocity; } -Object *PhysicsShapeQueryResult3D::get_result_object(int p_idx) const { - return result[p_idx].collider; +ObjectID PhysicsTestMotionResult3D::get_collider_id() const { + return result.collider_id; } -int PhysicsShapeQueryResult3D::get_result_object_shape(int p_idx) const { - return result[p_idx].shape; +RID PhysicsTestMotionResult3D::get_collider_rid() const { + return result.collider; } -PhysicsShapeQueryResult3D::PhysicsShapeQueryResult3D() { +Object *PhysicsTestMotionResult3D::get_collider() const { + return ObjectDB::get_instance(result.collider_id); } -void PhysicsShapeQueryResult3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_result_count"), &PhysicsShapeQueryResult3D::get_result_count); - ClassDB::bind_method(D_METHOD("get_result_rid", "idx"), &PhysicsShapeQueryResult3D::get_result_rid); - ClassDB::bind_method(D_METHOD("get_result_object_id", "idx"), &PhysicsShapeQueryResult3D::get_result_object_id); - ClassDB::bind_method(D_METHOD("get_result_object", "idx"), &PhysicsShapeQueryResult3D::get_result_object); - ClassDB::bind_method(D_METHOD("get_result_object_shape", "idx"), &PhysicsShapeQueryResult3D::get_result_object_shape); +int PhysicsTestMotionResult3D::get_collider_shape() const { + return result.collider_shape; +} + +real_t PhysicsTestMotionResult3D::get_collision_depth() const { + return result.collision_depth; +} + +real_t PhysicsTestMotionResult3D::get_collision_safe_fraction() const { + return result.collision_safe_fraction; +} + +real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const { + return result.collision_unsafe_fraction; +} + +void PhysicsTestMotionResult3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionResult3D::get_motion); + ClassDB::bind_method(D_METHOD("get_motion_remainder"), &PhysicsTestMotionResult3D::get_motion_remainder); + ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult3D::get_collision_point); + ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult3D::get_collision_normal); + ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult3D::get_collider_velocity); + ClassDB::bind_method(D_METHOD("get_collider_id"), &PhysicsTestMotionResult3D::get_collider_id); + ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult3D::get_collider_rid); + ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult3D::get_collider); + ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult3D::get_collider_shape); + ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult3D::get_collision_depth); + ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult3D::get_collision_safe_fraction); + ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult3D::get_collision_unsafe_fraction); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "", "get_motion"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion_remainder"), "", "get_motion_remainder"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_point"), "", "get_collision_point"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_normal"), "", "get_collision_normal"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id"); + ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_depth"), "", "get_collision_depth"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_safe_fraction"), "", "get_collision_safe_fraction"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_unsafe_fraction"), "", "get_collision_unsafe_fraction"); } /////////////////////////////////////// +bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result) { + MotionResult *r = nullptr; + if (p_result.is_valid()) { + r = p_result->get_result_ptr(); + } + return body_test_motion(p_body, p_from, p_motion, p_infinite_inertia, p_margin, r); +} + RID PhysicsServer3D::shape_create(ShapeType p_shape) { switch (p_shape) { case SHAPE_PLANE: @@ -458,7 +513,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer3D::area_set_space_override_mode); ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer3D::area_get_space_override_mode); - ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer3D::area_add_shape, DEFVAL(Transform()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer3D::area_add_shape, DEFVAL(Transform3D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer3D::area_set_shape); ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer3D::area_set_shape_transform); ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &PhysicsServer3D::area_set_shape_disabled); @@ -502,7 +557,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer3D::body_set_collision_mask); ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer3D::body_get_collision_mask); - ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform()), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer3D::body_add_shape, DEFVAL(Transform3D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer3D::body_set_shape); ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer3D::body_set_shape_transform); ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &PhysicsServer3D::body_set_shape_disabled); @@ -523,9 +578,6 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer3D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer3D::body_get_param); - ClassDB::bind_method(D_METHOD("body_set_kinematic_safe_margin", "body", "margin"), &PhysicsServer3D::body_set_kinematic_safe_margin); - ClassDB::bind_method(D_METHOD("body_get_kinematic_safe_margin", "body"), &PhysicsServer3D::body_get_kinematic_safe_margin); - ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer3D::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer3D::body_get_state); @@ -554,6 +606,8 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable); + ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "infinite_inertia", "margin", "result"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state); /* SOFT BODY API */ @@ -717,8 +771,8 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); - BIND_ENUM_CONSTANT(BODY_MODE_RIGID); - BIND_ENUM_CONSTANT(BODY_MODE_CHARACTER); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index c434109865..78fc026747 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -59,8 +59,8 @@ public: virtual void set_angular_velocity(const Vector3 &p_velocity) = 0; virtual Vector3 get_angular_velocity() const = 0; - virtual void set_transform(const Transform &p_transform) = 0; - virtual Transform get_transform() const = 0; + virtual void set_transform(const Transform3D &p_transform) = 0; + virtual Transform3D get_transform() const = 0; virtual void add_central_force(const Vector3 &p_force) = 0; virtual void add_force(const Vector3 &p_force, const Vector3 &p_position = Vector3()) = 0; @@ -94,15 +94,13 @@ public: PhysicsDirectBodyState3D(); }; -class PhysicsShapeQueryResult3D; - -class PhysicsShapeQueryParameters3D : public Reference { - GDCLASS(PhysicsShapeQueryParameters3D, Reference); +class PhysicsShapeQueryParameters3D : public RefCounted { + GDCLASS(PhysicsShapeQueryParameters3D, RefCounted); friend class PhysicsDirectSpaceState3D; RES shape_ref; RID shape; - Transform transform; + Transform3D transform; real_t margin; Set<RID> exclude; uint32_t collision_mask; @@ -119,8 +117,8 @@ public: void set_shape_rid(const RID &p_shape); RID get_shape_rid() const; - void set_transform(const Transform &p_transform); - Transform get_transform() const; + void set_transform(const Transform3D &p_transform); + Transform3D get_transform() const; void set_margin(real_t p_margin); real_t get_margin() const; @@ -157,8 +155,8 @@ public: struct ShapeResult { RID rid; ObjectID collider_id; - Object *collider; - int shape; + Object *collider = nullptr; + int shape = 0; }; virtual int intersect_point(const Vector3 &p_point, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; @@ -168,54 +166,34 @@ public: Vector3 normal; RID rid; ObjectID collider_id; - Object *collider; - int shape; + Object *collider = nullptr; + int shape = 0; }; virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &p_to, RayResult &r_result, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, bool p_pick_ray = false) = 0; - virtual int intersect_shape(const RID &p_shape, const Transform &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, ShapeResult *r_results, int p_result_max, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; struct ShapeRestInfo { Vector3 point; Vector3 normal; RID rid; ObjectID collider_id; - int shape; + int shape = 0; Vector3 linear_velocity; //velocity at contact point }; - virtual bool cast_motion(const RID &p_shape, const Transform &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0; + virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false, ShapeRestInfo *r_info = nullptr) = 0; - virtual bool collide_shape(RID p_shape, const Transform &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; - virtual bool rest_info(RID p_shape, const Transform &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0; PhysicsDirectSpaceState3D(); }; -class PhysicsShapeQueryResult3D : public Reference { - GDCLASS(PhysicsShapeQueryResult3D, Reference); - - Vector<PhysicsDirectSpaceState3D::ShapeResult> result; - - friend class PhysicsDirectSpaceState3D; - -protected: - static void _bind_methods(); - -public: - int get_result_count() const; - RID get_result_rid(int p_idx) const; - ObjectID get_result_object_id(int p_idx) const; - Object *get_result_object(int p_idx) const; - int get_result_object_shape(int p_idx) const; - - PhysicsShapeQueryResult3D(); -}; - class RenderingServerHandler { public: virtual void set_vertex(int p_vertex_id, const void *p_vector3) = 0; @@ -225,11 +203,15 @@ public: virtual ~RenderingServerHandler() {} }; +class PhysicsTestMotionResult3D; + class PhysicsServer3D : public Object { GDCLASS(PhysicsServer3D, Object); static PhysicsServer3D *singleton; + virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>()); + protected: static void _bind_methods(); @@ -335,13 +317,13 @@ public: virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0; virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0; - virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0; + virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) = 0; virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0; - virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) = 0; + virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) = 0; virtual int area_get_shape_count(RID p_area) const = 0; virtual RID area_get_shape(RID p_area, int p_shape_idx) const = 0; - virtual Transform area_get_shape_transform(RID p_area, int p_shape_idx) const = 0; + virtual Transform3D area_get_shape_transform(RID p_area, int p_shape_idx) const = 0; virtual void area_remove_shape(RID p_area, int p_shape_idx) = 0; virtual void area_clear_shapes(RID p_area) = 0; @@ -352,10 +334,10 @@ public: virtual ObjectID area_get_object_instance_id(RID p_area) const = 0; virtual void area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) = 0; - virtual void area_set_transform(RID p_area, const Transform &p_transform) = 0; + virtual void area_set_transform(RID p_area, const Transform3D &p_transform) = 0; virtual Variant area_get_param(RID p_parea, AreaParameter p_param) const = 0; - virtual Transform area_get_transform(RID p_area) const = 0; + virtual Transform3D area_get_transform(RID p_area) const = 0; virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) = 0; virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) = 0; @@ -374,8 +356,8 @@ public: enum BodyMode { BODY_MODE_STATIC, BODY_MODE_KINEMATIC, - BODY_MODE_RIGID, - BODY_MODE_CHARACTER + BODY_MODE_DYNAMIC, + BODY_MODE_DYNAMIC_LOCKED, }; virtual RID body_create() = 0; @@ -386,13 +368,13 @@ public: virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0; virtual BodyMode body_get_mode(RID p_body) const = 0; - virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0; + virtual void body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) = 0; virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0; - virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) = 0; + virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) = 0; virtual int body_get_shape_count(RID p_body) const = 0; virtual RID body_get_shape(RID p_body, int p_shape_idx) const = 0; - virtual Transform body_get_shape_transform(RID p_body, int p_shape_idx) const = 0; + virtual Transform3D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0; virtual void body_remove_shape(RID p_body, int p_shape_idx) = 0; virtual void body_clear_shapes(RID p_body) = 0; @@ -428,9 +410,6 @@ public: virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; - virtual void body_set_kinematic_safe_margin(RID p_body, real_t p_margin) = 0; - virtual real_t body_get_kinematic_safe_margin(RID p_body) const = 0; - //state enum BodyState { BODY_STATE_TRANSFORM, @@ -500,19 +479,17 @@ public: Vector3 collision_point; Vector3 collision_normal; Vector3 collider_velocity; - int collision_local_shape; + real_t collision_depth = 0.0; + real_t collision_safe_fraction = 0.0; + real_t collision_unsafe_fraction = 0.0; + int collision_local_shape = 0; ObjectID collider_id; RID collider; - int collider_shape; + int collider_shape = 0; Variant collider_metadata; - MotionResult() { - collision_local_shape = 0; - collider_id = ObjectID(); - collider_shape = 0; - } }; - virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; + virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_exclude_raycast_shapes = true) = 0; struct SeparationResult { real_t collision_depth; @@ -526,7 +503,7 @@ public: Variant collider_metadata; }; - virtual int body_test_ray_separation(RID p_body, const Transform &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0; + virtual int body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin = 0.001) = 0; /* SOFT BODY */ @@ -554,7 +531,7 @@ public: virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0; virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const = 0; - virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) = 0; + virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) = 0; virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0; @@ -642,7 +619,7 @@ public: HINGE_JOINT_FLAG_MAX }; - virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform &p_hinge_A, RID p_body_B, const Transform &p_hinge_B) = 0; + virtual void joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) = 0; virtual void joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) = 0; virtual void hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) = 0; @@ -679,7 +656,7 @@ public: }; - virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A + virtual void joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) = 0; //reference frame is A virtual void slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) = 0; virtual real_t slider_joint_get_param(RID p_joint, SliderJointParam p_param) const = 0; @@ -693,7 +670,7 @@ public: CONE_TWIST_MAX }; - virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A + virtual void joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) = 0; //reference frame is A virtual void cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) = 0; virtual real_t cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const = 0; @@ -734,7 +711,7 @@ public: G6DOF_JOINT_FLAG_MAX }; - virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform &p_local_frame_A, RID p_body_B, const Transform &p_local_frame_B) = 0; //reference frame is A + virtual void joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) = 0; //reference frame is A virtual void generic_6dof_joint_set_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param, real_t p_value) = 0; virtual real_t generic_6dof_joint_get_param(RID p_joint, Vector3::Axis, G6DOFJointAxisParam p_param) const = 0; @@ -775,6 +752,33 @@ public: ~PhysicsServer3D(); }; +class PhysicsTestMotionResult3D : public RefCounted { + GDCLASS(PhysicsTestMotionResult3D, RefCounted); + + PhysicsServer3D::MotionResult result; + friend class PhysicsServer3D; + +protected: + static void _bind_methods(); + +public: + PhysicsServer3D::MotionResult *get_result_ptr() const { return const_cast<PhysicsServer3D::MotionResult *>(&result); } + + Vector3 get_motion() const; + Vector3 get_motion_remainder() const; + + Vector3 get_collision_point() const; + Vector3 get_collision_normal() const; + Vector3 get_collider_velocity() const; + ObjectID get_collider_id() const; + RID get_collider_rid() const; + Object *get_collider() const; + int get_collider_shape() const; + real_t get_collision_depth() const; + real_t get_collision_safe_fraction() const; + real_t get_collision_unsafe_fraction() const; +}; + typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)(); class PhysicsServer3DManager { diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index deb230c4fb..ef82ce5cae 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -55,6 +55,7 @@ #include "audio_server.h" #include "camera/camera_feed.h" #include "camera_server.h" +#include "core/extension/native_extension_manager.h" #include "display_server.h" #include "navigation_server_2d.h" #include "navigation_server_3d.h" @@ -194,6 +195,7 @@ void register_server_types() { ClassDB::register_class<RDTextureFormat>(); ClassDB::register_class<RDTextureView>(); ClassDB::register_class<RDAttachmentFormat>(); + ClassDB::register_class<RDFramebufferPass>(); ClassDB::register_class<RDSamplerState>(); ClassDB::register_class<RDVertexAttribute>(); ClassDB::register_class<RDUniform>(); @@ -205,19 +207,19 @@ void register_server_types() { ClassDB::register_class<RDShaderSource>(); ClassDB::register_class<RDShaderBytecode>(); ClassDB::register_class<RDShaderFile>(); + ClassDB::register_class<RDPipelineSpecializationConstant>(); ClassDB::register_class<CameraFeed>(); ClassDB::register_virtual_class<PhysicsDirectBodyState2D>(); ClassDB::register_virtual_class<PhysicsDirectSpaceState2D>(); - ClassDB::register_virtual_class<PhysicsShapeQueryResult2D>(); ClassDB::register_class<PhysicsTestMotionResult2D>(); ClassDB::register_class<PhysicsShapeQueryParameters2D>(); ClassDB::register_class<PhysicsShapeQueryParameters3D>(); ClassDB::register_virtual_class<PhysicsDirectBodyState3D>(); ClassDB::register_virtual_class<PhysicsDirectSpaceState3D>(); - ClassDB::register_virtual_class<PhysicsShapeQueryResult3D>(); + ClassDB::register_class<PhysicsTestMotionResult3D>(); // Physics 2D GLOBAL_DEF(PhysicsServer2DManager::setting_property_name, "DEFAULT"); @@ -232,22 +234,26 @@ void register_server_types() { PhysicsServer3DManager::register_server("GodotPhysics3D", &_createGodotPhysics3DCallback); PhysicsServer3DManager::set_default_server("GodotPhysics3D"); + + NativeExtensionManager::get_singleton()->initialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); } void unregister_server_types() { + NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); + memdelete(shader_types); TextServer::finish_hex_code_box_fonts(); } void register_server_singletons() { - Engine::get_singleton()->add_singleton(Engine::Singleton("DisplayServer", DisplayServer::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut())); - Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut())); - Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton())); - Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("DisplayServer", DisplayServer::get_singleton(), "DisplayServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton(), "RenderingServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton(), "AudioServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton(), "PhysicsServer2D")); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton(), "PhysicsServer3D")); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut(), "NavigationServer2D")); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut(), "NavigationServer3D")); + Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager")); + Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton(), "XRServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer")); } diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index bfc7e7684f..f22ca738ae 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -36,6 +36,7 @@ #include "core/templates/self_list.h" #include "scene/resources/mesh.h" #include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering_server.h" class RasterizerSceneDummy : public RendererSceneRender { @@ -45,7 +46,7 @@ public: void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override {} void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) override {} void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override {} - void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {} + void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override {} void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override {} void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override {} void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override {} @@ -59,7 +60,7 @@ public: void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override {} void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override {} void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override {} - void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) override {} + void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override {} void geometry_instance_free(GeometryInstance *p_geometry_instance) override {} @@ -145,9 +146,9 @@ public: void directional_shadow_quality_set(RS::ShadowQuality p_quality) override {} RID light_instance_create(RID p_light) override { return RID(); } - void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) override {} + void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {} void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {} - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {} + void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {} void light_instance_mark_visible(RID p_light_instance) override {} RID reflection_atlas_create() override { return RID(); } @@ -155,7 +156,7 @@ public: void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {} RID reflection_probe_instance_create(RID p_probe) override { return RID(); } - void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) override {} + void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {} void reflection_probe_release_atlas_index(RID p_instance) override {} bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; } bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; } @@ -163,28 +164,28 @@ public: bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; } RID decal_instance_create(RID p_decal) override { return RID(); } - void decal_instance_set_transform(RID p_decal, const Transform &p_transform) override {} + void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {} RID lightmap_instance_create(RID p_lightmap) override { return RID(); } - void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) override {} + void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {} - RID gi_probe_instance_create(RID p_gi_probe) override { return RID(); } - void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) override {} - bool gi_probe_needs_update(RID p_probe) const override { return false; } - void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override {} + RID voxel_gi_instance_create(RID p_voxel_gi) override { return RID(); } + void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override {} + bool voxel_gi_needs_update(RID p_probe) const override { return false; } + void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override {} - void gi_probe_set_quality(RS::GIProbeQuality) override {} + void voxel_gi_set_quality(RS::VoxelGIQuality) override {} - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) override {} - void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {} - void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {} + void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {} + void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {} + void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {} void set_scene_pass(uint64_t p_pass) override {} void set_time(double p_time, double p_step) override {} void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {} RID render_buffers_create() override { return RID(); } - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) override {} + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {} void gi_set_use_half_resolution(bool p_enable) override {} void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {} @@ -225,7 +226,6 @@ public: } void texture_2d_layered_initialize(RID p_texture, const Vector<Ref<Image>> &p_layers, RS::TextureLayeredType p_layered_type) override {} - void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {} void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) override {} void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) override {} void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) override {} @@ -324,7 +324,9 @@ public: void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override {} RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override { return RS::BLEND_SHAPE_MODE_NORMALIZED; } - void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {} + void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {} + void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {} + void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) override {} void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override {} RID mesh_surface_get_material(RID p_mesh, int p_surface) const override { return RID(); } @@ -347,7 +349,7 @@ public: int multimesh_get_instance_count(RID p_multimesh) const override { return 0; } void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override {} - void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) override {} + void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override {} void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override {} void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override {} void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override {} @@ -355,7 +357,7 @@ public: RID multimesh_get_mesh(RID p_multimesh) const override { return RID(); } AABB multimesh_get_aabb(RID p_multimesh) const override { return AABB(); } - Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform(); } + Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override { return Transform3D(); } Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override { return Transform2D(); } Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override { return Color(); } Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override { return Color(); } @@ -365,23 +367,6 @@ public: void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override {} int multimesh_get_visible_instances(RID p_multimesh) const override { return 0; } - /* IMMEDIATE API */ - - RID immediate_allocate() override { return RID(); } - void immediate_initialize(RID p_rid) override {} - void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) override {} - void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) override {} - void immediate_normal(RID p_immediate, const Vector3 &p_normal) override {} - void immediate_tangent(RID p_immediate, const Plane &p_tangent) override {} - void immediate_color(RID p_immediate, const Color &p_color) override {} - void immediate_uv(RID p_immediate, const Vector2 &tex_uv) override {} - void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) override {} - void immediate_end(RID p_immediate) override {} - void immediate_clear(RID p_immediate) override {} - void immediate_set_material(RID p_immediate, RID p_material) override {} - RID immediate_get_material(RID p_immediate) const override { return RID(); } - AABB immediate_get_aabb(RID p_immediate) const override { return AABB(); } - /* SKELETON API */ RID skeleton_allocate() override { return RID(); } @@ -389,8 +374,8 @@ public: void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override {} void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override {} int skeleton_get_bone_count(RID p_skeleton) const override { return 0; } - void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) override {} - Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform(); } + void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override {} + Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override { return Transform3D(); } void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override {} Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override { return Transform2D(); } @@ -421,10 +406,8 @@ public: void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override {} void light_directional_set_blend_splits(RID p_light, bool p_enable) override {} bool light_directional_get_blend_splits(RID p_light) const override { return false; } - void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) override {} void light_directional_set_sky_only(RID p_light, bool p_sky_only) override {} bool light_directional_is_sky_only(RID p_light) const override { return false; } - RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const override { return RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; } RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override { return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; } RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override { return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; } @@ -482,52 +465,46 @@ public: AABB decal_get_aabb(RID p_decal) const override { return AABB(); } - /* GI PROBE API */ - - RID gi_probe_allocate() override { return RID(); } - void gi_probe_initialize(RID p_rid) override {} - void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {} + /* VOXEL GI API */ - AABB gi_probe_get_bounds(RID p_gi_probe) const override { return AABB(); } - Vector3i gi_probe_get_octree_size(RID p_gi_probe) const override { return Vector3i(); } - Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const override { return Vector<uint8_t>(); } - Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const override { return Vector<uint8_t>(); } - Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const override { return Vector<uint8_t>(); } + RID voxel_gi_allocate() override { return RID(); } + void voxel_gi_initialize(RID p_rid) override {} + void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) override {} - Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const override { return Vector<int>(); } - Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const override { return Transform(); } + AABB voxel_gi_get_bounds(RID p_voxel_gi) const override { return AABB(); } + Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override { return Vector3i(); } + Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); } + Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const override { return Vector<uint8_t>(); } + Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const override { return Vector<uint8_t>(); } - void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) override {} - float gi_probe_get_dynamic_range(RID p_gi_probe) const override { return 0; } + Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const override { return Vector<int>(); } + Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override { return Transform3D(); } - void gi_probe_set_propagation(RID p_gi_probe, float p_range) override {} - float gi_probe_get_propagation(RID p_gi_probe) const override { return 0; } + void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override {} + float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override { return 0; } - void gi_probe_set_energy(RID p_gi_probe, float p_range) override {} - float gi_probe_get_energy(RID p_gi_probe) const override { return 0.0; } + void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override {} + float voxel_gi_get_propagation(RID p_voxel_gi) const override { return 0; } - void gi_probe_set_ao(RID p_gi_probe, float p_ao) override {} - float gi_probe_get_ao(RID p_gi_probe) const override { return 0; } + void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override {} + float voxel_gi_get_energy(RID p_voxel_gi) const override { return 0.0; } - void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) override {} - float gi_probe_get_ao_size(RID p_gi_probe) const override { return 0; } + void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override {} + float voxel_gi_get_bias(RID p_voxel_gi) const override { return 0.0; } - void gi_probe_set_bias(RID p_gi_probe, float p_range) override {} - float gi_probe_get_bias(RID p_gi_probe) const override { return 0.0; } + void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override {} + float voxel_gi_get_normal_bias(RID p_voxel_gi) const override { return 0.0; } - void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) override {} - float gi_probe_get_normal_bias(RID p_gi_probe) const override { return 0.0; } + void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override {} + bool voxel_gi_is_interior(RID p_voxel_gi) const override { return false; } - void gi_probe_set_interior(RID p_gi_probe, bool p_enable) override {} - bool gi_probe_is_interior(RID p_gi_probe) const override { return false; } + void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override {} + bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override { return false; } - void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) override {} - bool gi_probe_is_using_two_bounces(RID p_gi_probe) const override { return false; } + void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override {} + float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override { return 0; } - void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) override {} - float gi_probe_get_anisotropy_strength(RID p_gi_probe) const override { return 0; } - - uint32_t gi_probe_get_version(RID p_gi_probe) override { return 0; } + uint32_t voxel_gi_get_version(RID p_voxel_gi) override { return 0; } /* LIGHTMAP CAPTURE */ RID lightmap_allocate() override { return RID(); } @@ -555,7 +532,7 @@ public: RID particles_allocate() override { return RID(); } void particles_initialize(RID p_rid) override {} void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override {} - void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {} + void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override {} void particles_set_emitting(RID p_particles, bool p_emitting) override {} void particles_set_amount(RID p_particles, int p_amount) override {} void particles_set_lifetime(RID p_particles, float p_lifetime) override {} @@ -577,7 +554,7 @@ public: void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override {} void particles_set_trails(RID p_particles, bool p_enable, float p_length) override {} - void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) override {} + void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) override {} void particles_restart(RID p_particles) override {} @@ -590,7 +567,7 @@ public: AABB particles_get_current_aabb(RID p_particles) override { return AABB(); } AABB particles_get_aabb(RID p_particles) const override { return AABB(); } - void particles_set_emission_transform(RID p_particles, const Transform &p_transform) override {} + void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override {} bool particles_get_emitting(RID p_particles) override { return false; } int particles_get_draw_passes(RID p_particles) const override { return 0; } @@ -621,9 +598,18 @@ public: bool particles_collision_is_heightfield(RID p_particles_collision) const override { return false; } RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override { return RID(); } - RID particles_collision_instance_create(RID p_collision) override { return RID(); }; - void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) override{}; - void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override{}; + RID particles_collision_instance_create(RID p_collision) override { return RID(); } + void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {} + void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {} + + /* VISIBILITY NOTIFIER */ + virtual RID visibility_notifier_allocate() override { return RID(); } + virtual void visibility_notifier_initialize(RID p_notifier) override {} + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override {} + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override {} + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const override { return AABB(); } + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override {} /* GLOBAL VARIABLES */ @@ -649,7 +635,7 @@ public: RID render_target_create() override { return RID(); } void render_target_set_position(RID p_render_target, int p_x, int p_y) override {} - void render_target_set_size(RID p_render_target, int p_width, int p_height) override {} + void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {} RID render_target_get_texture(RID p_render_target) override { return RID(); } void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {} void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {} @@ -677,17 +663,15 @@ public: return true; } + virtual void update_memory_info() override {} + virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) override { return 0; } + bool has_os_feature(const String &p_feature) const override { return false; } void update_dirty_resources() override {} void set_debug_generate_wireframes(bool p_generate) override {} - void render_info_begin_capture() override {} - void render_info_end_capture() override {} - int get_captured_render_info(RS::RenderInfo p_info) override { return 0; } - - uint64_t get_render_info(RS::RenderInfo p_info) override { return 0; } String get_video_adapter_name() const override { return String(); } String get_video_adapter_vendor() const override { return String(); } @@ -725,8 +709,6 @@ public: void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) override {} void set_shadow_texture_size(int p_size) override {} - void draw_window_margins(int *p_margins, RID *p_margin_textures) override {} - bool free(RID p_rid) override { return true; } void update() override {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 67003a6f64..ec0a8347f8 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -44,10 +44,10 @@ void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); for (int i = 0; i < p_child_item_count; i++) { - _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr); + _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true); } if (p_canvas_item) { - _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr); + _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true); } RendererCanvasRender::Item *list = nullptr; @@ -97,105 +97,14 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 } } -void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_PtrOwner<RendererCanvasCull::Item, true> &canvas_item_owner) { +void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<RendererCanvasCull::Item, true> &canvas_item_owner) { do { ysort_owner->ysort_children_count = -1; ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : nullptr; } while (ysort_owner && ysort_owner->sort_y); } -void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner) { - Item *ci = p_canvas_item; - - if (!ci->visible) { - return; - } - - if (ci->children_order_dirty) { - ci->child_items.sort_custom<ItemIndexSort>(); - ci->children_order_dirty = false; - } - - Rect2 rect = ci->get_rect(); - Transform2D xform = ci->xform; - if (snapping_2d_transforms_to_pixel) { - xform.elements[2] = xform.elements[2].floor(); - } - xform = p_transform * xform; - - Rect2 global_rect = xform.xform(rect); - global_rect.position += p_clip_rect.position; - - if (ci->use_parent_material && p_material_owner) { - ci->material_owner = p_material_owner; - } else { - p_material_owner = ci; - ci->material_owner = nullptr; - } - - Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a); - - if (modulate.a < 0.007) { - return; - } - - int child_item_count = ci->child_items.size(); - Item **child_items = ci->child_items.ptrw(); - - if (ci->clip) { - if (p_canvas_clip != nullptr) { - ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect); - } else { - ci->final_clip_rect = global_rect; - } - ci->final_clip_rect.position = ci->final_clip_rect.position.round(); - ci->final_clip_rect.size = ci->final_clip_rect.size.round(); - ci->final_clip_owner = ci; - - } else { - ci->final_clip_owner = p_canvas_clip; - } - - if (ci->sort_y) { - if (ci->ysort_children_count == -1) { - ci->ysort_children_count = 0; - _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count); - } - - child_item_count = ci->ysort_children_count; - child_items = (Item **)alloca(child_item_count * sizeof(Item *)); - - int i = 0; - _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i); - - SortArray<Item *, ItemPtrSort> sorter; - sorter.sort(child_items, child_item_count); - } - - if (ci->z_relative) { - p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); - } else { - p_z = ci->z_index; - } - - RendererCanvasRender::Item *canvas_group_from = nullptr; - bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); - if (use_canvas_group) { - int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; - canvas_group_from = z_last_list[zidx]; - } - - for (int i = 0; i < child_item_count; i++) { - if ((!child_items[i]->behind && !use_canvas_group) || (ci->sort_y && child_items[i]->sort_y)) { - continue; - } - if (ci->sort_y) { - _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner); - } else { - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); - } - } - +void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *ci, RendererCanvasCull::Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform) { if (ci->copy_back_buffer) { ci->copy_back_buffer->screen_rect = xform.xform(ci->copy_back_buffer->rect).intersection(p_clip_rect); } @@ -229,7 +138,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 // We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this. // If nothing has been drawn, we just take it over and draw it ourselves. if (ci->canvas_group->fit_empty && (ci->commands == nullptr || - (ci->commands->next == nullptr && ci->commands->type == Item::Command::TYPE_RECT && (static_cast<Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) { + (ci->commands->next == nullptr && ci->commands->type == RendererCanvasCull::Item::Command::TYPE_RECT && (static_cast<RendererCanvasCull::Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) { // No commands, or sole command is the one used to draw, so we (re)create the draw command. ci->clear(); @@ -264,42 +173,163 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } } - if (ci->update_when_visible) { - RenderingServerDefault::redraw_request(); + if (((ci->commands != nullptr || ci->visibility_notifier) && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { + //something to draw? + + if (ci->update_when_visible) { + RenderingServerDefault::redraw_request(); + } + + if (ci->commands != nullptr) { + ci->final_transform = xform; + ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); + ci->global_rect_cache = global_rect; + ci->global_rect_cache.position -= p_clip_rect.position; + ci->light_masked = false; + + int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + + if (z_last_list[zidx]) { + z_last_list[zidx]->next = ci; + z_last_list[zidx] = ci; + + } else { + z_list[zidx] = ci; + z_last_list[zidx] = ci; + } + + ci->z_final = p_z; + + ci->next = nullptr; + } + + if (ci->visibility_notifier) { + if (!ci->visibility_notifier->visible_element.in_list()) { + visibility_notifier_list.add(&ci->visibility_notifier->visible_element); + ci->visibility_notifier->just_visible = true; + } + + ci->visibility_notifier->visible_in_frame = RSG::rasterizer->get_frame_number(); + } } +} - if ((ci->commands != nullptr && p_clip_rect.intersects(global_rect, true)) || ci->vp_render || ci->copy_back_buffer) { - //something to draw? - ci->final_transform = xform; - ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); - ci->global_rect_cache = global_rect; - ci->global_rect_cache.position -= p_clip_rect.position; - ci->light_masked = false; +void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort) { + Item *ci = p_canvas_item; - int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + if (!ci->visible) { + return; + } - if (z_last_list[zidx]) { - z_last_list[zidx]->next = ci; - z_last_list[zidx] = ci; + if (ci->children_order_dirty) { + ci->child_items.sort_custom<ItemIndexSort>(); + ci->children_order_dirty = false; + } - } else { - z_list[zidx] = ci; - z_last_list[zidx] = ci; + Rect2 rect = ci->get_rect(); + + if (ci->visibility_notifier) { + if (ci->visibility_notifier->area.size != Vector2()) { + rect = rect.merge(ci->visibility_notifier->area); } + } - ci->z_final = p_z; + Transform2D xform = ci->xform; + if (snapping_2d_transforms_to_pixel) { + xform.elements[2] = xform.elements[2].floor(); + } + xform = p_transform * xform; - ci->next = nullptr; + Rect2 global_rect = xform.xform(rect); + global_rect.position += p_clip_rect.position; + + if (ci->use_parent_material && p_material_owner) { + ci->material_owner = p_material_owner; + } else { + p_material_owner = ci; + ci->material_owner = nullptr; } - for (int i = 0; i < child_item_count; i++) { - if (child_items[i]->behind || use_canvas_group || (ci->sort_y && child_items[i]->sort_y)) { - continue; + Color modulate(ci->modulate.r * p_modulate.r, ci->modulate.g * p_modulate.g, ci->modulate.b * p_modulate.b, ci->modulate.a * p_modulate.a); + + if (modulate.a < 0.007) { + return; + } + + int child_item_count = ci->child_items.size(); + Item **child_items = ci->child_items.ptrw(); + + if (ci->clip) { + if (p_canvas_clip != nullptr) { + ci->final_clip_rect = p_canvas_clip->final_clip_rect.intersection(global_rect); + } else { + ci->final_clip_rect = global_rect; } - if (ci->sort_y) { - _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner); + ci->final_clip_rect.position = ci->final_clip_rect.position.round(); + ci->final_clip_rect.size = ci->final_clip_rect.size.round(); + ci->final_clip_owner = ci; + + } else { + ci->final_clip_owner = p_canvas_clip; + } + + if (ci->z_relative) { + p_z = CLAMP(p_z + ci->z_index, RS::CANVAS_ITEM_Z_MIN, RS::CANVAS_ITEM_Z_MAX); + } else { + p_z = ci->z_index; + } + + if (ci->sort_y) { + if (allow_y_sort) { + if (ci->ysort_children_count == -1) { + ci->ysort_children_count = 0; + _collect_ysort_children(ci, Transform2D(), p_material_owner, nullptr, ci->ysort_children_count); + } + + child_item_count = ci->ysort_children_count + 1; + child_items = (Item **)alloca(child_item_count * sizeof(Item *)); + + child_items[0] = ci; + int i = 1; + _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i); + ci->ysort_xform = ci->xform.affine_inverse(); + + SortArray<Item *, ItemPtrSort> sorter; + sorter.sort(child_items, child_item_count); + + for (i = 0; i < child_item_count; i++) { + _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false); + } } else { - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner); + RendererCanvasRender::Item *canvas_group_from = nullptr; + bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); + if (use_canvas_group) { + int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + canvas_group_from = z_last_list[zidx]; + } + + _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform); + } + } else { + RendererCanvasRender::Item *canvas_group_from = nullptr; + bool use_canvas_group = ci->canvas_group != nullptr && (ci->canvas_group->fit_empty || ci->commands != nullptr); + if (use_canvas_group) { + int zidx = p_z - RS::CANVAS_ITEM_Z_MIN; + canvas_group_from = z_last_list[zidx]; + } + + for (int i = 0; i < child_item_count; i++) { + if (!child_items[i]->behind && !use_canvas_group) { + continue; + } + _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true); + } + _attach_canvas_item_for_draw(ci, p_canvas_clip, z_list, z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from, xform); + for (int i = 0; i < child_item_count; i++) { + if (child_items[i]->behind || use_canvas_group) { + continue; + } + _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true); } } } @@ -362,8 +392,7 @@ RID RendererCanvasCull::canvas_allocate() { return canvas_owner.allocate_rid(); } void RendererCanvasCull::canvas_initialize(RID p_rid) { - Canvas *canvas = memnew(Canvas); - canvas_owner.initialize_rid(p_rid, canvas); + canvas_owner.initialize_rid(p_rid); } void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) { @@ -399,8 +428,7 @@ RID RendererCanvasCull::canvas_item_allocate() { return canvas_item_owner.allocate_rid(); } void RendererCanvasCull::canvas_item_initialize(RID p_rid) { - Item *canvas_item = memnew(Item); - canvas_item_owner.initialize_rid(p_rid, canvas_item); + canvas_item_owner.initialize_rid(p_rid); } void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) { @@ -973,6 +1001,18 @@ void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) ci->ignore = p_ignore; } +void RendererCanvasCull::canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) { + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + + Item::CommandAnimationSlice *as = canvas_item->alloc_command<Item::CommandAnimationSlice>(); + ERR_FAIL_COND(!as); + as->animation_length = p_animation_length; + as->slice_begin = p_slice_begin; + as->slice_end = p_slice_end; + as->offset = p_offset; +} + void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -1084,6 +1124,26 @@ void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_ canvas_item->use_parent_material = p_enable; } +void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) { + Item *canvas_item = canvas_item_owner.getornull(p_item); + ERR_FAIL_COND(!canvas_item); + + if (p_enable) { + if (!canvas_item->visibility_notifier) { + canvas_item->visibility_notifier = visibility_notifier_allocator.alloc(); + } + canvas_item->visibility_notifier->area = p_area; + canvas_item->visibility_notifier->enter_callable = p_enter_callable; + canvas_item->visibility_notifier->exit_callable = p_exit_callable; + + } else { + if (canvas_item->visibility_notifier) { + visibility_notifier_allocator.free(canvas_item->visibility_notifier); + canvas_item->visibility_notifier = nullptr; + } + } +} + void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { Item *canvas_item = canvas_item_owner.getornull(p_item); ERR_FAIL_COND(!canvas_item); @@ -1109,9 +1169,9 @@ RID RendererCanvasCull::canvas_light_allocate() { return canvas_light_owner.allocate_rid(); } void RendererCanvasCull::canvas_light_initialize(RID p_rid) { - RendererCanvasRender::Light *clight = memnew(RendererCanvasRender::Light); + canvas_light_owner.initialize_rid(p_rid); + RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_rid); clight->light_internal = RSG::canvas_render->light_create(); - return canvas_light_owner.initialize_rid(p_rid, clight); } void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) { @@ -1305,9 +1365,7 @@ RID RendererCanvasCull::canvas_light_occluder_allocate() { return canvas_light_occluder_owner.allocate_rid(); } void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) { - RendererCanvasRender::LightOccluderInstance *occluder = memnew(RendererCanvasRender::LightOccluderInstance); - - return canvas_light_occluder_owner.initialize_rid(p_rid, occluder); + return canvas_light_occluder_owner.initialize_rid(p_rid); } void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) { @@ -1389,9 +1447,9 @@ RID RendererCanvasCull::canvas_occluder_polygon_allocate() { return canvas_light_occluder_polygon_owner.allocate_rid(); } void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) { - LightOccluderPolygon *occluder_poly = memnew(LightOccluderPolygon); + canvas_light_occluder_polygon_owner.initialize_rid(p_rid); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid); occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create(); - return canvas_light_occluder_polygon_owner.initialize_rid(p_rid, occluder_poly); } void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) { @@ -1466,6 +1524,44 @@ void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS:: ci->texture_repeat = p_repeat; } +void RendererCanvasCull::update_visibility_notifiers() { + SelfList<Item::VisibilityNotifierData> *E = visibility_notifier_list.first(); + while (E) { + SelfList<Item::VisibilityNotifierData> *N = E->next(); + + Item::VisibilityNotifierData *visibility_notifier = E->self(); + if (visibility_notifier->just_visible) { + visibility_notifier->just_visible = false; + + if (!visibility_notifier->enter_callable.is_null()) { + if (RSG::threaded) { + visibility_notifier->enter_callable.call_deferred(nullptr, 0); + } else { + Callable::CallError ce; + Variant ret; + visibility_notifier->enter_callable.call(nullptr, 0, ret, ce); + } + } + } else { + if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) { + visibility_notifier_list.remove(E); + + if (!visibility_notifier->exit_callable.is_null()) { + if (RSG::threaded) { + visibility_notifier->exit_callable.call_deferred(nullptr, 0); + } else { + Callable::CallError ce; + Variant ret; + visibility_notifier->exit_callable.call(nullptr, 0, ret, ce); + } + } + } + } + + E = N; + } +} + bool RendererCanvasCull::free(RID p_rid) { if (canvas_owner.owns(p_rid)) { Canvas *canvas = canvas_owner.getornull(p_rid); @@ -1496,8 +1592,6 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_owner.free(p_rid); - memdelete(canvas); - } else if (canvas_item_owner.owns(p_rid)) { Item *canvas_item = canvas_item_owner.getornull(p_rid); ERR_FAIL_COND_V(!canvas_item, true); @@ -1520,6 +1614,10 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_item->child_items[i]->parent = RID(); } + if (canvas_item->visibility_notifier != nullptr) { + visibility_notifier_allocator.free(canvas_item->visibility_notifier); + } + /* if (canvas_item->material) { canvas_item->material->owners.erase(canvas_item); @@ -1528,8 +1626,6 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_item_owner.free(p_rid); - memdelete(canvas_item); - } else if (canvas_light_owner.owns(p_rid)) { RendererCanvasRender::Light *canvas_light = canvas_light_owner.getornull(p_rid); ERR_FAIL_COND_V(!canvas_light, true); @@ -1544,7 +1640,6 @@ bool RendererCanvasCull::free(RID p_rid) { RSG::canvas_render->free(canvas_light->light_internal); canvas_light_owner.free(p_rid); - memdelete(canvas_light); } else if (canvas_light_occluder_owner.owns(p_rid)) { RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid); @@ -1563,7 +1658,6 @@ bool RendererCanvasCull::free(RID p_rid) { } canvas_light_occluder_owner.free(p_rid); - memdelete(occluder); } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid); @@ -1576,7 +1670,6 @@ bool RendererCanvasCull::free(RID p_rid) { } canvas_light_occluder_polygon_owner.free(p_rid); - memdelete(occluder_poly); } else { return false; } diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index b71f8e5a9a..79b5450d14 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -31,6 +31,7 @@ #ifndef RENDERING_SERVER_CANVAS_CULL_H #define RENDERING_SERVER_CANVAS_CULL_H +#include "core/templates/paged_allocator.h" #include "renderer_compositor.h" #include "renderer_viewport.h" @@ -55,6 +56,20 @@ public: Vector<Item *> child_items; + struct VisibilityNotifierData { + Rect2 area; + Callable enter_callable; + Callable exit_callable; + bool just_visible = false; + uint64_t visible_in_frame = 0; + SelfList<VisibilityNotifierData> visible_element; + VisibilityNotifierData() : + visible_element(this) { + } + }; + + VisibilityNotifierData *visibility_notifier = nullptr; + Item() { children_order_dirty = true; E = nullptr; @@ -101,9 +116,9 @@ public: } }; - RID_PtrOwner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner; + RID_Owner<LightOccluderPolygon, true> canvas_light_occluder_polygon_owner; - RID_PtrOwner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner; + RID_Owner<RendererCanvasRender::LightOccluderInstance, true> canvas_light_occluder_owner; struct Canvas : public RendererViewport::CanvasBase { Set<RID> viewports; @@ -148,17 +163,22 @@ public: } }; - mutable RID_PtrOwner<Canvas, true> canvas_owner; - RID_PtrOwner<Item, true> canvas_item_owner; - RID_PtrOwner<RendererCanvasRender::Light, true> canvas_light_owner; + mutable RID_Owner<Canvas, true> canvas_owner; + RID_Owner<Item, true> canvas_item_owner; + RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner; bool disable_scale; bool sdf_used = false; bool snapping_2d_transforms_to_pixel = false; + PagedAllocator<Item::VisibilityNotifierData> visibility_notifier_allocator; + SelfList<Item::VisibilityNotifierData>::List visibility_notifier_list; + + _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, const Transform2D &xform, const Rect2 &p_clip_rect, Rect2 global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool use_canvas_group, RendererCanvasRender::Item *canvas_group_from, const Transform2D &p_xform); + private: void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel); - void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner); + void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **z_list, RendererCanvasRender::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool allow_y_sort); RendererCanvasRender::Item **z_list; RendererCanvasRender::Item **z_last_list; @@ -211,6 +231,8 @@ public: void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture); void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform); void canvas_item_add_clip_ignore(RID p_item, bool p_ignore); + void canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset); + void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable); void canvas_item_set_z_index(RID p_item, int p_z); void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable); @@ -224,6 +246,8 @@ public: void canvas_item_set_use_parent_material(RID p_item, bool p_enable); + void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable); + void canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false); RID canvas_light_allocate(); @@ -283,6 +307,8 @@ public: void canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter); void canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat); + void update_visibility_notifiers(); + bool free(RID p_rid); RendererCanvasCull(); ~RendererCanvasCull(); diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 0266e137c0..8afe9ef410 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -180,6 +180,7 @@ public: TYPE_PARTICLES, TYPE_TRANSFORM, TYPE_CLIP_IGNORE, + TYPE_ANIMATION_SLICE, }; Command *next; @@ -286,6 +287,17 @@ public: } }; + struct CommandAnimationSlice : public Command { + double animation_length = 0; + double slice_begin = 0; + double slice_end = 0; + double offset = 0; + + CommandAnimationSlice() { + type = TYPE_ANIMATION_SLICE; + } + }; + struct ViewportRender { RenderingServer *owner; void *udata; @@ -596,8 +608,6 @@ public: virtual void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) = 0; virtual void set_shadow_texture_size(int p_size) = 0; - virtual void draw_window_margins(int *p_margins, RID *p_margin_textures) = 0; - virtual bool free(RID p_rid) = 0; virtual void update() = 0; diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index 8861522d34..80c4625261 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -30,6 +30,7 @@ #include "renderer_compositor.h" +#include "core/config/project_settings.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -39,4 +40,12 @@ RendererCompositor *RendererCompositor::create() { return _create_func(); } +bool RendererCompositor::is_xr_enabled() const { + return xr_enabled; +} + +RendererCompositor::RendererCompositor() { + xr_enabled = GLOBAL_GET("rendering/xr/enabled"); +} + RendererCanvasRender *RendererCanvasRender::singleton = nullptr; diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 41aaba0f4c..5fe9cdffba 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -36,11 +36,34 @@ #include "core/templates/self_list.h" #include "servers/rendering/renderer_canvas_render.h" #include "servers/rendering/renderer_scene.h" -#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/renderer_storage.h" #include "servers/rendering_server.h" +class RendererSceneRender; +struct BlitToScreen { + RID render_target; + Rect2i rect; + + struct { + bool use_layer = false; + uint32_t layer = 0; + } multi_view; + + struct { + //lens distorted parameters for VR + bool apply = false; + Vector2 eye_center; + float k1 = 0.0; + float k2 = 0.0; + + float upscale = 1.0; + float aspect_ratio = 1.0; + } lens_distortion; +}; class RendererCompositor { +private: + bool xr_enabled = false; + protected: static RendererCompositor *(*_create_func)(); @@ -56,27 +79,6 @@ public: virtual void initialize() = 0; virtual void begin_frame(double frame_step) = 0; - struct BlitToScreen { - RID render_target; - Rect2i rect; - - struct { - bool use_layer = false; - uint32_t layer = 0; - } multi_view; - - struct { - //lens distorted parameters for VR - bool apply = false; - Vector2 eye_center; - float k1 = 0.0; - float k2 = 0.0; - - float upscale = 1.0; - float aspect_ratio = 1.0; - } lens_distortion; - }; - virtual void prepare_for_blitting_render_targets() = 0; virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0; @@ -86,7 +88,9 @@ public: virtual float get_frame_delta_time() const = 0; virtual bool is_low_end() const = 0; + virtual bool is_xr_enabled() const; + RendererCompositor(); virtual ~RendererCompositor() {} }; diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index 2669a73014..b952ecbff0 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -374,7 +374,7 @@ void ClusterBuilderRD::setup(Size2i p_screen_size, uint32_t p_max_elements, RID } } -void ClusterBuilderRD::begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) { +void ClusterBuilderRD::begin(const Transform3D &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y) { view_xform = p_view_transform.affine_inverse(); projection = p_cam_projection; z_near = projection.get_z_near(); diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h index dc1707b534..ebb81abdad 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.h +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -167,7 +167,7 @@ private: uint32_t render_element_count = 0; uint32_t render_element_max = 0; - Transform view_xform; + Transform3D view_xform; CameraMatrix adjusted_projection; CameraMatrix projection; float z_far = 0; @@ -220,9 +220,9 @@ private: public: void setup(Size2i p_screen_size, uint32_t p_max_elements, RID p_depth_buffer, RID p_depth_buffer_sampler, RID p_color_buffer); - void begin(const Transform &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y); + void begin(const Transform3D &p_view_transform, const CameraMatrix &p_cam_projection, bool p_flip_y); - _FORCE_INLINE_ void add_light(LightType p_type, const Transform &p_transform, float p_radius, float p_spot_aperture) { + _FORCE_INLINE_ void add_light(LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) { if (p_type == LIGHT_TYPE_OMNI && cluster_count_by_type[ELEMENT_TYPE_OMNI_LIGHT] == max_elements_by_type) { return; //max number elements reached } @@ -232,7 +232,7 @@ public: RenderElementData &e = render_elements[render_element_count]; - Transform xform = view_xform * p_transform; + Transform3D xform = view_xform * p_transform; float radius = xform.basis.get_uniform_scale(); if (radius > 0.98 || radius < 1.02) { @@ -317,7 +317,7 @@ public: render_element_count++; } - _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform &p_transform, const Vector3 &p_half_extents) { + _FORCE_INLINE_ void add_box(BoxType p_box_type, const Transform3D &p_transform, const Vector3 &p_half_extents) { if (p_box_type == BOX_TYPE_DECAL && cluster_count_by_type[ELEMENT_TYPE_DECAL] == max_elements_by_type) { return; //max number elements reached } @@ -326,7 +326,7 @@ public: } RenderElementData &e = render_elements[render_element_count]; - Transform xform = view_xform * p_transform; + Transform3D xform = view_xform * p_transform; //extract scale and scale the matrix by it, makes things simpler Vector3 scale = p_half_extents; diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 563e08fdcb..5cf8895c8e 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -34,23 +34,9 @@ #include "core/math/math_defs.h" #include "core/os/os.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "thirdparty/misc/cubemap_coeffs.h" -static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) { - p_array[0] = p_basis.elements[0][0]; - p_array[1] = p_basis.elements[1][0]; - p_array[2] = p_basis.elements[2][0]; - p_array[3] = 0; - p_array[4] = p_basis.elements[0][1]; - p_array[5] = p_basis.elements[1][1]; - p_array[6] = p_basis.elements[2][1]; - p_array[7] = 0; - p_array[8] = p_basis.elements[0][2]; - p_array[9] = p_basis.elements[1][2]; - p_array[10] = p_basis.elements[2][2]; - p_array[11] = 0; -} - static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -517,11 +503,10 @@ void EffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal_roughness, R if (p_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_output, p_blur_radius), 1); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_metallic, p_normal_roughness), 3); } else { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_output), 1); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_metallic), 3); } + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_metallic), 3); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_scale_normal), 2); RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1); @@ -732,6 +717,11 @@ void EffectsRD::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Tone tonemap.push_constant.pixel_size[0] = 1.0 / p_settings.texture_size.x; tonemap.push_constant.pixel_size[1] = 1.0 / p_settings.texture_size.y; + if (p_settings.view_count > 1) { + // Use MULTIVIEW versions + mode += 4; + } + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, tonemap.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_color), 0); @@ -934,10 +924,10 @@ void EffectsRD::bokeh_dof(RID p_base_texture, RID p_depth_texture, const Size2i RD::get_singleton()->compute_list_end(); } -void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass) { - RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.gather_uniform_set, 0); +void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) { + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0); if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) { - RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, ssao.importance_map_uniform_set, 1); + RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); } for (int i = 0; i < 4; i++) { @@ -960,7 +950,7 @@ void EffectsRD::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> RD::get_singleton()->compute_list_add_barrier(p_compute_list); } -void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets) { +void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &p_depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set) { RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); RD::get_singleton()->draw_command_begin_label("SSAO"); /* FIRST PASS */ @@ -990,7 +980,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep u.ids.push_back(p_depth_mipmaps[3]); uniforms.push_back(u); } - ssao.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2); + r_downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.downsample_shader.version_get_shader(ssao.downsample_shader_version, 2), 2); } float depth_linearize_mul = -p_projection.matrix[3][2]; @@ -1025,7 +1015,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth_buffer), 0); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_depth_mipmaps[0]), 1); if (p_settings.quality > RS::ENV_SSAO_QUALITY_MEDIUM) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.downsample_uniform_set, 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, r_downsample_uniform_set, 2); } RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.downsample_push_constant, sizeof(SSAODownsamplePushConstant)); @@ -1109,7 +1099,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep u.ids.push_back(ssao.gather_constants_buffer); uniforms.push_back(u); } - ssao.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0); + r_gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0), 0); } if (p_invalidate_uniform_sets) { @@ -1136,7 +1126,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep u.ids.push_back(ssao.importance_map_load_counter); uniforms.push_back(u); } - ssao.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1); + r_importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1); } if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) { @@ -1147,7 +1137,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep ssao.importance_map_push_constant.power = p_settings.power; //base pass RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]); - gather_ssao(compute_list, p_ao_pong_slices, p_settings, true); + gather_ssao(compute_list, p_ao_pong_slices, p_settings, true, r_gather_uniform_set, RID()); //generate importance map RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]); @@ -1178,7 +1168,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]); } - gather_ssao(compute_list, p_ao_slices, p_settings, false); + gather_ssao(compute_list, p_ao_slices, p_settings, false, r_gather_uniform_set, r_importance_map_uniform_set); RD::get_singleton()->draw_command_end_label(); // Gather SSAO } @@ -1365,56 +1355,38 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, RD::get_singleton()->compute_list_end(); } -void EffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { - SkyPushConstant sky_push_constant; - - memset(&sky_push_constant, 0, sizeof(SkyPushConstant)); - - sky_push_constant.proj[0] = p_camera.matrix[2][0]; - sky_push_constant.proj[1] = p_camera.matrix[0][0]; - sky_push_constant.proj[2] = p_camera.matrix[2][1]; - sky_push_constant.proj[3] = p_camera.matrix[1][1]; - sky_push_constant.position[0] = p_position.x; - sky_push_constant.position[1] = p_position.y; - sky_push_constant.position[2] = p_position.z; - sky_push_constant.multiplier = p_multiplier; - sky_push_constant.time = p_time; - store_transform_3x3(p_orientation, sky_push_constant.orientation); - - RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb); - - RD::DrawListID draw_list = p_list; - - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format)); +void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { + ResolvePushConstant push_constant; + push_constant.screen_size[0] = p_screen_size.x; + push_constant.screen_size[1] = p_screen_size.y; + push_constant.samples = p_samples; - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_samplers, 0); - if (p_uniform_set.is_valid()) { //material may not have uniform set - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1); + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[p_source_voxel_gi.is_valid() ? RESOLVE_MODE_GI_VOXEL_GI : RESOLVE_MODE_GI]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_source_depth, p_source_normal_roughness), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_dest_depth, p_dest_normal_roughness), 1); + if (p_source_voxel_gi.is_valid()) { + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_voxel_gi), 2); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_voxel_gi), 3); } - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_fog, 3); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant)); - RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant)); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.x, p_screen_size.y, 1); - RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->compute_list_end(p_barrier); } -void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { +void EffectsRD::resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) { ResolvePushConstant push_constant; push_constant.screen_size[0] = p_screen_size.x; push_constant.screen_size[1] = p_screen_size.y; push_constant.samples = p_samples; RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[p_source_giprobe.is_valid() ? RESOLVE_MODE_GI_GIPROBE : RESOLVE_MODE_GI]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture_pair(p_source_depth, p_source_normal_roughness), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_image_pair(p_dest_depth, p_dest_normal_roughness), 1); - if (p_source_giprobe.is_valid()) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_giprobe), 2); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_giprobe), 3); - } + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, resolve.pipelines[RESOLVE_MODE_DEPTH]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_depth), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_depth), 1); RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ResolvePushConstant)); @@ -1553,12 +1525,29 @@ EffectsRD::EffectsRD() { tonemap_modes.push_back("\n#define USE_1D_LUT\n"); tonemap_modes.push_back("\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + // multiview versions of our shaders + tonemap_modes.push_back("\n#define MULTIVIEW\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + tonemap.shader.initialize(tonemap_modes); + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false); + tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, false); + } + tonemap.shader_version = tonemap.shader.version_create(); for (int i = 0; i < TONEMAP_MODE_MAX; i++) { - tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + if (tonemap.shader.is_variant_enabled(i)) { + tonemap.pipelines[i].setup(tonemap.shader.version_get_shader(tonemap.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + tonemap.pipelines[i].clear(); + } } } @@ -1907,7 +1896,8 @@ EffectsRD::EffectsRD() { { Vector<String> resolve_modes; resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n"); - resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define GIPROBE_RESOLVE\n"); + resolve_modes.push_back("\n#define MODE_RESOLVE_GI\n#define VOXEL_GI_RESOLVE\n"); + resolve_modes.push_back("\n#define MODE_RESOLVE_DEPTH\n"); resolve.shader.initialize(resolve_modes); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 1ba25e301b..33d32f0c57 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -55,6 +55,7 @@ #include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/tonemap.glsl.gen.h" +#include "servers/rendering/renderer_scene_render.h" #include "servers/rendering_server.h" @@ -170,6 +171,12 @@ class EffectsRD { TONEMAP_MODE_BICUBIC_GLOW_FILTER, TONEMAP_MODE_1D_LUT, TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT, + + TONEMAP_MODE_NORMAL_MULTIVIEW, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, + TONEMAP_MODE_1D_LUT_MULTIVIEW, + TONEMAP_MODE_BICUBIC_GLOW_FILTER_1D_LUT_MULTIVIEW, + TONEMAP_MODE_MAX }; @@ -378,12 +385,10 @@ class EffectsRD { SSAODownsamplePushConstant downsample_push_constant; SsaoDownsampleShaderRD downsample_shader; RID downsample_shader_version; - RID downsample_uniform_set; SSAOGatherPushConstant gather_push_constant; SsaoShaderRD gather_shader; RID gather_shader_version; - RID gather_uniform_set; RID gather_constants_buffer; bool gather_initialized = false; @@ -391,7 +396,6 @@ class EffectsRD { SsaoImportanceMapShaderRD importance_map_shader; RID importance_map_shader_version; RID importance_map_load_counter; - RID importance_map_uniform_set; RID counter_uniform_set; SSAOBlurPushConstant blur_push_constant; @@ -452,15 +456,6 @@ class EffectsRD { } filter; - struct SkyPushConstant { - float orientation[12]; - float proj[4]; - float position[3]; - float multiplier; - float time; - float pad[3]; - }; - enum SpecularMergeMode { SPECULAR_MERGE_ADD, SPECULAR_MERGE_SSR, @@ -585,7 +580,8 @@ class EffectsRD { enum ResolveMode { RESOLVE_MODE_GI, - RESOLVE_MODE_GI_GIPROBE, + RESOLVE_MODE_GI_VOXEL_GI, + RESOLVE_MODE_DEPTH, RESOLVE_MODE_MAX }; @@ -714,6 +710,7 @@ public: bool use_fxaa = false; bool use_debanding = false; Vector2i texture_size; + uint32_t view_count = 1; }; struct SSAOSettings { @@ -738,19 +735,19 @@ public: void tonemapper(RID p_source_color, RID p_dst_framebuffer, const TonemapSettings &p_settings); - void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass); - void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets); + void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set); + void generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_depth_mipmaps_texture, const Vector<RID> &depth_mipmaps, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_downsample_uniform_set, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set); void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); - void render_sky(RD::DrawListID p_list, float p_time, RID p_fb, RID p_samplers, RID p_fog, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const CameraMatrix &p_camera, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality); - void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_giprobe, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_giprobe, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL); + void resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL); + void resolve_depth(RID p_source_depth, RID p_dest_depth, Vector2i p_screen_size, int p_samples, uint32_t p_barrier = RD::BARRIER_MASK_ALL); void sort_buffer(RID p_uniform_set, int p_size); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 16c6273ff6..22bfd03115 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -93,8 +93,8 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular() } } -void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() { - if (!giprobe_buffer.is_valid()) { +void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_voxelgi() { + if (!voxelgi_buffer.is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8_UINT; tf.width = width; @@ -105,41 +105,41 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_giprobe() RD::TextureFormat tf_aa = tf; tf_aa.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; tf_aa.samples = texture_samples; - giprobe_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView()); + voxelgi_buffer_msaa = RD::get_singleton()->texture_create(tf_aa, RD::TextureView()); } else { tf.usage_bits |= RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; } tf.usage_bits |= RD::TEXTURE_USAGE_STORAGE_BIT; - giprobe_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); + voxelgi_buffer = RD::get_singleton()->texture_create(tf, RD::TextureView()); Vector<RID> fb; if (msaa != RS::VIEWPORT_MSAA_DISABLED) { fb.push_back(depth_msaa); fb.push_back(normal_roughness_buffer_msaa); - fb.push_back(giprobe_buffer_msaa); + fb.push_back(voxelgi_buffer_msaa); } else { fb.push_back(depth); fb.push_back(normal_roughness_buffer); - fb.push_back(giprobe_buffer); + fb.push_back(voxelgi_buffer); } - depth_normal_roughness_giprobe_fb = RD::get_singleton()->framebuffer_create(fb); + depth_normal_roughness_voxelgi_fb = RD::get_singleton()->framebuffer_create(fb); } } void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { - if (giprobe_buffer != RID()) { - RD::get_singleton()->free(giprobe_buffer); - giprobe_buffer = RID(); + if (voxelgi_buffer != RID()) { + RD::get_singleton()->free(voxelgi_buffer); + voxelgi_buffer = RID(); - if (giprobe_buffer_msaa.is_valid()) { - RD::get_singleton()->free(giprobe_buffer_msaa); - giprobe_buffer_msaa = RID(); + if (voxelgi_buffer_msaa.is_valid()) { + RD::get_singleton()->free(voxelgi_buffer_msaa); + voxelgi_buffer_msaa = RID(); } - depth_normal_roughness_giprobe_fb = RID(); + depth_normal_roughness_voxelgi_fb = RID(); } if (color_msaa.is_valid()) { @@ -183,9 +183,11 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() { } } -void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) { clear(); + ERR_FAIL_COND_MSG(p_view_count != 1, "Multiple views is currently not supported in this renderer, please use the mobile renderer for VR support"); + msaa = p_msaa; width = p_width; @@ -343,8 +345,20 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p mesh_surface = surf->surface_shadow; } else { - material_uniform_set = surf->material_uniform_set; - shader = surf->shader; +#ifdef DEBUG_ENABLED + if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) { + material_uniform_set = scene_shader.default_material_uniform_set; + shader = scene_shader.default_material_shader_ptr; + } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) { + material_uniform_set = scene_shader.overdraw_material_uniform_set; + shader = scene_shader.overdraw_material_shader_ptr; + } else { +#endif + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; +#ifdef DEBUG_ENABLED + } +#endif mesh_surface = surf->surface; } @@ -398,8 +412,8 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE; + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: { + shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI; } break; case PASS_MODE_DEPTH_MATERIAL: { shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; @@ -498,8 +512,8 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { - _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: { + _render_list_template<PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); } break; case PASS_MODE_DEPTH_MATERIAL: { _render_list_template<PASS_MODE_DEPTH_MATERIAL>(p_draw_list, p_framebuffer_Format, p_params, p_from_element, p_to_element); @@ -799,13 +813,16 @@ void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_rende RD::get_singleton()->buffer_update(scene_state.instance_buffer[p_render_list], 0, sizeof(SceneState::InstanceData) * scene_state.instance_data[p_render_list].size(), scene_state.instance_data[p_render_list].ptr(), RD::BARRIER_MASK_RASTER); } } -void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { +void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, int *p_render_info, uint32_t p_offset, int32_t p_max_elements, bool p_update_buffer) { RenderList *rl = &render_list[p_render_list]; uint32_t element_total = p_max_elements >= 0 ? uint32_t(p_max_elements) : rl->elements.size(); scene_state.instance_data[p_render_list].resize(p_offset + element_total); rl->element_info.resize(p_offset + element_total); + if (p_render_info) { + p_render_info[RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] += element_total; + } uint32_t repeats = 0; GeometryInstanceSurfaceDataCache *prev_surface = nullptr; for (uint32_t i = 0; i < element_total; i++) { @@ -817,7 +834,7 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u if (inst->store_transform_cache) { RendererStorageRD::store_transform(inst->transform, instance_data.transform); } else { - RendererStorageRD::store_transform(Transform(), instance_data.transform); + RendererStorageRD::store_transform(Transform3D(), instance_data.transform); } instance_data.flags = inst->flags_cache; @@ -841,6 +858,9 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u } } repeats = 1; + if (p_render_info) { + p_render_info[RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]++; + } } RenderElementInfo &element_info = rl->element_info[p_offset + i]; @@ -867,6 +887,11 @@ void RenderForwardClustered::_fill_instance_data(RenderListType p_render_list, u } } +_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) { + static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 }; + static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 }; + return (p_indices - subtractor[p_primitive]) / divisor[p_primitive]; +} void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) { if (p_render_list == RENDER_LIST_OPAQUE) { scene_state.used_sss = false; @@ -901,6 +926,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con uint32_t flags = inst->base_flags; //fill flags if appropriate + if (inst->non_uniform_scale) { + flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE; + } bool uses_lightmap = false; bool uses_gi = false; @@ -948,14 +976,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con flags |= INSTANCE_DATA_FLAG_USE_GI_BUFFERS; } - if (inst->gi_probes[0].is_valid()) { + if (inst->voxel_gi_instances[0].is_valid()) { uint32_t probe0_index = 0xFFFF; uint32_t probe1_index = 0xFFFF; - for (uint32_t j = 0; j < scene_state.giprobes_used; j++) { - if (scene_state.giprobe_ids[j] == inst->gi_probes[0]) { + for (uint32_t j = 0; j < scene_state.voxelgis_used; j++) { + if (scene_state.voxelgi_ids[j] == inst->voxel_gi_instances[0]) { probe0_index = j; - } else if (scene_state.giprobe_ids[j] == inst->gi_probes[1]) { + } else if (scene_state.voxelgi_ids[j] == inst->voxel_gi_instances[1]) { probe1_index = j; } } @@ -966,7 +994,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } inst->gi_offset_cache = probe0_index | (probe1_index << 16); - flags |= INSTANCE_DATA_FLAG_USE_GIPROBE; + flags |= INSTANCE_DATA_FLAG_USE_VOXEL_GI; uses_gi = true; } else { if (p_using_sdfgi && inst->can_sdfgi) { @@ -1006,17 +1034,41 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con distance = -distance_max; } - surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + uint32_t indices; + surf->sort.lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, &indices); + if (p_render_data->render_info) { + indices = _indices_to_primitives(surf->primitive, indices); + if (p_render_list == RENDER_LIST_OPAQUE) { //opaque + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices; + } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices; + } + } } else { surf->sort.lod_index = 0; + if (p_render_data->render_info) { + uint32_t to_draw = storage->mesh_surface_get_vertices_drawn_count(surf->surface); + to_draw = _indices_to_primitives(surf->primitive, to_draw); + to_draw *= inst->instance_count; + if (p_render_list == RENDER_LIST_OPAQUE) { //opaque + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface); + } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface); + } + } } // ADD Element if (p_pass_mode == PASS_MODE_COLOR) { - if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { +#ifdef DEBUG_ENABLED + bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW); +#else + bool force_alpha = false; +#endif + if (!force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) { rl->add_element(surf); } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) { render_list[RENDER_LIST_ALPHA].add_element(surf); if (uses_gi) { surf->sort.uses_forward_gi = 1; @@ -1061,14 +1113,14 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } } -void RenderForwardClustered::_setup_giprobes(const PagedArray<RID> &p_giprobes) { - scene_state.giprobes_used = MIN(p_giprobes.size(), uint32_t(MAX_GI_PROBES)); - for (uint32_t i = 0; i < scene_state.giprobes_used; i++) { - scene_state.giprobe_ids[i] = p_giprobes[i]; +void RenderForwardClustered::_setup_voxelgis(const PagedArray<RID> &p_voxelgis) { + scene_state.voxelgis_used = MIN(p_voxelgis.size(), uint32_t(MAX_VOXEL_GI_INSTANCESS)); + for (uint32_t i = 0; i < scene_state.voxelgis_used; i++) { + scene_state.voxelgi_ids[i] = p_voxelgis[i]; } } -void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { +void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) { scene_state.lightmaps_used = 0; for (int i = 0; i < (int)p_lightmaps.size(); i++) { if (i >= (int)scene_state.max_lightmaps) { @@ -1091,11 +1143,14 @@ void RenderForwardClustered::_setup_lightmaps(const PagedArray<RID> &p_lightmaps } void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) { + ERR_FAIL_COND_MSG(p_render_data->view_count != 1, "Multiview is currently not supported in the clustered renderer. Please use the mobile renderer for VR."); + RenderBufferDataForwardClustered *render_buffer = nullptr; if (p_render_data->render_buffers.is_valid()) { render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers); } RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment); + static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; //first of all, make a new render pass //fill up ubo @@ -1120,7 +1175,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool using_separate_specular = false; bool using_ssr = false; bool using_sdfgi = false; - bool using_giprobe = false; + bool using_voxelgi = false; bool reverse_cull = false; if (render_buffer) { @@ -1129,19 +1184,19 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co opaque_framebuffer = render_buffer->color_fb; - if (p_render_data->gi_probes->size() > 0) { - using_giprobe = true; + if (p_render_data->voxel_gi_instances->size() > 0) { + using_voxelgi = true; } - if (!p_render_data->environment.is_valid() && using_giprobe) { - depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE; + if (!p_render_data->environment.is_valid() && using_voxelgi) { + depth_pass_mode = PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI; - } else if (p_render_data->environment.is_valid() && (environment_is_ssr_enabled(p_render_data->environment) || environment_is_sdfgi_enabled(p_render_data->environment) || using_giprobe)) { + } else if (p_render_data->environment.is_valid() && (environment_is_ssr_enabled(p_render_data->environment) || environment_is_sdfgi_enabled(p_render_data->environment) || using_voxelgi)) { if (environment_is_sdfgi_enabled(p_render_data->environment)) { - depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also giprobe + depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; // also voxelgi using_sdfgi = true; } else { - depth_pass_mode = using_giprobe ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; + depth_pass_mode = using_voxelgi ? PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI : PASS_MODE_DEPTH_NORMAL_ROUGHNESS; } if (environment_is_ssr_enabled(p_render_data->environment)) { @@ -1164,10 +1219,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co depth_framebuffer = render_buffer->depth_normal_roughness_fb; depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); } break; - case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE: { + case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: { _allocate_normal_roughness_texture(render_buffer); - render_buffer->ensure_giprobe(); - depth_framebuffer = render_buffer->depth_normal_roughness_giprobe_fb; + render_buffer->ensure_voxelgi(); + depth_framebuffer = render_buffer->depth_normal_roughness_voxelgi_fb; depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0)); depth_pass_clear.push_back(Color(0, 0, 0, 0)); } break; @@ -1198,15 +1253,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_begin_label("Render Setup"); _setup_lightmaps(*p_render_data->lightmaps, p_render_data->cam_transform); - _setup_giprobes(*p_render_data->gi_probes); + _setup_voxelgis(*p_render_data->voxel_gi_instances); _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); _update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example) - _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_giprobe); + _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi); render_list[RENDER_LIST_OPAQUE].sort_by_key(); - render_list[RENDER_LIST_ALPHA].sort_by_depth(); - _fill_instance_data(RENDER_LIST_OPAQUE); + render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority(); + _fill_instance_data(RENDER_LIST_OPAQUE, p_render_data->render_info ? p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE] : (int *)nullptr); _fill_instance_data(RENDER_LIST_ALPHA); RD::get_singleton()->draw_command_end_label(); @@ -1293,7 +1348,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co clear_color = p_default_bg_color; } - bool debug_giprobes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION; + bool debug_voxelgis = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION; bool debug_sdfgi_probes = get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_SDFGI_PROBES; bool depth_pre_pass = depth_framebuffer.is_valid(); @@ -1301,7 +1356,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool continue_depth = false; if (depth_pre_pass) { //depth pre pass - bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_giprobe); + bool needs_pre_resolve = _needs_post_prepass_render(p_render_data, using_sdfgi || using_voxelgi); if (needs_pre_resolve) { RENDER_TIMESTAMP("GI + Render Depth Pre-Pass (parallel)"); } else { @@ -1312,34 +1367,33 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE, depth_pass_clear); RD::get_singleton()->draw_list_end(); //start compute processes here, so they run at the same time as depth pre-pass - _post_prepass_render(p_render_data, using_sdfgi || using_giprobe); + _post_prepass_render(p_render_data, using_sdfgi || using_voxelgi); } RD::get_singleton()->draw_command_begin_label("Render Depth Pre-Pass"); RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID()); - bool finish_depth = using_ssao || using_sdfgi || using_giprobe; + bool finish_depth = using_ssao || using_sdfgi || using_voxelgi; RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, render_buffer == nullptr, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); _render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear); RD::get_singleton()->draw_command_end_label(); if (needs_pre_resolve) { - _pre_resolve_render(p_render_data, using_sdfgi || using_giprobe); + _pre_resolve_render(p_render_data, using_sdfgi || using_voxelgi); } if (render_buffer && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { RENDER_TIMESTAMP("Resolve Depth Pre-Pass"); RD::get_singleton()->draw_command_begin_label("Resolve Depth Pre-Pass"); - if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE) { + if (depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || depth_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI) { if (needs_pre_resolve) { RD::get_singleton()->barrier(RD::BARRIER_MASK_RASTER, RD::BARRIER_MASK_COMPUTE); } - static int texture_samples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; - storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_giprobe ? render_buffer->giprobe_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_giprobe ? render_buffer->giprobe_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_samples[render_buffer->msaa]); + storage->get_effects()->resolve_gi(render_buffer->depth_msaa, render_buffer->normal_roughness_buffer_msaa, using_voxelgi ? render_buffer->voxelgi_buffer_msaa : RID(), render_buffer->depth, render_buffer->normal_roughness_buffer, using_voxelgi ? render_buffer->voxelgi_buffer : RID(), Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]); } else if (finish_depth) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); + storage->get_effects()->resolve_depth(render_buffer->depth_msaa, render_buffer->depth, Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]); } RD::get_singleton()->draw_command_end_label(); } @@ -1347,7 +1401,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co continue_depth = !finish_depth; } - _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_giprobe, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->giprobe_buffer : RID()); + _pre_opaque_render(p_render_data, using_ssao, using_sdfgi || using_voxelgi, render_buffer ? render_buffer->normal_roughness_buffer : RID(), render_buffer ? render_buffer->voxelgi_buffer : RID()); RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); @@ -1363,8 +1417,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; { - bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); - bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_giprobes || debug_sdfgi_probes); + bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes); + bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only || debug_voxelgis || debug_sdfgi_probes); //regular forward for now Vector<Color> c; @@ -1389,8 +1443,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); - if (debug_giprobes) { - //debug giprobes + if (debug_voxelgis) { + //debug voxelgis bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); @@ -1398,16 +1452,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co dc.set_depth_correction(true); CameraMatrix cm = (dc * p_render_data->cam_projection) * CameraMatrix(p_render_data->cam_transform.affine_inverse()); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(opaque_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); - RD::get_singleton()->draw_command_begin_label("Debug GIProbes"); - for (int i = 0; i < (int)p_render_data->gi_probes->size(); i++) { - gi.debug_giprobe((*p_render_data->gi_probes)[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, 1.0); + RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs"); + for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) { + gi.debug_voxel_gi((*p_render_data->voxel_gi_instances)[i], draw_list, opaque_framebuffer, cm, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION, 1.0); } RD::get_singleton()->draw_command_end_label(); RD::get_singleton()->draw_list_end(); } if (debug_sdfgi_probes) { - //debug giprobes + //debug voxelgis bool will_continue_color = (can_continue_color || draw_sky || draw_sky_fog_only); bool will_continue_depth = (can_continue_depth || draw_sky || draw_sky_fog_only); @@ -1431,7 +1485,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co projection = correction * p_render_data->cam_projection; } RD::get_singleton()->draw_command_begin_label("Draw Sky"); - sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_render_data->cam_transform, time); + sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time); RD::get_singleton()->draw_command_end_label(); } @@ -1443,7 +1497,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } if (render_buffer && !can_continue_depth && render_buffer->msaa != RS::VIEWPORT_MSAA_DISABLED) { - RD::get_singleton()->texture_resolve_multisample(render_buffer->depth_msaa, render_buffer->depth); + storage->get_effects()->resolve_depth(render_buffer->depth_msaa, render_buffer->depth, Vector2i(render_buffer->width, render_buffer->height), texture_multisamples[render_buffer->msaa]); } if (using_separate_specular) { @@ -1498,7 +1552,8 @@ void RenderForwardClustered::_render_shadow_begin() { render_list[RENDER_LIST_SECONDARY].clear(); scene_state.instance_data[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { + +void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; @@ -1513,6 +1568,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page render_data.instances = &p_instances; render_data.lod_camera_plane = p_camera_plane; render_data.lod_distance_multiplier = p_lod_distance_multiplier; + render_data.render_info = p_render_info; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; @@ -1530,7 +1586,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, true); uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from; render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size); - _fill_instance_data(RENDER_LIST_SECONDARY, render_list_from, render_list_size, false); + _fill_instance_data(RENDER_LIST_SECONDARY, p_render_info ? p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW] : (int *)nullptr, render_list_from, render_list_size, false); { //regular forward for now @@ -1585,7 +1641,7 @@ void RenderForwardClustered::_render_shadow_end(uint32_t p_barrier) { RD::get_singleton()->draw_command_end_label(); } -void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { +void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { RENDER_TIMESTAMP("Setup Render Collider Heightfield"); RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); @@ -1622,7 +1678,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con RD::get_singleton()->draw_command_end_label(); } -void RenderForwardClustered::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { +void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering Material"); RD::get_singleton()->draw_command_begin_label("Render Material"); @@ -1796,7 +1852,7 @@ void RenderForwardClustered::_render_sdfgi(RID p_render_buffers, const Vector3i render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size); //print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size)); - Transform to_bounds; + Transform3D to_bounds; to_bounds.origin = p_bounds.position; to_bounds.basis.scale(p_bounds.size); @@ -2058,11 +2114,11 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(MAX_GI_PROBES); + u.ids.resize(MAX_VOXEL_GI_INSTANCESS); RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - for (int i = 0; i < MAX_GI_PROBES; i++) { - if (p_render_data && i < (int)p_render_data->gi_probes->size()) { - RID tex = gi.gi_probe_instance_get_texture((*p_render_data->gi_probes)[i]); + for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) { + if (p_render_data && i < (int)p_render_data->voxel_gi_instances->size()) { + RID tex = gi.voxel_gi_instance_get_texture((*p_render_data->voxel_gi_instances)[i]); if (!tex.is_valid()) { tex = default_tex; } @@ -2169,7 +2225,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend RD::Uniform u; u.binding = 17; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.ids.push_back(rb ? render_buffers_get_gi_probe_buffer(p_render_data->render_buffers) : render_buffers_get_default_gi_probe_buffer()); + u.ids.push_back(rb ? render_buffers_get_voxel_gi_buffer(p_render_data->render_buffers) : render_buffers_get_default_voxel_gi_buffer()); uniforms.push_back(u); } { @@ -2278,13 +2334,13 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te } { - // No GIProbes + // No VoxelGIs RD::Uniform u; u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(MAX_GI_PROBES); + u.ids.resize(MAX_VOXEL_GI_INSTANCESS); RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - for (int i = 0; i < MAX_GI_PROBES; i++) { + for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) { u.ids.write[i] = default_tex; } @@ -2589,6 +2645,8 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome //Fill push constant + ginstance->base_flags = 0; + bool store_transform = true; if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { @@ -2632,7 +2690,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome ginstance->can_sdfgi = false; if (!lightmap_instance_is_valid(ginstance->lightmap_instance)) { - if (ginstance->gi_probes[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { + if (ginstance->voxel_gi_instances[0].is_null() && (ginstance->data->use_baked_light || ginstance->data->use_dynamic_gi)) { ginstance->can_sdfgi = true; } } @@ -2719,7 +2777,7 @@ void RenderForwardClustered::geometry_instance_set_mesh_instance(GeometryInstanc ginstance->mesh_instance = p_mesh_instance; _geometry_instance_mark_dirty(ginstance); } -void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { +void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->transform = p_transform; @@ -2732,6 +2790,7 @@ void RenderForwardClustered::geometry_instance_set_transform(GeometryInstance *p float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z)); float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z)); + ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9; ginstance->lod_model_scale = max_scale; @@ -2815,7 +2874,7 @@ void RenderForwardClustered::geometry_instance_free(GeometryInstance *p_geometry } uint32_t RenderForwardClustered::geometry_instance_get_pair_mask() { - return (1 << RS::INSTANCE_GI_PROBE); + return (1 << RS::INSTANCE_VOXEL_GI); } void RenderForwardClustered::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { } @@ -2824,30 +2883,31 @@ void RenderForwardClustered::geometry_instance_pair_reflection_probe_instances(G void RenderForwardClustered::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { } -Transform RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) { +Transform3D RenderForwardClustered::geometry_instance_get_transform(GeometryInstance *p_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance); - ERR_FAIL_COND_V(!ginstance, Transform()); + ERR_FAIL_COND_V(!ginstance, Transform3D()); return ginstance->transform; } + AABB RenderForwardClustered::geometry_instance_get_aabb(GeometryInstance *p_instance) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_instance); ERR_FAIL_COND_V(!ginstance, AABB()); return ginstance->data->aabb; } -void RenderForwardClustered::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { +void RenderForwardClustered::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); - if (p_gi_probe_instance_count > 0) { - ginstance->gi_probes[0] = p_gi_probe_instances[0]; + if (p_voxel_gi_instance_count > 0) { + ginstance->voxel_gi_instances[0] = p_voxel_gi_instances[0]; } else { - ginstance->gi_probes[0] = RID(); + ginstance->voxel_gi_instances[0] = RID(); } - if (p_gi_probe_instance_count > 1) { - ginstance->gi_probes[1] = p_gi_probe_instances[1]; + if (p_voxel_gi_instance_count > 1) { + ginstance->voxel_gi_instances[1] = p_voxel_gi_instances[1]; } else { - ginstance->gi_probes[1] = RID(); + ginstance->voxel_gi_instances[1] = RID(); } } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index bed3c3b219..750c0167e7 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -52,9 +52,9 @@ class RenderForwardClustered : public RendererSceneRenderRD { enum { SDFGI_MAX_CASCADES = 8, - MAX_GI_PROBES = 8, + MAX_VOXEL_GI_INSTANCESS = 8, MAX_LIGHTMAPS = 8, - MAX_GI_PROBES_PER_INSTANCE = 2, + MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE = 2, INSTANCE_DATA_BUFFER_MIN_SIZE = 4096 }; @@ -79,7 +79,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID depth; RID specular; RID normal_roughness_buffer; - RID giprobe_buffer; + RID voxelgi_buffer; RS::ViewportMSAA msaa; RD::TextureSamples texture_samples; @@ -89,11 +89,11 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID specular_msaa; RID normal_roughness_buffer_msaa; RID roughness_buffer_msaa; - RID giprobe_buffer_msaa; + RID voxelgi_buffer_msaa; RID depth_fb; RID depth_normal_roughness_fb; - RID depth_normal_roughness_giprobe_fb; + RID depth_normal_roughness_voxelgi_fb; RID color_fb; RID color_specular_fb; RID specular_only_fb; @@ -101,14 +101,14 @@ class RenderForwardClustered : public RendererSceneRenderRD { RID render_sdfgi_uniform_set; void ensure_specular(); - void ensure_giprobe(); + void ensure_voxelgi(); void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count); ~RenderBufferDataForwardClustered(); }; - virtual RenderBufferData *_create_render_buffer_data(); + virtual RenderBufferData *_create_render_buffer_data() override; void _allocate_normal_roughness_texture(RenderBufferDataForwardClustered *rb); RID render_base_uniform_set; @@ -117,8 +117,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - virtual void _base_uniforms_changed(); - virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); + virtual void _base_uniforms_changed() override; + virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override; void _update_render_base_uniform_set(); RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); @@ -132,7 +132,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { PASS_MODE_SHADOW_DP, PASS_MODE_DEPTH, PASS_MODE_DEPTH_NORMAL_ROUGHNESS, - PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, + PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI, PASS_MODE_DEPTH_MATERIAL, PASS_MODE_SDF, }; @@ -184,19 +184,19 @@ class RenderForwardClustered : public RendererSceneRenderRD { }; enum { + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5, INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, + INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11, INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16, INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF, - INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24, }; struct SceneState { @@ -204,7 +204,6 @@ class RenderForwardClustered : public RendererSceneRenderRD { struct UBO { float projection_matrix[16]; float inv_projection_matrix[16]; - float camera_matrix[16]; float inv_camera_matrix[16]; @@ -318,8 +317,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { uint32_t max_lightmap_captures; RID lightmap_capture_buffer; - RID giprobe_ids[MAX_GI_PROBES]; - uint32_t giprobes_used = 0; + RID voxelgi_ids[MAX_VOXEL_GI_INSTANCESS]; + uint32_t voxelgis_used = 0; bool used_screen_texture = false; bool used_normal_texture = false; @@ -350,8 +349,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { static RenderForwardClustered *singleton; void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); - void _setup_giprobes(const PagedArray<RID> &p_giprobes); - void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform); + void _setup_voxelgis(const PagedArray<RID> &p_voxelgis); + void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform); struct RenderElementInfo { uint32_t repeat : 22; @@ -372,7 +371,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { uint32_t render_list_thread_threshold = 500; void _update_instance_data_buffer(RenderListType p_render_list); - void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); + void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false); Map<Size2i, RID> sdfgi_framebuffer_size_cache; @@ -458,8 +457,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { bool can_sdfgi = false; //used during setup uint32_t base_flags = 0; - Transform transform; - RID gi_probes[MAX_GI_PROBES_PER_INSTANCE]; + Transform3D transform; + RID voxel_gi_instances[MAX_VOXEL_GI_INSTANCESS_PER_INSTANCE]; RID lightmap_instance; GeometryInstanceLightmapSH *lightmap_sh = nullptr; GeometryInstanceSurfaceDataCache *surface_caches = nullptr; @@ -552,7 +551,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { } }; - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + void sort_by_reverse_depth_and_priority() { //used for alpha SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter; sorter.sort(elements.ptr(), elements.size()); @@ -566,46 +565,46 @@ class RenderForwardClustered : public RendererSceneRenderRD { RenderList render_list[RENDER_LIST_MAX]; protected: - virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color); + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; - virtual void _render_shadow_begin(); - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); - virtual void _render_shadow_process(); - virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + virtual void _render_shadow_begin() override; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override; + virtual void _render_shadow_process() override; + virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override; - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances); + virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) override; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) override; public: - virtual GeometryInstance *geometry_instance_create(RID p_base); - virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); - virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); - virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials); - virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); - virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); - virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); - virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); - virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); - virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); - virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); - virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); - virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); - virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); - - virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); - virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); - - virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); - - virtual uint32_t geometry_instance_get_pair_mask(); - virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); - virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); - virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); - virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); - - virtual bool free(RID p_rid); + virtual GeometryInstance *geometry_instance_create(RID p_base) override; + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) override; + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override; + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override; + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override; + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override; + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override; + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override; + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override; + + virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) override; + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) override; + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) override; + + virtual uint32_t geometry_instance_get_pair_mask() override; + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override; + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override; + virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override; + + virtual bool free(RID p_rid) override; RenderForwardClustered(RendererStorageRD *p_storage); ~RenderForwardClustered(); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 5a26b5abbb..d39823a1a3 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -311,7 +311,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { //none, leave empty } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { blend_state = blend_state_depth_normal_roughness; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { + } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI) { blend_state = blend_state_depth_normal_roughness_giprobe; } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way @@ -320,8 +320,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { } else { //specular write blend_state = blend_state_opaque_specular; - depth_stencil.enable_depth_test = false; - depth_stencil.enable_depth_write = false; } } @@ -437,94 +435,14 @@ void SceneShaderForwardClustered::MaterialData::set_next_pass(RID p_pass) { next_pass = p_pass; } -void SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool SceneShaderForwardClustered::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardClustered *shader_singleton = (SceneShaderForwardClustered *)SceneShaderForwardClustered::singleton; - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); - } - - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); - - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); - } - - if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { - // This material does not require an uniform set, so don't create it. - return; - } - - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } - - Vector<RD::Uniform> uniforms; - - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } - - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardClustered::MATERIAL_UNIFORM_SET, RD::BARRIER_MASK_RASTER); } SceneShaderForwardClustered::MaterialData::~MaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } + free_parameters_uniform_set(uniform_set); } RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) { @@ -546,11 +464,9 @@ SceneShaderForwardClustered::~SceneShaderForwardClustered() { RD::get_singleton()->free(default_vec4_xform_buffer); RD::get_singleton()->free(shadow_sampler); - storage->free(wireframe_material_shader); storage->free(overdraw_material_shader); storage->free(default_shader); - storage->free(wireframe_material); storage->free(overdraw_material); storage->free(default_material); } @@ -560,17 +476,18 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin { Vector<String> shader_versions; - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_GIPROBE\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); - shader_versions.push_back(""); - shader_versions.push_back("\n#define USE_FORWARD_GI\n"); - shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); - shader_versions.push_back("\n#define USE_LIGHTMAP\n"); - shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_DEPTH_PASS + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n"); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_NORMAL_ROUGHNESS\n#define MODE_RENDER_VOXEL_GI\n"); // SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_SDF\n"); // SHADER_VERSION_DEPTH_PASS_WITH_SDF + shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS + shader_versions.push_back("\n#define USE_FORWARD_GI\n"); // SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n"); // SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR + shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS + shader_versions.push_back("\n#define MODE_MULTIPLE_RENDER_TARGETS\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR + shader.initialize(shader_versions, p_defines); } @@ -632,7 +549,6 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.renames["SSS_STRENGTH"] = "sss_strength"; actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; - actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; actions.renames["BACKLIGHT"] = "backlight"; actions.renames["AO"] = "ao"; @@ -656,6 +572,11 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.renames["CUSTOM2"] = "custom2_attrib"; actions.renames["CUSTOM3"] = "custom3_attrib"; + // not implemented but need these just in case code is in the shaders + actions.renames["VIEW_INDEX"] = "0"; + actions.renames["VIEW_MONO_LEFT"] = "0"; + actions.renames["VIEW_RIGHT"] = "1"; + //for light actions.renames["VIEW"] = "view"; actions.renames["LIGHT_COLOR"] = "light_color"; @@ -721,7 +642,6 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; } - actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; @@ -770,22 +690,23 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); default_shader_sdfgi_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_DEPTH_PASS_WITH_SDF); + + default_material_shader_ptr = md->shader_data; + default_material_uniform_set = md->uniform_set; } { overdraw_material_shader = storage->shader_allocate(); storage->shader_initialize(overdraw_material_shader); - storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished. + storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.1; }"); overdraw_material = storage->material_allocate(); storage->material_initialize(overdraw_material); storage->material_set_shader(overdraw_material, overdraw_material_shader); - wireframe_material_shader = storage->shader_allocate(); - storage->shader_initialize(wireframe_material_shader); - storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); - wireframe_material = storage->material_allocate(); - storage->material_initialize(wireframe_material); - storage->material_set_shader(wireframe_material, wireframe_material_shader); + MaterialData *md = (MaterialData *)storage->material_get_data(overdraw_material, RendererStorageRD::SHADER_TYPE_3D); + overdraw_material_shader_ptr = md->shader_data; + overdraw_material_uniform_set = md->uniform_set; } { diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 7c8879686b..810b1f3876 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -48,7 +48,7 @@ public: SHADER_VERSION_DEPTH_PASS, SHADER_VERSION_DEPTH_PASS_DP, SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, - SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI, SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, SHADER_VERSION_DEPTH_PASS_WITH_SDF, SHADER_VERSION_COLOR_PASS, @@ -56,6 +56,7 @@ public: SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, SHADER_VERSION_LIGHTMAP_COLOR_PASS, SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_MAX }; @@ -165,17 +166,14 @@ public: struct MaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; ShaderData *shader_data; - RID uniform_buffer; RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; uint64_t last_pass = 0; uint32_t index = 0; RID next_pass; uint8_t priority; virtual void set_render_priority(int p_priority); virtual void set_next_pass(RID p_pass); - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); virtual ~MaterialData(); }; @@ -191,8 +189,6 @@ public: RID default_material; RID overdraw_material_shader; RID overdraw_material; - RID wireframe_material_shader; - RID wireframe_material; RID default_shader_rd; RID default_shader_sdfgi_rd; @@ -201,6 +197,12 @@ public: RID shadow_sampler; + RID default_material_uniform_set; + ShaderData *default_material_shader_ptr = nullptr; + + RID overdraw_material_uniform_set; + ShaderData *overdraw_material_shader_ptr = nullptr; + SceneShaderForwardClustered(); ~SceneShaderForwardClustered(); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 4e93fa5333..7fbd6e23b0 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -53,13 +53,14 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::clear() { color_fb = RID(); } -void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) { +void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) { clear(); msaa = p_msaa; width = p_width; height = p_height; + view_count = p_view_count; color = p_color_buffer; depth = p_depth_buffer; @@ -71,13 +72,18 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b fb.push_back(p_color_buffer); fb.push_back(depth); - color_fb = RD::get_singleton()->framebuffer_create(fb); + color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count); } else { RD::TextureFormat tf; + if (view_count > 1) { + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + } else { + tf.texture_type = RD::TEXTURE_TYPE_2D; + } tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = p_width; tf.height = p_height; - tf.texture_type = RD::TEXTURE_TYPE_2D; + tf.array_layers = view_count; // create a layer for every view tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; RD::TextureSamples ts[RS::VIEWPORT_MSAA_MAX] = { @@ -103,7 +109,7 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b fb.push_back(color_msaa); fb.push_back(depth_msaa); - color_fb = RD::get_singleton()->framebuffer_create(fb); + color_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, view_count); } } } @@ -226,11 +232,11 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ RD::Uniform u; u.binding = 7; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.ids.resize(MAX_GI_PROBES); + u.ids.resize(MAX_VOXEL_GI_INSTANCESS); RID default_tex = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); - for (int i = 0; i < MAX_GI_PROBES; i++) { - if (i < (int)p_gi_probes.size()) { - RID tex = gi.gi_probe_instance_get_texture(p_gi_probes[i]); + for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) { + if (i < (int)p_voxel_gi_instances.size()) { + RID tex = gi.voxel_gi_instance_get_texture(p_voxel_gi_instances[i]); if (!tex.is_valid()) { tex = default_tex; } @@ -283,7 +289,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_ return render_pass_uniform_sets[p_index]; } -void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform) { +void RenderForwardMobile::_setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) { // This probably needs to change... scene_state.lightmaps_used = 0; for (int i = 0; i < (int)p_lightmaps.size(); i++) { @@ -329,6 +335,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color bool using_ssr = false; bool using_sss = false; + if (p_render_data->render_info) { + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_render_data->instances->size(); + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_render_data->instances->size(); + } + if (render_buffer) { // setup rendering to render buffer screen_size.x = render_buffer->width; @@ -363,7 +374,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR); render_list[RENDER_LIST_OPAQUE].sort_by_key(); - render_list[RENDER_LIST_ALPHA].sort_by_depth(); + render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority(); // we no longer use this... _fill_instance_data(RENDER_LIST_OPAQUE); @@ -479,7 +490,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color Vector<Color> c; c.push_back(clear_color.to_linear()); - RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); _render_list_with_threads(&render_list_params, opaque_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); } @@ -488,14 +499,16 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (draw_sky || draw_sky_fog_only) { RENDER_TIMESTAMP("Render Sky"); - CameraMatrix projection = p_render_data->cam_projection; + RD::get_singleton()->draw_command_begin_label("Draw Sky"); + if (p_render_data->reflection_probe.is_valid()) { CameraMatrix correction; correction.set_depth_correction(true); - projection = correction * p_render_data->cam_projection; + CameraMatrix projection = correction * p_render_data->cam_projection; + sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, 1, &projection, p_render_data->cam_transform, time); + } else { + sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time); } - RD::get_singleton()->draw_command_begin_label("Draw Sky"); - sky.draw(env, can_continue_color, can_continue_depth, opaque_framebuffer, projection, p_render_data->cam_transform, time); RD::get_singleton()->draw_command_end_label(); } @@ -522,7 +535,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); { - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); } @@ -547,17 +560,23 @@ void RenderForwardMobile::_render_shadow_begin() { render_list[RENDER_LIST_SECONDARY].clear(); } -void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end) { +void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, const Rect2i &p_rect, bool p_flip_y, bool p_clear_region, bool p_begin, bool p_end, RendererScene::RenderInfo *p_render_info) { uint32_t shadow_pass_index = scene_state.shadow_passes.size(); SceneState::ShadowPass shadow_pass; + if (p_render_info) { + p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_instances.size(); + p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_instances.size(); + } RenderDataRD render_data; render_data.cam_projection = p_projection; render_data.cam_transform = p_transform; + render_data.view_projection[0] = p_projection; render_data.z_near = 0.0; render_data.z_far = p_zfar; render_data.instances = &p_instances; + render_data.render_info = p_render_info; render_data.lod_camera_plane = p_camera_plane; render_data.lod_distance_multiplier = p_lod_distance_multiplier; @@ -622,7 +641,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) { for (uint32_t i = 0; i < scene_state.shadow_passes.size(); i++) { SceneState::ShadowPass &shadow_pass = scene_state.shadow_passes[i]; - RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); + RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.camera_plane, shadow_pass.lod_distance_multiplier, shadow_pass.screen_lod_threshold, 1, shadow_pass.element_from, RD::BARRIER_MASK_NO_BARRIER); _render_list_with_threads(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, shadow_pass.final_depth_action, Vector<Color>(), 1.0, 0, shadow_pass.rect); } @@ -634,7 +653,7 @@ void RenderForwardMobile::_render_shadow_end(uint32_t p_barrier) { /* */ -void RenderForwardMobile::_render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { +void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { RENDER_TIMESTAMP("Setup Rendering Material"); RD::get_singleton()->draw_command_begin_label("Render Material"); @@ -647,6 +666,7 @@ void RenderForwardMobile::_render_material(const Transform &p_cam_transform, con RenderDataRD render_data; render_data.cam_projection = p_cam_projection; render_data.cam_transform = p_cam_transform; + render_data.view_projection[0] = p_cam_projection; render_data.instances = &p_instances; _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -746,7 +766,7 @@ void RenderForwardMobile::_render_sdfgi(RID p_render_buffers, const Vector3i &p_ // we don't do GI in low end.. } -void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { +void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) { RENDER_TIMESTAMP("Setup Render Collider Heightfield"); RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield"); @@ -757,6 +777,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const RenderDataRD render_data; render_data.cam_projection = p_cam_projection; render_data.cam_transform = p_cam_transform; + render_data.view_projection[0] = p_cam_projection; render_data.z_near = 0.0; render_data.z_far = p_cam_projection.get_z_far(); render_data.instances = &p_instances; @@ -916,6 +937,12 @@ RID RenderForwardMobile::_render_buffers_get_normal_texture(RID p_render_buffers return RID(); } +_FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primitive, uint32_t p_indices) { + static const uint32_t divisor[RS::PRIMITIVE_MAX] = { 1, 2, 1, 3, 1 }; + static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 }; + return (p_indices - subtractor[p_primitive]) / divisor[p_primitive]; +} + void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append) { if (p_render_list == RENDER_LIST_OPAQUE) { scene_state.used_sss = false; @@ -952,6 +979,10 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const uint32_t flags = inst->base_flags; //fill flags if appropriate + if (inst->non_uniform_scale) { + flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE; + } + bool uses_lightmap = false; // bool uses_gi = false; @@ -1021,21 +1052,42 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const distance = -distance_max; } - surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + uint32_t indices; + surf->lod_index = storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, &indices); + if (p_render_data->render_info) { + indices = _indices_to_primitives(surf->primitive, indices); + if (p_render_list == RENDER_LIST_OPAQUE) { //opaque + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices; + } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices; + } + } } else { surf->lod_index = 0; + if (p_render_data->render_info) { + uint32_t to_draw = storage->mesh_surface_get_vertices_drawn_count(surf->surface); + to_draw = _indices_to_primitives(surf->primitive, to_draw); + to_draw *= inst->instance_count; + if (p_render_list == RENDER_LIST_OPAQUE) { //opaque + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface); + } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow + p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += storage->mesh_surface_get_vertices_drawn_count(surf->surface); + } + } } // ADD Element if (p_pass_mode == PASS_MODE_COLOR) { - if (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { +#ifdef DEBUG_ENABLED + bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW); +#else + bool force_alpha = false; +#endif + if (!force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) { rl->add_element(surf); } - if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA) { + if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) { render_list[RENDER_LIST_ALPHA].add_element(surf); - // if (uses_gi) { - // surf->sort.uses_forward_gi = 1; - // } } if (uses_lightmap) { @@ -1089,6 +1141,12 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, RendererStorageRD::store_transform(p_render_data->cam_transform, scene_state.ubo.camera_matrix); RendererStorageRD::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.inv_camera_matrix); + for (uint32_t v = 0; v < p_render_data->view_count; v++) { + projection = correction * p_render_data->view_projection[v]; + RendererStorageRD::store_camera(projection, scene_state.ubo.projection_matrix_view[v]); + RendererStorageRD::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]); + } + scene_state.ubo.z_far = p_render_data->z_far; scene_state.ubo.z_near = p_render_data->z_near; @@ -1364,7 +1422,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr if (inst->store_transform_cache) { RendererStorageRD::store_transform(inst->transform, push_constant.transform); } else { - RendererStorageRD::store_transform(Transform(), push_constant.transform); + RendererStorageRD::store_transform(Transform3D(), push_constant.transform); } push_constant.flags = inst->flags_cache; @@ -1395,8 +1453,20 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr mesh_surface = surf->surface_shadow; } else { - material_uniform_set = surf->material_uniform_set; - shader = surf->shader; +#ifdef DEBUG_ENABLED + if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) { + material_uniform_set = scene_shader.default_material_uniform_set; + shader = scene_shader.default_material_shader_ptr; + } else if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW)) { + material_uniform_set = scene_shader.overdraw_material_uniform_set; + shader = scene_shader.overdraw_material_shader_ptr; + } else { +#endif + material_uniform_set = surf->material_uniform_set; + shader = surf->shader; +#ifdef DEBUG_ENABLED + } +#endif mesh_surface = surf->surface; } @@ -1426,18 +1496,20 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr case PASS_MODE_COLOR: case PASS_MODE_COLOR_TRANSPARENT: { if (element_info.uses_lightmap) { - shader_version = SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS; + shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_LIGHTMAP_COLOR_PASS; } else { - shader_version = SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS; + shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_COLOR_PASS; } } break; case PASS_MODE_SHADOW: { - shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS; + shader_version = p_params->view_count > 1 ? SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_MULTIVIEW : SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS; } break; case PASS_MODE_SHADOW_DP: { - shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_DP; + ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for shadow DP pass"); + shader_version = SceneShaderForwardMobile::SHADER_VERSION_SHADOW_PASS_DP; } break; case PASS_MODE_DEPTH_MATERIAL: { + ERR_FAIL_COND_MSG(p_params->view_count > 1, "Multiview not supported for material pass"); shader_version = SceneShaderForwardMobile::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; } break; } @@ -1557,7 +1629,7 @@ void RenderForwardMobile::geometry_instance_set_mesh_instance(GeometryInstance * _geometry_instance_mark_dirty(ginstance); } -void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { +void RenderForwardMobile::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) { GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); ginstance->transform = p_transform; @@ -1645,9 +1717,9 @@ void RenderForwardMobile::geometry_instance_set_cast_double_sided_shadows(Geomet _geometry_instance_mark_dirty(ginstance); } -Transform RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) { +Transform3D RenderForwardMobile::geometry_instance_get_transform(GeometryInstance *p_instance) { GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_instance); - ERR_FAIL_COND_V(!ginstance, Transform()); + ERR_FAIL_COND_V(!ginstance, Transform3D()); return ginstance->transform; } @@ -1725,7 +1797,7 @@ void RenderForwardMobile::geometry_instance_pair_decal_instances(GeometryInstanc } } -void RenderForwardMobile::geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) { +void RenderForwardMobile::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) { // We do not have this here! } @@ -1976,6 +2048,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry //Fill push constant bool store_transform = true; + ginstance->base_flags = 0; if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) { ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index bf911319f2..f40f713c03 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -85,14 +85,15 @@ protected: RID color_fb; int width, height; + uint32_t view_count; void clear(); - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa); + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count); ~RenderBufferDataForwardMobile(); }; - virtual RenderBufferData *_create_render_buffer_data(); + virtual RenderBufferData *_create_render_buffer_data() override; /* Rendering */ @@ -104,7 +105,7 @@ protected: PASS_MODE_SHADOW_DP, // PASS_MODE_DEPTH, // PASS_MODE_DEPTH_NORMAL_ROUGHNESS, - // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_GIPROBE, + // PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI, PASS_MODE_DEPTH_MATERIAL, // PASS_MODE_SDF, }; @@ -120,6 +121,7 @@ protected: bool reverse_cull = false; PassMode pass_mode = PASS_MODE_COLOR; // bool no_gi = false; + uint32_t view_count = 1; RID render_pass_uniform_set; bool force_wireframe = false; Vector2 uv_offset; @@ -130,13 +132,14 @@ protected: uint32_t element_offset = 0; uint32_t barrier = RD::BARRIER_MASK_ALL; - RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { + RenderListParameters(GeometryInstanceSurfaceDataCache **p_elements, RenderElementInfo *p_element_info, int p_element_count, bool p_reverse_cull, PassMode p_pass_mode, RID p_render_pass_uniform_set, bool p_force_wireframe = false, const Vector2 &p_uv_offset = Vector2(), const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, uint32_t p_view_count = 1, uint32_t p_element_offset = 0, uint32_t p_barrier = RD::BARRIER_MASK_ALL) { elements = p_elements; element_info = p_element_info; element_count = p_element_count; reverse_cull = p_reverse_cull; pass_mode = p_pass_mode; // no_gi = p_no_gi; + view_count = p_view_count; render_pass_uniform_set = p_render_pass_uniform_set; force_wireframe = p_force_wireframe; uv_offset = p_uv_offset; @@ -149,23 +152,23 @@ protected: }; RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); - virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color); + virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override; - virtual void _render_shadow_begin(); - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true); - virtual void _render_shadow_process(); - virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL); + virtual void _render_shadow_begin() override; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) override; + virtual void _render_shadow_process() override; + virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override; - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); - virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture); - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances); + virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; + virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; + virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) override; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) override; uint64_t lightmap_texture_array_version = 0xFFFFFFFF; - virtual void _base_uniforms_changed(); + virtual void _base_uniforms_changed() override; void _update_render_base_uniform_set(); - virtual RID _render_buffers_get_normal_texture(RID p_render_buffers); + virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override; void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false); void _fill_instance_data(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); @@ -174,7 +177,7 @@ protected: static RenderForwardMobile *singleton; void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0); - void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform &p_cam_transform); + void _setup_lightmaps(const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform); RID render_base_uniform_set; LocalVector<RID> render_pass_uniform_sets; @@ -196,10 +199,12 @@ protected: struct UBO { float projection_matrix[16]; float inv_projection_matrix[16]; - float camera_matrix[16]; float inv_camera_matrix[16]; + float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; + float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16]; + float viewport_size[2]; float screen_pixel_size[2]; @@ -351,7 +356,7 @@ protected: } }; - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha + void sort_by_reverse_depth_and_priority() { //used for alpha SortArray<GeometryInstanceSurfaceDataCache *, SortByReverseDepthAndPriority> sorter; sorter.sort(elements.ptr(), elements.size()); @@ -385,19 +390,19 @@ protected: // check which ones of these apply, probably all except GI and SDFGI enum { + INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5, INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6, INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7, INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8, INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9, INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10, - INSTANCE_DATA_FLAG_USE_GIPROBE = 1 << 11, + INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11, INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12, INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13, INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14, INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16, INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF, - INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 24, }; struct GeometryInstanceLightmapSH { @@ -489,7 +494,7 @@ protected: RID transforms_uniform_set; float depth = 0; bool mirror = false; - Transform transform; + Transform3D transform; bool store_transform_cache = true; // if true we copy our transform into our PushConstant, if false we use our transforms UBO and clear our PushConstants transform bool non_uniform_scale = false; AABB transformed_aabb; //needed for LOD @@ -563,38 +568,38 @@ public: void _geometry_instance_update(GeometryInstance *p_geometry_instance); void _update_dirty_geometry_instances(); - virtual GeometryInstance *geometry_instance_create(RID p_base); - virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton); - virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override); - virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials); - virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance); - virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb); - virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask); - virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias); - virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable); - virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable); - virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index); - virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9); - virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset); - virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable); - - virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance); - virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance); - - virtual void geometry_instance_free(GeometryInstance *p_geometry_instance); - - virtual uint32_t geometry_instance_get_pair_mask(); - virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count); - virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count); - virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count); - virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count); - - virtual bool free(RID p_rid); - - virtual bool is_dynamic_gi_supported() const; - virtual bool is_clustered_enabled() const; - virtual bool is_volumetric_supported() const; - virtual uint32_t get_max_elements() const; + virtual GeometryInstance *geometry_instance_create(RID p_base) override; + virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; + virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; + virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) override; + virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; + virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override; + virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override; + virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override; + virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override; + virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; + virtual void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override; + virtual void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override; + virtual void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override; + + virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) override; + virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) override; + + virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) override; + + virtual uint32_t geometry_instance_get_pair_mask() override; + virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override; + virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; + virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override; + virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override; + + virtual bool free(RID p_rid) override; + + virtual bool is_dynamic_gi_supported() const override; + virtual bool is_clustered_enabled() const override; + virtual bool is_volumetric_supported() const override; + virtual uint32_t get_max_elements() const override; RenderForwardMobile(RendererStorageRD *p_storage); ~RenderForwardMobile(); diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 883273c8a5..7709c8aadc 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/math/math_defs.h" #include "render_forward_mobile.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" using namespace RendererSceneRenderImplementation; @@ -291,12 +292,12 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { multisample_state.enable_alpha_to_one = true; } - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) { blend_state = blend_state_blend; if (depth_draw == DEPTH_DRAW_OPAQUE) { depth_stencil.enable_depth_write = false; //alpha does not draw depth } - } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) { //none, blend state contains nothing } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way @@ -304,57 +305,16 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { pipelines[i][j][k].clear(); continue; // do not use this version (will error if using it is attempted) } - - /* - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_blend; - if (depth_draw == DEPTH_DRAW_OPAQUE) { - depth_stencil.enable_depth_write = false; //alpha does not draw depth - } - } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { - if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, blend state contains nothing - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else { - blend_state = blend_state_opaque; //writes to normal and roughness in opaque way - } - } else { - pipelines[i][j][k].clear(); - continue; // do not use this version (will error if using it is attempted) - } - */ } else { - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { + if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_MULTIVIEW || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW) { blend_state = blend_state_opaque; - } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { + } else if (k == SHADER_VERSION_SHADOW_PASS || k == SHADER_VERSION_SHADOW_PASS_MULTIVIEW || k == SHADER_VERSION_SHADOW_PASS_DP) { //none, leave empty } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way } else { // ??? } - - /* - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_COLOR_PASS_WITH_FORWARD_GI || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_opaque; - } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, leave empty - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { - blend_state = blend_state_depth_normal_roughness; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_GIPROBE) { - blend_state = blend_state_depth_normal_roughness_giprobe; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { - blend_state = RD::PipelineColorBlendState(); //no color targets for SDF - } else { - //specular write - blend_state = blend_state_opaque_specular; - depth_stencil.enable_depth_test = false; - depth_stencil.enable_depth_write = false; - } - */ } RID shader_variant = shader_singleton->shader.version_get_shader(version, k); @@ -469,94 +429,14 @@ void SceneShaderForwardMobile::MaterialData::set_next_pass(RID p_pass) { next_pass = p_pass; } -void SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { SceneShaderForwardMobile *shader_singleton = (SceneShaderForwardMobile *)SceneShaderForwardMobile::singleton; - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), RD::BARRIER_MASK_RASTER); - } - - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); - - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); - } - - if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { - // This material does not require an uniform set, so don't create it. - return; - } - - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } - - Vector<RD::Uniform> uniforms; - - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } - - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, shader_singleton->shader.version_get_shader(shader_data->version, 0), RenderForwardMobile::MATERIAL_UNIFORM_SET, RD::BARRIER_MASK_RASTER); } SceneShaderForwardMobile::MaterialData::~MaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } + free_parameters_uniform_set(uniform_set); } RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) { @@ -585,10 +465,22 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p Vector<String> shader_versions; shader_versions.push_back(""); // SHADER_VERSION_COLOR_PASS shader_versions.push_back("\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // !BAS! SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here... - shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_DEPTH_PASS_DP (maybe rename to SHADER_VERSION_SHADOW_PASS_DP?) + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS, should probably change this to MODE_RENDER_SHADOW because we don't have a depth pass here... + shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_DUAL_PARABOLOID\n"); // SHADER_VERSION_SHADOW_PASS_DP shader_versions.push_back("\n#define MODE_RENDER_DEPTH\n#define MODE_RENDER_MATERIAL\n"); // SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL + + // multiview versions of our shaders + shader_versions.push_back("\n#define USE_MULTIVIEW\n"); // SHADER_VERSION_COLOR_PASS_MULTIVIEW + shader_versions.push_back("\n#define USE_MULTIVIEW\n#define USE_LIGHTMAP\n"); // SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW + shader_versions.push_back("\n#define USE_MULTIVIEW\n#define MODE_RENDER_DEPTH\n"); // SHADER_VERSION_SHADOW_PASS_MULTIVIEW + shader.initialize(shader_versions, p_defines); + + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW, false); + shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false); + shader.set_variant_enabled(SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false); + } } storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_3D, _create_shader_funcs); @@ -603,7 +495,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.renames["INV_CAMERA_MATRIX"] = "scene_data.inv_camera_matrix"; actions.renames["CAMERA_MATRIX"] = "scene_data.camera_matrix"; actions.renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions.renames["INV_PROJECTION_MATRIX"] = "scene_data.inv_projection_matrix"; + actions.renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix"; actions.renames["MODELVIEW_MATRIX"] = "modelview"; actions.renames["MODELVIEW_NORMAL_MATRIX"] = "modelview_normal"; @@ -649,7 +541,6 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.renames["SSS_STRENGTH"] = "sss_strength"; actions.renames["SSS_TRANSMITTANCE_COLOR"] = "transmittance_color"; actions.renames["SSS_TRANSMITTANCE_DEPTH"] = "transmittance_depth"; - actions.renames["SSS_TRANSMITTANCE_CURVE"] = "transmittance_curve"; actions.renames["SSS_TRANSMITTANCE_BOOST"] = "transmittance_boost"; actions.renames["BACKLIGHT"] = "backlight"; actions.renames["AO"] = "ao"; @@ -673,6 +564,10 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.renames["CUSTOM2"] = "custom2_attrib"; actions.renames["CUSTOM3"] = "custom3_attrib"; + actions.renames["VIEW_INDEX"] = "ViewIndex"; + actions.renames["VIEW_MONO_LEFT"] = "0"; + actions.renames["VIEW_RIGHT"] = "1"; + //for light actions.renames["VIEW"] = "view"; actions.renames["LIGHT_COLOR"] = "light_color"; @@ -737,7 +632,6 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; } - actions.render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; @@ -784,22 +678,23 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p MaterialData *md = (MaterialData *)storage->material_get_data(default_material, RendererStorageRD::SHADER_TYPE_3D); default_shader_rd = shader.version_get_shader(md->shader_data->version, SHADER_VERSION_COLOR_PASS); + + default_material_shader_ptr = md->shader_data; + default_material_uniform_set = md->uniform_set; } { overdraw_material_shader = storage->shader_allocate(); storage->shader_initialize(overdraw_material_shader); - storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished. + storage->shader_set_code(overdraw_material_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.1; }"); overdraw_material = storage->material_allocate(); storage->material_initialize(overdraw_material); storage->material_set_shader(overdraw_material, overdraw_material_shader); - wireframe_material_shader = storage->shader_allocate(); - storage->shader_initialize(wireframe_material_shader); - storage->shader_set_code(wireframe_material_shader, "shader_type spatial;\nrender_mode wireframe,unshaded;\n void fragment() { ALBEDO=vec3(0.0,0.0,0.0); }"); - wireframe_material = storage->material_allocate(); - storage->material_initialize(wireframe_material); - storage->material_set_shader(wireframe_material, wireframe_material_shader); + MaterialData *md = (MaterialData *)storage->material_get_data(overdraw_material, RendererStorageRD::SHADER_TYPE_3D); + overdraw_material_shader_ptr = md->shader_data; + overdraw_material_uniform_set = md->uniform_set; } { @@ -827,11 +722,9 @@ SceneShaderForwardMobile::~SceneShaderForwardMobile() { RD::get_singleton()->free(default_vec4_xform_buffer); RD::get_singleton()->free(shadow_sampler); - storage->free(wireframe_material_shader); storage->free(overdraw_material_shader); storage->free(default_shader); - storage->free(wireframe_material); storage->free(overdraw_material); storage->free(default_material); } diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index 1517197d25..5c9e35fd0d 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -47,8 +47,13 @@ public: SHADER_VERSION_COLOR_PASS, SHADER_VERSION_LIGHTMAP_COLOR_PASS, SHADER_VERSION_SHADOW_PASS, - SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_SHADOW_PASS_DP, SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + + SHADER_VERSION_COLOR_PASS_MULTIVIEW, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, + SHADER_VERSION_SHADOW_PASS_MULTIVIEW, + SHADER_VERSION_MAX }; @@ -158,17 +163,14 @@ public: struct MaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; ShaderData *shader_data; - RID uniform_buffer; RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; uint64_t last_pass = 0; uint32_t index = 0; RID next_pass; uint8_t priority; virtual void set_render_priority(int p_priority); virtual void set_next_pass(RID p_pass); - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); virtual ~MaterialData(); }; @@ -184,8 +186,6 @@ public: RID default_material; RID overdraw_material_shader; RID overdraw_material; - RID wireframe_material_shader; - RID wireframe_material; RID default_shader_rd; RID default_vec4_xform_buffer; @@ -193,6 +193,12 @@ public: RID shadow_sampler; + RID default_material_uniform_set; + ShaderData *default_material_shader_ptr = nullptr; + + RID overdraw_material_uniform_set; + ShaderData *overdraw_material_shader_ptr = nullptr; + SceneShaderForwardMobile(); ~SceneShaderForwardMobile(); diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index b2b919c40e..22888ddbe5 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -31,20 +31,21 @@ #include "pipeline_cache_rd.h" #include "core/os/memory.h" -RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe) { +RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass) { RD::PipelineMultisampleState multisample_state_version = multisample_state; - multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id); + multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id, p_render_pass); RD::PipelineRasterizationState raster_state_version = rasterization_state; raster_state_version.wireframe = p_wireframe; - RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags); + RID pipeline = RD::get_singleton()->render_pipeline_create(shader, p_framebuffer_format_id, p_vertex_format_id, render_primitive, raster_state_version, multisample_state_version, depth_stencil_state, blend_state, dynamic_state_flags, p_render_pass); ERR_FAIL_COND_V(pipeline.is_null(), RID()); versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1)); versions[version_count].framebuffer_id = p_framebuffer_format_id; versions[version_count].vertex_id = p_vertex_format_id; versions[version_count].wireframe = p_wireframe; versions[version_count].pipeline = pipeline; + versions[version_count].render_pass = p_render_pass; version_count++; return pipeline; } diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.h b/servers/rendering/renderer_rd/pipeline_cache_rd.h index b1c8f21ecc..387a8a038f 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.h +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.h @@ -50,6 +50,7 @@ class PipelineCacheRD { struct Version { RD::VertexFormatID vertex_id; RD::FramebufferFormatID framebuffer_id; + uint32_t render_pass; bool wireframe; RID pipeline; }; @@ -57,7 +58,7 @@ class PipelineCacheRD { Version *versions; uint32_t version_count; - RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe); + RID _generate_version(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe, uint32_t p_render_pass); void _clear(); @@ -65,7 +66,7 @@ public: void setup(RID p_shader, RD::RenderPrimitive p_primitive, const RD::PipelineRasterizationState &p_rasterization_state, RD::PipelineMultisampleState p_multisample, const RD::PipelineDepthStencilState &p_depth_stencil_state, const RD::PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0); void update_shader(RID p_shader); - _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false) { + _FORCE_INLINE_ RID get_render_pipeline(RD::VertexFormatID p_vertex_format_id, RD::FramebufferFormatID p_framebuffer_format_id, bool p_wireframe = false, uint32_t p_render_pass = 0) { #ifdef DEBUG_ENABLED ERR_FAIL_COND_V_MSG(shader.is_null(), RID(), "Attempted to use an unused shader variant (shader is null),"); @@ -74,13 +75,13 @@ public: spin_lock.lock(); RID result; for (uint32_t i = 0; i < version_count; i++) { - if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe) { + if (versions[i].vertex_id == p_vertex_format_id && versions[i].framebuffer_id == p_framebuffer_format_id && versions[i].wireframe == p_wireframe && versions[i].render_pass == p_render_pass) { result = versions[i].pipeline; spin_lock.unlock(); return result; } } - result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe); + result = _generate_version(p_vertex_format_id, p_framebuffer_format_id, p_wireframe, p_render_pass); spin_lock.unlock(); return result; } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 70c1705bff..1e3dbe69a3 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -76,7 +76,7 @@ void RendererCanvasRenderRD::_update_transform_2d_to_mat2x3(const Transform2D &p p_mat2x3[5] = p_transform.elements[2][1]; } -void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) { +void RendererCanvasRenderRD::_update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4) { p_mat4[0] = p_transform.basis.elements[0][0]; p_mat4[1] = p_transform.basis.elements[1][0]; p_mat4[2] = p_transform.basis.elements[2][0]; @@ -408,6 +408,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend PushConstant push_constant; Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; + Transform2D draw_transform; _update_transform_2d_to_mat2x3(base_transform, push_constant.world); Color base_color = p_item->final_modulate; @@ -464,8 +465,15 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend RID last_texture; Size2 texpixel_size; + bool skipping = false; + const Item::Command *c = p_item->commands; while (c) { + if (skipping && c->type != Item::Command::TYPE_ANIMATION_SLICE) { + c = c->next; + continue; + } + push_constant.flags = base_flags | (push_constant.flags & (FLAGS_DEFAULT_NORMAL_MAP_USED | FLAGS_DEFAULT_SPECULAR_MAP_USED)); //reset on each command for sanity, keep canvastexture binding config switch (c->type) { @@ -724,7 +732,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend mesh_instance = m->mesh_instance; texture = m->texture; modulate = m->modulate; - _update_transform_2d_to_mat2x3(base_transform * m->transform, push_constant.world); + _update_transform_2d_to_mat2x3(base_transform * draw_transform * m->transform, push_constant.world); } else if (c->type == Item::Command::TYPE_MULTIMESH) { const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c); RID multimesh = mm->multimesh; @@ -857,10 +865,10 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend for (int j = 0; j < 6; j++) { push_constant.world[j] = world_backup[j]; } - } break; case Item::Command::TYPE_TRANSFORM: { const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c); + draw_transform = transform->xform; _update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world); } break; @@ -879,6 +887,14 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend } } break; + case Item::Command::TYPE_ANIMATION_SLICE: { + const Item::CommandAnimationSlice *as = static_cast<const Item::CommandAnimationSlice *>(c); + double current_time = RendererCompositorRD::singleton->get_total_time(); + double local_time = Math::fposmod(current_time - as->offset, as->animation_length); + skipping = !(local_time >= as->slice_begin && local_time < as->slice_end); + + RenderingServerDefault::redraw_request(); // animation visible means redraw request + } break; } c = c->next; @@ -1250,7 +1266,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p Size2i ssize = storage->render_target_get_size(p_to_render_target); - Transform screen_transform; + Transform3D screen_transform; screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f)); _update_transform_to_mat4(screen_transform, state_buffer.screen_transform); @@ -1539,7 +1555,7 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, } Vector3 cam_target = Basis(Vector3(0, 0, Math_TAU * ((i + 3) / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); + projection = projection * CameraMatrix(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); ShadowRenderPushConstant push_constant; for (int y = 0; y < 4; y++) { @@ -1617,7 +1633,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh CameraMatrix projection; projection.set_orthogonal(-half_size, half_size, -0.5, 0.5, 0.0, distance); - projection = projection * CameraMatrix(Transform().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse()); + projection = projection * CameraMatrix(Transform3D().looking_at(Vector3(0, 1, 0), Vector3(0, 0, -1)).affine_inverse()); ShadowRenderPushConstant push_constant; for (int y = 0; y < 4; y++) { @@ -2185,94 +2201,14 @@ RendererStorageRD::ShaderData *RendererCanvasRenderRD::_create_shader_func() { return shader_data; } -void RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { RendererCanvasRenderRD *canvas_singleton = (RendererCanvasRenderRD *)RendererCanvasRender::singleton; - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); - } - - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); - - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), false); - } - - if (shader_data->ubo_size == 0) { - // This material does not require an uniform set, so don't create it. - return; - } - - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } - - Vector<RD::Uniform> uniforms; - - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } - - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, canvas_singleton->shader.canvas_shader.version_get_shader(shader_data->version, 0), MATERIAL_UNIFORM_SET); } RendererCanvasRenderRD::MaterialData::~MaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } + free_parameters_uniform_set(uniform_set); } RendererStorageRD::MaterialData *RendererCanvasRenderRD::_create_material_func(ShaderData *p_shader) { diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 890a4e3649..7c4f62832c 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -201,14 +201,11 @@ class RendererCanvasRenderRD : public RendererCanvasRender { struct MaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; ShaderData *shader_data; - RID uniform_buffer; RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); virtual ~MaterialData(); }; @@ -433,7 +430,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { _FORCE_INLINE_ void _update_transform_2d_to_mat2x3(const Transform2D &p_transform, float *p_mat2x3); _FORCE_INLINE_ void _update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4); - _FORCE_INLINE_ void _update_transform_to_mat4(const Transform &p_transform, float *p_mat4); + _FORCE_INLINE_ void _update_transform_to_mat4(const Transform3D &p_transform, float *p_mat4); void _update_shadow_atlas(); @@ -457,8 +454,6 @@ public: void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) {} - void draw_window_margins(int *p_margins, RID *p_margin_textures) {} - virtual void set_shadow_texture_size(int p_size); void set_time(double p_time); diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 1337d36762..a8f086b0f9 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -31,7 +31,7 @@ #include "renderer_compositor_rd.h" #include "core/config/project_settings.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" void RendererCompositorRD::prepare_for_blitting_render_targets() { RD::get_singleton()->prepare_screen_for_drawing(); @@ -60,8 +60,7 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID } Size2 screen_size(RD::get_singleton()->screen_get_width(p_screen), RD::get_singleton()->screen_get_height(p_screen)); - BlitMode mode = p_render_targets[i].lens_distortion.apply ? BLIT_MODE_LENS : p_render_targets[i].multi_view.use_layer ? BLIT_MODE_USE_LAYER : - BLIT_MODE_NORMAL; + BlitMode mode = p_render_targets[i].lens_distortion.apply ? BLIT_MODE_LENS : (p_render_targets[i].multi_view.use_layer ? BLIT_MODE_USE_LAYER : BLIT_MODE_NORMAL); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[mode]); RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0); @@ -111,13 +110,14 @@ void RendererCompositorRD::initialize() { blit_modes.push_back("\n"); blit_modes.push_back("\n#define USE_LAYER\n"); blit_modes.push_back("\n#define USE_LAYER\n#define APPLY_LENS_DISTORTION\n"); + blit_modes.push_back("\n"); blit.shader.initialize(blit_modes); blit.shader_version = blit.shader.version_create(); for (int i = 0; i < BLIT_MODE_MAX; i++) { - blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RenderingDevice::PipelineColorBlendState::create_disabled(), 0); + blit.pipelines[i] = RD::get_singleton()->render_pipeline_create(blit.shader.version_get_shader(blit.shader_version, i), RD::get_singleton()->screen_get_framebuffer_format(), RD::INVALID_ID, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), i == BLIT_MODE_NORMAL_ALPHA ? RenderingDevice::PipelineColorBlendState::create_blend() : RenderingDevice::PipelineColorBlendState::create_disabled(), 0); } //create index array for copy shader @@ -153,6 +153,81 @@ void RendererCompositorRD::finalize() { RD::get_singleton()->free(blit.sampler); } +void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { + RD::get_singleton()->prepare_screen_for_drawing(); + + RID texture = storage->texture_allocate(); + storage->texture_2d_initialize(texture, p_image); + RID rd_texture = storage->texture_get_rd_texture(texture); + + RID uset; + { + Vector<RD::Uniform> uniforms; + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE; + u.binding = 0; + u.ids.push_back(blit.sampler); + u.ids.push_back(rd_texture); + uniforms.push_back(u); + uset = RD::get_singleton()->uniform_set_create(uniforms, blit.shader.version_get_shader(blit.shader_version, BLIT_MODE_NORMAL), 0); + } + + Size2 window_size = DisplayServer::get_singleton()->window_get_size(); + print_line("window size: " + window_size); + + Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); + Rect2 screenrect; + if (p_scale) { + if (window_size.width > window_size.height) { + //scale horizontally + screenrect.size.y = window_size.height; + screenrect.size.x = imgrect.size.x * window_size.height / imgrect.size.y; + screenrect.position.x = (window_size.width - screenrect.size.x) / 2; + + } else { + //scale vertically + screenrect.size.x = window_size.width; + screenrect.size.y = imgrect.size.y * window_size.width / imgrect.size.x; + screenrect.position.y = (window_size.height - screenrect.size.y) / 2; + } + } else { + screenrect = imgrect; + screenrect.position += ((Size2(window_size.width, window_size.height) - screenrect.size) / 2.0).floor(); + } + + screenrect.position /= window_size; + screenrect.size /= window_size; + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin_for_screen(DisplayServer::MAIN_WINDOW_ID, p_color); + + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, blit.pipelines[BLIT_MODE_NORMAL_ALPHA]); + RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0); + + blit.push_constant.rect[0] = screenrect.position.x; + blit.push_constant.rect[1] = screenrect.position.y; + blit.push_constant.rect[2] = screenrect.size.width; + blit.push_constant.rect[3] = screenrect.size.height; + blit.push_constant.layer = 0; + blit.push_constant.eye_center[0] = 0; + blit.push_constant.eye_center[1] = 0; + blit.push_constant.k1 = 0; + blit.push_constant.k2 = 0; + blit.push_constant.upscale = 1.0; + blit.push_constant.aspect_ratio = 1.0; + + print_line("rect: " + screenrect); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &blit.push_constant, sizeof(BlitPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + + RD::get_singleton()->draw_list_end(); + + RD::get_singleton()->swap_buffers(); + + RD::get_singleton()->free(texture); +} + RendererCompositorRD *RendererCompositorRD::singleton = nullptr; RendererCompositorRD::RendererCompositorRD() { diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 7a78322051..15b3b77ed9 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -50,6 +50,7 @@ protected: BLIT_MODE_NORMAL, BLIT_MODE_USE_LAYER, BLIT_MODE_LENS, + BLIT_MODE_NORMAL_ALPHA, BLIT_MODE_MAX }; @@ -88,7 +89,7 @@ public: RendererCanvasRender *get_canvas() { return canvas; } RendererSceneRender *get_scene() { return scene; } - void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) {} + void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter); void initialize(); void begin_frame(double frame_step); diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index b289b17fad..98d08f68e8 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -1099,7 +1099,7 @@ void RendererSceneGIRD::SDFGI::update_cascades() { RD::get_singleton()->buffer_update(cascades_ubo, 0, sizeof(SDFGI::Cascade::UBO) * SDFGI::MAX_CASCADES, cascade_data, RD::BARRIER_MASK_COMPUTE); } -void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) { +void RendererSceneGIRD::SDFGI::debug_draw(const CameraMatrix &p_projection, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture) { if (!debug_uniform_set.is_valid() || !RD::get_singleton()->uniform_set_is_valid(debug_uniform_set)) { Vector<RD::Uniform> uniforms; { @@ -1367,7 +1367,7 @@ void RendererSceneGIRD::SDFGI::debug_probes(RD::DrawListID p_draw_list, RID p_fr } } -void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) { +void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) { /* Update general SDFGI Buffer */ SDFGIData sdfgi_data; @@ -1862,7 +1862,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, #if 0 Vector<uint8_t> data = RD::get_singleton()->texture_get_data(cascades[cascade].sdf, 0); Ref<Image> img; - img.instance(); + img.instantiate(); for (uint32_t i = 0; i < cascade_size; i++) { Vector<uint8_t> subarr = data.subarray(128 * 128 * i, 128 * 128 * (i + 1) - 1); img->create(cascade_size, cascade_size, false, Image::FORMAT_L8, subarr); @@ -1875,7 +1875,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, #if 0 Vector<uint8_t> data = RD::get_singleton()->texture_get_data(render_albedo, 0); Ref<Image> img; - img.instance(); + img.instantiate(); for (uint32_t i = 0; i < cascade_size; i++) { Vector<uint8_t> subarr = data.subarray(128 * 128 * i * 2, 128 * 128 * (i + 1) * 2 - 1); img->createcascade_size, cascade_size, false, Image::FORMAT_RGB565, subarr); @@ -2012,10 +2012,10 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32 } //////////////////////////////////////////////////////////////////////////////// -// GIProbeInstance +// VoxelGIInstance -void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { - uint32_t data_version = storage->gi_probe_get_data_version(probe); +void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { + uint32_t data_version = storage->voxel_gi_get_data_version(probe); // (RE)CREATE IF NEEDED @@ -2034,11 +2034,11 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c dynamic_maps.clear(); - Vector3i octree_size = storage->gi_probe_get_octree_size(probe); + Vector3i octree_size = storage->voxel_gi_get_octree_size(probe); if (octree_size != Vector3i()) { //can create a 3D texture - Vector<int> levels = storage->gi_probe_get_level_counts(probe); + Vector<int> levels = storage->voxel_gi_get_level_counts(probe); RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; @@ -2064,7 +2064,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c } for (int i = 0; i < levels.size(); i++) { - GIProbeInstance::Mipmap mipmap; + VoxelGIInstance::Mipmap mipmap; mipmap.texture = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), texture, 0, i, RD::TEXTURE_SLICE_3D); mipmap.level = levels.size() - i - 1; mipmap.cell_offset = 0; @@ -2078,14 +2078,14 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; - u.ids.push_back(storage->gi_probe_get_octree_buffer(probe)); + u.ids.push_back(storage->voxel_gi_get_octree_buffer(probe)); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; - u.ids.push_back(storage->gi_probe_get_data_buffer(probe)); + u.ids.push_back(storage->voxel_gi_get_data_buffer(probe)); uniforms.push_back(u); } @@ -2100,7 +2100,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; - u.ids.push_back(storage->gi_probe_get_sdf_texture(probe)); + u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe)); uniforms.push_back(u); } { @@ -2118,11 +2118,11 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; - u.ids.push_back(gi->gi_probe_lights_uniform); + u.ids.push_back(gi->voxel_gi_lights_uniform); copy_uniforms.push_back(u); } - mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT], 0); + mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT], 0); copy_uniforms = uniforms; //restore @@ -2133,9 +2133,9 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c u.ids.push_back(texture); copy_uniforms.push_back(u); } - mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0); + mipmap.second_bounce_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE], 0); } else { - mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP], 0); + mipmap.uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP], 0); } } @@ -2147,7 +2147,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c uniforms.push_back(u); } - mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE], 0); + mipmap.write_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE], 0); mipmaps.push_back(mipmap); } @@ -2158,7 +2158,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c int mipmap_index = 0; while (mipmap_index < mipmaps.size()) { - GIProbeInstance::DynamicMap dmap; + VoxelGIInstance::DynamicMap dmap; if (oversample > 0) { dmap.size = dynamic_map_size * (1 << oversample); @@ -2217,7 +2217,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 3; - u.ids.push_back(gi->gi_probe_lights_uniform); + u.ids.push_back(gi->voxel_gi_lights_uniform); uniforms.push_back(u); } @@ -2253,7 +2253,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; - u.ids.push_back(storage->gi_probe_get_sdf_texture(probe)); + u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe)); uniforms.push_back(u); } { @@ -2278,7 +2278,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c uniforms.push_back(u); } - dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0); + dmap.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING], 0); } } else { bool plot = dmap.mipmap >= 0; @@ -2322,7 +2322,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 9; - u.ids.push_back(storage->gi_probe_get_sdf_texture(probe)); + u.ids.push_back(storage->voxel_gi_get_sdf_texture(probe)); uniforms.push_back(u); } { @@ -2345,7 +2345,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c dmap.uniform_set = RD::get_singleton()->uniform_set_create( uniforms, - gi->giprobe_lighting_shader_version_shaders[(write && plot) ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)], + gi->voxel_gi_lighting_shader_version_shaders[(write && plot) ? VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT : (write ? VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE : VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT)], 0); } @@ -2370,15 +2370,15 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c uint32_t light_count = 0; if (p_update_light_instances || p_dynamic_objects.size() > 0) { - light_count = MIN(gi->gi_probe_max_lights, (uint32_t)p_light_instances.size()); + light_count = MIN(gi->voxel_gi_max_lights, (uint32_t)p_light_instances.size()); { - Transform to_cell = storage->gi_probe_get_to_cell_xform(probe); - Transform to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse(); + Transform3D to_cell = storage->voxel_gi_get_to_cell_xform(probe); + Transform3D to_probe_xform = (transform * to_cell.affine_inverse()).affine_inverse(); //update lights for (uint32_t i = 0; i < light_count; i++) { - GIProbeLight &l = gi->gi_probe_lights[i]; + VoxelGILight &l = gi->voxel_gi_lights[i]; RID light_instance = p_light_instances[i]; RID light = p_scene_render->light_instance_get_base_light(light_instance); @@ -2399,7 +2399,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE))); l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION); - Transform xform = p_scene_render->light_instance_get_base_transform(light_instance); + Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance); Vector3 pos = to_probe_xform.xform(xform.origin); Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_axis(2)).normalized(); @@ -2415,7 +2415,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c l.has_shadow = storage->light_has_shadow(light); } - RD::get_singleton()->buffer_update(gi->gi_probe_lights_uniform, 0, sizeof(GIProbeLight) * light_count, gi->gi_probe_lights); + RD::get_singleton()->buffer_update(gi->voxel_gi_lights_uniform, 0, sizeof(VoxelGILight) * light_count, gi->voxel_gi_lights); } } @@ -2424,17 +2424,17 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c if (mipmaps.size()) { //can update mipmaps - Vector3i probe_size = storage->gi_probe_get_octree_size(probe); + Vector3i probe_size = storage->voxel_gi_get_octree_size(probe); - GIProbePushConstant push_constant; + VoxelGIPushConstant push_constant; push_constant.limits[0] = probe_size.x; push_constant.limits[1] = probe_size.y; push_constant.limits[2] = probe_size.z; push_constant.stack_size = mipmaps.size(); push_constant.emission_scale = 1.0; - push_constant.propagation = storage->gi_probe_get_propagation(probe); - push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe); + push_constant.propagation = storage->voxel_gi_get_propagation(probe); + push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe); push_constant.light_count = light_count; push_constant.aniso_strength = 0; @@ -2446,7 +2446,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c int passes; if (p_update_light_instances) { - passes = storage->gi_probe_is_using_two_bounces(probe) ? 2 : 1; + passes = storage->voxel_gi_is_using_two_bounces(probe) ? 2 : 1; } else { passes = 1; //only re-blitting is necessary } @@ -2457,9 +2457,9 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c if (p_update_light_instances) { for (int i = 0; i < mipmaps.size(); i++) { if (i == 0) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[pass == 0 ? GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT : GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[pass == 0 ? VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT : VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE]); } else if (i == 1) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP]); } if (pass == 1 || i > 0) { @@ -2477,7 +2477,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1; while (wg_todo) { int wg_count = MIN(wg_todo, wg_limit_x); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant)); RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); wg_todo -= wg_count; push_constant.cell_offset += wg_count * wg_size; @@ -2487,7 +2487,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::get_singleton()->compute_list_add_barrier(compute_list); //wait til previous step is done } - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_WRITE_TEXTURE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE]); for (int i = 0; i < mipmaps.size(); i++) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mipmaps[i].write_uniform_set, 0); @@ -2498,7 +2498,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c int wg_todo = (mipmaps[i].cell_count - 1) / wg_size + 1; while (wg_todo) { int wg_count = MIN(wg_todo, wg_limit_x); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbePushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIPushConstant)); RD::get_singleton()->compute_list_dispatch(compute_list, wg_count, 1, 1); wg_todo -= wg_count; push_constant.cell_offset += wg_count * wg_size; @@ -2513,15 +2513,15 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c has_dynamic_object_data = false; //clear until dynamic object data is used again if (p_dynamic_objects.size() && dynamic_maps.size()) { - Vector3i octree_size = storage->gi_probe_get_octree_size(probe); + Vector3i octree_size = storage->voxel_gi_get_octree_size(probe); int multiplier = dynamic_maps[0].size / MAX(MAX(octree_size.x, octree_size.y), octree_size.z); - Transform oversample_scale; + Transform3D oversample_scale; oversample_scale.basis.scale(Vector3(multiplier, multiplier, multiplier)); - Transform to_cell = oversample_scale * storage->gi_probe_get_to_cell_xform(probe); - Transform to_world_xform = transform * to_cell.affine_inverse(); - Transform to_probe_xform = to_world_xform.affine_inverse(); + Transform3D to_cell = oversample_scale * storage->voxel_gi_get_to_cell_xform(probe); + Transform3D to_world_xform = transform * to_cell.affine_inverse(); + Transform3D to_probe_xform = to_world_xform.affine_inverse(); AABB probe_aabb(Vector3(), octree_size); @@ -2529,7 +2529,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c for (int i = 0; i < (int)p_dynamic_objects.size(); i++) { RendererSceneRender::GeometryInstance *instance = p_dynamic_objects[i]; - //transform aabb to giprobe + //transform aabb to voxel_gi AABB aabb = (to_probe_xform * p_scene_render->geometry_instance_get_transform(instance)).xform(p_scene_render->geometry_instance_get_aabb(instance)); //this needs to wrap to grid resolution to avoid jitter @@ -2576,7 +2576,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c Vector3 up_dir = render_up[j]; Vector3 center = aabb.position + aabb.size * 0.5; - Transform xform; + Transform3D xform; xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir); Vector3 x_dir = xform.basis.get_axis(0).abs(); @@ -2601,8 +2601,8 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size)); - GIProbeDynamicPushConstant push_constant; - memset(&push_constant, 0, sizeof(GIProbeDynamicPushConstant)); + VoxelGIDynamicPushConstant push_constant; + memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant)); push_constant.limits[0] = octree_size.x; push_constant.limits[1] = octree_size.y; push_constant.limits[2] = octree_size.z; @@ -2619,7 +2619,7 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c push_constant.z_base = xform.origin[z_axis]; push_constant.z_sign = (z_flip ? -1.0 : 1.0); push_constant.pos_multiplier = float(1.0) / multiplier; - push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe); + push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe); push_constant.flip_x = x_flip; push_constant.flip_y = y_flip; push_constant.rect_pos[0] = rect.position[0]; @@ -2631,16 +2631,16 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c push_constant.prev_rect_size[0] = 0; push_constant.prev_rect_size[1] = 0; push_constant.on_mipmap = false; - push_constant.propagation = storage->gi_probe_get_propagation(probe); + push_constant.propagation = storage->voxel_gi_get_propagation(probe); push_constant.pad[0] = 0; push_constant.pad[1] = 0; push_constant.pad[2] = 0; //process lighting RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[0].uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant)); RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); //print_line("rect: " + itos(i) + ": " + rect); @@ -2695,14 +2695,14 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c RD::get_singleton()->compute_list_add_barrier(compute_list); if (dynamic_maps[k].mipmap < 0) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE]); } else if (k < dynamic_maps.size() - 1) { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT]); } else { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, gi->voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT]); } RD::get_singleton()->compute_list_bind_uniform_set(compute_list, dynamic_maps[k].uniform_set, 0); - RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(GIProbeDynamicPushConstant)); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(VoxelGIDynamicPushConstant)); RD::get_singleton()->compute_list_dispatch(compute_list, (rect.size.x - 1) / 8 + 1, (rect.size.y - 1) / 8 + 1, 1); } @@ -2713,22 +2713,22 @@ void RendererSceneGIRD::GIProbeInstance::update(bool p_update_light_instances, c has_dynamic_object_data = true; //clear until dynamic object data is used again } - last_probe_version = storage->gi_probe_get_version(probe); + last_probe_version = storage->voxel_gi_get_version(probe); } -void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { +void RendererSceneGIRD::VoxelGIInstance::debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { if (mipmaps.size() == 0) { return; } - CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->gi_probe_get_to_cell_xform(probe).affine_inverse()); + CameraMatrix cam_transform = (p_camera_with_transform * CameraMatrix(transform)) * CameraMatrix(storage->voxel_gi_get_to_cell_xform(probe).affine_inverse()); int level = 0; - Vector3i octree_size = storage->gi_probe_get_octree_size(probe); + Vector3i octree_size = storage->voxel_gi_get_octree_size(probe); - GIProbeDebugPushConstant push_constant; + VoxelGIDebugPushConstant push_constant; push_constant.alpha = p_alpha; - push_constant.dynamic_range = storage->gi_probe_get_dynamic_range(probe); + push_constant.dynamic_range = storage->voxel_gi_get_dynamic_range(probe); push_constant.cell_offset = mipmaps[level].cell_offset; push_constant.level = level; @@ -2743,15 +2743,15 @@ void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p } } - if (gi->giprobe_debug_uniform_set.is_valid()) { - RD::get_singleton()->free(gi->giprobe_debug_uniform_set); + if (gi->voxel_gi_debug_uniform_set.is_valid()) { + RD::get_singleton()->free(gi->voxel_gi_debug_uniform_set); } Vector<RD::Uniform> uniforms; { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; - u.ids.push_back(storage->gi_probe_get_data_buffer(probe)); + u.ids.push_back(storage->voxel_gi_get_data_buffer(probe)); uniforms.push_back(u); } { @@ -2776,19 +2776,19 @@ void RendererSceneGIRD::GIProbeInstance::debug(RD::DrawListID p_draw_list, RID p cell_count = mipmaps[level].cell_count; } - gi->giprobe_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->giprobe_debug_shader_version_shaders[0], 0); + gi->voxel_gi_debug_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, gi->voxel_gi_debug_shader_version_shaders[0], 0); - int giprobe_debug_pipeline = GI_PROBE_DEBUG_COLOR; + int voxel_gi_debug_pipeline = VOXEL_GI_DEBUG_COLOR; if (p_emission) { - giprobe_debug_pipeline = GI_PROBE_DEBUG_EMISSION; + voxel_gi_debug_pipeline = VOXEL_GI_DEBUG_EMISSION; } else if (p_lighting) { - giprobe_debug_pipeline = has_dynamic_object_data ? GI_PROBE_DEBUG_LIGHT_FULL : GI_PROBE_DEBUG_LIGHT; + voxel_gi_debug_pipeline = has_dynamic_object_data ? VOXEL_GI_DEBUG_LIGHT_FULL : VOXEL_GI_DEBUG_LIGHT; } RD::get_singleton()->draw_list_bind_render_pipeline( p_draw_list, - gi->giprobe_debug_shader_version_pipelines[giprobe_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->giprobe_debug_uniform_set, 0); - RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(GIProbeDebugPushConstant)); + gi->voxel_gi_debug_shader_version_pipelines[voxel_gi_debug_pipeline].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, gi->voxel_gi_debug_uniform_set, 0); + RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(VoxelGIDebugPushConstant)); RD::get_singleton()->draw_list_draw(p_draw_list, false, cell_count, 36); } @@ -2812,13 +2812,13 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p { //kinda complicated to compute the amount of slots, we try to use as many as we can - gi_probe_max_lights = 32; + voxel_gi_max_lights = 32; - gi_probe_lights = memnew_arr(GIProbeLight, gi_probe_max_lights); - gi_probe_lights_uniform = RD::get_singleton()->uniform_buffer_create(gi_probe_max_lights * sizeof(GIProbeLight)); - gi_probe_quality = RS::GIProbeQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/gi_probes/quality")), 0, 1)); + voxel_gi_lights = memnew_arr(VoxelGILight, voxel_gi_max_lights); + voxel_gi_lights_uniform = RD::get_singleton()->uniform_buffer_create(voxel_gi_max_lights * sizeof(VoxelGILight)); + voxel_gi_quality = RS::VoxelGIQuality(CLAMP(int(GLOBAL_GET("rendering/global_illumination/voxel_gi/quality")), 0, 1)); - String defines = "\n#define MAX_LIGHTS " + itos(gi_probe_max_lights) + "\n"; + String defines = "\n#define MAX_LIGHTS " + itos(voxel_gi_max_lights) + "\n"; Vector<String> versions; versions.push_back("\n#define MODE_COMPUTE_LIGHT\n"); @@ -2830,11 +2830,11 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n"); versions.push_back("\n#define MODE_DYNAMIC\n#define MODE_DYNAMIC_SHRINK\n#define MODE_DYNAMIC_SHRINK_PLOT\n#define MODE_DYNAMIC_SHRINK_WRITE\n"); - giprobe_shader.initialize(versions, defines); - giprobe_lighting_shader_version = giprobe_shader.version_create(); - for (int i = 0; i < GI_PROBE_SHADER_VERSION_MAX; i++) { - giprobe_lighting_shader_version_shaders[i] = giprobe_shader.version_get_shader(giprobe_lighting_shader_version, i); - giprobe_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(giprobe_lighting_shader_version_shaders[i]); + voxel_gi_shader.initialize(versions, defines); + voxel_gi_lighting_shader_version = voxel_gi_shader.version_create(); + for (int i = 0; i < VOXEL_GI_SHADER_VERSION_MAX; i++) { + voxel_gi_lighting_shader_version_shaders[i] = voxel_gi_shader.version_get_shader(voxel_gi_lighting_shader_version, i); + voxel_gi_lighting_shader_version_pipelines[i] = RD::get_singleton()->compute_pipeline_create(voxel_gi_lighting_shader_version_shaders[i]); } } @@ -2846,10 +2846,10 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p versions.push_back("\n#define MODE_DEBUG_EMISSION\n"); versions.push_back("\n#define MODE_DEBUG_LIGHT\n#define MODE_DEBUG_LIGHT_FULL\n"); - giprobe_debug_shader.initialize(versions, defines); - giprobe_debug_shader_version = giprobe_debug_shader.version_create(); - for (int i = 0; i < GI_PROBE_DEBUG_MAX; i++) { - giprobe_debug_shader_version_shaders[i] = giprobe_debug_shader.version_get_shader(giprobe_debug_shader_version, i); + voxel_gi_debug_shader.initialize(versions, defines); + voxel_gi_debug_shader_version = voxel_gi_debug_shader.version_create(); + for (int i = 0; i < VOXEL_GI_DEBUG_MAX; i++) { + voxel_gi_debug_shader_version_shaders[i] = voxel_gi_debug_shader.version_get_shader(voxel_gi_debug_shader_version, i); RD::PipelineRasterizationState rs; rs.cull_mode = RD::POLYGON_CULL_FRONT; @@ -2858,7 +2858,7 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p ds.enable_depth_write = true; ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - giprobe_debug_shader_version_pipelines[i].setup(giprobe_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); + voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); } } @@ -2944,12 +2944,12 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p //calculate tables String defines = "\n#define SDFGI_OCT_SIZE " + itos(SDFGI::LIGHTPROBE_OCT_SIZE) + "\n"; Vector<String> gi_modes; - gi_modes.push_back("\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define USE_VOXEL_GI_INSTANCES\n"); gi_modes.push_back("\n#define USE_SDFGI\n"); - gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_VOXEL_GI_INSTANCES\n"); gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n"); - gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_GIPROBES\n"); + gi_modes.push_back("\n#define MODE_HALF_RES\n#define USE_SDFGI\n\n#define USE_VOXEL_GI_INSTANCES\n"); shader.initialize(gi_modes, defines); shader_version = shader.version_create(); @@ -2991,17 +2991,17 @@ void RendererSceneGIRD::init(RendererStorageRD *p_storage, RendererSceneSkyRD *p } } } - default_giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(GIProbeData) * MAX_GIPROBES); + default_voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(VoxelGIData) * MAX_VOXEL_GI_INSTANCES); half_resolution = GLOBAL_GET("rendering/global_illumination/gi/use_half_resolution"); } void RendererSceneGIRD::free() { - RD::get_singleton()->free(default_giprobe_buffer); - RD::get_singleton()->free(gi_probe_lights_uniform); + RD::get_singleton()->free(default_voxel_gi_buffer); + RD::get_singleton()->free(voxel_gi_lights_uniform); RD::get_singleton()->free(sdfgi_ubo); - giprobe_debug_shader.version_free(giprobe_debug_shader_version); - giprobe_shader.version_free(giprobe_lighting_shader_version); + voxel_gi_debug_shader.version_free(voxel_gi_debug_shader_version); + voxel_gi_shader.version_free(voxel_gi_lighting_shader_version); shader.version_free(shader_version); sdfgi_shader.debug_probes.version_free(sdfgi_shader.debug_probes_shader); sdfgi_shader.debug.version_free(sdfgi_shader.debug_shader); @@ -3009,7 +3009,7 @@ void RendererSceneGIRD::free() { sdfgi_shader.integrate.version_free(sdfgi_shader.integrate_shader); sdfgi_shader.preprocess.version_free(sdfgi_shader.preprocess_shader); - memdelete_arr(gi_probe_lights); + memdelete_arr(voxel_gi_lights); } RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size) { @@ -3020,36 +3020,34 @@ RendererSceneGIRD::SDFGI *RendererSceneGIRD::create_sdfgi(RendererSceneEnvironme return sdfgi; } -void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render) { - r_gi_probes_used = 0; +void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) { + r_voxel_gi_instances_used = 0; // feels a little dirty to use our container this way but.... RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(rb == nullptr); - RID gi_probe_buffer = p_scene_render->render_buffers_get_gi_probe_buffer(p_render_buffers); + RID voxel_gi_buffer = p_scene_render->render_buffers_get_voxel_gi_buffer(p_render_buffers); - RD::get_singleton()->draw_command_begin_label("GIProbes Setup"); + VoxelGIData voxel_gi_data[MAX_VOXEL_GI_INSTANCES]; - GIProbeData gi_probe_data[MAX_GIPROBES]; + bool voxel_gi_instances_changed = false; - bool giprobes_changed = false; - - Transform to_camera; + Transform3D to_camera; to_camera.origin = p_transform.origin; //only translation, make local - for (int i = 0; i < MAX_GIPROBES; i++) { + for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) { RID texture; - if (i < (int)p_gi_probes.size()) { - GIProbeInstance *gipi = get_probe_instance(p_gi_probes[i]); + if (i < (int)p_voxel_gi_instances.size()) { + VoxelGIInstance *gipi = get_probe_instance(p_voxel_gi_instances[i]); if (gipi) { texture = gipi->texture; - GIProbeData &gipd = gi_probe_data[i]; + VoxelGIData &gipd = voxel_gi_data[i]; RID base_probe = gipi->probe; - Transform to_cell = storage->gi_probe_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera; + Transform3D to_cell = storage->voxel_gi_get_to_cell_xform(gipi->probe) * gipi->transform.affine_inverse() * to_camera; gipd.xform[0] = to_cell.basis.elements[0][0]; gipd.xform[1] = to_cell.basis.elements[1][0]; @@ -3068,36 +3066,33 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_ gipd.xform[14] = to_cell.origin.z; gipd.xform[15] = 1; - Vector3 bounds = storage->gi_probe_get_octree_size(base_probe); + Vector3 bounds = storage->voxel_gi_get_octree_size(base_probe); gipd.bounds[0] = bounds.x; gipd.bounds[1] = bounds.y; gipd.bounds[2] = bounds.z; - gipd.dynamic_range = storage->gi_probe_get_dynamic_range(base_probe) * storage->gi_probe_get_energy(base_probe); - gipd.bias = storage->gi_probe_get_bias(base_probe); - gipd.normal_bias = storage->gi_probe_get_normal_bias(base_probe); - gipd.blend_ambient = !storage->gi_probe_is_interior(base_probe); - gipd.anisotropy_strength = 0; - gipd.ao = storage->gi_probe_get_ao(base_probe); - gipd.ao_size = Math::pow(storage->gi_probe_get_ao_size(base_probe), 4.0f); + gipd.dynamic_range = storage->voxel_gi_get_dynamic_range(base_probe) * storage->voxel_gi_get_energy(base_probe); + gipd.bias = storage->voxel_gi_get_bias(base_probe); + gipd.normal_bias = storage->voxel_gi_get_normal_bias(base_probe); + gipd.blend_ambient = !storage->voxel_gi_is_interior(base_probe); gipd.mipmaps = gipi->mipmaps.size(); } - r_gi_probes_used++; + r_voxel_gi_instances_used++; } if (texture == RID()) { texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); } - if (texture != rb->gi.giprobe_textures[i]) { - giprobes_changed = true; - rb->gi.giprobe_textures[i] = texture; + if (texture != rb->gi.voxel_gi_textures[i]) { + voxel_gi_instances_changed = true; + rb->gi.voxel_gi_textures[i] = texture; } } - if (giprobes_changed) { + if (voxel_gi_instances_changed) { if (RD::get_singleton()->uniform_set_is_valid(rb->gi.uniform_set)) { RD::get_singleton()->free(rb->gi.uniform_set); } @@ -3112,14 +3107,16 @@ void RendererSceneGIRD::setup_giprobes(RID p_render_buffers, const Transform &p_ } } - if (p_gi_probes.size() > 0) { - RD::get_singleton()->buffer_update(gi_probe_buffer, 0, sizeof(GIProbeData) * MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()), gi_probe_data, RD::BARRIER_MASK_COMPUTE); - } + if (p_voxel_gi_instances.size() > 0) { + RD::get_singleton()->draw_command_begin_label("VoxelGIs Setup"); - RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->buffer_update(voxel_gi_buffer, 0, sizeof(VoxelGIData) * MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()), voxel_gi_data, RD::BARRIER_MASK_COMPUTE); + + RD::get_singleton()->draw_command_end_label(); + } } -void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render) { +void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) { RD::get_singleton()->draw_command_begin_label("GI Render"); RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); @@ -3157,11 +3154,11 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; - push_constant.max_giprobes = MIN((uint64_t)MAX_GIPROBES, p_gi_probes.size()); - push_constant.high_quality_vct = gi_probe_quality == RS::GI_PROBE_QUALITY_HIGH; + push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()); + push_constant.high_quality_vct = voxel_gi_quality == RS::VOXEL_GI_QUALITY_HIGH; bool use_sdfgi = rb->sdfgi != nullptr; - bool use_giprobes = push_constant.max_giprobes > 0; + bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0; if (env) { push_constant.ao_color[0] = env->ao_color.r; @@ -3311,7 +3308,7 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 14; - RID buffer = p_gi_probe_buffer.is_valid() ? p_gi_probe_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); + RID buffer = p_voxel_gi_buffer.is_valid() ? p_voxel_gi_buffer : storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK); u.ids.push_back(buffer); uniforms.push_back(u); } @@ -3326,15 +3323,15 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 16; - u.ids.push_back(rb->gi.giprobe_buffer); + u.ids.push_back(rb->gi.voxel_gi_buffer); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 17; - for (int i = 0; i < MAX_GIPROBES; i++) { - u.ids.push_back(rb->gi.giprobe_textures[i]); + for (int i = 0; i < MAX_VOXEL_GI_INSTANCES; i++) { + u.ids.push_back(rb->gi.voxel_gi_textures[i]); } uniforms.push_back(u); } @@ -3345,10 +3342,11 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ Mode mode; if (rb->gi.using_half_size_gi) { - mode = (use_sdfgi && use_giprobes) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_GIPROBE); + mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_HALF_RES_COMBINED : (use_sdfgi ? MODE_HALF_RES_SDFGI : MODE_HALF_RES_VOXEL_GI); } else { - mode = (use_sdfgi && use_giprobes) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_GIPROBE); + mode = (use_sdfgi && use_voxel_gi_instances) ? MODE_COMBINED : (use_sdfgi ? MODE_SDFGI : MODE_VOXEL_GI); } + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(true); RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, pipelines[mode]); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->gi.uniform_set, 0); @@ -3364,39 +3362,39 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::get_singleton()->draw_command_end_label(); } -RID RendererSceneGIRD::gi_probe_instance_create(RID p_base) { - GIProbeInstance gi_probe; - gi_probe.gi = this; - gi_probe.storage = storage; - gi_probe.probe = p_base; - RID rid = gi_probe_instance_owner.make_rid(gi_probe); +RID RendererSceneGIRD::voxel_gi_instance_create(RID p_base) { + VoxelGIInstance voxel_gi; + voxel_gi.gi = this; + voxel_gi.storage = storage; + voxel_gi.probe = p_base; + RID rid = voxel_gi_instance_owner.make_rid(voxel_gi); return rid; } -void RendererSceneGIRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { - GIProbeInstance *gi_probe = get_probe_instance(p_probe); - ERR_FAIL_COND(!gi_probe); +void RendererSceneGIRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) { + VoxelGIInstance *voxel_gi = get_probe_instance(p_probe); + ERR_FAIL_COND(!voxel_gi); - gi_probe->transform = p_xform; + voxel_gi->transform = p_xform; } -bool RendererSceneGIRD::gi_probe_needs_update(RID p_probe) const { - GIProbeInstance *gi_probe = get_probe_instance(p_probe); - ERR_FAIL_COND_V(!gi_probe, false); +bool RendererSceneGIRD::voxel_gi_needs_update(RID p_probe) const { + VoxelGIInstance *voxel_gi = get_probe_instance(p_probe); + ERR_FAIL_COND_V(!voxel_gi, false); - return gi_probe->last_probe_version != storage->gi_probe_get_version(gi_probe->probe); + return voxel_gi->last_probe_version != storage->voxel_gi_get_version(voxel_gi->probe); } -void RendererSceneGIRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { - GIProbeInstance *gi_probe = get_probe_instance(p_probe); - ERR_FAIL_COND(!gi_probe); +void RendererSceneGIRD::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) { + VoxelGIInstance *voxel_gi = get_probe_instance(p_probe); + ERR_FAIL_COND(!voxel_gi); - gi_probe->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render); + voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render); } -void RendererSceneGIRD::debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { - GIProbeInstance *gi_probe = gi_probe_instance_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererSceneGIRD::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { + VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha); + voxel_gi->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha); } diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index 59f5f374d1..128bf09063 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -38,13 +38,13 @@ #include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_rd/shaders/gi.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/giprobe.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/giprobe_debug.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sdfgi_debug.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sdfgi_debug_probes.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sdfgi_integrate.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/sdfgi_preprocess.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/voxel_gi.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" @@ -56,9 +56,9 @@ class RendererSceneGIRD { private: RendererStorageRD *storage; - /* GIPROBE INSTANCE */ + /* VOXEL_GI INSTANCE */ - struct GIProbeLight { + struct VoxelGILight { uint32_t type; float energy; float radius; @@ -74,7 +74,7 @@ private: uint32_t has_shadow; }; - struct GIProbePushConstant { + struct VoxelGIPushConstant { int32_t limits[3]; uint32_t stack_size; @@ -89,7 +89,7 @@ private: uint32_t pad; }; - struct GIProbeDynamicPushConstant { + struct VoxelGIDynamicPushConstant { int32_t limits[3]; uint32_t light_count; int32_t x_dir[3]; @@ -110,36 +110,36 @@ private: float pad[3]; }; - GIProbeLight *gi_probe_lights; - uint32_t gi_probe_max_lights; - RID gi_probe_lights_uniform; + VoxelGILight *voxel_gi_lights; + uint32_t voxel_gi_max_lights; + RID voxel_gi_lights_uniform; enum { - GI_PROBE_SHADER_VERSION_COMPUTE_LIGHT, - GI_PROBE_SHADER_VERSION_COMPUTE_SECOND_BOUNCE, - GI_PROBE_SHADER_VERSION_COMPUTE_MIPMAP, - GI_PROBE_SHADER_VERSION_WRITE_TEXTURE, - GI_PROBE_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING, - GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE, - GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_PLOT, - GI_PROBE_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT, - GI_PROBE_SHADER_VERSION_MAX + VOXEL_GI_SHADER_VERSION_COMPUTE_LIGHT, + VOXEL_GI_SHADER_VERSION_COMPUTE_SECOND_BOUNCE, + VOXEL_GI_SHADER_VERSION_COMPUTE_MIPMAP, + VOXEL_GI_SHADER_VERSION_WRITE_TEXTURE, + VOXEL_GI_SHADER_VERSION_DYNAMIC_OBJECT_LIGHTING, + VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE, + VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_PLOT, + VOXEL_GI_SHADER_VERSION_DYNAMIC_SHRINK_WRITE_PLOT, + VOXEL_GI_SHADER_VERSION_MAX }; - GiprobeShaderRD giprobe_shader; - RID giprobe_lighting_shader_version; - RID giprobe_lighting_shader_version_shaders[GI_PROBE_SHADER_VERSION_MAX]; - RID giprobe_lighting_shader_version_pipelines[GI_PROBE_SHADER_VERSION_MAX]; + VoxelGiShaderRD voxel_gi_shader; + RID voxel_gi_lighting_shader_version; + RID voxel_gi_lighting_shader_version_shaders[VOXEL_GI_SHADER_VERSION_MAX]; + RID voxel_gi_lighting_shader_version_pipelines[VOXEL_GI_SHADER_VERSION_MAX]; enum { - GI_PROBE_DEBUG_COLOR, - GI_PROBE_DEBUG_LIGHT, - GI_PROBE_DEBUG_EMISSION, - GI_PROBE_DEBUG_LIGHT_FULL, - GI_PROBE_DEBUG_MAX + VOXEL_GI_DEBUG_COLOR, + VOXEL_GI_DEBUG_LIGHT, + VOXEL_GI_DEBUG_EMISSION, + VOXEL_GI_DEBUG_LIGHT_FULL, + VOXEL_GI_DEBUG_MAX }; - struct GIProbeDebugPushConstant { + struct VoxelGIDebugPushConstant { float projection[16]; uint32_t cell_offset; float dynamic_range; @@ -149,11 +149,11 @@ private: uint32_t pad; }; - GiprobeDebugShaderRD giprobe_debug_shader; - RID giprobe_debug_shader_version; - RID giprobe_debug_shader_version_shaders[GI_PROBE_DEBUG_MAX]; - PipelineCacheRD giprobe_debug_shader_version_pipelines[GI_PROBE_DEBUG_MAX]; - RID giprobe_debug_uniform_set; + VoxelGiDebugShaderRD voxel_gi_debug_shader; + RID voxel_gi_debug_shader_version; + RID voxel_gi_debug_shader_version_shaders[VOXEL_GI_DEBUG_MAX]; + PipelineCacheRD voxel_gi_debug_shader_version_pipelines[VOXEL_GI_DEBUG_MAX]; + RID voxel_gi_debug_uniform_set; /* SDFGI */ @@ -326,11 +326,11 @@ private: } sdfgi_shader; public: - /* GIPROBE INSTANCE */ + /* VOXEL_GI INSTANCE */ - //@TODO GIProbeInstance is still directly used in the render code, we'll address this when we refactor the render code itself. + //@TODO VoxelGIInstance is still directly used in the render code, we'll address this when we refactor the render code itself. - struct GIProbeInstance { + struct VoxelGIInstance { // access to our containers RendererStorageRD *storage; RendererSceneGIRD *gi; @@ -374,25 +374,25 @@ public: bool has_dynamic_object_data = false; - Transform transform; + Transform3D transform; void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render); void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); }; - mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner; + mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner; - _FORCE_INLINE_ GIProbeInstance *get_probe_instance(RID p_probe) const { - return gi_probe_instance_owner.getornull(p_probe); + _FORCE_INLINE_ VoxelGIInstance *get_probe_instance(RID p_probe) const { + return voxel_gi_instance_owner.getornull(p_probe); }; - _FORCE_INLINE_ RID gi_probe_instance_get_texture(RID p_probe) { - GIProbeInstance *gi_probe = get_probe_instance(p_probe); - ERR_FAIL_COND_V(!gi_probe, RID()); - return gi_probe->texture; + _FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) { + VoxelGIInstance *voxel_gi = get_probe_instance(p_probe); + ERR_FAIL_COND_V(!voxel_gi, RID()); + return voxel_gi->texture; }; - RS::GIProbeQuality gi_probe_quality = RS::GI_PROBE_QUALITY_HIGH; + RS::VoxelGIQuality voxel_gi_quality = RS::VOXEL_GI_QUALITY_HIGH; /* SDFGI */ @@ -527,10 +527,10 @@ public: int get_pending_region_data(int p_region, Vector3i &r_local_offset, Vector3i &r_local_size, AABB &r_bounds) const; void update_cascades(); - void debug_draw(const CameraMatrix &p_projection, const Transform &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture); + void debug_draw(const CameraMatrix &p_projection, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture); void debug_probes(RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); - void pre_process_gi(const Transform &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render); + void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render); void render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render); void render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render); }; @@ -551,13 +551,13 @@ public: /* GI */ enum { - MAX_GIPROBES = 8 + MAX_VOXEL_GI_INSTANCES = 8 }; // Struct for use in render buffer struct RenderBuffersGI { - RID giprobe_textures[MAX_GIPROBES]; - RID giprobe_buffer; + RID voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; + RID voxel_gi_buffer; RID full_buffer; RID full_dispatch; @@ -601,7 +601,7 @@ public: ProbeCascadeData cascades[SDFGI::MAX_CASCADES]; }; - struct GIProbeData { + struct VoxelGIData { float xform[16]; float bounds[3]; float dynamic_range; @@ -611,9 +611,9 @@ public: uint32_t blend_ambient; uint32_t texture_slot; - float anisotropy_strength; - float ao; - float ao_size; + uint32_t pad0; + uint32_t pad1; + uint32_t pad2; uint32_t mipmaps; }; @@ -624,7 +624,7 @@ public: float proj_info[4]; float ao_color[3]; - uint32_t max_giprobes; + uint32_t max_voxel_gi_instances; uint32_t high_quality_vct; uint32_t orthogonal; @@ -635,16 +635,16 @@ public: RID sdfgi_ubo; enum Mode { - MODE_GIPROBE, + MODE_VOXEL_GI, MODE_SDFGI, MODE_COMBINED, - MODE_HALF_RES_GIPROBE, + MODE_HALF_RES_VOXEL_GI, MODE_HALF_RES_SDFGI, MODE_HALF_RES_COMBINED, MODE_MAX }; - RID default_giprobe_buffer; + RID default_voxel_gi_buffer; bool half_resolution = false; GiShaderRD shader; @@ -659,14 +659,14 @@ public: SDFGI *create_sdfgi(RendererSceneEnvironmentRD *p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size); - void setup_giprobes(RID p_render_buffers, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, uint32_t &r_gi_probes_used, RendererSceneRenderRD *p_scene_render); - void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_gi_probe_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform, const PagedArray<RID> &p_gi_probes, RendererSceneRenderRD *p_scene_render); + void setup_voxel_gi_instances(RID p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render); + void process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render); - RID gi_probe_instance_create(RID p_base); - void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); - bool gi_probe_needs_update(RID p_probe) const; - void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render); - void debug_giprobe(RID p_gi_probe, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); + RID voxel_gi_instance_create(RID p_base); + void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform); + bool voxel_gi_needs_update(RID p_probe) const; + void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render); + void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha); }; #endif /* !RENDERING_SERVER_SCENE_GI_RD_H */ diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 1f01de1333..a70514e9e5 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -486,7 +486,7 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba color.b *= env->bg_energy; Ref<Image> ret; - ret.instance(); + ret.instantiate(); ret->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF); for (int i = 0; i < p_size.width; i++) { for (int j = 0; j < p_size.height; j++) { @@ -570,7 +570,7 @@ RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) { return reflection_probe_instance_owner.make_rid(rpi); } -void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { +void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); ERR_FAIL_COND(!rpi); @@ -709,6 +709,10 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc } } + if (rpi->atlas_index != -1) { // should we fail if this is still -1 ? + atlas->reflections.write[rpi->atlas_index].owner = p_instance; + } + rpi->atlas = p_reflection_atlas; rpi->rendering = true; rpi->dirty = false; @@ -1233,7 +1237,7 @@ RID RendererSceneRenderRD::light_instance_create(RID p_light) { return li; } -void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) { +void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); @@ -1247,7 +1251,7 @@ void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const light_instance->aabb = p_aabb; } -void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); ERR_FAIL_COND(!light_instance); @@ -1305,7 +1309,7 @@ RID RendererSceneRenderRD::decal_instance_create(RID p_decal) { return decal_instance_owner.make_rid(di); } -void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform &p_transform) { +void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { DecalInstance *di = decal_instance_owner.getornull(p_decal); ERR_FAIL_COND(!di); di->transform = p_transform; @@ -1318,7 +1322,7 @@ RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) { li.lightmap = p_lightmap; return lightmap_instance_owner.make_rid(li); } -void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) { +void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap); ERR_FAIL_COND(!li); li->transform = p_transform; @@ -1326,28 +1330,28 @@ void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, cons ///////////////////////////////// -RID RendererSceneRenderRD::gi_probe_instance_create(RID p_base) { - return gi.gi_probe_instance_create(p_base); +RID RendererSceneRenderRD::voxel_gi_instance_create(RID p_base) { + return gi.voxel_gi_instance_create(p_base); } -void RendererSceneRenderRD::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { - gi.gi_probe_instance_set_transform_to_data(p_probe, p_xform); +void RendererSceneRenderRD::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) { + gi.voxel_gi_instance_set_transform_to_data(p_probe, p_xform); } -bool RendererSceneRenderRD::gi_probe_needs_update(RID p_probe) const { +bool RendererSceneRenderRD::voxel_gi_needs_update(RID p_probe) const { if (!is_dynamic_gi_supported()) { return false; } - return gi.gi_probe_needs_update(p_probe); + return gi.voxel_gi_needs_update(p_probe); } -void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) { +void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) { if (!is_dynamic_gi_supported()) { return; } - gi.gi_probe_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this); + gi.voxel_gi_update(p_probe, p_update_light_instances, p_light_instances, p_dynamic_objects, this); } void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { @@ -1728,7 +1732,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen settings.half_screen_size = Size2i(buffer_width, buffer_height); settings.quarter_screen_size = Size2i(half_width, half_height); - storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid); + storage->get_effects()->generate_ssao(rb->depth_texture, p_normal_buffer, rb->ssao.depth, rb->ssao.depth_slices, rb->ssao.ao_deinterleaved, rb->ssao.ao_deinterleaved_slices, rb->ssao.ao_pong, rb->ssao.ao_pong_slices, rb->ssao.ao_final, rb->ssao.importance_map[0], rb->ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ssao.downsample_uniform_set, rb->ssao.gather_uniform_set, rb->ssao.importance_map_uniform_set); } void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) { @@ -1857,6 +1861,8 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende } } + tonemap.view_count = p_render_data->view_count; + storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); } @@ -1959,17 +1965,17 @@ RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { return rb->ssao.ao_final; } -RID RendererSceneRenderRD::render_buffers_get_gi_probe_buffer(RID p_render_buffers) { +RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); - if (rb->gi.giprobe_buffer.is_null()) { - rb->gi.giprobe_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::GIProbeData) * RendererSceneGIRD::MAX_GIPROBES); + if (rb->gi.voxel_gi_buffer.is_null()) { + rb->gi.voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::VoxelGIData) * RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES); } - return rb->gi.giprobe_buffer; + return rb->gi.voxel_gi_buffer; } -RID RendererSceneRenderRD::render_buffers_get_default_gi_probe_buffer() { - return gi.default_giprobe_buffer; +RID RendererSceneRenderRD::render_buffers_get_default_voxel_gi_buffer() { + return gi.default_voxel_gi_buffer; } RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) { @@ -2112,7 +2118,9 @@ float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID return rb->volumetric_fog->spread; } -void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) { +void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { + ERR_FAIL_COND_MSG(p_view_count == 0, "Must have atleast 1 view"); + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); rb->width = p_width; rb->height = p_height; @@ -2120,6 +2128,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; rb->use_debanding = p_use_debanding; + rb->view_count = p_view_count; if (is_clustered_enabled()) { if (rb->cluster_builder == nullptr) { @@ -2132,9 +2141,13 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p { RD::TextureFormat tf; + if (rb->view_count > 1) { + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + } tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; tf.width = rb->width; tf.height = rb->height; + tf.array_layers = rb->view_count; // create a layer for every view tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; @@ -2147,6 +2160,9 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p { RD::TextureFormat tf; + if (rb->view_count > 1) { + tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + } if (rb->msaa == RS::VIEWPORT_MSAA_DISABLED) { tf.format = RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_D24_UNORM_S8_UINT, RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ? RD::DATA_FORMAT_D24_UNORM_S8_UINT : RD::DATA_FORMAT_D32_SFLOAT_S8_UINT; } else { @@ -2156,6 +2172,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.width = p_width; tf.height = p_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; + tf.array_layers = rb->view_count; // create a layer for every view if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { tf.usage_bits |= RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; @@ -2166,7 +2183,7 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p rb->depth_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } - rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa); + rb->data->configure(rb->texture, rb->depth_texture, p_width, p_height, p_msaa, p_view_count); if (is_clustered_enabled()) { rb->cluster_builder->setup(Size2i(p_width, p_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); @@ -2284,7 +2301,7 @@ RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_g return rb->data; } -void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment) { +void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment) { cluster.reflection_count = 0; for (uint32_t i = 0; i < (uint32_t)p_reflections.size(); i++) { @@ -2344,8 +2361,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti reflection_ubo.ambient[1] = ambient_linear.g * interior_ambient_energy; reflection_ubo.ambient[2] = ambient_linear.b * interior_ambient_energy; - Transform transform = rpi->transform; - Transform proj = (p_camera_inverse_transform * transform).inverse(); + Transform3D transform = rpi->transform; + Transform3D proj = (p_camera_inverse_transform * transform).inverse(); RendererStorageRD::store_transform(proj, reflection_ubo.local_matrix); if (current_cluster_builder != nullptr) { @@ -2360,8 +2377,8 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti } } -void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { - Transform inverse_transform = p_camera_transform.affine_inverse(); +void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count) { + Transform3D inverse_transform = p_camera_transform.affine_inverse(); r_directional_light_count = 0; r_positional_light_count = 0; @@ -2387,7 +2404,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const // Copy to SkyDirectionalLightData if (r_directional_light_count < sky.sky_scene_state.max_directional_lights) { RendererSceneSkyRD::SkyDirectionalLightData &sky_light_data = sky.sky_scene_state.directional_lights[r_directional_light_count]; - Transform light_transform = li->transform; + Transform3D light_transform = li->transform; Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized(); sky_light_data.direction[0] = world_direction.x; @@ -2423,7 +2440,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const Cluster::DirectionalLightData &light_data = cluster.directional_lights[r_directional_light_count]; - Transform light_transform = li->transform; + Transform3D light_transform = li->transform; Vector3 direction = inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized(); @@ -2513,7 +2530,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const CameraMatrix rectm; rectm.set_light_atlas_rect(atlas_rect); - Transform modelview = (inverse_transform * li->shadow_transform[j].transform).inverse(); + Transform3D modelview = (inverse_transform * li->shadow_transform[j].transform).inverse(); CameraMatrix shadow_mtx = rectm * bias * matrix * modelview; light_data.shadow_split_offsets[j] = split; @@ -2609,7 +2626,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const LightInstance *li = (i < cluster.omni_light_count) ? cluster.omni_light_sort[index].instance : cluster.spot_light_sort[index].instance; RID base = li->light; - Transform light_transform = li->transform; + Transform3D light_transform = li->transform; float sign = storage->light_is_negative(base) ? -1 : 1; Color linear_col = storage->light_get_color(base).to_linear(); @@ -2709,7 +2726,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const if (type == RS::LIGHT_OMNI) { light_data.atlas_rect[3] *= 0.5; //one paraboloid on top of another - Transform proj = (inverse_transform * light_transform).inverse(); + Transform3D proj = (inverse_transform * light_transform).inverse(); RendererStorageRD::store_transform(proj, light_data.shadow_matrix); @@ -2721,7 +2738,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const } } else if (type == RS::LIGHT_SPOT) { - Transform modelview = (inverse_transform * light_transform).inverse(); + Transform3D modelview = (inverse_transform * light_transform).inverse(); CameraMatrix bias; bias.set_light_bias(); @@ -2765,8 +2782,8 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const } } -void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform) { - Transform uv_xform; +void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) { + Transform3D uv_xform; uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0)); uv_xform.origin = Vector3(-1.0, 0.0, -1.0); @@ -2785,7 +2802,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const } RID decal = di->decal; - Transform xform = di->transform; + Transform3D xform = di->transform; real_t distance = -p_camera_inverse_xform.xform(xform.origin).z; @@ -2817,7 +2834,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const di->render_index = i; di->cull_mask = storage->decal_get_cull_mask(decal); - Transform xform = di->transform; + Transform3D xform = di->transform; float fade = 1.0; if (storage->decal_is_distance_fade_enabled(decal)) { @@ -2834,9 +2851,9 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Vector3 decal_extents = storage->decal_get_extents(decal); - Transform scale_xform; + Transform3D scale_xform; scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z)); - Transform to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); + Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); RendererStorageRD::store_transform(to_decal_xform, dd.xform); Vector3 normal = xform.basis.get_axis(Vector3::AXIS_Y).normalized(); @@ -3066,7 +3083,7 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { rb->volumetric_fog = nullptr; } -void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count) { +void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count) { ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); ERR_FAIL_COND(!rb); @@ -3228,7 +3245,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; u.binding = 11; - u.ids.push_back(render_buffers_get_gi_probe_buffer(p_render_buffers)); + u.ids.push_back(render_buffers_get_voxel_gi_buffer(p_render_buffers)); uniforms.push_back(u); } @@ -3236,8 +3253,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 12; - for (int i = 0; i < RendererSceneGIRD::MAX_GIPROBES; i++) { - u.ids.push_back(rb->gi.giprobe_textures[i]); + for (int i = 0; i < RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES; i++) { + u.ids.push_back(rb->gi.voxel_gi_textures[i]); } uniforms.push_back(u); } @@ -3362,10 +3379,10 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e params.cam_rotation[10] = p_cam_transform.basis[2][2]; params.cam_rotation[11] = 0; params.filter_axis = 0; - params.max_gi_probes = env->volumetric_fog_gi_inject > 0.001 ? p_gi_probe_count : 0; + params.max_voxel_gi_instances = env->volumetric_fog_gi_inject > 0.001 ? p_voxel_gi_count : 0; params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; - Transform to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform; + Transform3D to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform; storage->store_transform(to_prev_cam_view, params.to_prev_view); params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection; @@ -3492,17 +3509,15 @@ void RendererSceneRenderRD::_pre_resolve_render(RenderDataRD *p_render_data, boo } } -void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer) { +void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer) { // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time if (p_render_data->render_buffers.is_valid() && p_use_gi) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); ERR_FAIL_COND(rb == nullptr); - if (rb->sdfgi == nullptr) { - return; + if (rb->sdfgi != nullptr) { + rb->sdfgi->store_probes(); } - - rb->sdfgi->store_probes(); } render_state.cube_shadows.clear(); @@ -3511,7 +3526,6 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool Plane camera_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier(); - { for (int i = 0; i < render_state.render_shadow_count; i++) { LightInstance *li = light_instance_owner.getornull(render_state.render_shadows[i].light); @@ -3527,7 +3541,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //cube shadows are rendered in their own way for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true); + _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, true, true, true, p_render_data->render_info); } if (render_state.directional_shadows.size()) { @@ -3557,11 +3571,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //render directional shadows for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false); + _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info); } //render positional shadows for (uint32_t i = 0; i < render_state.shadows.size(); i++) { - _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true); + _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info); } _render_shadow_process(); @@ -3569,7 +3583,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool //start GI if (render_gi) { - gi.process_gi(p_render_data->render_buffers, p_normal_roughness_buffer, p_gi_probe_buffer, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, *p_render_data->gi_probes, this); + gi.process_gi(p_render_data->render_buffers, p_normal_roughness_buffer, p_voxel_gi_buffer, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, *p_render_data->voxel_gi_instances, this); } //Do shadow rendering (in parallel with GI) @@ -3625,12 +3639,12 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } } if (is_volumetric_supported()) { - _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.gi_probe_count); + _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count); } } } -void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data) { +void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { // getting this here now so we can direct call a bunch of things more easily RenderBuffers *rb = nullptr; if (p_render_buffers.is_valid()) { @@ -3643,16 +3657,24 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & { render_data.render_buffers = p_render_buffers; - render_data.cam_transform = p_cam_transform; - render_data.cam_projection = p_cam_projection; - render_data.cam_ortogonal = p_cam_projection.is_orthogonal(); // !BAS! Shouldn't this be p_cam_ortogonal ? - render_data.z_near = p_cam_projection.get_z_near(); - render_data.z_far = p_cam_projection.get_z_far(); + // Our first camera is used by default + render_data.cam_transform = p_camera_data->main_transform; + render_data.cam_projection = p_camera_data->main_projection; + render_data.view_projection[0] = p_camera_data->main_projection; + render_data.cam_ortogonal = p_camera_data->is_ortogonal; + + render_data.view_count = p_camera_data->view_count; + for (uint32_t v = 0; v < p_camera_data->view_count; v++) { + render_data.view_projection[v] = p_camera_data->view_projection[v]; + } + + render_data.z_near = p_camera_data->main_projection.get_z_near(); + render_data.z_far = p_camera_data->main_projection.get_z_far(); render_data.instances = &p_instances; render_data.lights = &p_lights; render_data.reflection_probes = &p_reflection_probes; - render_data.gi_probes = &p_gi_probes; + render_data.voxel_gi_instances = &p_voxel_gi_instances; render_data.decals = &p_decals; render_data.lightmaps = &p_lightmaps; render_data.environment = p_environment; @@ -3662,8 +3684,9 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & render_data.reflection_probe = p_reflection_probe; render_data.reflection_probe_pass = p_reflection_probe_pass; - render_data.lod_distance_multiplier = p_cam_projection.get_lod_multiplier(); - render_data.lod_camera_plane = Plane(p_cam_transform.get_origin(), -p_cam_transform.basis.get_axis(Vector3::AXIS_Z)); + // this should be the same for all cameras.. + render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier(); + render_data.lod_camera_plane = Plane(p_camera_data->main_transform.get_origin(), -p_camera_data->main_transform.basis.get_axis(Vector3::AXIS_Z)); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { render_data.screen_lod_threshold = 0.0; @@ -3676,6 +3699,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & render_state.render_sdfgi_regions = p_render_sdfgi_regions; render_state.render_sdfgi_region_count = p_render_sdfgi_region_count; render_state.sdfgi_update_data = p_sdfgi_update_data; + render_data.render_info = r_render_info; } PagedArray<RID> empty; @@ -3683,7 +3707,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { render_data.lights = ∅ render_data.reflection_probes = ∅ - render_data.gi_probes = ∅ + render_data.voxel_gi_instances = ∅ } //sdfgi first @@ -3703,12 +3727,12 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & clear_color = storage->get_default_clear_color(); } - //assign render indices to giprobes + //assign render indices to voxel_gi_instances if (is_dynamic_gi_supported()) { - for (uint32_t i = 0; i < (uint32_t)p_gi_probes.size(); i++) { - RendererSceneGIRD::GIProbeInstance *giprobe_inst = gi.gi_probe_instance_owner.getornull(p_gi_probes[i]); - if (giprobe_inst) { - giprobe_inst->render_index = i; + for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) { + RendererSceneGIRD::VoxelGIInstance *voxel_gi_inst = gi.voxel_gi_instance_owner.getornull(p_voxel_gi_instances[i]); + if (voxel_gi_inst) { + voxel_gi_inst->render_index = i; } } } @@ -3730,17 +3754,16 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & current_cluster_builder = nullptr; } - if (rb != nullptr && rb->sdfgi != nullptr) { - rb->sdfgi->update_cascades(); - - rb->sdfgi->pre_process_gi(p_cam_transform, &render_data, this); - } + render_state.voxel_gi_count = 0; - render_state.gi_probe_count = 0; - if (rb != nullptr && rb->sdfgi != nullptr) { - gi.setup_giprobes(render_data.render_buffers, render_data.cam_transform, *render_data.gi_probes, render_state.gi_probe_count, this); + if (rb != nullptr) { + if (rb->sdfgi) { + rb->sdfgi->update_cascades(); + rb->sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this); + rb->sdfgi->update_light(); + } - rb->sdfgi->update_light(); + gi.setup_voxel_gi_instances(render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this); } render_state.depth_prepass_used = false; @@ -3782,12 +3805,12 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const Transform & _render_buffers_post_process_and_tonemap(&render_data); _render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex); if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SDFGI && rb != nullptr && rb->sdfgi != nullptr) { - rb->sdfgi->debug_draw(p_cam_projection, p_cam_transform, rb->width, rb->height, rb->render_target, rb->texture); + rb->sdfgi->debug_draw(render_data.cam_projection, render_data.cam_transform, rb->width, rb->height, rb->render_target, rb->texture); } } } -void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region) { +void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RendererScene::RenderInfo *p_render_info) { LightInstance *light_instance = light_instance_owner.getornull(p_light); ERR_FAIL_COND(!light_instance); @@ -3808,7 +3831,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, bool flip_y = false; CameraMatrix light_projection; - Transform light_transform; + Transform3D light_transform; if (storage->light_get_type(light_instance->light) == RS::LIGHT_DIRECTIONAL) { //set pssm stuff @@ -3933,7 +3956,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, if (render_cubemap) { //rendering to cubemap - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, Rect2(), false, true, true, true); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, Rect2(), false, true, true, true, p_render_info); if (finalize_cubemap) { _render_shadow_process(); _render_shadow_end(); @@ -3954,15 +3977,15 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, } else { //render shadow - _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass); + _render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info); } } -void RendererSceneRenderRD::render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { +void RendererSceneRenderRD::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) { _render_material(p_cam_transform, p_cam_projection, p_cam_ortogonal, p_instances, p_framebuffer, p_region); } -void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) { +void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) { ERR_FAIL_COND(!storage->particles_collision_is_heightfield(p_collider)); Vector3 extents = storage->particles_collision_get_extents(p_collider) * p_transform.basis.get_scale(); CameraMatrix cm; @@ -3971,7 +3994,7 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, Vector3 cam_pos = p_transform.origin; cam_pos.y += extents.y; - Transform cam_xform; + Transform3D cam_xform; cam_xform.set_look_at(cam_pos, cam_pos - p_transform.basis.get_axis(Vector3::AXIS_Y), -p_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); RID fb = storage->particles_collision_get_heightfield_framebuffer(p_collider); @@ -4018,19 +4041,19 @@ bool RendererSceneRenderRD::free(RID p_rid) { decal_instance_owner.free(p_rid); } else if (lightmap_instance_owner.owns(p_rid)) { lightmap_instance_owner.free(p_rid); - } else if (gi.gi_probe_instance_owner.owns(p_rid)) { - RendererSceneGIRD::GIProbeInstance *gi_probe = gi.gi_probe_instance_owner.getornull(p_rid); - if (gi_probe->texture.is_valid()) { - RD::get_singleton()->free(gi_probe->texture); - RD::get_singleton()->free(gi_probe->write_buffer); + } else if (gi.voxel_gi_instance_owner.owns(p_rid)) { + RendererSceneGIRD::VoxelGIInstance *voxel_gi = gi.voxel_gi_instance_owner.getornull(p_rid); + if (voxel_gi->texture.is_valid()) { + RD::get_singleton()->free(voxel_gi->texture); + RD::get_singleton()->free(voxel_gi->write_buffer); } - for (int i = 0; i < gi_probe->dynamic_maps.size(); i++) { - RD::get_singleton()->free(gi_probe->dynamic_maps[i].texture); - RD::get_singleton()->free(gi_probe->dynamic_maps[i].depth); + for (int i = 0; i < voxel_gi->dynamic_maps.size(); i++) { + RD::get_singleton()->free(voxel_gi->dynamic_maps[i].texture); + RD::get_singleton()->free(voxel_gi->dynamic_maps[i].depth); } - gi.gi_probe_instance_owner.free(p_rid); + gi.voxel_gi_instance_owner.free(p_rid); } else if (sky.sky_owner.owns(p_rid)) { sky.update_dirty_skys(); sky.free_sky(p_rid); @@ -4153,7 +4176,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto { PackedByteArray data = RD::get_singleton()->texture_get_data(albedo_alpha_tex, 0); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data); RD::get_singleton()->free(albedo_alpha_tex); ret.push_back(img); @@ -4162,7 +4185,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto { PackedByteArray data = RD::get_singleton()->texture_get_data(normal_tex, 0); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data); RD::get_singleton()->free(normal_tex); ret.push_back(img); @@ -4171,7 +4194,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto { PackedByteArray data = RD::get_singleton()->texture_get_data(orm_tex, 0); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBA8, data); RD::get_singleton()->free(orm_tex); ret.push_back(img); @@ -4180,7 +4203,7 @@ TypedArray<Image> RendererSceneRenderRD::bake_render_uv2(RID p_base, const Vecto { PackedByteArray data = RD::get_singleton()->texture_get_data(emission_tex, 0); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(p_image_size.width, p_image_size.height, false, Image::FORMAT_RGBAH, data); RD::get_singleton()->free(emission_tex); ret.push_back(img); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 1f82ae6dec..be3d3551c7 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -40,23 +40,28 @@ #include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h" +#include "servers/rendering/renderer_scene.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" struct RenderDataRD { RID render_buffers = RID(); - Transform cam_transform = Transform(); + Transform3D cam_transform = Transform3D(); CameraMatrix cam_projection = CameraMatrix(); bool cam_ortogonal = false; + // For stereo rendering + uint32_t view_count = 1; + CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; + float z_near = 0.0; float z_far = 0.0; const PagedArray<RendererSceneRender::GeometryInstance *> *instances = nullptr; const PagedArray<RID> *lights = nullptr; const PagedArray<RID> *reflection_probes = nullptr; - const PagedArray<RID> *gi_probes = nullptr; + const PagedArray<RID> *voxel_gi_instances = nullptr; const PagedArray<RID> *decals = nullptr; const PagedArray<RID> *lightmaps = nullptr; RID environment = RID(); @@ -75,6 +80,8 @@ struct RenderDataRD { uint32_t cluster_max_elements = 0; uint32_t directional_light_count = 0; + + RendererScene::RenderInfo *render_info = nullptr; }; class RendererSceneRenderRD : public RendererSceneRender { @@ -87,26 +94,26 @@ protected: double time_step = 0; struct RenderBufferData { - virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa) = 0; + virtual void configure(RID p_color_buffer, RID p_depth_buffer, int p_width, int p_height, RS::ViewportMSAA p_msaa, uint32_t p_view_count) = 0; virtual ~RenderBufferData() {} }; virtual RenderBufferData *_create_render_buffer_data() = 0; - void _setup_lights(const PagedArray<RID> &p_lights, const Transform &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); - void _setup_decals(const PagedArray<RID> &p_decals, const Transform &p_camera_inverse_xform); - void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform &p_camera_inverse_transform, RID p_environment); + void _setup_lights(const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count); + void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform); + void _setup_reflections(const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment); virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0; virtual void _render_shadow_begin() = 0; - virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true) = 0; + virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<GeometryInstance *> &p_instances, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RendererScene::RenderInfo *p_render_info = nullptr) = 0; virtual void _render_shadow_process() = 0; virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0; - virtual void _render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void _render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void _render_uv2(const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void _render_sdfgi(RID p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<GeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture) = 0; - virtual void _render_particle_collider_heightfield(RID p_fb, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0; + virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) = 0; void _debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform); @@ -123,7 +130,7 @@ protected: void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi); void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi); - void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_gi_probe_buffer); + void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_gi, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer); // needed for a single argument calls (material and uv2) PagedArrayPool<GeometryInstance *> cull_argument_pool; @@ -184,7 +191,7 @@ private: uint32_t render_index = 0; uint32_t cull_mask = 0; - Transform transform; + Transform3D transform; }; mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; @@ -193,7 +200,7 @@ private: struct DecalInstance { RID decal; - Transform transform; + Transform3D transform; uint32_t render_index; uint32_t cull_mask; }; @@ -204,7 +211,7 @@ private: struct LightmapInstance { RID lightmap; - Transform transform; + Transform3D transform; }; mutable RID_Owner<LightmapInstance> lightmap_instance_owner; @@ -312,7 +319,7 @@ private: struct LightInstance { struct ShadowTransform { CameraMatrix camera; - Transform transform; + Transform3D transform; float farplane; float split; float bias_scale; @@ -329,7 +336,7 @@ private: AABB aabb; RID self; RID light; - Transform transform; + Transform3D transform; Vector3 light_vector; Vector3 spot_vector; @@ -411,6 +418,7 @@ private: RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; bool use_debanding = false; + uint32_t view_count = 1; RID render_target; @@ -454,6 +462,10 @@ private: Vector<RID> ao_pong_slices; RID ao_final; RID importance_map[2]; + + RID downsample_uniform_set; + RID gather_uniform_set; + RID importance_map_uniform_set; } ssao; struct SSR { @@ -631,7 +643,7 @@ private: int render_sdfgi_region_count = 0; const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr; - uint32_t gi_probe_count = 0; + uint32_t voxel_gi_count = 0; LocalVector<int> cube_shadows; LocalVector<int> shadows; @@ -663,7 +675,7 @@ private: int last_shadow_filter = -1; - Transform prev_cam_transform; + Transform3D prev_cam_transform; }; enum { @@ -692,7 +704,7 @@ private: float detail_spread; float gi_inject; - uint32_t max_gi_probes; + uint32_t max_voxel_gi_instances; uint32_t cluster_type_size; float screen_size[2]; @@ -721,7 +733,7 @@ private: bool volumetric_fog_filter_active = true; void _volumetric_fog_erase(RenderBuffers *rb); - void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_gi_probe_count); + void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count); RID shadow_sampler; @@ -737,18 +749,18 @@ private: uint32_t max_cluster_elements = 512; - void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true); + void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RendererScene::RenderInfo *p_render_info = nullptr); public: - virtual Transform geometry_instance_get_transform(GeometryInstance *p_instance) = 0; + virtual Transform3D geometry_instance_get_transform(GeometryInstance *p_instance) = 0; virtual AABB geometry_instance_get_aabb(GeometryInstance *p_instance) = 0; /* SHADOW ATLAS API */ - RID shadow_atlas_create(); - void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false); - void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision); - bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version); + virtual RID shadow_atlas_create() override; + virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override; + virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; + virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND_V(!atlas, false); @@ -767,9 +779,9 @@ public: return Size2(atlas->size, atlas->size); } - void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false); - int get_directional_light_shadow_size(RID p_light_intance); - void set_directional_shadow_count(int p_count); + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override; + virtual int get_directional_light_shadow_size(RID p_light_intance) override; + virtual void set_directional_shadow_count(int p_count) override; _FORCE_INLINE_ RID directional_shadow_get_texture() { return directional_shadow.depth; @@ -781,43 +793,43 @@ public: /* SDFGI UPDATE */ - virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position); - virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const; - virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const; - virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const; + virtual void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override; + virtual int sdfgi_get_pending_region_count(RID p_render_buffers) const override; + virtual AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override; + virtual uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override; RID sdfgi_get_ubo() const { return gi.sdfgi_ubo; } /* SKY API */ - virtual RID sky_allocate(); - virtual void sky_initialize(RID p_rid); + virtual RID sky_allocate() override; + virtual void sky_initialize(RID p_rid) override; - void sky_set_radiance_size(RID p_sky, int p_radiance_size); - void sky_set_mode(RID p_sky, RS::SkyMode p_mode); - void sky_set_material(RID p_sky, RID p_material); - Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size); + virtual void sky_set_radiance_size(RID p_sky, int p_radiance_size) override; + virtual void sky_set_mode(RID p_sky, RS::SkyMode p_mode) override; + virtual void sky_set_material(RID p_sky, RID p_material) override; + virtual Ref<Image> sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override; /* ENVIRONMENT API */ - virtual RID environment_allocate(); - virtual void environment_initialize(RID p_rid); + virtual RID environment_allocate() override; + virtual void environment_initialize(RID p_rid) override; - void environment_set_background(RID p_env, RS::EnvironmentBG p_bg); - void environment_set_sky(RID p_env, RID p_sky); - void environment_set_sky_custom_fov(RID p_env, float p_scale); - void environment_set_sky_orientation(RID p_env, const Basis &p_orientation); - void environment_set_bg_color(RID p_env, const Color &p_color); - void environment_set_bg_energy(RID p_env, float p_energy); - void environment_set_canvas_max_layer(RID p_env, int p_max_layer); - void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()); + virtual void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override; + virtual void environment_set_sky(RID p_env, RID p_sky) override; + virtual void environment_set_sky_custom_fov(RID p_env, float p_scale) override; + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) override; + virtual void environment_set_bg_color(RID p_env, const Color &p_color) override; + virtual void environment_set_bg_energy(RID p_env, float p_energy) override; + virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) override; - RS::EnvironmentBG environment_get_background(RID p_env) const; + virtual RS::EnvironmentBG environment_get_background(RID p_env) const override; RID environment_get_sky(RID p_env) const; float environment_get_sky_custom_fov(RID p_env) const; Basis environment_get_sky_orientation(RID p_env) const; Color environment_get_bg_color(RID p_env) const; float environment_get_bg_energy(RID p_env) const; - int environment_get_canvas_max_layer(RID p_env) const; + virtual int environment_get_canvas_max_layer(RID p_env) const override; Color environment_get_ambient_light_color(RID p_env) const; RS::EnvironmentAmbientSource environment_get_ambient_source(RID p_env) const; float environment_get_ambient_light_energy(RID p_env) const; @@ -825,13 +837,13 @@ public: RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const; Color environment_get_ao_color(RID p_env) const; - bool is_environment(RID p_env) const; + virtual bool is_environment(RID p_env) const override; - void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); - void environment_glow_set_use_bicubic_upscale(bool p_enable); - void environment_glow_set_use_high_quality(bool p_enable); + virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override; + virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) override; + virtual void environment_glow_set_use_high_quality(bool p_enable) override; - void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective); + virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override; bool environment_is_fog_enabled(RID p_env) const; Color environment_get_fog_light_color(RID p_env) const; float environment_get_fog_light_energy(RID p_env) const; @@ -841,54 +853,54 @@ public: float environment_get_fog_height_density(RID p_env) const; float environment_get_fog_aerial_perspective(RID p_env) const; - void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount); + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override; - virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth); - virtual void environment_set_volumetric_fog_filter_active(bool p_enable); + virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override; + virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override; - void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); - void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to); + virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) override; + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override; + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; bool environment_is_ssao_enabled(RID p_env) const; float environment_get_ssao_ao_affect(RID p_env) const; float environment_get_ssao_light_affect(RID p_env) const; bool environment_is_ssr_enabled(RID p_env) const; bool environment_is_sdfgi_enabled(RID p_env) const; - virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); - virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count); - virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames); - virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update); + virtual void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override; + virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override; + virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override; + virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override; - void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality); + virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const; - void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); - void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction); + virtual void environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) override; + virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override; - virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size); + virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override; - virtual RID camera_effects_allocate(); - virtual void camera_effects_initialize(RID p_rid); + virtual RID camera_effects_allocate() override; + virtual void camera_effects_initialize(RID p_rid) override; - virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter); - virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape); + virtual void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override; + virtual void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override; - virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount); - virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure); + virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override; + virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override; - RID light_instance_create(RID p_light); - void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); - void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb); - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()); - void light_instance_mark_visible(RID p_light_instance); + virtual RID light_instance_create(RID p_light) override; + virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; + virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; + virtual void light_instance_mark_visible(RID p_light_instance) override; _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { LightInstance *li = light_instance_owner.getornull(p_light_instance); return li->light; } - _FORCE_INLINE_ Transform light_instance_get_base_transform(RID p_light_instance) { + _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) { LightInstance *li = light_instance_owner.getornull(p_light_instance); return li->transform; } @@ -945,7 +957,7 @@ public: return float(1.0) / shadow_size; } - _FORCE_INLINE_ Transform + _FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) { LightInstance *li = light_instance_owner.getornull(p_light_instance); return li->shadow_transform[p_index].transform; @@ -1008,9 +1020,9 @@ public: return li->light_type; } - virtual RID reflection_atlas_create(); - virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count); - virtual int reflection_atlas_get_size(RID p_ref_atlas) const; + virtual RID reflection_atlas_create() override; + virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; + virtual int reflection_atlas_get_size(RID p_ref_atlas) const override; _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas); @@ -1018,13 +1030,13 @@ public: return atlas->reflection; } - virtual RID reflection_probe_instance_create(RID p_probe); - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); - virtual void reflection_probe_release_atlas_index(RID p_instance); - virtual bool reflection_probe_instance_needs_redraw(RID p_instance); - virtual bool reflection_probe_instance_has_reflection(RID p_instance); - virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas); - virtual bool reflection_probe_instance_postprocess_step(RID p_instance); + virtual RID reflection_probe_instance_create(RID p_probe) override; + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + virtual void reflection_probe_release_atlas_index(RID p_instance) override; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; + virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override; uint32_t reflection_probe_instance_get_resolution(RID p_instance); RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index); @@ -1063,9 +1075,9 @@ public: return rpi->last_pass; } - _FORCE_INLINE_ Transform reflection_probe_instance_get_transform(RID p_instance) { + _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); - ERR_FAIL_COND_V(!rpi, Transform()); + ERR_FAIL_COND_V(!rpi, Transform3D()); return rpi->transform; } @@ -1077,21 +1089,21 @@ public: return rpi->atlas_index; } - virtual RID decal_instance_create(RID p_decal); - virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform); + virtual RID decal_instance_create(RID p_decal) override; + virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const { DecalInstance *decal = decal_instance_owner.getornull(p_decal); return decal->decal; } - _FORCE_INLINE_ Transform decal_instance_get_transform(RID p_decal) const { + _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const { DecalInstance *decal = decal_instance_owner.getornull(p_decal); return decal->transform; } - virtual RID lightmap_instance_create(RID p_lightmap); - virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform); + virtual RID lightmap_instance_create(RID p_lightmap) override; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr; } @@ -1100,7 +1112,7 @@ public: LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); return li->lightmap; } - _FORCE_INLINE_ Transform lightmap_instance_get_transform(RID p_lightmap_instance) { + _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) { LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); return li->transform; } @@ -1109,22 +1121,22 @@ public: /* gi light probes */ - RID gi_probe_instance_create(RID p_base); - void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform); - bool gi_probe_needs_update(RID p_probe) const; - void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects); - void gi_probe_set_quality(RS::GIProbeQuality p_quality) { gi.gi_probe_quality = p_quality; } + virtual RID voxel_gi_instance_create(RID p_base) override; + virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override; + virtual bool voxel_gi_needs_update(RID p_probe) const override; + virtual void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RendererSceneRender::GeometryInstance *> &p_dynamic_objects) override; + virtual void voxel_gi_set_quality(RS::VoxelGIQuality p_quality) override { gi.voxel_gi_quality = p_quality; } /* render buffers */ - RID render_buffers_create(); - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding); - void gi_set_use_half_resolution(bool p_enable); + virtual RID render_buffers_create() override; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; + virtual void gi_set_use_half_resolution(bool p_enable) override; RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); - RID render_buffers_get_gi_probe_buffer(RID p_render_buffers); - RID render_buffers_get_default_gi_probe_buffer(); + RID render_buffers_get_voxel_gi_buffer(RID p_render_buffers); + RID render_buffers_get_default_voxel_gi_buffer(); RID render_buffers_get_gi_ambient_texture(RID p_render_buffers); RID render_buffers_get_gi_reflection_texture(RID p_render_buffers); @@ -1147,30 +1159,30 @@ public: float render_buffers_get_volumetric_fog_end(RID p_render_buffers); float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); - void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr); + virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; - void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region); + virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; - void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances); + virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override; - virtual void set_scene_pass(uint64_t p_pass) { + virtual void set_scene_pass(uint64_t p_pass) override { scene_pass = p_pass; } _FORCE_INLINE_ uint64_t get_scene_pass() { return scene_pass; } - virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit); - virtual bool screen_space_roughness_limiter_is_active() const; + virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) override; + virtual bool screen_space_roughness_limiter_is_active() const override; virtual float screen_space_roughness_limiter_get_amount() const; virtual float screen_space_roughness_limiter_get_limit() const; - virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality); + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override; RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const; - virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale); + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override; - virtual void shadows_quality_set(RS::ShadowQuality p_quality); - virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality); + virtual void shadows_quality_set(RS::ShadowQuality p_quality) override; + virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) override; _FORCE_INLINE_ RS::ShadowQuality shadows_quality_get() const { return shadows_quality; } _FORCE_INLINE_ RS::ShadowQuality directional_shadow_quality_get() const { return directional_shadow_quality; } _FORCE_INLINE_ float shadows_quality_radius_get() const { return shadows_quality_radius; } @@ -1189,18 +1201,18 @@ public: int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; - virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size); + virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override; - virtual bool free(RID p_rid); + virtual bool free(RID p_rid) override; - virtual void update(); + virtual void update() override; - virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw); + virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override; _FORCE_INLINE_ RS::ViewportDebugDraw get_debug_draw_mode() const { return debug_draw; } - void set_time(double p_time, double p_step); + virtual void set_time(double p_time, double p_step) override; RID get_reflection_probe_buffer(); RID get_omni_light_buffer(); @@ -1209,7 +1221,7 @@ public: RID get_decal_buffer(); int get_max_directional_lights() const; - void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir); + virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override; virtual bool is_dynamic_gi_supported() const; virtual bool is_clustered_enabled() const; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 966a1c6815..e701219617 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/math/math_defs.h" #include "renderer_scene_render_rd.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "servers/rendering/rendering_server_default.h" //////////////////////////////////////////////////////////////////////////////// @@ -126,8 +127,12 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { depth_stencil_state.enable_depth_test = true; depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; - RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); - pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0); + if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) { + RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); + pipelines[i].setup(shader_variant, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), depth_stencil_state, RD::PipelineColorBlendState::create_disabled(), 0); + } else { + pipelines[i].clear(); + } } valid = true; @@ -225,96 +230,73 @@ RendererSceneSkyRD::SkyShaderData::~SkyShaderData() { //////////////////////////////////////////////////////////////////////////////// // Sky material -void RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; uniform_set_updated = true; - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); - } + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); +} - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); +RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() { + free_parameters_uniform_set(uniform_set); +} - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; +//////////////////////////////////////////////////////////////////////////////// +// Render sky + +static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_array) { + p_array[0] = p_basis.elements[0][0]; + p_array[1] = p_basis.elements[1][0]; + p_array[2] = p_basis.elements[2][0]; + p_array[3] = 0; + p_array[4] = p_basis.elements[0][1]; + p_array[5] = p_basis.elements[1][1]; + p_array[6] = p_basis.elements[2][1]; + p_array[7] = 0; + p_array[8] = p_basis.elements[0][2]; + p_array[9] = p_basis.elements[1][2]; + p_array[10] = p_basis.elements[2][2]; + p_array[11] = 0; +} - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } +void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const CameraMatrix *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position) { + SkyPushConstant sky_push_constant; - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); - } + memset(&sky_push_constant, 0, sizeof(SkyPushConstant)); - if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { - // This material does not require an uniform set, so don't create it. - return; + for (uint32_t v = 0; v < p_view_count; v++) { + // We only need key components of our projection matrix + sky_push_constant.projections[v][0] = p_projections[v].matrix[2][0]; + sky_push_constant.projections[v][1] = p_projections[v].matrix[0][0]; + sky_push_constant.projections[v][2] = p_projections[v].matrix[2][1]; + sky_push_constant.projections[v][3] = p_projections[v].matrix[1][1]; } + sky_push_constant.position[0] = p_position.x; + sky_push_constant.position[1] = p_position.y; + sky_push_constant.position[2] = p_position.z; + sky_push_constant.multiplier = p_multiplier; + sky_push_constant.time = p_time; + store_transform_3x3(p_orientation, sky_push_constant.orientation); - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } + RenderingDevice::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(p_fb); - Vector<RD::Uniform> uniforms; + RD::DrawListID draw_list = p_list; - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, p_pipeline->get_render_pipeline(RD::INVALID_ID, fb_format)); - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.uniform_set, 0); + if (p_uniform_set.is_valid()) { //material may not have uniform set + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1); } + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_singleton->sky.sky_shader.shader.version_get_shader(shader_data->version, 0), SKY_SET_MATERIAL); -} + RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); -RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } + RD::get_singleton()->draw_list_set_push_constant(draw_list, &sky_push_constant, sizeof(SkyPushConstant)); - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } + RD::get_singleton()->draw_list_draw(draw_list, true); } //////////////////////////////////////////////////////////////////////////////// @@ -623,7 +605,7 @@ Ref<Image> RendererSceneSkyRD::Sky::bake_panorama(RendererStorageRD *p_storage, RD::get_singleton()->free(rad_tex); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(p_size.width, p_size.height, false, Image::FORMAT_RGBAF, data); for (int i = 0; i < p_size.width; i++) { for (int j = 0; j < p_size.height; j++) { @@ -694,7 +676,18 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n"); // Cubemap sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_HALF_RES_PASS\n"); // Half Res Cubemap sky_modes.push_back("\n#define USE_CUBEMAP_PASS\n#define USE_QUARTER_RES_PASS\n"); // Quarter res Cubemap + + sky_modes.push_back("\n#define USE_MULTIVIEW\n"); // Full size multiview + sky_modes.push_back("\n#define USE_HALF_RES_PASS\n#define USE_MULTIVIEW\n"); // Half Res multiview + sky_modes.push_back("\n#define USE_QUARTER_RES_PASS\n#define USE_MULTIVIEW\n"); // Quarter res multiview + sky_shader.shader.initialize(sky_modes, defines); + + if (!RendererCompositorRD::singleton->is_xr_enabled()) { + sky_shader.shader.set_variant_enabled(SKY_VERSION_BACKGROUND_MULTIVIEW, false); + sky_shader.shader.set_variant_enabled(SKY_VERSION_HALF_RES_MULTIVIEW, false); + sky_shader.shader.set_variant_enabled(SKY_VERSION_QUARTER_RES_MULTIVIEW, false); + } } // register our shader funds @@ -876,9 +869,44 @@ void RendererSceneSkyRD::init(RendererStorageRD *p_storage) { sky_scene_state.fog_only_texture_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky_shader.default_shader_rd, SKY_SET_TEXTURES); } + + { //create index array for copy shaders + Vector<uint8_t> pv; + pv.resize(6 * 4); + { + uint8_t *w = pv.ptrw(); + int *p32 = (int *)w; + p32[0] = 0; + p32[1] = 1; + p32[2] = 2; + p32[3] = 0; + p32[4] = 2; + p32[5] = 3; + } + index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv); + index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6); + } +} + +RendererSceneSkyRD::~RendererSceneSkyRD() { + // TODO cleanup anything created in init... + + if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.uniform_set)) { + RD::get_singleton()->free(sky_scene_state.uniform_set); + } + + if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.default_fog_uniform_set)) { + RD::get_singleton()->free(sky_scene_state.default_fog_uniform_set); + } + + if (RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_only_texture_uniform_set)) { + RD::get_singleton()->free(sky_scene_state.fog_only_texture_uniform_set); + } + + RD::get_singleton()->free(index_buffer); //array gets freed as dependency } -void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { +void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) { ERR_FAIL_COND(!p_env); // I guess without an environment we also can't have a sky... SkyMaterialData *material = nullptr; @@ -1048,7 +1076,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo); } -void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) { +void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time) { ERR_FAIL_COND(!p_env); Sky *sky = get_sky(p_env->sky); @@ -1135,12 +1163,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM RD::DrawListID cubemap_draw_list; for (int i = 0; i < 6; i++) { - Transform local_view; + Transform3D local_view; local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd); cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } } @@ -1153,12 +1181,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM RD::DrawListID cubemap_draw_list; for (int i = 0; i < 6; i++) { - Transform local_view; + Transform3D local_view; local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd); cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } } @@ -1167,12 +1195,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP]; for (int i = 0; i < 6; i++) { - Transform local_view; + Transform3D local_view; local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]); RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd); cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - storage->get_effects()->render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, cm, local_view.basis, multiplier, p_transform.origin); + _render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view.basis, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } @@ -1213,9 +1241,12 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM } } -void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time) { +void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time) { ERR_FAIL_COND(!p_env); + ERR_FAIL_COND(p_view_count == 0); + ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); + Sky *sky = get_sky(p_env->sky); ERR_FAIL_COND(!sky); @@ -1257,24 +1288,28 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont float multiplier = p_env->bg_energy; float custom_fov = p_env->sky_custom_fov; + // Camera CameraMatrix camera; + uint32_t view_count = p_view_count; + const CameraMatrix *projections = p_projections; if (custom_fov) { - float near_plane = p_projection.get_z_near(); - float far_plane = p_projection.get_z_far(); - float aspect = p_projection.get_aspect(); + // With custom fov we don't support stereo... + float near_plane = p_projections[0].get_z_near(); + float far_plane = p_projections[0].get_z_far(); + float aspect = p_projections[0].get_aspect(); camera.set_perspective(custom_fov, aspect, near_plane, far_plane); - } else { - camera = p_projection; + view_count = 1; + projections = &camera; } sky_transform = p_transform.basis * sky_transform; if (shader_data->uses_quarter_res) { - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_QUARTER_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES]; RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd); @@ -1282,12 +1317,12 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont clear_colors.push_back(Color(0.0, 0.0, 0.0)); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); - storage->get_effects()->render_sky(draw_list, p_time, sky->quarter_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); + _render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } if (shader_data->uses_half_res) { - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_HALF_RES]; + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES]; RID texture_uniform_set = sky->get_textures(storage, SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd); @@ -1295,11 +1330,11 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont clear_colors.push_back(Color(0.0, 0.0, 0.0)); RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); - storage->get_effects()->render_sky(draw_list, p_time, sky->half_res_framebuffer, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); + _render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } - PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_BACKGROUND]; + PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND]; RID texture_uniform_set; if (sky) { @@ -1309,7 +1344,7 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont } RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ); - storage->get_effects()->render_sky(draw_list, p_time, p_fb, sky_scene_state.uniform_set, sky_scene_state.fog_uniform_set, pipeline, material->uniform_set, texture_uniform_set, camera, sky_transform, multiplier, p_transform.origin); + _render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, multiplier, p_transform.origin); RD::get_singleton()->draw_list_end(); } diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 73390a586b..4f852e55a7 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -43,9 +43,6 @@ class RendererSceneRenderRD; class RendererSceneSkyRD { -private: - RendererStorageRD *storage; - public: enum SkySet { SKY_SET_UNIFORMS, @@ -55,6 +52,22 @@ public: SKY_SET_MAX }; + // Skys need less info from Directional Lights than the normal shaders + struct SkyDirectionalLightData { + float direction[3]; + float energy; + float color[3]; + float size; + uint32_t enabled; + uint32_t pad[3]; + }; + +private: + RendererStorageRD *storage; + + RID index_buffer; + RID index_array; + enum SkyTextureSetVersion { SKY_TEXTURE_SET_BACKGROUND, SKY_TEXTURE_SET_HALF_RES, @@ -72,19 +85,61 @@ public: SKY_VERSION_CUBEMAP, SKY_VERSION_CUBEMAP_HALF_RES, SKY_VERSION_CUBEMAP_QUARTER_RES, + + SKY_VERSION_BACKGROUND_MULTIVIEW, + SKY_VERSION_HALF_RES_MULTIVIEW, + SKY_VERSION_QUARTER_RES_MULTIVIEW, + SKY_VERSION_MAX }; - // Skys need less info from Directional Lights than the normal shaders - struct SkyDirectionalLightData { - float direction[3]; - float energy; - float color[3]; - float size; - uint32_t enabled; - uint32_t pad[3]; + struct SkyPushConstant { + float orientation[12]; // 48 - 48 + float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80 + float position[3]; // 12 - 92 + float multiplier; // 4 - 96 + float time; // 4 - 100 + float pad[3]; // 12 - 112 // Using pad to align on 16 bytes + // 128 is the max size of a push constant. We can replace "pad" but we can't add any more. }; + struct SkyShaderData : public RendererStorageRD::ShaderData { + bool valid; + RID version; + + PipelineCacheRD pipelines[SKY_VERSION_MAX]; + Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; + Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + + Vector<uint32_t> ubo_offsets; + uint32_t ubo_size; + + String path; + String code; + Map<StringName, RID> default_texture_params; + + bool uses_time; + bool uses_position; + bool uses_half_res; + bool uses_quarter_res; + bool uses_light; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + SkyShaderData(); + virtual ~SkyShaderData(); + }; + + void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const CameraMatrix *p_projections, const Basis &p_orientation, float p_multiplier, const Vector3 &p_position); + +public: struct SkySceneState { struct UBO { uint32_t volumetric_fog_enabled; @@ -155,40 +210,6 @@ public: void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end); }; - struct SkyShaderData : public RendererStorageRD::ShaderData { - bool valid; - RID version; - - PipelineCacheRD pipelines[SKY_VERSION_MAX]; - Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; - Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; - - Vector<uint32_t> ubo_offsets; - uint32_t ubo_size; - - String path; - String code; - Map<StringName, RID> default_texture_params; - - bool uses_time; - bool uses_position; - bool uses_half_res; - bool uses_quarter_res; - bool uses_light; - - virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); - virtual void get_param_list(List<PropertyInfo> *p_param_list) const; - virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; - virtual bool is_param_texture(const StringName &p_param) const; - virtual bool is_animated() const; - virtual bool casts_shadows() const; - virtual Variant get_default_parameter(const StringName &p_parameter) const; - virtual RS::ShaderNativeSourceCode get_native_source_code() const; - SkyShaderData(); - virtual ~SkyShaderData(); - }; - /* Sky shader */ struct SkyShader { @@ -203,15 +224,12 @@ public: struct SkyMaterialData : public RendererStorageRD::MaterialData { uint64_t last_frame; SkyShaderData *shader_data; - RID uniform_buffer; RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; bool uniform_set_updated; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); virtual ~SkyMaterialData(); }; @@ -265,12 +283,12 @@ public: static RendererStorageRD::MaterialData *_create_sky_material_funcs(RendererStorageRD::ShaderData *p_shader); RendererSceneSkyRD(); - void init(RendererStorageRD *p_storage); + ~RendererSceneSkyRD(); - void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); - void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform &p_transform, double p_time); - void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, const CameraMatrix &p_projection, const Transform &p_transform, double p_time); + void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render); + void update(RendererSceneEnvironmentRD *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform, double p_time); + void draw(RendererSceneEnvironmentRD *p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const CameraMatrix *p_projections, const Transform3D &p_transform, double p_time); void invalidate_sky(Sky *p_sky); void update_dirty_skys(); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 7a26e40c0a..6738f499bd 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -35,6 +35,7 @@ #include "core/io/resource_loader.h" #include "core/math/math_defs.h" #include "renderer_compositor_rd.h" +#include "servers/rendering/rendering_server_globals.h" #include "servers/rendering/shader_language.h" bool RendererStorageRD::can_create_resources_async() const { @@ -883,10 +884,6 @@ void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_im RD::get_singleton()->texture_update(tex->rd_texture, p_layer, validated->get_data()); } -void RendererStorageRD::texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer) { - _texture_2d_update(p_texture, p_image, p_layer, true); -} - void RendererStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer) { _texture_2d_update(p_texture, p_image, p_layer, false); } @@ -972,7 +969,7 @@ void RendererStorageRD::texture_2d_placeholder_initialize(RID p_texture) { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; - image.instance(); + image.instantiate(); image->create(4, 4, false, Image::FORMAT_RGBA8); for (int i = 0; i < 4; i++) { @@ -988,7 +985,7 @@ void RendererStorageRD::texture_2d_layered_placeholder_initialize(RID p_texture, //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; - image.instance(); + image.instantiate(); image->create(4, 4, false, Image::FORMAT_RGBA8); for (int i = 0; i < 4; i++) { @@ -1014,7 +1011,7 @@ void RendererStorageRD::texture_3d_placeholder_initialize(RID p_texture) { //this could be better optimized to reuse an existing image , done this way //for now to get it working Ref<Image> image; - image.instance(); + image.instantiate(); image->create(4, 4, false, Image::FORMAT_RGBA8); for (int i = 0; i < 4; i++) { @@ -1044,7 +1041,7 @@ Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const { Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); ERR_FAIL_COND_V(data.size() == 0, Ref<Image>()); Ref<Image> image; - image.instance(); + image.instantiate(); image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); ERR_FAIL_COND_V(image->is_empty(), Ref<Image>()); if (tex->format != tex->validated_format) { @@ -1067,7 +1064,7 @@ Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) c Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, p_layer); ERR_FAIL_COND_V(data.size() == 0, Ref<Image>()); Ref<Image> image; - image.instance(); + image.instantiate(); image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); ERR_FAIL_COND_V(image->is_empty(), Ref<Image>()); if (tex->format != tex->validated_format) { @@ -1095,7 +1092,7 @@ Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { Vector<uint8_t> sub_region = all_data.subarray(bs.offset, bs.offset + bs.buffer_size - 1); Ref<Image> img; - img.instance(); + img.instantiate(); img->create(bs.size.width, bs.size.height, false, tex->validated_format, sub_region); ERR_FAIL_COND_V(img->is_empty(), Vector<Ref<Image>>()); if (tex->format != tex->validated_format) { @@ -1234,7 +1231,7 @@ RID RendererStorageRD::canvas_texture_allocate() { return canvas_texture_owner.allocate_rid(); } void RendererStorageRD::canvas_texture_initialize(RID p_rid) { - canvas_texture_owner.initialize_rid(p_rid, memnew(CanvasTexture)); + canvas_texture_owner.initialize_rid(p_rid); } void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { @@ -1440,8 +1437,10 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { material->shader_type = new_type; } - for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) { - shader->data->set_default_texture_param(E->key(), E->get()); + if (shader->data) { + for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) { + shader->data->set_default_texture_param(E->key(), E->get()); + } } } @@ -1527,27 +1526,18 @@ RID RendererStorageRD::material_allocate() { return material_owner.allocate_rid(); } void RendererStorageRD::material_initialize(RID p_rid) { - Material material; - material.data = nullptr; - material.shader = nullptr; - material.shader_type = SHADER_TYPE_MAX; - material.update_next = nullptr; - material.update_requested = false; - material.uniform_dirty = false; - material.texture_dirty = false; - material.priority = 0; - material.self = p_rid; - material_owner.initialize_rid(p_rid, material); + material_owner.initialize_rid(p_rid); + Material *material = material_owner.getornull(p_rid); + material->self = p_rid; } void RendererStorageRD::_material_queue_update(Material *material, bool p_uniform, bool p_texture) { - if (material->update_requested) { + if (material->update_element.in_list()) { return; } - material->update_next = material_update_list; - material_update_list = material; - material->update_requested = true; + material_update_list.add(&material->update_element); + material->uniform_dirty = material->uniform_dirty || p_uniform; material->texture_dirty = material->texture_dirty || p_texture; } @@ -1602,6 +1592,7 @@ void RendererStorageRD::material_set_param(RID p_material, const StringName &p_p if (p_value.get_type() == Variant::NIL) { material->params.erase(p_param); } else { + ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); //object not allowed material->params[p_param] = p_value; } @@ -1878,8 +1869,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy gui[1] = v.position.y; gui[2] = v.size.x; gui[3] = v.size.y; - } else if (value.get_type() == Variant::QUAT) { - Quat v = value; + } else if (value.get_type() == Variant::QUATERNION) { + Quaternion v = value; gui[0] = v.x; gui[1] = v.y; @@ -1926,7 +1917,7 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy gui[11] = 0; } break; case ShaderLanguage::TYPE_MAT4: { - Transform v = value; + Transform3D v = value; float *gui = (float *)data; gui[0] = v.basis.elements[0][0]; @@ -2233,6 +2224,10 @@ RendererStorageRD::MaterialData::~MaterialData() { //unregister material from those using global textures rs->global_variables.materials_using_texture.erase(global_texture_E); } + + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + } } void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { @@ -2382,6 +2377,105 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari } } +void RendererStorageRD::MaterialData::free_parameters_uniform_set(RID p_uniform_set) { + if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) { + RD::get_singleton()->uniform_set_set_invalidation_callback(p_uniform_set, nullptr, nullptr); + RD::get_singleton()->free(p_uniform_set); + } +} + +bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, RID> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) { + if ((uint32_t)ubo_data.size() != p_ubo_size) { + p_uniform_dirty = true; + if (uniform_buffer.is_valid()) { + RD::get_singleton()->free(uniform_buffer); + uniform_buffer = RID(); + } + + ubo_data.resize(p_ubo_size); + if (ubo_data.size()) { + uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); + memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear + } + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, nullptr, nullptr); + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + //check whether buffer changed + if (p_uniform_dirty && ubo_data.size()) { + update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), false); + RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier); + } + + uint32_t tex_uniform_count = p_texture_uniforms.size(); + + if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) { + texture_cache.resize(tex_uniform_count); + p_textures_dirty = true; + + //clear previous uniform set + if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, nullptr, nullptr); + RD::get_singleton()->free(uniform_set); + uniform_set = RID(); + } + } + + if (p_textures_dirty && tex_uniform_count) { + update_textures(p_parameters, p_default_texture_params, p_texture_uniforms, texture_cache.ptrw(), true); + } + + if (p_ubo_size == 0 && p_texture_uniforms.size() == 0) { + // This material does not require an uniform set, so don't create it. + return false; + } + + if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { + //no reason to update uniform set, only UBO (or nothing) was needed to update + return false; + } + + Vector<RD::Uniform> uniforms; + + { + if (p_ubo_size) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 0; + u.ids.push_back(uniform_buffer); + uniforms.push_back(u); + } + + const RID *textures = texture_cache.ptrw(); + for (uint32_t i = 0; i < tex_uniform_count; i++) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 1 + i; + u.ids.push_back(textures[i]); + uniforms.push_back(u); + } + } + + uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_shader_uniform_set); + + RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, _material_uniform_set_erased, &self); + + return true; +} + +void RendererStorageRD::_material_uniform_set_erased(const RID &p_set, void *p_material) { + RID rid = *(RID *)p_material; + Material *material = base_singleton->material_owner.getornull(rid); + if (material) { + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); + } +} + void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { Material *material = material_owner.getornull(p_material); if (material->shader_type != p_shader_type) { @@ -2393,20 +2487,23 @@ void RendererStorageRD::material_force_update_textures(RID p_material, ShaderTyp } void RendererStorageRD::_update_queued_materials() { - Material *material = material_update_list; - while (material) { - Material *next = material->update_next; + while (material_update_list.first()) { + Material *material = material_update_list.first()->self(); + bool uniforms_changed = false; if (material->data) { - material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty); + uniforms_changed = material->data->update_parameters(material->params, material->uniform_dirty, material->texture_dirty); } - material->update_requested = false; material->texture_dirty = false; material->uniform_dirty = false; - material->update_next = nullptr; - material = next; + + material_update_list.remove(&material->update_element); + + if (uniforms_changed) { + //some implementations such as 3D renderer cache the matreial uniform set, so update is required + material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); + } } - material_update_list = nullptr; } /* MESH API */ @@ -2461,7 +2558,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su } break; case RS::ARRAY_COLOR: { - attrib_stride += sizeof(int16_t) * 4; + attrib_stride += sizeof(uint32_t); } break; case RS::ARRAY_TEX_UV: { attrib_stride += sizeof(float) * 2; @@ -2549,6 +2646,7 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su s->lods[i].index_buffer = RD::get_singleton()->index_buffer_create(indices, is_index_16 ? RD::INDEX_BUFFER_FORMAT_UINT16 : RD::INDEX_BUFFER_FORMAT_UINT32, p_surface.lods[i].index_data); s->lods[i].index_array = RD::get_singleton()->index_array_create(s->lods[i].index_buffer, 0, indices); s->lods[i].edge_length = p_surface.lods[i].edge_length; + s->lods[i].index_count = indices; } } } @@ -2653,7 +2751,7 @@ RS::BlendShapeMode RendererStorageRD::mesh_get_blend_shape_mode(RID p_mesh) cons return mesh->blend_shape_mode; } -void RendererStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { +void RendererStorageRD::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); @@ -2664,6 +2762,30 @@ void RendererStorageRD::mesh_surface_update_region(RID p_mesh, int p_surface, in RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->vertex_buffer, p_offset, data_size, r); } +void RendererStorageRD::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); + ERR_FAIL_COND(p_data.size() == 0); + ERR_FAIL_COND(mesh->surfaces[p_surface]->attribute_buffer.is_null()); + uint64_t data_size = p_data.size(); + const uint8_t *r = p_data.ptr(); + + RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->attribute_buffer, p_offset, data_size, r); +} + +void RendererStorageRD::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { + Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND(!mesh); + ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); + ERR_FAIL_COND(p_data.size() == 0); + ERR_FAIL_COND(mesh->surfaces[p_surface]->skin_buffer.is_null()); + uint64_t data_size = p_data.size(); + const uint8_t *r = p_data.ptr(); + + RD::get_singleton()->buffer_update(mesh->surfaces[p_surface]->skin_buffer, p_offset, data_size, r); +} + void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); @@ -2776,7 +2898,7 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { const float *dataptr = baseptr + j * 8; - Transform mtx; + Transform3D mtx; mtx.basis.elements[0].x = dataptr[0]; mtx.basis.elements[1].x = dataptr[1]; @@ -2803,7 +2925,7 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { const float *dataptr = baseptr + j * 12; - Transform mtx; + Transform3D mtx; mtx.basis.elements[0][0] = dataptr[0]; mtx.basis.elements[0][1] = dataptr[1]; @@ -2932,7 +3054,8 @@ RID RendererStorageRD::mesh_instance_create(RID p_base) { Mesh *mesh = mesh_owner.getornull(p_base); ERR_FAIL_COND_V(!mesh, RID()); - MeshInstance *mi = memnew(MeshInstance); + RID rid = mesh_instance_owner.make_rid(); + MeshInstance *mi = mesh_instance_owner.getornull(rid); mi->mesh = mesh; @@ -2944,7 +3067,7 @@ RID RendererStorageRD::mesh_instance_create(RID p_base) { mi->dirty = true; - return mesh_instance_owner.make_rid(mi); + return rid; } void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) { MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); @@ -3231,8 +3354,8 @@ void RendererStorageRD::_mesh_surface_generate_version_for_input_mask(Mesh::Surf case RS::ARRAY_COLOR: { vd.offset = attribute_stride; - vd.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - attribute_stride += sizeof(int16_t) * 4; + vd.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + attribute_stride += sizeof(int8_t) * 4; buffer = s->attribute_buffer; } break; case RS::ARRAY_TEX_UV: { @@ -3478,7 +3601,7 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl AABB mesh_aabb = mesh_get_aabb(multimesh->mesh); for (int i = 0; i < p_instances; i++) { const float *data = p_data + multimesh->stride_cache * i; - Transform t; + Transform3D t; if (multimesh->xform_format == RS::MULTIMESH_TRANSFORM_3D) { t.basis.elements[0][0] = data[0]; @@ -3514,7 +3637,7 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl multimesh->aabb = aabb; } -void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) { +void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); @@ -3621,15 +3744,15 @@ RID RendererStorageRD::multimesh_get_mesh(RID p_multimesh) const { return multimesh->mesh; } -Transform RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { +Transform3D RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); - ERR_FAIL_COND_V(!multimesh, Transform()); - ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform()); - ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform()); + ERR_FAIL_COND_V(!multimesh, Transform3D()); + ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D()); + ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D()); _multimesh_make_local(multimesh); - Transform t; + Transform3D t; { const float *r = multimesh->data_cache.ptr(); @@ -3823,7 +3946,7 @@ void RendererStorageRD::_update_dirty_multimeshes() { if (multimesh->data_cache_used_dirty_regions) { uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; - uint32_t visible_region_count = (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; + uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float); @@ -3894,6 +4017,7 @@ void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) } bool RendererStorageRD::particles_get_emitting(RID p_particles) { + ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); @@ -4065,7 +4189,7 @@ void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, flo particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); } -void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) { +void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) { @@ -4161,7 +4285,7 @@ void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitt } } -void RendererStorageRD::particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { +void RendererStorageRD::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(particles->amount == 0); @@ -4216,6 +4340,10 @@ void RendererStorageRD::particles_request_process(RID p_particles) { } AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { + if (RSG::threaded) { + WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care."); + } + const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); @@ -4229,7 +4357,7 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer); - Transform inv = particles->emission_transform.affine_inverse(); + Transform3D inv = particles->emission_transform.affine_inverse(); AABB aabb; if (buffer.size()) { @@ -4272,7 +4400,7 @@ AABB RendererStorageRD::particles_get_aabb(RID p_particles) const { return particles->custom_aabb; } -void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform &p_transform) { +void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) { Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); @@ -4396,7 +4524,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta frame_params.randomness = p_particles->randomness; if (p_particles->use_local_coords) { - store_transform(Transform(), frame_params.emission_transform); + store_transform(Transform3D(), frame_params.emission_transform); } else { store_transform(p_particles->emission_transform, frame_params.emission_transform); } @@ -4416,7 +4544,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta RID collision_3d_textures[ParticlesFrameParams::MAX_3D_TEXTURES]; RID collision_heightmap_texture; - Transform to_particles; + Transform3D to_particles; if (p_particles->use_local_coords) { to_particles = p_particles->emission_transform.affine_inverse(); } @@ -4473,7 +4601,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, float p_delta ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision); ERR_CONTINUE(!pc); - Transform to_collider = pci->transform; + Transform3D to_collider = pci->transform; if (p_particles->use_local_coords) { to_collider = to_particles * to_collider; } @@ -5100,6 +5228,7 @@ void RendererStorageRD::update_particles() { } bool RendererStorageRD::particles_is_inactive(RID p_particles) const { + ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, false); return !particles->emitting && particles->inactive; @@ -5250,94 +5379,14 @@ RendererStorageRD::ShaderData *RendererStorageRD::_create_particles_shader_func( return shader_data; } -void RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { +bool RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { uniform_set_updated = true; - if ((uint32_t)ubo_data.size() != shader_data->ubo_size) { - p_uniform_dirty = true; - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - uniform_buffer = RID(); - } - - ubo_data.resize(shader_data->ubo_size); - if (ubo_data.size()) { - uniform_buffer = RD::get_singleton()->uniform_buffer_create(ubo_data.size()); - memset(ubo_data.ptrw(), 0, ubo_data.size()); //clear - } - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - //check whether buffer changed - if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(shader_data->uniforms, shader_data->ubo_offsets.ptr(), p_parameters, ubo_data.ptrw(), ubo_data.size(), false); - RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw()); - } - - uint32_t tex_uniform_count = shader_data->texture_uniforms.size(); - - if ((uint32_t)texture_cache.size() != tex_uniform_count) { - texture_cache.resize(tex_uniform_count); - p_textures_dirty = true; - - //clear previous uniform set - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - uniform_set = RID(); - } - } - - if (p_textures_dirty && tex_uniform_count) { - update_textures(p_parameters, shader_data->default_texture_params, shader_data->texture_uniforms, texture_cache.ptrw(), true); - } - - if (shader_data->ubo_size == 0 && shader_data->texture_uniforms.size() == 0) { - // This material does not require an uniform set, so don't create it. - return; - } - - if (!p_textures_dirty && uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - //no reason to update uniform set, only UBO (or nothing) was needed to update - return; - } - - Vector<RD::Uniform> uniforms; - - { - if (shader_data->ubo_size) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; - u.binding = 0; - u.ids.push_back(uniform_buffer); - uniforms.push_back(u); - } - - const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); - uniforms.push_back(u); - } - } - - uniform_set = RD::get_singleton()->uniform_set_create(uniforms, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, base_singleton->particles_shader.shader.version_get_shader(shader_data->version, 0), 3); } RendererStorageRD::ParticlesMaterialData::~ParticlesMaterialData() { - if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) { - RD::get_singleton()->free(uniform_set); - } - - if (uniform_buffer.is_valid()) { - RD::get_singleton()->free(uniform_buffer); - } + free_parameters_uniform_set(uniform_set); } RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) { @@ -5522,7 +5571,7 @@ RID RendererStorageRD::particles_collision_instance_create(RID p_collision) { pci.collision = p_collision; return particles_collision_instance_owner.make_rid(pci); } -void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) { +void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) { ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); ERR_FAIL_COND(!pci); pci->transform = p_transform; @@ -5533,6 +5582,59 @@ void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_ pci->active = p_active; } +/* VISIBILITY NOTIFIER */ + +RID RendererStorageRD::visibility_notifier_allocate() { + return visibility_notifier_owner.allocate_rid(); +} +void RendererStorageRD::visibility_notifier_initialize(RID p_notifier) { + visibility_notifier_owner.initialize_rid(p_notifier, VisibilityNotifier()); +} +void RendererStorageRD::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND(!vn); + vn->aabb = p_aabb; + vn->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); +} +void RendererStorageRD::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND(!vn); + vn->enter_callback = p_enter_callbable; + vn->exit_callback = p_exit_callable; +} + +AABB RendererStorageRD::visibility_notifier_get_aabb(RID p_notifier) const { + const VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND_V(!vn, AABB()); + return vn->aabb; +} +void RendererStorageRD::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + ERR_FAIL_COND(!vn); + + if (p_enter) { + if (!vn->enter_callback.is_null()) { + if (p_deferred) { + vn->enter_callback.call_deferred(nullptr, 0); + } else { + Variant r; + Callable::CallError ce; + vn->enter_callback.call(nullptr, 0, r, ce); + } + } + } else { + if (!vn->exit_callback.is_null()) { + if (p_deferred) { + vn->exit_callback.call_deferred(nullptr, 0); + } else { + Variant r; + Callable::CallError ce; + vn->exit_callback.call(nullptr, 0, r, ce); + } + } + } +} + /* SKELETON API */ RID RendererStorageRD::skeleton_allocate() { @@ -5600,7 +5702,7 @@ int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const { return skeleton->size; } -void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) { +void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); ERR_FAIL_COND(!skeleton); @@ -5625,16 +5727,16 @@ void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, _skeleton_make_dirty(skeleton); } -Transform RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { +Transform3D RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); - ERR_FAIL_COND_V(!skeleton, Transform()); - ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform()); - ERR_FAIL_COND_V(skeleton->use_2d, Transform()); + ERR_FAIL_COND_V(!skeleton, Transform3D()); + ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D()); + ERR_FAIL_COND_V(skeleton->use_2d, Transform3D()); const float *dataptr = skeleton->data.ptr() + p_bone * 12; - Transform t; + Transform3D t; t.basis.elements[0][0] = dataptr[0]; t.basis.elements[0][1] = dataptr[1]; @@ -5948,20 +6050,6 @@ RS::LightDirectionalShadowMode RendererStorageRD::light_directional_get_shadow_m return light->directional_shadow_mode; } -void RendererStorageRD::light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) { - Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND(!light); - - light->directional_range_mode = p_range_mode; -} - -RS::LightDirectionalShadowDepthRangeMode RendererStorageRD::light_directional_get_shadow_depth_range_mode(RID p_light) const { - const Light *light = light_owner.getornull(p_light); - ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); - - return light->directional_range_mode; -} - uint32_t RendererStorageRD::light_get_max_sdfgi_cascade(RID p_light) { const Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, 0); @@ -6324,36 +6412,36 @@ AABB RendererStorageRD::decal_get_aabb(RID p_decal) const { return AABB(-decal->extents, decal->extents * 2.0); } -RID RendererStorageRD::gi_probe_allocate() { - return gi_probe_owner.allocate_rid(); +RID RendererStorageRD::voxel_gi_allocate() { + return voxel_gi_owner.allocate_rid(); } -void RendererStorageRD::gi_probe_initialize(RID p_gi_probe) { - gi_probe_owner.initialize_rid(p_gi_probe, GIProbe()); +void RendererStorageRD::voxel_gi_initialize(RID p_voxel_gi) { + voxel_gi_owner.initialize_rid(p_voxel_gi, VoxelGI()); } -void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - if (gi_probe->octree_buffer.is_valid()) { - RD::get_singleton()->free(gi_probe->octree_buffer); - RD::get_singleton()->free(gi_probe->data_buffer); - if (gi_probe->sdf_texture.is_valid()) { - RD::get_singleton()->free(gi_probe->sdf_texture); + if (voxel_gi->octree_buffer.is_valid()) { + RD::get_singleton()->free(voxel_gi->octree_buffer); + RD::get_singleton()->free(voxel_gi->data_buffer); + if (voxel_gi->sdf_texture.is_valid()) { + RD::get_singleton()->free(voxel_gi->sdf_texture); } - gi_probe->sdf_texture = RID(); - gi_probe->octree_buffer = RID(); - gi_probe->data_buffer = RID(); - gi_probe->octree_buffer_size = 0; - gi_probe->data_buffer_size = 0; - gi_probe->cell_count = 0; + voxel_gi->sdf_texture = RID(); + voxel_gi->octree_buffer = RID(); + voxel_gi->data_buffer = RID(); + voxel_gi->octree_buffer_size = 0; + voxel_gi->data_buffer_size = 0; + voxel_gi->cell_count = 0; } - gi_probe->to_cell_xform = p_to_cell_xform; - gi_probe->bounds = p_aabb; - gi_probe->octree_size = p_octree_size; - gi_probe->level_counts = p_level_counts; + voxel_gi->to_cell_xform = p_to_cell_xform; + voxel_gi->bounds = p_aabb; + voxel_gi->octree_size = p_octree_size; + voxel_gi->level_counts = p_level_counts; if (p_octree_cells.size()) { ERR_FAIL_COND(p_octree_cells.size() % 32 != 0); //cells size must be a multiple of 32 @@ -6362,42 +6450,42 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform & ERR_FAIL_COND(p_data_cells.size() != (int)cell_count * 16); //see that data size matches - gi_probe->cell_count = cell_count; - gi_probe->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells); - gi_probe->octree_buffer_size = p_octree_cells.size(); - gi_probe->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells); - gi_probe->data_buffer_size = p_data_cells.size(); + voxel_gi->cell_count = cell_count; + voxel_gi->octree_buffer = RD::get_singleton()->storage_buffer_create(p_octree_cells.size(), p_octree_cells); + voxel_gi->octree_buffer_size = p_octree_cells.size(); + voxel_gi->data_buffer = RD::get_singleton()->storage_buffer_create(p_data_cells.size(), p_data_cells); + voxel_gi->data_buffer_size = p_data_cells.size(); if (p_distance_field.size()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = gi_probe->octree_size.x; - tf.height = gi_probe->octree_size.y; - tf.depth = gi_probe->octree_size.z; + tf.width = voxel_gi->octree_size.x; + tf.height = voxel_gi->octree_size.y; + tf.depth = voxel_gi->octree_size.z; tf.texture_type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; Vector<Vector<uint8_t>> s; s.push_back(p_distance_field); - gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s); + voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView(), s); } #if 0 { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = gi_probe->octree_size.x; - tf.height = gi_probe->octree_size.y; - tf.depth = gi_probe->octree_size.z; + tf.width = voxel_gi->octree_size.x; + tf.height = voxel_gi->octree_size.y; + tf.depth = voxel_gi->octree_size.z; tf.type = RD::TEXTURE_TYPE_3D; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UNORM); tf.shareable_formats.push_back(RD::DATA_FORMAT_R8_UINT); - gi_probe->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + voxel_gi->sdf_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); } RID shared_tex; { RD::TextureView tv; tv.format_override = RD::DATA_FORMAT_R8_UINT; - shared_tex = RD::get_singleton()->texture_create_shared(tv, gi_probe->sdf_texture); + shared_tex = RD::get_singleton()->texture_create_shared(tv, voxel_gi->sdf_texture); } //update SDF texture Vector<RD::Uniform> uniforms; @@ -6405,14 +6493,14 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform & RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 1; - u.ids.push_back(gi_probe->octree_buffer); + u.ids.push_back(voxel_gi->octree_buffer); uniforms.push_back(u); } { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 2; - u.ids.push_back(gi_probe->data_buffer); + u.ids.push_back(voxel_gi->data_buffer); uniforms.push_back(u); } { @@ -6423,24 +6511,24 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform & uniforms.push_back(u); } - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, giprobe_sdf_shader_version_shader, 0); + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, voxel_gi_sdf_shader_version_shader, 0); { uint32_t push_constant[4] = { 0, 0, 0, 0 }; - for (int i = 0; i < gi_probe->level_counts.size() - 1; i++) { - push_constant[0] += gi_probe->level_counts[i]; + for (int i = 0; i < voxel_gi->level_counts.size() - 1; i++) { + push_constant[0] += voxel_gi->level_counts[i]; } - push_constant[1] = push_constant[0] + gi_probe->level_counts[gi_probe->level_counts.size() - 1]; + push_constant[1] = push_constant[0] + voxel_gi->level_counts[voxel_gi->level_counts.size() - 1]; print_line("offset: " + itos(push_constant[0])); print_line("size: " + itos(push_constant[1])); //create SDF RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, giprobe_sdf_shader_pipeline); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, voxel_gi_sdf_shader_pipeline); RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0); RD::get_singleton()->compute_list_set_push_constant(compute_list, push_constant, sizeof(uint32_t) * 4); - RD::get_singleton()->compute_list_dispatch(compute_list, gi_probe->octree_size.x / 4, gi_probe->octree_size.y / 4, gi_probe->octree_size.z / 4); + RD::get_singleton()->compute_list_dispatch(compute_list, voxel_gi->octree_size.x / 4, voxel_gi->octree_size.y / 4, voxel_gi->octree_size.z / 4); RD::get_singleton()->compute_list_end(); } @@ -6450,232 +6538,206 @@ void RendererStorageRD::gi_probe_allocate_data(RID p_gi_probe, const Transform & #endif } - gi_probe->version++; - gi_probe->data_version++; + voxel_gi->version++; + voxel_gi->data_version++; - gi_probe->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); + voxel_gi->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } -AABB RendererStorageRD::gi_probe_get_bounds(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, AABB()); +AABB RendererStorageRD::voxel_gi_get_bounds(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, AABB()); - return gi_probe->bounds; + return voxel_gi->bounds; } -Vector3i RendererStorageRD::gi_probe_get_octree_size(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, Vector3i()); - return gi_probe->octree_size; +Vector3i RendererStorageRD::voxel_gi_get_octree_size(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, Vector3i()); + return voxel_gi->octree_size; } -Vector<uint8_t> RendererStorageRD::gi_probe_get_octree_cells(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); +Vector<uint8_t> RendererStorageRD::voxel_gi_get_octree_cells(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>()); - if (gi_probe->octree_buffer.is_valid()) { - return RD::get_singleton()->buffer_get_data(gi_probe->octree_buffer); + if (voxel_gi->octree_buffer.is_valid()) { + return RD::get_singleton()->buffer_get_data(voxel_gi->octree_buffer); } return Vector<uint8_t>(); } -Vector<uint8_t> RendererStorageRD::gi_probe_get_data_cells(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); +Vector<uint8_t> RendererStorageRD::voxel_gi_get_data_cells(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>()); - if (gi_probe->data_buffer.is_valid()) { - return RD::get_singleton()->buffer_get_data(gi_probe->data_buffer); + if (voxel_gi->data_buffer.is_valid()) { + return RD::get_singleton()->buffer_get_data(voxel_gi->data_buffer); } return Vector<uint8_t>(); } -Vector<uint8_t> RendererStorageRD::gi_probe_get_distance_field(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, Vector<uint8_t>()); +Vector<uint8_t> RendererStorageRD::voxel_gi_get_distance_field(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>()); - if (gi_probe->data_buffer.is_valid()) { - return RD::get_singleton()->texture_get_data(gi_probe->sdf_texture, 0); + if (voxel_gi->data_buffer.is_valid()) { + return RD::get_singleton()->texture_get_data(voxel_gi->sdf_texture, 0); } return Vector<uint8_t>(); } -Vector<int> RendererStorageRD::gi_probe_get_level_counts(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, Vector<int>()); +Vector<int> RendererStorageRD::voxel_gi_get_level_counts(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, Vector<int>()); - return gi_probe->level_counts; + return voxel_gi->level_counts; } -Transform RendererStorageRD::gi_probe_get_to_cell_xform(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, Transform()); +Transform3D RendererStorageRD::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, Transform3D()); - return gi_probe->to_cell_xform; + return voxel_gi->to_cell_xform; } -void RendererStorageRD::gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->dynamic_range = p_range; - gi_probe->version++; + voxel_gi->dynamic_range = p_range; + voxel_gi->version++; } -float RendererStorageRD::gi_probe_get_dynamic_range(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); +float RendererStorageRD::voxel_gi_get_dynamic_range(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); - return gi_probe->dynamic_range; + return voxel_gi->dynamic_range; } -void RendererStorageRD::gi_probe_set_propagation(RID p_gi_probe, float p_range) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->propagation = p_range; - gi_probe->version++; + voxel_gi->propagation = p_range; + voxel_gi->version++; } -float RendererStorageRD::gi_probe_get_propagation(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->propagation; +float RendererStorageRD::voxel_gi_get_propagation(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->propagation; } -void RendererStorageRD::gi_probe_set_energy(RID p_gi_probe, float p_energy) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_energy(RID p_voxel_gi, float p_energy) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->energy = p_energy; + voxel_gi->energy = p_energy; } -float RendererStorageRD::gi_probe_get_energy(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->energy; +float RendererStorageRD::voxel_gi_get_energy(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->energy; } -void RendererStorageRD::gi_probe_set_ao(RID p_gi_probe, float p_ao) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_bias(RID p_voxel_gi, float p_bias) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->ao = p_ao; + voxel_gi->bias = p_bias; } -float RendererStorageRD::gi_probe_get_ao(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->ao; +float RendererStorageRD::voxel_gi_get_bias(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->bias; } -void RendererStorageRD::gi_probe_set_ao_size(RID p_gi_probe, float p_strength) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_normal_bias) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->ao_size = p_strength; + voxel_gi->normal_bias = p_normal_bias; } -float RendererStorageRD::gi_probe_get_ao_size(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->ao_size; +float RendererStorageRD::voxel_gi_get_normal_bias(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->normal_bias; } -void RendererStorageRD::gi_probe_set_bias(RID p_gi_probe, float p_bias) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->bias = p_bias; + voxel_gi->anisotropy_strength = p_strength; } -float RendererStorageRD::gi_probe_get_bias(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->bias; +float RendererStorageRD::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->anisotropy_strength; } -void RendererStorageRD::gi_probe_set_normal_bias(RID p_gi_probe, float p_normal_bias) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); - - gi_probe->normal_bias = p_normal_bias; -} +void RendererStorageRD::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); -float RendererStorageRD::gi_probe_get_normal_bias(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->normal_bias; + voxel_gi->interior = p_enable; } -void RendererStorageRD::gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); +void RendererStorageRD::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND(!voxel_gi); - gi_probe->anisotropy_strength = p_strength; + voxel_gi->use_two_bounces = p_enable; + voxel_gi->version++; } -float RendererStorageRD::gi_probe_get_anisotropy_strength(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->anisotropy_strength; +bool RendererStorageRD::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, false); + return voxel_gi->use_two_bounces; } -void RendererStorageRD::gi_probe_set_interior(RID p_gi_probe, bool p_enable) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); - - gi_probe->interior = p_enable; +bool RendererStorageRD::voxel_gi_is_interior(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->interior; } -void RendererStorageRD::gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND(!gi_probe); - - gi_probe->use_two_bounces = p_enable; - gi_probe->version++; +uint32_t RendererStorageRD::voxel_gi_get_version(RID p_voxel_gi) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->version; } -bool RendererStorageRD::gi_probe_is_using_two_bounces(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, false); - return gi_probe->use_two_bounces; +uint32_t RendererStorageRD::voxel_gi_get_data_version(RID p_voxel_gi) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, 0); + return voxel_gi->data_version; } -bool RendererStorageRD::gi_probe_is_interior(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->interior; +RID RendererStorageRD::voxel_gi_get_octree_buffer(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, RID()); + return voxel_gi->octree_buffer; } -uint32_t RendererStorageRD::gi_probe_get_version(RID p_gi_probe) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->version; +RID RendererStorageRD::voxel_gi_get_data_buffer(RID p_voxel_gi) const { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, RID()); + return voxel_gi->data_buffer; } -uint32_t RendererStorageRD::gi_probe_get_data_version(RID p_gi_probe) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, 0); - return gi_probe->data_version; -} +RID RendererStorageRD::voxel_gi_get_sdf_texture(RID p_voxel_gi) { + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + ERR_FAIL_COND_V(!voxel_gi, RID()); -RID RendererStorageRD::gi_probe_get_octree_buffer(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, RID()); - return gi_probe->octree_buffer; -} - -RID RendererStorageRD::gi_probe_get_data_buffer(RID p_gi_probe) const { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, RID()); - return gi_probe->data_buffer; -} - -RID RendererStorageRD::gi_probe_get_sdf_texture(RID p_gi_probe) { - GIProbe *gi_probe = gi_probe_owner.getornull(p_gi_probe); - ERR_FAIL_COND_V(!gi_probe, RID()); - - return gi_probe->sdf_texture; + return voxel_gi->sdf_texture; } /* LIGHTMAP API */ @@ -6911,9 +6973,13 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) { rd_format.width = rt->size.width; rd_format.height = rt->size.height; rd_format.depth = 1; - rd_format.array_layers = 1; + rd_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview rd_format.mipmaps = 1; - rd_format.texture_type = RD::TEXTURE_TYPE_2D; + if (rd_format.array_layers > 1) { // why are we not using rt->texture_type ?? + rd_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; + } else { + rd_format.texture_type = RD::TEXTURE_TYPE_2D; + } rd_format.samples = RD::TEXTURE_SAMPLES_1; rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rd_format.shareable_formats.push_back(rt->color_format); @@ -6925,7 +6991,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) { Vector<RID> fb_textures; fb_textures.push_back(rt->color); - rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures); + rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count); if (rt->framebuffer.is_null()) { _clear_render_target(rt); ERR_FAIL_COND(rt->framebuffer.is_null()); @@ -7039,12 +7105,15 @@ void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x, //unused for this render target } -void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height) { +void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); - rt->size.x = p_width; - rt->size.y = p_height; - _update_render_target(rt); + if (rt->size.x != p_width || rt->size.y != p_height || rt->view_count != p_view_count) { + rt->size.x = p_width; + rt->size.y = p_height; + rt->view_count = p_view_count; + _update_render_target(rt); + } } RID RendererStorageRD::render_target_get_texture(RID p_render_target) { @@ -7566,8 +7635,8 @@ void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_ } else if (decal_owner.owns(p_base)) { Decal *decal = decal_owner.getornull(p_base); p_instance->update_dependency(&decal->dependency); - } else if (gi_probe_owner.owns(p_base)) { - GIProbe *gip = gi_probe_owner.getornull(p_base); + } else if (voxel_gi_owner.owns(p_base)) { + VoxelGI *gip = voxel_gi_owner.getornull(p_base); p_instance->update_dependency(&gip->dependency); } else if (lightmap_owner.owns(p_base)) { Lightmap *lm = lightmap_owner.getornull(p_base); @@ -7581,6 +7650,9 @@ void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_ } else if (particles_collision_owner.owns(p_base)) { ParticlesCollision *pc = particles_collision_owner.getornull(p_base); p_instance->update_dependency(&pc->dependency); + } else if (visibility_notifier_owner.owns(p_base)) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_base); + p_instance->update_dependency(&vn->dependency); } } @@ -7604,8 +7676,8 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { if (decal_owner.owns(p_rid)) { return RS::INSTANCE_DECAL; } - if (gi_probe_owner.owns(p_rid)) { - return RS::INSTANCE_GI_PROBE; + if (voxel_gi_owner.owns(p_rid)) { + return RS::INSTANCE_VOXEL_GI; } if (light_owner.owns(p_rid)) { return RS::INSTANCE_LIGHT; @@ -7619,6 +7691,9 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { if (particles_collision_owner.owns(p_rid)) { return RS::INSTANCE_PARTICLES_COLLISION; } + if (visibility_notifier_owner.owns(p_rid)) { + return RS::INSTANCE_VISIBLITY_NOTIFIER; + } return RS::INSTANCE_NONE; } @@ -8129,7 +8204,7 @@ void RendererStorageRD::_global_variable_store_in_buffer(int32_t p_index, RS::Gl } break; case RS::GLOBAL_VAR_TYPE_TRANSFORM: { GlobalVariables::Value *bv = &global_variables.buffer_values[p_index]; - Transform v = p_value; + Transform3D v = p_value; bv[0].x = v.basis.elements[0][0]; bv[0].y = v.basis.elements[1][0]; bv[0].z = v.basis.elements[2][0]; @@ -8265,6 +8340,9 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c if (!global_variables.variables.has(p_name)) { return; //variable may not exist } + + ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); + GlobalVariables::Variable &gv = global_variables.variables[p_name]; gv.override = p_value; @@ -8552,6 +8630,7 @@ bool RendererStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { Texture *t = texture_owner.getornull(p_rid); + ERR_FAIL_COND_V(!t, false); ERR_FAIL_COND_V(t->is_render_target, false); if (RD::get_singleton()->texture_is_valid(t->rd_texture_srgb)) { @@ -8588,8 +8667,6 @@ bool RendererStorageRD::free(RID p_rid) { texture_owner.free(p_rid); } else if (canvas_texture_owner.owns(p_rid)) { - CanvasTexture *ct = canvas_texture_owner.getornull(p_rid); - memdelete(ct); canvas_texture_owner.free(p_rid); } else if (shader_owner.owns(p_rid)) { Shader *shader = shader_owner.getornull(p_rid); @@ -8605,9 +8682,6 @@ bool RendererStorageRD::free(RID p_rid) { } else if (material_owner.owns(p_rid)) { Material *material = material_owner.getornull(p_rid); - if (material->update_requested) { - _update_queued_materials(); - } material_set_shader(p_rid, RID()); //clean up shader material->dependency.deleted_notify(p_rid); @@ -8635,7 +8709,6 @@ bool RendererStorageRD::free(RID p_rid) { mi->I = nullptr; mesh_instance_owner.free(p_rid); - memdelete(mi); } else if (multimesh_owner.owns(p_rid)) { _update_dirty_multimeshes(); @@ -8662,11 +8735,11 @@ bool RendererStorageRD::free(RID p_rid) { } decal->dependency.deleted_notify(p_rid); decal_owner.free(p_rid); - } else if (gi_probe_owner.owns(p_rid)) { - gi_probe_allocate_data(p_rid, Transform(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate - GIProbe *gi_probe = gi_probe_owner.getornull(p_rid); - gi_probe->dependency.deleted_notify(p_rid); - gi_probe_owner.free(p_rid); + } else if (voxel_gi_owner.owns(p_rid)) { + voxel_gi_allocate_data(p_rid, Transform3D(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate + VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_rid); + voxel_gi->dependency.deleted_notify(p_rid); + voxel_gi_owner.free(p_rid); } else if (lightmap_owner.owns(p_rid)) { lightmap_set_textures(p_rid, RID(), false); Lightmap *lightmap = lightmap_owner.getornull(p_rid); @@ -8694,6 +8767,10 @@ bool RendererStorageRD::free(RID p_rid) { } particles_collision->dependency.deleted_notify(p_rid); particles_collision_owner.free(p_rid); + } else if (visibility_notifier_owner.owns(p_rid)) { + VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_rid); + vn->dependency.deleted_notify(p_rid); + visibility_notifier_owner.free(p_rid); } else if (particles_collision_instance_owner.owns(p_rid)) { particles_collision_instance_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { @@ -8747,6 +8824,29 @@ String RendererStorageRD::get_captured_timestamp_name(uint32_t p_index) const { return RD::get_singleton()->get_captured_timestamp_name(p_index); } +void RendererStorageRD::update_memory_info() { + texture_mem_cache = RenderingDevice::get_singleton()->get_memory_usage(RenderingDevice::MEMORY_TEXTURES); + buffer_mem_cache = RenderingDevice::get_singleton()->get_memory_usage(RenderingDevice::MEMORY_BUFFERS); + total_mem_cache = RenderingDevice::get_singleton()->get_memory_usage(RenderingDevice::MEMORY_TOTAL); +} +uint64_t RendererStorageRD::get_rendering_info(RS::RenderingInfo p_info) { + if (p_info == RS::RENDERING_INFO_TEXTURE_MEM_USED) { + return texture_mem_cache; + } else if (p_info == RS::RENDERING_INFO_BUFFER_MEM_USED) { + return buffer_mem_cache; + } else if (p_info == RS::RENDERING_INFO_VIDEO_MEM_USED) { + return total_mem_cache; + } + return 0; +} + +String RendererStorageRD::get_video_adapter_name() const { + return RenderingDevice::get_singleton()->get_device_name(); +} +String RendererStorageRD::get_video_adapter_vendor() const { + return RenderingDevice::get_singleton()->get_device_vendor_name(); +} + RendererStorageRD *RendererStorageRD::base_singleton = nullptr; RendererStorageRD::RendererStorageRD() { @@ -8767,7 +8867,6 @@ RendererStorageRD::RendererStorageRD() { memset(global_variables.buffer_dirty_regions, 0, sizeof(bool) * global_variables.buffer_size / GlobalVariables::BUFFER_DIRTY_REGION_SIZE); global_variables.buffer = RD::get_singleton()->storage_buffer_create(sizeof(GlobalVariables::Value) * global_variables.buffer_size); - material_update_list = nullptr; { //create default textures RD::TextureFormat tformat; @@ -9181,10 +9280,10 @@ RendererStorageRD::RendererStorageRD() { { Vector<String> sdf_versions; sdf_versions.push_back(""); //one only - giprobe_sdf_shader.initialize(sdf_versions); - giprobe_sdf_shader_version = giprobe_sdf_shader.version_create(); - giprobe_sdf_shader_version_shader = giprobe_sdf_shader.version_get_shader(giprobe_sdf_shader_version, 0); - giprobe_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(giprobe_sdf_shader_version_shader); + voxel_gi_sdf_shader.initialize(sdf_versions); + voxel_gi_sdf_shader_version = voxel_gi_sdf_shader.version_create(); + voxel_gi_sdf_shader_version_shader = voxel_gi_sdf_shader.version_get_shader(voxel_gi_sdf_shader_version, 0); + voxel_gi_sdf_shader_pipeline = RD::get_singleton()->compute_pipeline_create(voxel_gi_sdf_shader_version_shader); } using_lightmap_array = true; // high end @@ -9400,7 +9499,7 @@ RendererStorageRD::~RendererStorageRD() { RD::get_singleton()->free(mesh_default_rd_buffers[i]); } - giprobe_sdf_shader.version_free(giprobe_sdf_shader_version); + voxel_gi_sdf_shader.version_free(voxel_gi_sdf_shader_version); particles_shader.copy_shader.version_free(particles_shader.copy_shader_version); rt_sdf.shader.version_free(rt_sdf.shader_version); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 67fbeb3008..1a33569c33 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -38,15 +38,15 @@ #include "servers/rendering/renderer_rd/effects_rd.h" #include "servers/rendering/renderer_rd/shader_compiler_rd.h" #include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/particles.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/particles_copy.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/skeleton.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" class RendererStorageRD : public RendererStorage { public: - static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { + static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; p_array[1] = p_mtx.basis.elements[1][0]; p_array[2] = p_mtx.basis.elements[2][0]; @@ -95,7 +95,7 @@ public: p_array[11] = 0; } - static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform &p_mtx, float *p_array) { + static _FORCE_INLINE_ void store_transform_transposed_3x4(const Transform3D &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; p_array[1] = p_mtx.basis.elements[0][1]; p_array[2] = p_mtx.basis.elements[0][2]; @@ -155,9 +155,13 @@ public: virtual void set_render_priority(int p_priority) = 0; virtual void set_next_pass(RID p_pass) = 0; - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0; + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) = 0; virtual ~MaterialData(); + //to be used internally by update_parameters, in the most common configuration of material parameters + bool update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, RID> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL); + void free_parameters_uniform_set(RID p_uniform_set); + private: friend class RendererStorageRD; RID self; @@ -165,8 +169,14 @@ public: List<RID>::Element *global_texture_E = nullptr; uint64_t global_textures_pass = 0; Map<StringName, uint64_t> used_global_textures; + + //internally by update_parameters_uniform_set + Vector<uint8_t> ubo_data; + RID uniform_buffer; + Vector<RID> texture_cache; }; typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *); + static void _material_uniform_set_erased(const RID &p_set, void *p_material); enum DefaultRDTexture { DEFAULT_RD_TEXTURE_WHITE, @@ -221,7 +231,7 @@ private: ~CanvasTexture(); }; - RID_PtrOwner<CanvasTexture, true> canvas_texture_owner; + RID_Owner<CanvasTexture, true> canvas_texture_owner; /* TEXTURE API */ struct Texture { @@ -373,25 +383,28 @@ private: struct Material { RID self; - MaterialData *data; - Shader *shader; + MaterialData *data = nullptr; + Shader *shader = nullptr; //shortcut to shader data and type - ShaderType shader_type; + ShaderType shader_type = SHADER_TYPE_MAX; uint32_t shader_id = 0; - bool update_requested; - bool uniform_dirty; - bool texture_dirty; - Material *update_next; + bool uniform_dirty = false; + bool texture_dirty = false; Map<StringName, Variant> params; - int32_t priority; + int32_t priority = 0; RID next_pass; + SelfList<Material> update_element; + Dependency dependency; + + Material() : + update_element(this) {} }; MaterialDataRequestFunction material_data_request_func[SHADER_TYPE_MAX]; mutable RID_Owner<Material, true> material_owner; - Material *material_update_list; + SelfList<Material>::List material_update_list; void _material_queue_update(Material *material, bool p_uniform, bool p_texture); void _update_queued_materials(); @@ -434,6 +447,7 @@ private: struct LOD { float edge_length = 0.0; + uint32_t index_count = 0; RID index_buffer; RID index_array; }; @@ -513,7 +527,7 @@ private: void _mesh_instance_clear(MeshInstance *mi); void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface); - mutable RID_PtrOwner<MeshInstance> mesh_instance_owner; + mutable RID_Owner<MeshInstance> mesh_instance_owner; SelfList<MeshInstance>::List dirty_mesh_instance_weights; SelfList<MeshInstance>::List dirty_mesh_instance_arrays; @@ -726,7 +740,7 @@ private: RS::ParticlesDrawOrder draw_order = RS::PARTICLES_DRAW_ORDER_INDEX; Vector<RID> draw_passes; - Vector<Transform> trail_bind_poses; + Vector<Transform3D> trail_bind_poses; bool trail_bind_poses_dirty = false; RID trail_bind_pose_buffer; RID trail_bind_pose_uniform_set; @@ -771,7 +785,7 @@ private: bool force_sub_emit = false; - Transform emission_transform; + Transform3D emission_transform; Vector<uint8_t> emission_buffer_data; @@ -894,17 +908,14 @@ private: } struct ParticlesMaterialData : public MaterialData { - uint64_t last_frame; - ParticlesShaderData *shader_data; - RID uniform_buffer; + uint64_t last_frame = 0; + ParticlesShaderData *shader_data = nullptr; RID uniform_set; - Vector<RID> texture_cache; - Vector<uint8_t> ubo_data; - bool uniform_set_updated; + bool uniform_set_updated = false; virtual void set_render_priority(int p_priority) {} virtual void set_next_pass(RID p_pass) {} - virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); virtual ~ParticlesMaterialData(); }; @@ -941,12 +952,23 @@ private: struct ParticlesCollisionInstance { RID collision; - Transform transform; + Transform3D transform; bool active = false; }; mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner; + /* visibility_notifier */ + + struct VisibilityNotifier { + AABB aabb; + Callable enter_callback; + Callable exit_callback; + Dependency dependency; + }; + + mutable RID_Owner<VisibilityNotifier> visibility_notifier_owner; + /* Skeleton */ struct Skeleton { @@ -991,7 +1013,6 @@ private: uint32_t cull_mask = 0xFFFFFFFF; RS::LightOmniShadowMode omni_shadow_mode = RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; RS::LightDirectionalShadowMode directional_shadow_mode = RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; - RS::LightDirectionalShadowDepthRangeMode directional_range_mode = RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; bool directional_blend_splits = false; bool directional_sky_only = false; uint64_t version = 0; @@ -1045,9 +1066,9 @@ private: mutable RID_Owner<Decal, true> decal_owner; - /* GI PROBE */ + /* VOXEL GI */ - struct GIProbe { + struct VoxelGI { RID octree_buffer; RID data_buffer; RID sdf_texture; @@ -1059,14 +1080,12 @@ private: int cell_count = 0; - Transform to_cell_xform; + Transform3D to_cell_xform; AABB bounds; Vector3i octree_size; float dynamic_range = 4.0; float energy = 1.0; - float ao = 0.0; - float ao_size = 0.5; float bias = 1.4; float normal_bias = 0.0; float propagation = 0.7; @@ -1081,12 +1100,12 @@ private: Dependency dependency; }; - GiprobeSdfShaderRD giprobe_sdf_shader; - RID giprobe_sdf_shader_version; - RID giprobe_sdf_shader_version_shader; - RID giprobe_sdf_shader_pipeline; + VoxelGiSdfShaderRD voxel_gi_sdf_shader; + RID voxel_gi_sdf_shader_version; + RID voxel_gi_sdf_shader_version_shader; + RID voxel_gi_sdf_shader_pipeline; - mutable RID_Owner<GIProbe, true> gi_probe_owner; + mutable RID_Owner<VoxelGI, true> voxel_gi_owner; /* REFLECTION PROBE */ @@ -1125,6 +1144,7 @@ private: struct RenderTarget { Size2i size; + uint32_t view_count; RID framebuffer; RID color; @@ -1286,7 +1306,6 @@ public: virtual void _texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate); - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0); virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data); virtual void texture_proxy_update(RID p_texture, RID p_proxy_to); @@ -1445,7 +1464,9 @@ public: virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode); virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const; - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data); + virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data); + virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data); + virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data); virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material); virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const; @@ -1514,10 +1535,18 @@ public: return s->lod_count > 0; } - _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold) const { + _FORCE_INLINE_ uint32_t mesh_surface_get_vertices_drawn_count(void *p_surface) const { + Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); + return s->index_count ? s->index_count : s->vertex_count; + } + + _FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_lod_threshold, uint32_t *r_index_count = nullptr) const { Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface); int32_t current_lod = -1; + if (r_index_count) { + *r_index_count = s->index_count; + } for (uint32_t i = 0; i < s->lod_count; i++) { float screen_size = s->lods[i].edge_length * p_model_scale / p_distance_threshold; if (screen_size > p_lod_threshold) { @@ -1528,6 +1557,9 @@ public: if (current_lod == -1) { return 0; } else { + if (r_index_count) { + *r_index_count = s->lods[current_lod].index_count; + } return current_lod + 1; } } @@ -1661,14 +1693,14 @@ public: int multimesh_get_instance_count(RID p_multimesh) const; void multimesh_set_mesh(RID p_multimesh, RID p_mesh); - void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform); + void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform); void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform); void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color); void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color); RID multimesh_get_mesh(RID p_multimesh) const; - Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const; + Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const; Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const; Color multimesh_instance_get_color(RID p_multimesh, int p_index) const; Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const; @@ -1734,24 +1766,6 @@ public: return multimesh->uniform_set_2d; } - /* IMMEDIATE API */ - - RID immediate_allocate() { return RID(); } - void immediate_initialize(RID p_immediate) {} - - virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) {} - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {} - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) {} - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) {} - virtual void immediate_color(RID p_immediate, const Color &p_color) {} - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) {} - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {} - virtual void immediate_end(RID p_immediate) {} - virtual void immediate_clear(RID p_immediate) {} - virtual void immediate_set_material(RID p_immediate, RID p_material) {} - virtual RID immediate_get_material(RID p_immediate) const { return RID(); } - virtual AABB immediate_get_aabb(RID p_immediate) const { return AABB(); } - /* SKELETON API */ RID skeleton_allocate(); @@ -1759,10 +1773,10 @@ public: void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false); void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform); - void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform); + void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform3D &p_world_transform); int skeleton_get_bone_count(RID p_skeleton) const; - void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform); - Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; + void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform); + Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const; void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform); Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; @@ -1820,8 +1834,6 @@ public: bool light_directional_get_blend_splits(RID p_light) const; void light_directional_set_sky_only(RID p_light, bool p_sky_only); bool light_directional_is_sky_only(RID p_light) const; - void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode); - RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); @@ -2019,59 +2031,53 @@ public: virtual AABB decal_get_aabb(RID p_decal) const; - /* GI PROBE API */ - - RID gi_probe_allocate(); - void gi_probe_initialize(RID p_gi_probe); - - void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); + /* VOXEL GI API */ - AABB gi_probe_get_bounds(RID p_gi_probe) const; - Vector3i gi_probe_get_octree_size(RID p_gi_probe) const; - Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const; - Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const; - Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const; + RID voxel_gi_allocate(); + void voxel_gi_initialize(RID p_voxel_gi); - Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const; - Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const; + void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts); - void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range); - float gi_probe_get_dynamic_range(RID p_gi_probe) const; + AABB voxel_gi_get_bounds(RID p_voxel_gi) const; + Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const; + Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const; + Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const; + Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const; - void gi_probe_set_propagation(RID p_gi_probe, float p_range); - float gi_probe_get_propagation(RID p_gi_probe) const; + Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const; + Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const; - void gi_probe_set_energy(RID p_gi_probe, float p_energy); - float gi_probe_get_energy(RID p_gi_probe) const; + void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range); + float voxel_gi_get_dynamic_range(RID p_voxel_gi) const; - void gi_probe_set_ao(RID p_gi_probe, float p_ao); - float gi_probe_get_ao(RID p_gi_probe) const; + void voxel_gi_set_propagation(RID p_voxel_gi, float p_range); + float voxel_gi_get_propagation(RID p_voxel_gi) const; - void gi_probe_set_ao_size(RID p_gi_probe, float p_strength); - float gi_probe_get_ao_size(RID p_gi_probe) const; + void voxel_gi_set_energy(RID p_voxel_gi, float p_energy); + float voxel_gi_get_energy(RID p_voxel_gi) const; - void gi_probe_set_bias(RID p_gi_probe, float p_bias); - float gi_probe_get_bias(RID p_gi_probe) const; + void voxel_gi_set_bias(RID p_voxel_gi, float p_bias); + float voxel_gi_get_bias(RID p_voxel_gi) const; - void gi_probe_set_normal_bias(RID p_gi_probe, float p_range); - float gi_probe_get_normal_bias(RID p_gi_probe) const; + void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range); + float voxel_gi_get_normal_bias(RID p_voxel_gi) const; - void gi_probe_set_interior(RID p_gi_probe, bool p_enable); - bool gi_probe_is_interior(RID p_gi_probe) const; + void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable); + bool voxel_gi_is_interior(RID p_voxel_gi) const; - void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable); - bool gi_probe_is_using_two_bounces(RID p_gi_probe) const; + void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable); + bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const; - void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength); - float gi_probe_get_anisotropy_strength(RID p_gi_probe) const; + void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength); + float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const; - uint32_t gi_probe_get_version(RID p_probe); - uint32_t gi_probe_get_data_version(RID p_probe); + uint32_t voxel_gi_get_version(RID p_probe); + uint32_t voxel_gi_get_data_version(RID p_probe); - RID gi_probe_get_octree_buffer(RID p_gi_probe) const; - RID gi_probe_get_data_buffer(RID p_gi_probe) const; + RID voxel_gi_get_octree_buffer(RID p_voxel_gi) const; + RID voxel_gi_get_data_buffer(RID p_voxel_gi) const; - RID gi_probe_get_sdf_texture(RID p_gi_probe); + RID voxel_gi_get_sdf_texture(RID p_voxel_gi); /* LIGHTMAP CAPTURE */ @@ -2147,10 +2153,10 @@ public: void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align); void particles_set_trails(RID p_particles, bool p_enable, float p_length); - void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses); + void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses); void particles_restart(RID p_particles); - void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); + void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags); void particles_set_subemitter(RID p_particles, RID p_subemitter_particles); @@ -2163,7 +2169,7 @@ public: AABB particles_get_current_aabb(RID p_particles); AABB particles_get_aabb(RID p_particles) const; - void particles_set_emission_transform(RID p_particles, const Transform &p_transform); + void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform); bool particles_get_emitting(RID p_particles); int particles_get_draw_passes(RID p_particles) const; @@ -2252,9 +2258,17 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + virtual RID visibility_notifier_allocate(); + virtual void visibility_notifier_initialize(RID p_notifier); + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb); + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable); + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const; + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred); + //used from 2D and 3D virtual RID particles_collision_instance_create(RID p_collision); - virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform); + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform); virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active); /* GLOBAL VARIABLES API */ @@ -2282,7 +2296,7 @@ public: RID render_target_create(); void render_target_set_position(RID p_render_target, int p_x, int p_y); - void render_target_set_size(RID p_render_target, int p_width, int p_height); + void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count); RID render_target_get_texture(RID p_render_target); void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); @@ -2330,13 +2344,16 @@ public: void set_debug_generate_wireframes(bool p_generate) {} - void render_info_begin_capture() {} - void render_info_end_capture() {} - int get_captured_render_info(RS::RenderInfo p_info) { return 0; } + //keep cached since it can be called form any thread + uint64_t texture_mem_cache = 0; + uint64_t buffer_mem_cache = 0; + uint64_t total_mem_cache = 0; + + virtual void update_memory_info(); + virtual uint64_t get_rendering_info(RS::RenderingInfo p_info); - uint64_t get_render_info(RS::RenderInfo p_info) { return 0; } - String get_video_adapter_name() const { return String(); } - String get_video_adapter_vendor() const { return String(); } + String get_video_adapter_name() const; + String get_video_adapter_vendor() const; virtual void capture_timestamps_begin(); virtual void capture_timestamp(const String &p_name); diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index 7deedb80c3..b347197289 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -1504,7 +1504,6 @@ ShaderCompilerRD::ShaderCompilerRD() { actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; } - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 6f29ff42bc..27305cc938 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -31,8 +31,8 @@ #include "shader_rd.h" #include "core/io/compression.h" -#include "core/os/dir_access.h" -#include "core/os/file_access.h" +#include "core/io/dir_access.h" +#include "core/io/file_access.h" #include "renderer_compositor_rd.h" #include "servers/rendering/rendering_device.h" #include "thirdparty/misc/smolv.h" diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 2186bd174b..a443bcdcb8 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -65,7 +65,7 @@ void main() { #elif defined(USE_ATTRIBUTES) vec2 vertex = vertex_attrib; - vec4 color = color_attrib; + vec4 color = color_attrib * draw_data.modulation; vec2 uv = uv_attrib; uvec4 bones = bone_attrib; diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index bfd5c4c88d..60c881881d 100644 --- a/servers/rendering/renderer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -35,7 +35,7 @@ layout(set = 0, binding = 11) uniform texture2DArray lightprobe_texture; layout(set = 0, binding = 12) uniform texture2D depth_buffer; layout(set = 0, binding = 13) uniform texture2D normal_roughness_buffer; -layout(set = 0, binding = 14) uniform utexture2D giprobe_buffer; +layout(set = 0, binding = 14) uniform utexture2D voxel_gi_buffer; layout(set = 0, binding = 15, std140) uniform SDFGI { vec3 grid_size; @@ -65,9 +65,9 @@ layout(set = 0, binding = 15, std140) uniform SDFGI { } sdfgi; -#define MAX_GI_PROBES 8 +#define MAX_VOXEL_GI_INSTANCES 8 -struct GIProbeData { +struct VoxelGIData { mat4 xform; vec3 bounds; float dynamic_range; @@ -77,18 +77,18 @@ struct GIProbeData { bool blend_ambient; uint texture_slot; - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; + uint pad0; + uint pad1; + uint pad2; uint mipmaps; }; -layout(set = 0, binding = 16, std140) uniform GIProbes { - GIProbeData data[MAX_GI_PROBES]; +layout(set = 0, binding = 16, std140) uniform VoxelGIs { + VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; } -gi_probes; +voxel_gi_instances; -layout(set = 0, binding = 17) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +layout(set = 0, binding = 17) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; layout(push_constant, binding = 0, std430) uniform Params { ivec2 screen_size; @@ -98,7 +98,7 @@ layout(push_constant, binding = 0, std430) uniform Params { vec4 proj_info; vec3 ao_color; - uint max_giprobes; + uint max_voxel_gi_instances; bool high_quality_vct; bool orthogonal; @@ -155,7 +155,7 @@ vec3 reconstruct_position(ivec2 screen_pos) { return pos; } -void sdfgi_probe_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) { +void sdfvoxel_gi_process(uint cascade, vec3 cascade_pos, vec3 cam_pos, vec3 cam_normal, vec3 cam_specular_normal, float roughness, out vec3 diffuse_light, out vec3 specular_light) { cascade_pos += cam_normal * sdfgi.normal_bias; vec3 base_pos = floor(cascade_pos); @@ -293,7 +293,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o float blend; vec3 diffuse, specular; - sdfgi_probe_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular); + sdfvoxel_gi_process(cascade, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse, specular); { //process blend @@ -323,7 +323,7 @@ void sdfgi_process(vec3 vertex, vec3 normal, vec3 reflection, float roughness, o } else { vec3 diffuse2, specular2; cascade_pos = (cam_pos - sdfgi.cascades[cascade + 1].position) * sdfgi.cascades[cascade + 1].to_probe; - sdfgi_probe_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2); + sdfvoxel_gi_process(cascade + 1, cascade_pos, cam_pos, cam_normal, reflection, roughness, diffuse2, specular2); diffuse = mix(diffuse, diffuse2, blend); specular = mix(specular, specular2, blend); } @@ -494,26 +494,26 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 return color; } -void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) { - position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz; - ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz); - normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz); +void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, inout vec4 out_spec, inout vec4 out_diff, inout float out_blend) { + position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz; + ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz); + normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz); - position += normal * gi_probes.data[index].normal_bias; + position += normal * voxel_gi_instances.data[index].normal_bias; //this causes corrupted pixels, i have no idea why.. - if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) { + if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) { return; } - mat3 dir_xform = mat3(gi_probes.data[index].xform) * normal_xform; + mat3 dir_xform = mat3(voxel_gi_instances.data[index].xform) * normal_xform; - vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0); + vec3 blendv = abs(position / voxel_gi_instances.data[index].bounds * 2.0 - 1.0); float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); //float blend=1.0; - float max_distance = length(gi_probes.data[index].bounds); - vec3 cell_size = 1.0 / gi_probes.data[index].bounds; + float max_distance = length(voxel_gi_instances.data[index].bounds); + vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds; //irradiance @@ -534,7 +534,7 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 for (uint i = 0; i < cone_dir_count; i++) { vec3 dir = normalize(dir_xform * cone_dirs[i]); - light += cone_weights[i] * voxel_cone_trace(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias); + light += cone_weights[i] * voxel_cone_trace(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias); } } else { const uint cone_dir_count = 4; @@ -547,42 +547,21 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 float cone_weights[cone_dir_count] = float[](0.25, 0.25, 0.25, 0.25); for (int i = 0; i < cone_dir_count; i++) { vec3 dir = normalize(dir_xform * cone_dirs[i]); - light += cone_weights[i] * voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, max_distance, gi_probes.data[index].bias); + light += cone_weights[i] * voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, max_distance, voxel_gi_instances.data[index].bias); } } - if (gi_probes.data[index].ambient_occlusion > 0.001) { - float size = 1.0 + gi_probes.data[index].ambient_occlusion_size * 7.0; - - float taps, blend; - blend = modf(size, taps); - float ao = 0.0; - for (float i = 1.0; i <= taps; i++) { - vec3 ofs = (position + normal * (i * 0.5 + 1.0)) * cell_size; - ao += textureLod(sampler3D(gi_probe_textures[index], linear_sampler_with_mipmaps), ofs, i - 1.0).a * i; - } - - if (blend > 0.001) { - vec3 ofs = (position + normal * ((taps + 1.0) * 0.5 + 1.0)) * cell_size; - ao += textureLod(sampler3D(gi_probe_textures[index], linear_sampler_with_mipmaps), ofs, taps).a * (taps + 1.0) * blend; - } - - ao = 1.0 - min(1.0, ao); - - light.rgb = mix(params.ao_color, light.rgb, mix(1.0, ao, gi_probes.data[index].ambient_occlusion)); - } - - light.rgb *= gi_probes.data[index].dynamic_range; - if (!gi_probes.data[index].blend_ambient) { + light.rgb *= voxel_gi_instances.data[index].dynamic_range; + if (!voxel_gi_instances.data[index].blend_ambient) { light.a = 1.0; } out_diff += light * blend; //radiance - vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias); - irr_light.rgb *= gi_probes.data[index].dynamic_range; - if (!gi_probes.data[index].blend_ambient) { + vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias); + irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range; + if (!voxel_gi_instances.data[index].blend_ambient) { irr_light.a = 1.0; } @@ -614,9 +593,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref sdfgi_process(vertex, normal, reflection, roughness, ambient_light, reflection_light); #endif -#ifdef USE_GIPROBES +#ifdef USE_VOXEL_GI_INSTANCES { - uvec2 giprobe_tex = texelFetch(usampler2D(giprobe_buffer, linear_sampler), pos, 0).rg; + uvec2 voxel_gi_tex = texelFetch(usampler2D(voxel_gi_buffer, linear_sampler), pos, 0).rg; roughness *= roughness; //find arbitrary tangent and bitangent, then build a matrix vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); @@ -628,9 +607,9 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref vec4 spec_accum = vec4(0.0); float blend_accum = 0.0; - for (uint i = 0; i < params.max_giprobes; i++) { - if (any(equal(uvec2(i), giprobe_tex))) { - gi_probe_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum); + for (uint i = 0; i < params.max_voxel_gi_instances; i++) { + if (any(equal(uvec2(i), voxel_gi_tex))) { + voxel_gi_compute(i, vertex, normal, reflection, normal_mat, roughness, spec_accum, amb_accum, blend_accum); } } if (blend_accum > 0.0) { diff --git a/servers/rendering/renderer_rd/shaders/resolve.glsl b/servers/rendering/renderer_rd/shaders/resolve.glsl index 2286a26485..fecf812a8c 100644 --- a/servers/rendering/renderer_rd/shaders/resolve.glsl +++ b/servers/rendering/renderer_rd/shaders/resolve.glsl @@ -6,6 +6,11 @@ layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +#ifdef MODE_RESOLVE_DEPTH +layout(set = 0, binding = 0) uniform sampler2DMS source_depth; +layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth; +#endif + #ifdef MODE_RESOLVE_GI layout(set = 0, binding = 0) uniform sampler2DMS source_depth; layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness; @@ -13,9 +18,9 @@ layout(set = 0, binding = 1) uniform sampler2DMS source_normal_roughness; layout(r32f, set = 1, binding = 0) uniform restrict writeonly image2D dest_depth; layout(rgba8, set = 1, binding = 1) uniform restrict writeonly image2D dest_normal_roughness; -#ifdef GIPROBE_RESOLVE -layout(set = 2, binding = 0) uniform usampler2DMS source_giprobe; -layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_giprobe; +#ifdef VOXEL_GI_RESOLVE +layout(set = 2, binding = 0) uniform usampler2DMS source_voxel_gi; +layout(rg8ui, set = 3, binding = 0) uniform restrict writeonly uimage2D dest_voxel_gi; #endif #endif @@ -34,12 +39,23 @@ void main() { return; } +#ifdef MODE_RESOLVE_DEPTH + + float depth_avg = 0.0; + for (int i = 0; i < params.sample_count; i++) { + depth_avg += texelFetch(source_depth, pos, i).r; + } + depth_avg /= float(params.sample_count); + imageStore(dest_depth, pos, vec4(depth_avg)); + +#endif + #ifdef MODE_RESOLVE_GI float best_depth = 1e20; vec4 best_normal_roughness = vec4(0.0); -#ifdef GIPROBE_RESOLVE - uvec2 best_giprobe; +#ifdef VOXEL_GI_RESOLVE + uvec2 best_voxel_gi; #endif #if 0 @@ -50,8 +66,8 @@ void main() { best_depth = depth; best_normal_roughness = texelFetch(source_normal_roughness,pos,i); -#ifdef GIPROBE_RESOLVE - best_giprobe = texelFetch(source_giprobe,pos,i).rg; +#ifdef VOXEL_GI_RESOLVE + best_voxel_gi = texelFetch(source_voxel_gi,pos,i).rg; #endif } } @@ -204,16 +220,16 @@ void main() { #endif best_depth = texelFetch(source_depth, pos, best_index).r; best_normal_roughness = texelFetch(source_normal_roughness, pos, best_index); -#ifdef GIPROBE_RESOLVE - best_giprobe = texelFetch(source_giprobe, pos, best_index).rg; +#ifdef VOXEL_GI_RESOLVE + best_voxel_gi = texelFetch(source_voxel_gi, pos, best_index).rg; #endif #endif imageStore(dest_depth, pos, vec4(best_depth)); imageStore(dest_normal_roughness, pos, vec4(best_normal_roughness)); -#ifdef GIPROBE_RESOLVE - imageStore(dest_giprobe, pos, uvec4(best_giprobe, 0, 0)); +#ifdef VOXEL_GI_RESOLVE + imageStore(dest_voxel_gi, pos, uvec4(best_voxel_gi, 0, 0)); #endif #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index e09b8f15be..74d5af5cb6 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -426,8 +426,8 @@ layout(location = 4) out float depth_output_buffer; #ifdef MODE_RENDER_NORMAL_ROUGHNESS layout(location = 0) out vec4 normal_roughness_output_buffer; -#ifdef MODE_RENDER_GIPROBE -layout(location = 1) out uvec2 giprobe_buffer; +#ifdef MODE_RENDER_VOXEL_GI +layout(location = 1) out uvec2 voxel_gi_buffer; #endif #endif //MODE_RENDER_NORMAL @@ -547,9 +547,8 @@ void main() { vec3 view = -normalize(vertex_interp); vec3 albedo = vec3(1.0); vec3 backlight = vec3(0.0); - vec4 transmittance_color = vec4(0.0); + vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0); float transmittance_depth = 0.0; - float transmittance_curve = 1.0; float transmittance_boost = 0.0; float metallic = 0.0; float specular = 0.5; @@ -634,12 +633,8 @@ void main() { } #ifdef LIGHT_TRANSMITTANCE_USED -#ifdef SSS_MODE_SKIN - transmittance_color.a = sss_strength; -#else transmittance_color.a *= sss_strength; #endif -#endif #ifndef USE_SHADOW_TO_OPACITY @@ -850,7 +845,7 @@ void main() { if (scene_data.roughness_limiter_enabled) { //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; - vec3 dndu = dFdx(normal), dndv = dFdx(normal); + vec3 dndu = dFdx(normal), dndv = dFdy(normal); float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); @@ -904,7 +899,7 @@ void main() { } #endif // USE_LIGHTMAP #if defined(CUSTOM_IRRADIANCE_USED) - ambient_light = mix(specular_light, custom_irradiance.rgb, custom_irradiance.a); + ambient_light = mix(ambient_light, custom_irradiance.rgb, custom_irradiance.a); #endif #endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) @@ -1042,7 +1037,7 @@ void main() { } } - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; vec3 ref_vec = normalize(reflect(normalize(vertex), normal)); @@ -1054,12 +1049,12 @@ void main() { vec4 amb_accum = vec4(0.0); vec4 spec_accum = vec4(0.0); - gi_probe_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); + voxel_gi_compute(index1, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); uint index2 = instances.data[instance_index].gi_offset >> 16; if (index2 != 0xFFFF) { - gi_probe_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); + voxel_gi_compute(index2, vertex, normal, ref_vec, normal_mat, roughness * roughness, ambient_light, specular_light, spec_accum, amb_accum); } if (amb_accum.a > 0.0) { @@ -1423,57 +1418,18 @@ void main() { BIAS_FUNC(v, 0) pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.x, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix1 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; - - transmittance_z = z - shadow_z; - } -#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 1) pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.y, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix2 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; - - transmittance_z = z - shadow_z; - } -#endif } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 2) pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.z, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix3 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; - - transmittance_z = z - shadow_z; - } -#endif } else { vec4 v = vec4(vertex, 1.0); @@ -1481,19 +1437,6 @@ void main() { BIAS_FUNC(v, 3) pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); -#ifdef LIGHT_TRANSMITTANCE_USED - { - vec4 trans_vertex = vec4(vertex - normalize(normal_interp) * directional_lights.data[i].shadow_transmittance_bias.w, 1.0); - vec4 trans_coord = directional_lights.data[i].shadow_matrix4 * trans_vertex; - trans_coord /= trans_coord.w; - - float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; - - transmittance_z = z - shadow_z; - } -#endif } pssm_coord /= pssm_coord.w; @@ -1562,8 +1505,8 @@ void main() { trans_coord /= trans_coord.w; float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.x; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.x; + shadow_z *= directional_lights.data[i].shadow_z_range.x; + float z = trans_coord.z * directional_lights.data[i].shadow_z_range.x; transmittance_z = z - shadow_z; } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { @@ -1572,8 +1515,8 @@ void main() { trans_coord /= trans_coord.w; float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.y; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.y; + shadow_z *= directional_lights.data[i].shadow_z_range.y; + float z = trans_coord.z * directional_lights.data[i].shadow_z_range.y; transmittance_z = z - shadow_z; } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { @@ -1582,8 +1525,8 @@ void main() { trans_coord /= trans_coord.w; float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.z; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.z; + shadow_z *= directional_lights.data[i].shadow_z_range.z; + float z = trans_coord.z * directional_lights.data[i].shadow_z_range.z; transmittance_z = z - shadow_z; @@ -1593,221 +1536,219 @@ void main() { trans_coord /= trans_coord.w; float shadow_z = textureLod(sampler2D(directional_shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), trans_coord.xy, 0.0).r; - shadow_z *= directional_lights.data[i].shadow_transmittance_z_scale.w; - float z = trans_coord.z * directional_lights.data[i].shadow_transmittance_z_scale.w; + shadow_z *= directional_lights.data[i].shadow_z_range.w; + float z = trans_coord.z * directional_lights.data[i].shadow_z_range.w; transmittance_z = z - shadow_z; } + } #endif - float shadow = 1.0; + float shadow = 1.0; - if (i < 4) { - shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; - } else { - shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; - } + if (i < 4) { + shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; + } else { + shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; + } - blur_shadow(shadow); + blur_shadow(shadow); - light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, + light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, - transmittance_z, + transmittance_color, + transmittance_depth, + transmittance_boost, + transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim, rim_tint, albedo, + rim, rim_tint, albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - binormal, tangent, anisotropy, + binormal, tangent, anisotropy, #endif #ifdef USE_SOFT_SHADOW - directional_lights.data[i].size, + directional_lights.data[i].size, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, - specular_light); - } + diffuse_light, + specular_light); } + } - { //omni lights + { //omni lights - uint cluster_omni_offset = cluster_offset; + uint cluster_omni_offset = cluster_offset; - uint item_min; - uint item_max; - uint item_from; - uint item_to; + uint item_min; + uint item_max; + uint item_from; + uint item_to; - cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); #ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); #endif - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_omni_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); #ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); #else uint merged_mask = mask; #endif - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); #ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } #endif - uint light_index = 32 * i + bit; + uint light_index = 32 * i + bit; - if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + if (!bool(omni_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } - if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { - continue; // Statically baked light and object uses lightmap, skip - } + if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } - float shadow = light_process_omni_shadow(light_index, vertex, view); + float shadow = light_process_omni_shadow(light_index, vertex, view); - shadow = blur_shadow(shadow); + shadow = blur_shadow(shadow); - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED - rim, - rim_tint, - albedo, + rim, + rim_tint, + albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, binormal, anisotropy, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, specular_light); - } + diffuse_light, specular_light); } } + } - { //spot lights + { //spot lights - uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; + uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size; - uint item_min; - uint item_max; - uint item_from; - uint item_to; + uint item_min; + uint item_max; + uint item_from; + uint item_to; - cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); #ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); #endif - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_spot_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); #ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); #else uint merged_mask = mask; #endif - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); #ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } #endif - uint light_index = 32 * i + bit; + uint light_index = 32 * i + bit; - if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { - continue; //not masked - } + if (!bool(spot_lights.data[light_index].mask & instances.data[instance_index].layer_mask)) { + continue; //not masked + } - if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { - continue; // Statically baked light and object uses lightmap, skip - } + if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { + continue; // Statically baked light and object uses lightmap, skip + } - float shadow = light_process_spot_shadow(light_index, vertex, view); + float shadow = light_process_spot_shadow(light_index, vertex, view); - shadow = blur_shadow(shadow); + shadow = blur_shadow(shadow); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, #ifdef LIGHT_BACKLIGHT_USED - backlight, + backlight, #endif #ifdef LIGHT_TRANSMITTANCE_USED - transmittance_color, - transmittance_depth, - transmittance_curve, - transmittance_boost, + transmittance_color, + transmittance_depth, + transmittance_boost, #endif #ifdef LIGHT_RIM_USED - rim, - rim_tint, - albedo, + rim, + rim_tint, + albedo, #endif #ifdef LIGHT_CLEARCOAT_USED - clearcoat, clearcoat_gloss, + clearcoat, clearcoat_gloss, #endif #ifdef LIGHT_ANISOTROPY_USED - tangent, binormal, anisotropy, + tangent, binormal, anisotropy, #endif #ifdef USE_SHADOW_TO_OPACITY - alpha, + alpha, #endif - diffuse_light, specular_light); - } + diffuse_light, specular_light); } } + } #ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); #if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } + if (alpha < alpha_scissor) { + discard; + } #endif // ALPHA_SCISSOR_USED #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { - discard; - } + if (alpha < opaque_prepass_threshold) { + discard; + } #endif // USE_OPAQUE_PREPASS @@ -1819,126 +1760,126 @@ void main() { #ifdef MODE_RENDER_SDF - { - vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; - ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); - - uint albedo16 = 0x1; //solid flag - albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; - albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; - albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; - - imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); - - uint facing_bits = 0; - const vec3 aniso_dir[6] = vec3[]( - vec3(1, 0, 0), - vec3(0, 1, 0), - vec3(0, 0, 1), - vec3(-1, 0, 0), - vec3(0, -1, 0), - vec3(0, 0, -1)); - - vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); - - float closest_dist = -1e20; - - for (uint i = 0; i < 6; i++) { - float d = dot(cam_normal, aniso_dir[i]); - if (d > closest_dist) { - closest_dist = d; - facing_bits = (1 << i); - } + { + vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz; + ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size)); + + uint albedo16 = 0x1; //solid flag + albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11; + albedo16 |= clamp(uint(albedo.g * 31.0), 0, 31) << 6; + albedo16 |= clamp(uint(albedo.b * 31.0), 0, 31) << 1; + + imageStore(albedo_volume_grid, grid_pos, uvec4(albedo16)); + + uint facing_bits = 0; + const vec3 aniso_dir[6] = vec3[]( + vec3(1, 0, 0), + vec3(0, 1, 0), + vec3(0, 0, 1), + vec3(-1, 0, 0), + vec3(0, -1, 0), + vec3(0, 0, -1)); + + vec3 cam_normal = mat3(scene_data.camera_matrix) * normalize(normal_interp); + + float closest_dist = -1e20; + + for (uint i = 0; i < 6; i++) { + float d = dot(cam_normal, aniso_dir[i]); + if (d > closest_dist) { + closest_dist = d; + facing_bits = (1 << i); } + } - imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits + imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits - if (length(emission) > 0.001) { - float lumas[6]; - vec3 light_total = vec3(0); + if (length(emission) > 0.001) { + float lumas[6]; + vec3 light_total = vec3(0); - for (int i = 0; i < 6; i++) { - float strength = max(0.0, dot(cam_normal, aniso_dir[i])); - vec3 light = emission * strength; - light_total += light; - lumas[i] = max(light.r, max(light.g, light.b)); - } + for (int i = 0; i < 6; i++) { + float strength = max(0.0, dot(cam_normal, aniso_dir[i])); + vec3 light = emission * strength; + light_total += light; + lumas[i] = max(light.r, max(light.g, light.b)); + } - float luma_total = max(light_total.r, max(light_total.g, light_total.b)); + float luma_total = max(light_total.r, max(light_total.g, light_total.b)); - uint light_aniso = 0; + uint light_aniso = 0; - for (int i = 0; i < 6; i++) { - light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); - } + for (int i = 0; i < 6; i++) { + light_aniso |= min(31, uint((lumas[i] / luma_total) * 31.0)) << (i * 5); + } - //compress to RGBE9995 to save space + //compress to RGBE9995 to save space - const float pow2to9 = 512.0f; - const float B = 15.0f; - const float N = 9.0f; - const float LN2 = 0.6931471805599453094172321215; + const float pow2to9 = 512.0f; + const float B = 15.0f; + const float N = 9.0f; + const float LN2 = 0.6931471805599453094172321215; - float cRed = clamp(light_total.r, 0.0, 65408.0); - float cGreen = clamp(light_total.g, 0.0, 65408.0); - float cBlue = clamp(light_total.b, 0.0, 65408.0); + float cRed = clamp(light_total.r, 0.0, 65408.0); + float cGreen = clamp(light_total.g, 0.0, 65408.0); + float cBlue = clamp(light_total.b, 0.0, 65408.0); - float cMax = max(cRed, max(cGreen, cBlue)); + float cMax = max(cRed, max(cGreen, cBlue)); - float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; + float expp = max(-B - 1.0f, floor(log(cMax) / LN2)) + 1.0f + B; - float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); + float sMax = floor((cMax / pow(2.0f, expp - B - N)) + 0.5f); - float exps = expp + 1.0f; + float exps = expp + 1.0f; - if (0.0 <= sMax && sMax < pow2to9) { - exps = expp; - } + if (0.0 <= sMax && sMax < pow2to9) { + exps = expp; + } - float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); - float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); - float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); - //store as 8985 to have 2 extra neighbour bits - uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); + float sRed = floor((cRed / pow(2.0f, exps - B - N)) + 0.5f); + float sGreen = floor((cGreen / pow(2.0f, exps - B - N)) + 0.5f); + float sBlue = floor((cBlue / pow(2.0f, exps - B - N)) + 0.5f); + //store as 8985 to have 2 extra neighbour bits + uint light_rgbe = ((uint(sRed) & 0x1FF) >> 1) | ((uint(sGreen) & 0x1FF) << 8) | (((uint(sBlue) & 0x1FF) >> 1) << 17) | ((uint(exps) & 0x1F) << 25); - imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); - imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); - } + imageStore(emission_grid, grid_pos, uvec4(light_rgbe)); + imageStore(emission_aniso_grid, grid_pos, uvec4(light_aniso)); } + } #endif #ifdef MODE_RENDER_MATERIAL - albedo_output_buffer.rgb = albedo; - albedo_output_buffer.a = alpha; + albedo_output_buffer.rgb = albedo; + albedo_output_buffer.a = alpha; - normal_output_buffer.rgb = normal * 0.5 + 0.5; - normal_output_buffer.a = 0.0; - depth_output_buffer.r = -vertex.z; + normal_output_buffer.rgb = normal * 0.5 + 0.5; + normal_output_buffer.a = 0.0; + depth_output_buffer.r = -vertex.z; - orm_output_buffer.r = ao; - orm_output_buffer.g = roughness; - orm_output_buffer.b = metallic; - orm_output_buffer.a = sss_strength; + orm_output_buffer.r = ao; + orm_output_buffer.g = roughness; + orm_output_buffer.b = metallic; + orm_output_buffer.a = sss_strength; - emission_output_buffer.rgb = emission; - emission_output_buffer.a = 0.0; + emission_output_buffer.rgb = emission; + emission_output_buffer.a = 0.0; #endif #ifdef MODE_RENDER_NORMAL_ROUGHNESS - normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); - -#ifdef MODE_RENDER_GIPROBE - if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_GIPROBE)) { // process giprobes - uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; - uint index2 = instances.data[instance_index].gi_offset >> 16; - giprobe_buffer.x = index1 & 0xFF; - giprobe_buffer.y = index2 & 0xFF; - } else { - giprobe_buffer.x = 0xFF; - giprobe_buffer.y = 0xFF; - } + normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness); + +#ifdef MODE_RENDER_VOXEL_GI + if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances + uint index1 = instances.data[instance_index].gi_offset & 0xFFFF; + uint index2 = instances.data[instance_index].gi_offset >> 16; + voxel_gi_buffer.x = index1 & 0xFF; + voxel_gi_buffer.y = index2 & 0xFF; + } else { + voxel_gi_buffer.x = 0xFF; + voxel_gi_buffer.y = 0xFF; + } #endif #endif //MODE_RENDER_NORMAL_ROUGHNESS @@ -1996,4 +1937,4 @@ void main() { #endif //MODE_MULTIPLE_RENDER_TARGETS #endif //MODE_RENDER_DEPTH - } +} diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index ca75d6300e..6599a42bab 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -1,7 +1,7 @@ #define M_PI 3.14159265359 #define ROUGHNESS_MAX_LOD 5 -#define MAX_GI_PROBES 8 +#define MAX_VOXEL_GI_INSTANCES 8 #if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) @@ -15,7 +15,7 @@ #include "cluster_data_inc.glsl" #include "decal_data_inc.glsl" -#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_GIPROBE) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) +#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) #ifndef NORMAL_USED #define NORMAL_USED #endif @@ -52,12 +52,13 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12]; layout(set = 0, binding = 2) uniform sampler shadow_sampler; +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5) #define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) #define INSTANCE_FLAGS_USE_SDFGI (1 << 7) #define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) #define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) #define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) -#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11) +#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11) #define INSTANCE_FLAGS_MULTIMESH (1 << 12) #define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) #define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) @@ -66,8 +67,6 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler; //3 bits of stride #define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF -#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24) - layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { LightData data[]; } @@ -122,7 +121,7 @@ layout(set = 0, binding = 12, std430) restrict readonly buffer GlobalVariableDat } global_variables; -struct SDFGIProbeCascadeData { +struct SDFVoxelGICascadeData { vec3 position; float to_probe; ivec3 probe_world_offset; @@ -153,7 +152,7 @@ layout(set = 0, binding = 13, std140) uniform SDFGI { vec3 cascade_probe_size; uint pad5; - SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES]; + SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES]; } sdfgi; @@ -275,7 +274,7 @@ layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas; layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES]; -layout(set = 1, binding = 7) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer { uint data[]; @@ -306,7 +305,7 @@ layout(set = 1, binding = 14) uniform texture2D reflection_buffer; layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture; layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades; -struct GIProbeData { +struct VoxelGIData { mat4 xform; vec3 bounds; float dynamic_range; @@ -322,10 +321,10 @@ struct GIProbeData { uint mipmaps; }; -layout(set = 1, binding = 17, std140) uniform GIProbes { - GIProbeData data[MAX_GI_PROBES]; +layout(set = 1, binding = 17, std140) uniform VoxelGIs { + VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; } -gi_probes; +voxel_gi_instances; layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl index b41f16cbe7..c88bd0a14b 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_gi_inc.glsl @@ -48,24 +48,24 @@ vec4 voxel_cone_trace_45_degrees(texture3D probe, vec3 cell_size, vec3 pos, vec3 return color; } -void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) { - position = (gi_probes.data[index].xform * vec4(position, 1.0)).xyz; - ref_vec = normalize((gi_probes.data[index].xform * vec4(ref_vec, 0.0)).xyz); - normal = normalize((gi_probes.data[index].xform * vec4(normal, 0.0)).xyz); +void voxel_gi_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 normal_xform, float roughness, vec3 ambient, vec3 environment, inout vec4 out_spec, inout vec4 out_diff) { + position = (voxel_gi_instances.data[index].xform * vec4(position, 1.0)).xyz; + ref_vec = normalize((voxel_gi_instances.data[index].xform * vec4(ref_vec, 0.0)).xyz); + normal = normalize((voxel_gi_instances.data[index].xform * vec4(normal, 0.0)).xyz); - position += normal * gi_probes.data[index].normal_bias; + position += normal * voxel_gi_instances.data[index].normal_bias; //this causes corrupted pixels, i have no idea why.. - if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, gi_probes.data[index].bounds))))) { + if (any(bvec2(any(lessThan(position, vec3(0.0))), any(greaterThan(position, voxel_gi_instances.data[index].bounds))))) { return; } - vec3 blendv = abs(position / gi_probes.data[index].bounds * 2.0 - 1.0); + vec3 blendv = abs(position / voxel_gi_instances.data[index].bounds * 2.0 - 1.0); float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0); //float blend=1.0; - float max_distance = length(gi_probes.data[index].bounds); - vec3 cell_size = 1.0 / gi_probes.data[index].bounds; + float max_distance = length(voxel_gi_instances.data[index].bounds); + vec3 cell_size = 1.0 / voxel_gi_instances.data[index].bounds; //radiance @@ -83,26 +83,26 @@ void gi_probe_compute(uint index, vec3 position, vec3 normal, vec3 ref_vec, mat3 vec3 light = vec3(0.0); for (int i = 0; i < MAX_CONE_DIRS; i++) { - vec3 dir = normalize((gi_probes.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz); + vec3 dir = normalize((voxel_gi_instances.data[index].xform * vec4(normal_xform * cone_dirs[i], 0.0)).xyz); - vec4 cone_light = voxel_cone_trace_45_degrees(gi_probe_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, gi_probes.data[index].bias); + vec4 cone_light = voxel_cone_trace_45_degrees(voxel_gi_textures[index], cell_size, position, dir, cone_angle_tan, max_distance, voxel_gi_instances.data[index].bias); - if (gi_probes.data[index].blend_ambient) { + if (voxel_gi_instances.data[index].blend_ambient) { cone_light.rgb = mix(ambient, cone_light.rgb, min(1.0, cone_light.a / 0.95)); } light += cone_weights[i] * cone_light.rgb; } - light *= gi_probes.data[index].dynamic_range; + light *= voxel_gi_instances.data[index].dynamic_range; out_diff += vec4(light * blend, blend); //irradiance - vec4 irr_light = voxel_cone_trace(gi_probe_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, gi_probes.data[index].bias); - if (gi_probes.data[index].blend_ambient) { + vec4 irr_light = voxel_cone_trace(voxel_gi_textures[index], cell_size, position, ref_vec, tan(roughness * 0.5 * M_PI * 0.99), max_distance, voxel_gi_instances.data[index].bias); + if (voxel_gi_instances.data[index].blend_ambient) { irr_light.rgb = mix(environment, irr_light.rgb, min(1.0, irr_light.a / 0.95)); } - irr_light.rgb *= gi_probes.data[index].dynamic_range; + irr_light.rgb *= voxel_gi_instances.data[index].dynamic_range; //irr_light=vec3(0.0); out_spec += vec4(irr_light.rgb * blend, blend); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 32a86cb166..b6e89acb46 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -80,7 +80,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, #ifdef LIGHT_TRANSMITTANCE_USED vec4 transmittance_color, float transmittance_depth, - float transmittance_curve, float transmittance_boost, float transmittance_z, #endif @@ -144,12 +143,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, float metallic = unpackUnorm4x8(orms).z; if (metallic < 1.0) { float roughness = unpackUnorm4x8(orms).y; - -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif #if defined(DIFFUSE_LAMBERT_WRAP) // energy conserving lambert wrap shader @@ -194,9 +188,8 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, #ifdef LIGHT_TRANSMITTANCE_USED -#ifdef SSS_MODE_SKIN - { +#ifdef SSS_MODE_SKIN float scale = 8.25 / transmittance_depth; float d = scale * abs(transmittance_z); float dd = -d * d; @@ -208,19 +201,15 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); - } #else - if (transmittance_depth > 0.0) { - float fade = clamp(abs(transmittance_z / transmittance_depth), 0.0, 1.0); - - fade = pow(max(0.0, 1.0 - fade), transmittance_curve); - fade *= clamp(transmittance_boost - NdotL, 0.0, 1.0); - - diffuse_light += transmittance_color.rgb * light_color * (1.0 / M_PI) * transmittance_color.a * fade; + float scale = 8.25 / transmittance_depth; + float d = scale * abs(transmittance_z); + float dd = -d * d; + diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); +#endif } - -#endif //SSS_MODE_SKIN +#else #endif //LIGHT_TRANSMITTANCE_USED } @@ -243,7 +232,11 @@ void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float attenuation, #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); +#ifdef USE_SOFT_SHADOWS float cRdotV = clamp(A + dot(R, V), 0.0, 1.0); +#else + float cRdotV = clamp(dot(R, V), 0.0, 1.0); +#endif float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float phong = pow(cRdotV, shininess); phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); @@ -578,7 +571,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_TRANSMITTANCE_USED vec4 transmittance_color, float transmittance_depth, - float transmittance_curve, float transmittance_boost, #endif #ifdef LIGHT_RIM_USED @@ -618,20 +610,22 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v //redo shadowmapping, but shrink the model a bit to avoid arctifacts vec4 splane = (omni_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * omni_lights.data[idx].transmittance_bias, 1.0)); - shadow_len = length(splane.xyz); - splane = normalize(splane.xyz); + float shadow_len = length(splane.xyz); + splane.xyz = normalize(splane.xyz); if (splane.z >= 0.0) { splane.z += 1.0; - + clamp_rect.y += clamp_rect.w; } else { splane.z = 1.0 - splane.z; } splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; splane.z = shadow_len * omni_lights.data[idx].inv_radius; splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + // splane.xy = clamp(splane.xy,clamp_rect.xy + scene_data.shadow_atlas_pixel_size,clamp_rect.xy + clamp_rect.zw - scene_data.shadow_atlas_pixel_size ); splane.w = 1.0; //needed? i think it should be 1 already float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; @@ -705,7 +699,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_TRANSMITTANCE_USED transmittance_color, transmittance_depth, - transmittance_curve, transmittance_boost, transmittance_z, #endif @@ -830,7 +823,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_TRANSMITTANCE_USED vec4 transmittance_color, float transmittance_depth, - float transmittance_curve, float transmittance_boost, #endif #ifdef LIGHT_RIM_USED @@ -877,13 +869,17 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v float transmittance_z = transmittance_depth; transmittance_color.a *= light_attenuation; { - splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); + vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal_interp) * spot_lights.data[idx].transmittance_bias, 1.0)); splane /= splane.w; splane.xy = splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy; float shadow_z = textureLod(sampler2D(shadow_atlas, material_samplers[SAMPLER_LINEAR_CLAMP]), splane.xy, 0.0).r; - //reconstruct depth - shadow_z /= spot_lights.data[idx].inv_radius; + + shadow_z = shadow_z * 2.0 - 1.0; + float z_far = 1.0 / spot_lights.data[idx].inv_radius; + float z_near = 0.01; + shadow_z = 2.0 * z_near * z_far / (z_far + z_near - shadow_z * (z_far - z_near)); + //distance to light plane float z = dot(spot_dir, -light_rel_vec); transmittance_z = z - shadow_z; @@ -899,7 +895,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_TRANSMITTANCE_USED transmittance_color, transmittance_depth, - transmittance_curve, transmittance_boost, transmittance_z, #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index d488c99b6d..1bc17e140f 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -96,6 +96,18 @@ layout(location = 8) out float dp_clip; #endif +#ifdef USE_MULTIVIEW +#ifdef has_VK_KHR_multiview +#define ViewIndex gl_ViewIndex +#else +// !BAS! This needs to become an input once we implement our fallback! +#define ViewIndex 0 +#endif +#else +// Set to zero, not supported in non stereo +#define ViewIndex 0 +#endif //USE_MULTIVIEW + invariant gl_Position; #GLOBALS @@ -234,7 +246,13 @@ void main() { vec4 position; #endif +#ifdef USE_MULTIVIEW + mat4 projection_matrix = scene_data.projection_matrix_view[ViewIndex]; + mat4 inv_projection_matrix = scene_data.inv_projection_matrix_view[ViewIndex]; +#else mat4 projection_matrix = scene_data.projection_matrix; + mat4 inv_projection_matrix = scene_data.inv_projection_matrix; +#endif //USE_MULTIVIEW //using world coordinates #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) @@ -386,10 +404,26 @@ layout(location = 8) in float dp_clip; #endif +#ifdef USE_MULTIVIEW +#ifdef has_VK_KHR_multiview +#define ViewIndex gl_ViewIndex +#else +// !BAS! This needs to become an input once we implement our fallback! +#define ViewIndex 0 +#endif +#else +// Set to zero, not supported in non stereo +#define ViewIndex 0 +#endif //USE_MULTIVIEW + //defines to keep compatibility with vertex #define world_matrix draw_call.transform +#ifdef USE_MULTIVIEW +#define projection_matrix scene_data.projection_matrix_view[ViewIndex] +#else #define projection_matrix scene_data.projection_matrix +#endif #if defined(ENABLE_SSS) && defined(ENABLE_TRANSMITTANCE) //both required for transmittance to be enabled @@ -509,7 +543,6 @@ void main() { vec3 backlight = vec3(0.0); vec4 transmittance_color = vec4(0.0); float transmittance_depth = 0.0; - float transmittance_curve = 1.0; float transmittance_boost = 0.0; float metallic = 0.0; float specular = 0.5; @@ -761,7 +794,7 @@ void main() { if (scene_data.roughness_limiter_enabled) { //http://www.jp.square-enix.com/tech/library/pdf/ImprovedGeometricSpecularAA.pdf float roughness2 = roughness * roughness; - vec3 dndu = dFdx(normal), dndv = dFdx(normal); + vec3 dndu = dFdx(normal), dndv = dFdy(normal); float variance = scene_data.roughness_limiter_amount * (dot(dndu, dndu) + dot(dndv, dndv)); float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2); @@ -1259,7 +1292,6 @@ void main() { #ifdef LIGHT_TRANSMITTANCE_USED transmittance_color, transmittance_depth, - transmittance_curve, transmittance_boost, transmittance_z, #endif @@ -1310,7 +1342,6 @@ void main() { #ifdef LIGHT_TRANSMITTANCE_USED transmittance_color, transmittance_depth, - transmittance_curve, transmittance_boost, #endif */ @@ -1359,7 +1390,6 @@ void main() { #ifdef LIGHT_TRANSMITTANCE_USED transmittance_color, transmittance_depth, - transmittance_curve, transmittance_boost, #endif */ diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl index 0156b58574..d4ebcbeec4 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -1,4 +1,9 @@ #define M_PI 3.14159265359 +#define MAX_VIEWS 2 + +#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview) +#extension GL_EXT_multiview : enable +#endif #include "decal_data_inc.glsl" @@ -46,12 +51,13 @@ layout(set = 0, binding = 1) uniform sampler material_samplers[12]; layout(set = 0, binding = 2) uniform sampler shadow_sampler; +#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 5) #define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 6) #define INSTANCE_FLAGS_USE_SDFGI (1 << 7) #define INSTANCE_FLAGS_USE_LIGHTMAP_CAPTURE (1 << 8) #define INSTANCE_FLAGS_USE_LIGHTMAP (1 << 9) #define INSTANCE_FLAGS_USE_SH_LIGHTMAP (1 << 10) -#define INSTANCE_FLAGS_USE_GIPROBE (1 << 11) +#define INSTANCE_FLAGS_USE_VOXEL_GI (1 << 11) #define INSTANCE_FLAGS_MULTIMESH (1 << 12) #define INSTANCE_FLAGS_MULTIMESH_FORMAT_2D (1 << 13) #define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) @@ -60,8 +66,6 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler; //3 bits of stride #define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF -#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 24) - layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { LightData data[]; } @@ -121,10 +125,13 @@ global_variables; layout(set = 1, binding = 0, std140) uniform SceneData { mat4 projection_matrix; mat4 inv_projection_matrix; - mat4 camera_matrix; mat4 inv_camera_matrix; + // only used for multiview + mat4 projection_matrix_view[MAX_VIEWS]; + mat4 inv_projection_matrix_view[MAX_VIEWS]; + vec2 viewport_size; vec2 screen_pixel_size; diff --git a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl index 7e06516d90..2328effe7b 100644 --- a/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl @@ -36,12 +36,12 @@ void main() { float divisor = 0.0; vec4 color; float depth; - vec3 normal; + vec4 normal; if (params.filtered) { color = vec4(0.0); depth = 0.0; - normal = vec3(0.0); + normal = vec4(0.0); for (int i = 0; i < 4; i++) { ivec2 ofs = ssC << 1; @@ -53,7 +53,9 @@ void main() { } color += texelFetch(source_ssr, ofs, 0); float d = texelFetch(source_depth, ofs, 0).r; - normal += texelFetch(source_normal, ofs, 0).xyz * 2.0 - 1.0; + vec4 nr = texelFetch(source_normal, ofs, 0); + normal.xyz += nr.xyz * 2.0 - 1.0; + normal.w += nr.w; d = d * 2.0 - 1.0; if (params.orthogonal) { @@ -66,11 +68,12 @@ void main() { color /= 4.0; depth /= 4.0; - normal = normalize(normal / 4.0) * 0.5 + 0.5; + normal.xyz = normalize(normal.xyz / 4.0) * 0.5 + 0.5; + normal.w /= 4.0; } else { color = texelFetch(source_ssr, ssC << 1, 0); depth = texelFetch(source_depth, ssC << 1, 0).r; - normal = texelFetch(source_normal, ssC << 1, 0).xyz; + normal = texelFetch(source_normal, ssC << 1, 0); depth = depth * 2.0 - 1.0; if (params.orthogonal) { @@ -83,5 +86,5 @@ void main() { imageStore(dest_ssr, ssC, color); imageStore(dest_depth, ssC, vec4(depth)); - imageStore(dest_normal, ssC, vec4(normal, 0.0)); + imageStore(dest_normal, ssC, normal); } diff --git a/servers/rendering/renderer_rd/shaders/sky.glsl b/servers/rendering/renderer_rd/shaders/sky.glsl index 9924da37d5..41c6325bc5 100644 --- a/servers/rendering/renderer_rd/shaders/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/sky.glsl @@ -4,11 +4,17 @@ #VERSION_DEFINES +#define MAX_VIEWS 2 + +#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview) +#extension GL_EXT_multiview : enable +#endif + layout(location = 0) out vec2 uv_interp; layout(push_constant, binding = 1, std430) uniform Params { mat3 orientation; - vec4 proj; + vec4 projections[MAX_VIEWS]; vec4 position_multiplier; float time; } @@ -26,15 +32,29 @@ void main() { #VERSION_DEFINES +#ifdef USE_MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +// !BAS! This needs to become an input once we implement our fallback! +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#else // USE_MULTIVIEW +// Set to zero, not supported in non stereo +#define ViewIndex 0 +#endif //USE_MULTIVIEW + #define M_PI 3.14159265359 +#define MAX_VIEWS 2 layout(location = 0) in vec2 uv_interp; layout(push_constant, binding = 1, std430) uniform Params { mat3 orientation; - vec4 proj; + vec4 projections[MAX_VIEWS]; vec4 position_multiplier; - float time; //TODO consider adding vec2 screen res, and float radiance size + float time; } params; @@ -85,7 +105,6 @@ struct DirectionalLightData { layout(set = 0, binding = 3, std140) uniform DirectionalLights { DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; } - directional_lights; #ifdef MATERIAL_UNIFORMS_USED @@ -154,8 +173,8 @@ vec4 fog_process(vec3 view, vec3 sky_color) { void main() { vec3 cube_normal; cube_normal.z = -1.0; - cube_normal.x = (cube_normal.z * (-uv_interp.x - params.proj.x)) / params.proj.y; - cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.proj.z)) / params.proj.w; + cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y; + cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w; cube_normal = mat3(params.orientation) * cube_normal; cube_normal.z = -cube_normal.z; cube_normal = normalize(cube_normal); diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 86b4da6b08..23f83b3b9c 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -4,6 +4,12 @@ #VERSION_DEFINES +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#endif +#endif + layout(location = 0) out vec2 uv_interp; void main() { @@ -18,9 +24,22 @@ void main() { #VERSION_DEFINES +#ifdef MULTIVIEW +#ifdef has_VK_KHR_multiview +#extension GL_EXT_multiview : enable +#define ViewIndex gl_ViewIndex +#else // has_VK_KHR_multiview +#define ViewIndex 0 +#endif // has_VK_KHR_multiview +#endif //MULTIVIEW + layout(location = 0) in vec2 uv_interp; +#ifdef MULTIVIEW +layout(set = 0, binding = 0) uniform sampler2DArray source_color; +#else layout(set = 0, binding = 0) uniform sampler2D source_color; +#endif layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; layout(set = 2, binding = 0) uniform sampler2D source_glow; #ifdef USE_1D_LUT @@ -277,10 +296,17 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { const float FXAA_REDUCE_MUL = (1.0 / 8.0); const float FXAA_SPAN_MAX = 8.0; +#ifdef MULTIVIEW + vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; + vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(1.0, -1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; + vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; + vec3 rgbSE = textureLod(source_color, vec3(uv_interp + vec2(1.0, 1.0) * params.pixel_size, ViewIndex), 0.0).xyz * exposure; +#else vec3 rgbNW = textureLod(source_color, uv_interp + vec2(-1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure; vec3 rgbNE = textureLod(source_color, uv_interp + vec2(1.0, -1.0) * params.pixel_size, 0.0).xyz * exposure; vec3 rgbSW = textureLod(source_color, uv_interp + vec2(-1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure; vec3 rgbSE = textureLod(source_color, uv_interp + vec2(1.0, 1.0) * params.pixel_size, 0.0).xyz * exposure; +#endif vec3 rgbM = color; vec3 luma = vec3(0.299, 0.587, 0.114); float lumaNW = dot(rgbNW, luma); @@ -305,8 +331,13 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { dir * rcpDirMin)) * params.pixel_size; +#ifdef MULTIVIEW + vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz); +#else vec3 rgbA = 0.5 * exposure * (textureLod(source_color, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source_color, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source_color, uv_interp + dir * 0.5, 0.0).xyz); +#endif float lumaB = dot(rgbB, luma); if ((lumaB < lumaMin) || (lumaB > lumaMax)) { @@ -329,7 +360,11 @@ vec3 screen_space_dither(vec2 frag_coord) { } void main() { +#ifdef MULTIVIEW + vec3 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f).rgb; +#else vec3 color = textureLod(source_color, uv_interp, 0.0f).rgb; +#endif // Exposure diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index c793b6ebe1..f2010222e5 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -72,9 +72,9 @@ layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_ma layout(set = 0, binding = 10) uniform sampler shadow_sampler; -#define MAX_GI_PROBES 8 +#define MAX_VOXEL_GI_INSTANCES 8 -struct GIProbeData { +struct VoxelGIData { mat4 xform; vec3 bounds; float dynamic_range; @@ -90,12 +90,12 @@ struct GIProbeData { uint mipmaps; }; -layout(set = 0, binding = 11, std140) uniform GIProbes { - GIProbeData data[MAX_GI_PROBES]; +layout(set = 0, binding = 11, std140) uniform VoxelGIs { + VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; } -gi_probes; +voxel_gi_instances; -layout(set = 0, binding = 12) uniform texture3D gi_probe_textures[MAX_GI_PROBES]; +layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps; @@ -104,7 +104,7 @@ layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps; // SDFGI Integration on set 1 #define SDFGI_MAX_CASCADES 8 -struct SDFGIProbeCascadeData { +struct SDFVoxelGICascadeData { vec3 position; float to_probe; ivec3 probe_world_offset; @@ -135,7 +135,7 @@ layout(set = 1, binding = 0, std140) uniform SDFGI { vec3 cascade_probe_size; uint pad5; - SDFGIProbeCascadeData cascades[SDFGI_MAX_CASCADES]; + SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES]; } sdfgi; @@ -162,7 +162,7 @@ layout(set = 0, binding = 14, std140) uniform Params { float detail_spread; float gi_inject; - uint max_gi_probes; + uint max_voxel_gi_instances; uint cluster_type_size; vec2 screen_size; @@ -533,21 +533,21 @@ void main() { vec3 world_pos = mat3(params.cam_rotation) * view_pos; - for (uint i = 0; i < params.max_gi_probes; i++) { - vec3 position = (gi_probes.data[i].xform * vec4(world_pos, 1.0)).xyz; + for (uint i = 0; i < params.max_voxel_gi_instances; i++) { + vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz; //this causes corrupted pixels, i have no idea why.. - if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, gi_probes.data[i].bounds))))) { - position /= gi_probes.data[i].bounds; + if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) { + position /= voxel_gi_instances.data[i].bounds; vec4 light = vec4(0.0); - for (uint j = 0; j < gi_probes.data[i].mipmaps; j++) { - vec4 slight = textureLod(sampler3D(gi_probe_textures[i], linear_sampler_with_mipmaps), position, float(j)); + for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) { + vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j)); float a = (1.0 - light.a); light += a * slight; } - light.rgb *= gi_probes.data[i].dynamic_range * params.gi_inject; + light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject; total_light += light.rgb; } diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl index 49a493cdc7..49a493cdc7 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi.glsl diff --git a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl index 7d4d72967a..7d4d72967a 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_debug.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi_debug.glsl diff --git a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl index e20b3f680d..e20b3f680d 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe_sdf.glsl +++ b/servers/rendering/renderer_rd/shaders/voxel_gi_sdf.glsl diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index db1e3d1377..8273e53d46 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -42,7 +42,7 @@ public: virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0; virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0; virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0; - virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0; + virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0; virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0; virtual void camera_set_environment(RID p_camera, RID p_env) = 0; virtual void camera_set_camera_effects(RID p_camera, RID p_fx) = 0; @@ -56,13 +56,14 @@ public: virtual RID scenario_allocate() = 0; virtual void scenario_initialize(RID p_rid) = 0; - virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) = 0; virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0; virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx) = 0; virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0; virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) = 0; virtual bool is_scenario(RID p_scenario) const = 0; virtual RID scenario_get_environment(RID p_scenario) = 0; + virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0; + virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) = 0; virtual RID instance_allocate() = 0; virtual void instance_initialize(RID p_rid) = 0; @@ -70,7 +71,7 @@ public: virtual void instance_set_base(RID p_instance, RID p_base) = 0; virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; - virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0; @@ -79,9 +80,9 @@ public: virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0; virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; - virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0; virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0; + virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0; // don't use these in a game! virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0; @@ -92,8 +93,7 @@ public: virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0; virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; - virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; - virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0; + virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0; virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; @@ -189,23 +189,28 @@ public: virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; virtual TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) = 0; - virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; + virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0; virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) = 0; virtual void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) = 0; - virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; - virtual void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas) = 0; + + struct RenderInfo { + int info[RS::VIEWPORT_RENDER_INFO_TYPE_MAX][RS::VIEWPORT_RENDER_INFO_MAX] = {}; + }; + + virtual void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info = nullptr) = 0; virtual void update() = 0; virtual void render_probes() = 0; + virtual void update_visibility_notifiers() = 0; virtual bool free(RID p_rid) = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index fcea8e4ffc..271c039aad 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -43,7 +43,7 @@ RID RendererSceneCull::camera_allocate() { return camera_owner.allocate_rid(); } void RendererSceneCull::camera_initialize(RID p_rid) { - camera_owner.initialize_rid(p_rid, memnew(Camera)); + camera_owner.initialize_rid(p_rid); } void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) { @@ -74,7 +74,7 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p camera->zfar = p_z_far; } -void RendererSceneCull::camera_set_transform(RID p_camera, const Transform &p_transform) { +void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) { Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); camera->transform = p_transform.orthonormalized(); @@ -190,26 +190,26 @@ void RendererSceneCull::_instance_pair(Instance *p_A, Instance *p_B) { ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture } - } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - geom->gi_probes.insert(B); + geom->voxel_gi_instances.insert(B); if (A->dynamic_gi) { - gi_probe->dynamic_geometries.insert(A); + voxel_gi->dynamic_geometries.insert(A); } else { - gi_probe->geometries.insert(A); + voxel_gi->geometries.insert(A); } if (A->scenario && A->array_index >= 0) { InstanceData &idata = A->scenario->instance_data[A->array_index]; - idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY; } - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - gi_probe->lights.insert(A); + } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); + voxel_gi->lights.insert(A); } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); RSG::storage->particles_add_collision(A->base, collision->instance); @@ -281,25 +281,25 @@ void RendererSceneCull::_instance_unpair(Instance *p_A, Instance *p_B) { ((RendererSceneCull *)self)->_instance_queue_update(A, false, false); //need to update capture } - } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_GI_PROBE) && B->base_type == RS::INSTANCE_GI_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); + } else if (self->geometry_instance_pair_mask & (1 << RS::INSTANCE_VOXEL_GI) && B->base_type == RS::INSTANCE_VOXEL_GI && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data); - geom->gi_probes.erase(B); + geom->voxel_gi_instances.erase(B); if (A->dynamic_gi) { - gi_probe->dynamic_geometries.erase(A); + voxel_gi->dynamic_geometries.erase(A); } else { - gi_probe->geometries.erase(A); + voxel_gi->geometries.erase(A); } if (A->scenario && A->array_index >= 0) { InstanceData &idata = A->scenario->instance_data[A->array_index]; - idata.flags |= InstanceData::FLAG_GEOM_GI_PROBE_DIRTY; + idata.flags |= InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY; } - } else if (B->base_type == RS::INSTANCE_GI_PROBE && A->base_type == RS::INSTANCE_LIGHT) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(B->base_data); - gi_probe->lights.erase(A); + } else if (B->base_type == RS::INSTANCE_VOXEL_GI && A->base_type == RS::INSTANCE_LIGHT) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(B->base_data); + voxel_gi->lights.erase(A); } else if (B->base_type == RS::INSTANCE_PARTICLES_COLLISION && A->base_type == RS::INSTANCE_PARTICLES) { InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(B->base_data); RSG::storage->particles_remove_collision(A->base, collision->instance); @@ -310,7 +310,9 @@ RID RendererSceneCull::scenario_allocate() { return scenario_owner.allocate_rid(); } void RendererSceneCull::scenario_initialize(RID p_rid) { - Scenario *scenario = memnew(Scenario); + scenario_owner.initialize_rid(p_rid); + + Scenario *scenario = scenario_owner.getornull(p_rid); scenario->self = p_rid; scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create(); @@ -323,16 +325,9 @@ void RendererSceneCull::scenario_initialize(RID p_rid) { scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool); scenario->instance_data.set_page_pool(&instance_data_page_pool); + scenario->instance_visibility.set_page_pool(&instance_visibility_data_page_pool); RendererSceneOcclusionCull::get_singleton()->add_scenario(p_rid); - - scenario_owner.initialize_rid(p_rid, scenario); -} - -void RendererSceneCull::scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode) { - Scenario *scenario = scenario_owner.getornull(p_scenario); - ERR_FAIL_COND(!scenario); - scenario->debug = p_debug_mode; } void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) { @@ -369,6 +364,37 @@ RID RendererSceneCull::scenario_get_environment(RID p_scenario) { return scenario->environment; } +void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + if (!scenario->viewport_visibility_masks.has(p_viewport)) { + return; + } + + uint64_t mask = scenario->viewport_visibility_masks[p_viewport]; + scenario->used_viewport_visibility_bits &= ~mask; + scenario->viewport_visibility_masks.erase(p_viewport); +} + +void RendererSceneCull::scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) { + Scenario *scenario = scenario_owner.getornull(p_scenario); + ERR_FAIL_COND(!scenario); + ERR_FAIL_COND(scenario->viewport_visibility_masks.has(p_viewport)); + + uint64_t new_mask = 1; + while (new_mask & scenario->used_viewport_visibility_bits) { + new_mask <<= 1; + } + + if (new_mask == 0) { + ERR_PRINT("Only 64 viewports per scenario allowed when using visibility ranges."); + new_mask = ((uint64_t)1) << 63; + } + + scenario->viewport_visibility_masks[p_viewport] = new_mask; + scenario->used_viewport_visibility_bits |= new_mask; +} + /* INSTANCING API */ void RendererSceneCull::_instance_queue_update(Instance *p_instance, bool p_update_aabb, bool p_update_dependencies) { @@ -390,10 +416,9 @@ RID RendererSceneCull::instance_allocate() { return instance_owner.allocate_rid(); } void RendererSceneCull::instance_initialize(RID p_rid) { - Instance *instance = memnew(Instance); + instance_owner.initialize_rid(p_rid); + Instance *instance = instance_owner.getornull(p_rid); instance->self = p_rid; - - instance_owner.initialize_rid(p_rid, instance); } void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { @@ -447,7 +472,6 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { switch (instance->base_type) { case RS::INSTANCE_MESH: case RS::INSTANCE_MULTIMESH: - case RS::INSTANCE_IMMEDIATE: case RS::INSTANCE_PARTICLES: { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); scene_render->geometry_instance_free(geom->geometry_instance); @@ -474,6 +498,9 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); RSG::storage->free(collision->instance); } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + //none + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data); scene_render->free(reflection_probe->instance); @@ -494,23 +521,23 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } scene_render->free(lightmap_data->instance); } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data); #ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + if (voxel_gi->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI."); } #endif #ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + if (voxel_gi->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI."); } #endif - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); + if (voxel_gi->update_element.in_list()) { + voxel_gi_update_list.remove(&voxel_gi->update_element); } - scene_render->free(gi_probe->probe_instance); + scene_render->free(voxel_gi->probe_instance); } break; case RS::INSTANCE_OCCLUDER: { @@ -556,7 +583,6 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } break; case RS::INSTANCE_MESH: case RS::INSTANCE_MULTIMESH: - case RS::INSTANCE_IMMEDIATE: case RS::INSTANCE_PARTICLES: { InstanceGeometryData *geom = memnew(InstanceGeometryData); instance->base_data = geom; @@ -583,6 +609,11 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); instance->base_data = collision; } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData); + vnd->base = p_base; + instance->base_data = vnd; + } break; case RS::INSTANCE_REFLECTION_PROBE: { InstanceReflectionProbeData *reflection_probe = memnew(InstanceReflectionProbeData); reflection_probe->owner = instance; @@ -602,16 +633,16 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { instance->base_data = lightmap_data; lightmap_data->instance = scene_render->lightmap_instance_create(p_base); } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); - instance->base_data = gi_probe; - gi_probe->owner = instance; + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = memnew(InstanceVoxelGIData); + instance->base_data = voxel_gi; + voxel_gi->owner = instance; - if (scenario && !gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); + if (scenario && !voxel_gi->update_element.in_list()) { + voxel_gi_update_list.add(&voxel_gi->update_element); } - gi_probe->probe_instance = scene_render->gi_probe_instance_create(p_base); + voxel_gi->probe_instance = scene_render->voxel_gi_instance_create(p_base); } break; case RS::INSTANCE_OCCLUDER: { @@ -668,22 +699,22 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { case RS::INSTANCE_PARTICLES_COLLISION: { heightfield_particle_colliders_update_list.erase(instance); } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data); #ifdef DEBUG_ENABLED - if (gi_probe->geometries.size()) { - ERR_PRINT("BUG, indexing did not unpair geometries from GIProbe."); + if (voxel_gi->geometries.size()) { + ERR_PRINT("BUG, indexing did not unpair geometries from VoxelGI."); } #endif #ifdef DEBUG_ENABLED - if (gi_probe->lights.size()) { - ERR_PRINT("BUG, indexing did not unpair lights from GIProbe."); + if (voxel_gi->lights.size()) { + ERR_PRINT("BUG, indexing did not unpair lights from VoxelGI."); } #endif - if (gi_probe->update_element.in_list()) { - gi_probe_update_list.remove(&gi_probe->update_element); + if (voxel_gi->update_element.in_list()) { + voxel_gi_update_list.remove(&voxel_gi->update_element); } } break; case RS::INSTANCE_OCCLUDER: { @@ -714,10 +745,10 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { light->D = scenario->directional_lights.push_back(instance); } } break; - case RS::INSTANCE_GI_PROBE: { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); + case RS::INSTANCE_VOXEL_GI: { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data); + if (!voxel_gi->update_element.in_list()) { + voxel_gi_update_list.add(&voxel_gi->update_element); } } break; case RS::INSTANCE_OCCLUDER: { @@ -746,7 +777,7 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) } } -void RendererSceneCull::instance_set_transform(RID p_instance, const Transform &p_transform) { +void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D &p_transform) { Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); @@ -849,7 +880,7 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { } inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { - return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES || p_type == RS::INSTANCE_IMMEDIATE; + return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_PARTICLES; } void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { @@ -902,9 +933,6 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) } } -void RendererSceneCull::instance_set_exterior(RID p_instance, bool p_enabled) { -} - void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); @@ -1103,10 +1131,142 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, } } -void RendererSceneCull::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { +void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + instance->visibility_range_begin = p_min; + instance->visibility_range_end = p_max; + instance->visibility_range_begin_margin = p_min_margin; + instance->visibility_range_end_margin = p_max_margin; + + _update_instance_visibility_dependencies(instance); + + if (instance->scenario && instance->visibility_index != -1) { + InstanceVisibilityData &vd = instance->scenario->instance_visibility[instance->visibility_index]; + vd.range_begin = instance->visibility_range_begin; + vd.range_end = instance->visibility_range_end; + vd.range_begin_margin = instance->visibility_range_begin_margin; + vd.range_end_margin = instance->visibility_range_end_margin; + } } -void RendererSceneCull::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) { +void RendererSceneCull::instance_set_visibility_parent(RID p_instance, RID p_parent_instance) { + Instance *instance = instance_owner.getornull(p_instance); + ERR_FAIL_COND(!instance); + + Instance *old_parent = instance->visibility_parent; + if (old_parent) { + if ((1 << old_parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && old_parent->base_data) { + InstanceGeometryData *old_parent_geom = static_cast<InstanceGeometryData *>(old_parent->base_data); + old_parent_geom->visibility_dependencies.erase(instance); + _update_instance_visibility_depth(old_parent); + } + instance->visibility_parent = nullptr; + } + + Instance *parent = instance_owner.getornull(p_parent_instance); + ERR_FAIL_COND(p_parent_instance.is_valid() && !parent); + + if (parent) { + if ((1 << parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && parent->base_data) { + InstanceGeometryData *parent_geom = static_cast<InstanceGeometryData *>(parent->base_data); + parent_geom->visibility_dependencies.insert(instance); + _update_instance_visibility_depth(parent); + } + instance->visibility_parent = parent; + } + + _update_instance_visibility_dependencies(instance); +} + +void RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) { + bool cycle_detected = false; + Set<Instance *> traversed_nodes; + + { + Instance *instance = p_instance; + while (instance && ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + if (!geom->visibility_dependencies.is_empty()) { + uint32_t depth = 0; + for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { + if (((1 << E->get()->base_type) & RS::INSTANCE_GEOMETRY_MASK) == 0 || !E->get()->base_data) { + continue; + } + InstanceGeometryData *child_geom = static_cast<InstanceGeometryData *>(E->get()->base_data); + depth = MAX(depth, child_geom->visibility_dependencies_depth); + } + geom->visibility_dependencies_depth = depth + 1; + } else { + geom->visibility_dependencies_depth = 0; + } + + if (instance->scenario && instance->visibility_index != -1) { + instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth); + } + + traversed_nodes.insert(instance); + + instance = instance->visibility_parent; + if (traversed_nodes.has(instance)) { + cycle_detected = true; + break; + } + } + } + + if (cycle_detected) { + ERR_PRINT("Cycle detected in the visibility dependecies tree."); + for (Set<Instance *>::Element *E = traversed_nodes.front(); E; E = E->next()) { + Instance *instance = E->get(); + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + geom->visibility_dependencies_depth = 0; + if (instance->scenario && instance->visibility_index != -1) { + instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth); + } + } + } +} + +void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_instance) { + bool is_geometry_instance = ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && p_instance->base_data; + bool has_visibility_range = p_instance->visibility_range_begin > 0.0 || p_instance->visibility_range_end > 0.0; + bool needs_visibility_cull = has_visibility_range && is_geometry_instance && p_instance->array_index != -1; + + if (!needs_visibility_cull && p_instance->visibility_index != -1) { + p_instance->scenario->instance_visibility.remove(p_instance->visibility_index); + p_instance->visibility_index = -1; + } else if (needs_visibility_cull && p_instance->visibility_index == -1) { + InstanceVisibilityData vd; + vd.instance = p_instance; + vd.range_begin = p_instance->visibility_range_begin; + vd.range_end = p_instance->visibility_range_end; + vd.range_begin_margin = p_instance->visibility_range_begin_margin; + vd.range_end_margin = p_instance->visibility_range_end_margin; + vd.position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f; + vd.array_index = p_instance->array_index; + + InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data); + p_instance->scenario->instance_visibility.insert(vd, geom_data->visibility_dependencies_depth); + } + + if (p_instance->scenario && p_instance->array_index != -1) { + p_instance->scenario->instance_data[p_instance->array_index].visibility_index = p_instance->visibility_index; + + InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data); + if ((has_visibility_range || p_instance->visibility_parent) && (p_instance->visibility_index == -1 || (geom_data && geom_data->visibility_dependencies_depth == 0))) { + p_instance->scenario->instance_data[p_instance->array_index].flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK; + } else { + p_instance->scenario->instance_data[p_instance->array_index].flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK; + } + + if (p_instance->visibility_parent) { + p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = p_instance->visibility_parent->array_index; + } else { + p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = -1; + } + } } void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) { @@ -1155,6 +1315,8 @@ void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, c Instance *instance = instance_owner.getornull(p_instance); ERR_FAIL_COND(!instance); + ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); + Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.find(p_parameter); if (!E) { @@ -1253,10 +1415,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data); scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform); - } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(p_instance->base_data); + } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data); - scene_render->gi_probe_instance_set_transform_to_data(gi_probe->probe_instance, p_instance->transform); + scene_render->voxel_gi_instance_set_transform_to_data(voxel_gi->probe_instance, p_instance->transform); } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { RSG::storage->particles_set_emission_transform(p_instance->base, p_instance->transform); } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { @@ -1352,12 +1514,22 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { idata.layer_mask = p_instance->layer_mask; idata.flags = p_instance->base_type; //changing it means de-indexing, so this never needs to be changed later idata.base_rid = p_instance->base; + idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1; + idata.visibility_index = p_instance->visibility_index; + switch (p_instance->base_type) { case RS::INSTANCE_MESH: case RS::INSTANCE_MULTIMESH: - case RS::INSTANCE_IMMEDIATE: case RS::INSTANCE_PARTICLES: { - idata.instance_geometry = static_cast<InstanceGeometryData *>(p_instance->base_data)->geometry_instance; + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); + idata.instance_geometry = geom->geometry_instance; + + for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + if (dep_instance->array_index != -1) { + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = p_instance->array_index; + } + } } break; case RS::INSTANCE_LIGHT: { idata.instance_data_rid = static_cast<InstanceLightData *>(p_instance->base_data)->instance.get_id(); @@ -1371,8 +1543,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { case RS::INSTANCE_LIGHTMAP: { idata.instance_data_rid = static_cast<InstanceLightmapData *>(p_instance->base_data)->instance.get_id(); } break; - case RS::INSTANCE_GI_PROBE: { - idata.instance_data_rid = static_cast<InstanceGIProbeData *>(p_instance->base_data)->probe_instance.get_id(); + case RS::INSTANCE_VOXEL_GI: { + idata.instance_data_rid = static_cast<InstanceVoxelGIData *>(p_instance->base_data)->probe_instance.get_id(); + } break; + case RS::INSTANCE_VISIBLITY_NOTIFIER: { + idata.visibility_notifier = static_cast<InstanceVisibilityNotifierData *>(p_instance->base_data); } break; default: { } @@ -1404,6 +1579,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { p_instance->scenario->instance_data.push_back(idata); p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb)); + _update_instance_visibility_dependencies(p_instance); } else { if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY].update(p_instance->indexer_id, bvh_aabb); @@ -1413,6 +1589,10 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { p_instance->scenario->instance_aabbs[p_instance->array_index] = InstanceBounds(p_instance->transformed_aabb); } + if (p_instance->visibility_index != -1) { + p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f; + } + //move instance and repair pair_pass++; @@ -1425,7 +1605,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if ((1 << p_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { pair.pair_mask |= 1 << RS::INSTANCE_LIGHT; - pair.pair_mask |= 1 << RS::INSTANCE_GI_PROBE; + pair.pair_mask |= 1 << RS::INSTANCE_VOXEL_GI; pair.pair_mask |= 1 << RS::INSTANCE_LIGHTMAP; if (p_instance->base_type == RS::INSTANCE_PARTICLES) { pair.pair_mask |= 1 << RS::INSTANCE_PARTICLES_COLLISION; @@ -1439,7 +1619,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; if (RSG::storage->light_get_bake_mode(p_instance->base) == RS::LIGHT_BAKE_DYNAMIC) { - pair.pair_mask |= (1 << RS::INSTANCE_GI_PROBE); + pair.pair_mask |= (1 << RS::INSTANCE_VOXEL_GI); pair.bvh2 = &p_instance->scenario->indexers[Scenario::INDEXER_VOLUMES]; } } else if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE)) { @@ -1451,7 +1631,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { } else if (p_instance->base_type == RS::INSTANCE_PARTICLES_COLLISION) { pair.pair_mask = (1 << RS::INSTANCE_PARTICLES); pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; - } else if (p_instance->base_type == RS::INSTANCE_GI_PROBE) { + } else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) { //lights and geometries pair.pair_mask = RS::INSTANCE_GEOMETRY_MASK | (1 << RS::INSTANCE_LIGHT); pair.bvh = &p_instance->scenario->indexers[Scenario::INDEXER_GEOMETRY]; @@ -1486,9 +1666,24 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { //replace this by last int32_t swap_with_index = p_instance->scenario->instance_data.size() - 1; if (swap_with_index != p_instance->array_index) { - p_instance->scenario->instance_data[swap_with_index].instance->array_index = p_instance->array_index; //swap + Instance *swapped_instance = p_instance->scenario->instance_data[swap_with_index].instance; + swapped_instance->array_index = p_instance->array_index; //swap p_instance->scenario->instance_data[p_instance->array_index] = p_instance->scenario->instance_data[swap_with_index]; p_instance->scenario->instance_aabbs[p_instance->array_index] = p_instance->scenario->instance_aabbs[swap_with_index]; + + if (swapped_instance->visibility_index != -1) { + swapped_instance->scenario->instance_visibility[swapped_instance->visibility_index].array_index = swapped_instance->array_index; + } + + if ((1 << swapped_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(swapped_instance->base_data); + for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + if (dep_instance != p_instance && dep_instance->array_index != -1) { + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = swapped_instance->array_index; + } + } + } } // pop last @@ -1504,8 +1699,17 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, nullptr, 0); scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0); scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0); - scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, nullptr, 0); + scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, nullptr, 0); + + for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + if (dep_instance->array_index != -1) { + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = -1; + } + } } + + _update_instance_visibility_dependencies(p_instance); } void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { @@ -1534,14 +1738,6 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { } } break; - case RenderingServer::INSTANCE_IMMEDIATE: { - if (p_instance->custom_aabb) { - new_aabb = *p_instance->custom_aabb; - } else { - new_aabb = RSG::storage->immediate_get_aabb(p_instance->base); - } - - } break; case RenderingServer::INSTANCE_PARTICLES: { if (p_instance->custom_aabb) { new_aabb = *p_instance->custom_aabb; @@ -1554,6 +1750,9 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); } break; + case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: { + new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base); + } break; case RenderingServer::INSTANCE_LIGHT: { new_aabb = RSG::storage->light_get_aabb(p_instance->base); @@ -1566,8 +1765,8 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { new_aabb = RSG::storage->decal_get_aabb(p_instance->base); } break; - case RenderingServer::INSTANCE_GI_PROBE: { - new_aabb = RSG::storage->gi_probe_get_bounds(p_instance->base); + case RenderingServer::INSTANCE_VOXEL_GI: { + new_aabb = RSG::storage->voxel_gi_get_bounds(p_instance->base); } break; case RenderingServer::INSTANCE_LIGHTMAP: { @@ -1605,7 +1804,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) continue; //we are inside, ignore exteriors } - Transform to_bounds = lightmap->transform.affine_inverse(); + Transform3D to_bounds = lightmap->transform.affine_inverse(); Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center Vector3 lm_pos = to_bounds.xform(center); @@ -1666,10 +1865,10 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, p_instance->lightmap_sh.ptr()); } -void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { +void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - Transform light_transform = p_instance->transform; + Transform3D light_transform = p_instance->transform; light_transform.orthonormalize(); //scale does not count on lights real_t max_distance = p_cam_projection.get_z_far(); @@ -1680,8 +1879,6 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); real_t min_distance = MIN(p_cam_projection.get_z_near(), max_distance); - RS::LightDirectionalShadowDepthRangeMode depth_range_mode = RSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); - real_t pancake_size = RSG::storage->light_get_param(p_instance->base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE); real_t range = max_distance - min_distance; @@ -1745,7 +1942,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in // obtain the light frustum ranges (given endpoints) - Transform transform = light_transform; //discard scale and stabilize light + Transform3D transform = light_transform; //discard scale and stabilize light Vector3 x_vec = transform.basis.get_axis(Vector3::AXIS_X).normalized(); Vector3 y_vec = transform.basis.get_axis(Vector3::AXIS_Y).normalized(); @@ -1841,22 +2038,13 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in } } - x_max_cam = x_vec.dot(center) + radius + soft_shadow_expand; - x_min_cam = x_vec.dot(center) - radius - soft_shadow_expand; - y_max_cam = y_vec.dot(center) + radius + soft_shadow_expand; - y_min_cam = y_vec.dot(center) - radius - soft_shadow_expand; - - if (depth_range_mode == RS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { - //this trick here is what stabilizes the shadow (make potential jaggies to not move) - //at the cost of some wasted resolution. Still the quality increase is very well worth it - - real_t unit = radius * 2.0 / texture_size; - - x_max_cam = Math::snapped(x_max_cam, unit); - x_min_cam = Math::snapped(x_min_cam, unit); - y_max_cam = Math::snapped(y_max_cam, unit); - y_min_cam = Math::snapped(y_min_cam, unit); - } + // This trick here is what stabilizes the shadow (make potential jaggies to not move) + // at the cost of some wasted resolution. Still, the quality increase is very well worth it. + const real_t unit = radius * 2.0 / texture_size; + x_max_cam = Math::snapped(x_vec.dot(center) + radius + soft_shadow_expand, unit); + x_min_cam = Math::snapped(x_vec.dot(center) - radius - soft_shadow_expand, unit); + y_max_cam = Math::snapped(y_vec.dot(center) + radius + soft_shadow_expand, unit); + y_min_cam = Math::snapped(y_vec.dot(center) - radius - soft_shadow_expand, unit); } //now that we know all ranges, we can proceed to make the light frustum planes, for culling octree @@ -1944,7 +2132,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in Vector2 uv_scale(1.0 / (x_max_cam - x_min_cam), 1.0 / (y_max_cam - y_min_cam)); - Transform ortho_transform; + Transform3D ortho_transform; ortho_transform.basis = transform.basis; ortho_transform.origin = x_vec * (x_min_cam + half_x) + y_vec * (y_min_cam + half_y) + z_vec * z_max; @@ -1961,10 +2149,10 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in } } -bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) { +bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_screen_lod_threshold) { InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); - Transform light_transform = p_instance->transform; + Transform3D light_transform = p_instance->transform; light_transform.orthonormalize(); //scale does not count on lights bool animated_material_found = false; @@ -2071,7 +2259,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons Vector3(0, -1, 0) }; - Transform xform = light_transform * Transform().looking_at(view_normals[i], view_up[i]); + Transform3D xform = light_transform * Transform3D().looking_at(view_normals[i], view_up[i]); Vector<Plane> planes = cm.get_projection_planes(xform); @@ -2186,153 +2374,159 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons return animated_material_found; } -void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { -// render to mono camera +void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) { #ifndef _3D_DISABLED Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); - /* STEP 1 - SETUP CAMERA */ - CameraMatrix camera_matrix; - bool ortho = false; - - switch (camera->type) { - case Camera::ORTHOGONAL: { - camera_matrix.set_orthogonal( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = true; - } break; - case Camera::PERSPECTIVE: { - camera_matrix.set_perspective( - camera->fov, - p_viewport_size.width / (float)p_viewport_size.height, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; + RendererSceneRender::CameraData camera_data; + + // Setup Camera(s) + if (p_xr_interface.is_null()) { + // Normal camera + Transform3D transform = camera->transform; + CameraMatrix projection; + bool vaspect = camera->vaspect; + bool is_ortogonal = false; + + switch (camera->type) { + case Camera::ORTHOGONAL: { + projection.set_orthogonal( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); + is_ortogonal = true; + } break; + case Camera::PERSPECTIVE: { + projection.set_perspective( + camera->fov, + p_viewport_size.width / (float)p_viewport_size.height, + camera->znear, + camera->zfar, + camera->vaspect); - } break; - case Camera::FRUSTUM: { - camera_matrix.set_frustum( - camera->size, - p_viewport_size.width / (float)p_viewport_size.height, - camera->offset, - camera->znear, - camera->zfar, - camera->vaspect); - ortho = false; - } break; + } break; + case Camera::FRUSTUM: { + projection.set_frustum( + camera->size, + p_viewport_size.width / (float)p_viewport_size.height, + camera->offset, + camera->znear, + camera->zfar, + camera->vaspect); + } break; + } + + camera_data.set_camera(transform, projection, is_ortogonal, vaspect); + } else { + // Setup our camera for our XR interface. + // We can support multiple views here each with their own camera + Transform3D transforms[RendererSceneRender::MAX_RENDER_VIEWS]; + CameraMatrix projections[RendererSceneRender::MAX_RENDER_VIEWS]; + + uint32_t view_count = p_xr_interface->get_view_count(); + ERR_FAIL_COND_MSG(view_count > RendererSceneRender::MAX_RENDER_VIEWS, "Requested view count is not supported"); + + float aspect = p_viewport_size.width / (float)p_viewport_size.height; + + Transform3D world_origin = XRServer::get_singleton()->get_world_origin(); + + // We ignore our camera position, it will have been positioned with a slightly old tracking position. + // Instead we take our origin point and have our XR interface add fresh tracking data! Whoohoo! + for (uint32_t v = 0; v < view_count; v++) { + transforms[v] = p_xr_interface->get_transform_for_view(v, world_origin); + projections[v] = p_xr_interface->get_projection_for_view(v, aspect, camera->znear, camera->zfar); + } + + if (view_count == 1) { + camera_data.set_camera(transforms[0], projections[0], false, camera->vaspect); + } else if (view_count == 2) { + camera_data.set_multiview_camera(view_count, transforms, projections, false, camera->vaspect); + } else { + // this won't be called (see fail check above) but keeping this comment to indicate we may support more then 2 views in the future... + } } RID environment = _render_get_environment(p_camera, p_scenario); RENDER_TIMESTAMP("Update occlusion buffer") - RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera->transform, camera_matrix, ortho, RendererThreadPool::singleton->thread_work_pool); + // For now just cull on the first camera + RendererSceneOcclusionCull::get_singleton()->buffer_update(p_viewport, camera_data.main_transform, camera_data.main_projection, camera_data.is_ortogonal, RendererThreadPool::singleton->thread_work_pool); - _render_scene(camera->transform, camera_matrix, ortho, camera->vaspect, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); + _render_scene(&camera_data, p_render_buffers, environment, camera->effects, camera->visible_layers, p_scenario, p_viewport, p_shadow_atlas, RID(), -1, p_screen_lod_threshold, true, r_render_info); #endif } -void RendererSceneCull::render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas) { - // render for AR/VR interface -#if 0 - Camera *camera = camera_owner.getornull(p_camera); - ERR_FAIL_COND(!camera); +void RendererSceneCull::_visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data) { + uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); + uint32_t bin_from = p_thread * cull_data->cull_count / total_threads; + uint32_t bin_to = (p_thread + 1 == total_threads) ? cull_data->cull_count : ((p_thread + 1) * cull_data->cull_count / total_threads); - /* SETUP CAMERA, we are ignoring type and FOV here */ - float aspect = p_viewport_size.width / (float)p_viewport_size.height; - CameraMatrix camera_matrix = p_interface->get_projection_for_eye(p_eye, aspect, camera->znear, camera->zfar); + _visibility_cull(*cull_data, cull_data->cull_offset + bin_from, cull_data->cull_offset + bin_to); +} - // We also ignore our camera position, it will have been positioned with a slightly old tracking position. - // Instead we take our origin point and have our ar/vr interface add fresh tracking data! Whoohoo! - Transform world_origin = XRServer::get_singleton()->get_world_origin(); - Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); +void RendererSceneCull::_visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to) { + Scenario *scenario = cull_data.scenario; + for (unsigned int i = p_from; i < p_to; i++) { + InstanceVisibilityData &vd = scenario->instance_visibility[i]; + InstanceData &idata = scenario->instance_data[vd.array_index]; - RID environment = _render_get_environment(p_camera, p_scenario); + if (idata.parent_array_index >= 0) { + uint32_t parent_flags = scenario->instance_data[idata.parent_array_index].flags; + if ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) || (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE) == 0) { + idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + continue; + } + } - // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye - if (p_eye == XRInterface::EYE_LEFT) { - // Center our transform, we assume basis is equal. - Transform mono_transform = cam_transform; - Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); - mono_transform.origin += right_transform.origin; - mono_transform.origin *= 0.5; - - // We need to combine our projection frustums for culling. - // Ideally we should use our clipping planes for this and combine them, - // however our shadow map logic uses our projection matrix. - // Note: as our left and right frustums should be mirrored, we don't need our right projection matrix. - - // - get some base values we need - float eye_dist = (mono_transform.origin - cam_transform.origin).length(); - float z_near = camera_matrix.get_z_near(); // get our near plane - float z_far = camera_matrix.get_z_far(); // get our far plane - float width = (2.0 * z_near) / camera_matrix.matrix[0][0]; - float x_shift = width * camera_matrix.matrix[2][0]; - float height = (2.0 * z_near) / camera_matrix.matrix[1][1]; - float y_shift = height * camera_matrix.matrix[2][1]; - - // printf("Eye_dist = %f, Near = %f, Far = %f, Width = %f, Shift = %f\n", eye_dist, z_near, z_far, width, x_shift); - - // - calculate our near plane size (horizontal only, right_near is mirrored) - float left_near = -eye_dist - ((width - x_shift) * 0.5); - - // - calculate our far plane size (horizontal only, right_far is mirrored) - float left_far = -eye_dist - (z_far * (width - x_shift) * 0.5 / z_near); - float left_far_right_eye = eye_dist - (z_far * (width + x_shift) * 0.5 / z_near); - if (left_far > left_far_right_eye) { - // on displays smaller then double our iod, the right eye far frustrum can overtake the left eyes. - left_far = left_far_right_eye; - } - - // - figure out required z-shift - float slope = (left_far - left_near) / (z_far - z_near); - float z_shift = (left_near / slope) - z_near; - - // - figure out new vertical near plane size (this will be slightly oversized thanks to our z-shift) - float top_near = (height - y_shift) * 0.5; - top_near += (top_near / z_near) * z_shift; - float bottom_near = -(height + y_shift) * 0.5; - bottom_near += (bottom_near / z_near) * z_shift; - - // printf("Left_near = %f, Left_far = %f, Top_near = %f, Bottom_near = %f, Z_shift = %f\n", left_near, left_far, top_near, bottom_near, z_shift); - - // - generate our frustum - CameraMatrix combined_matrix; - combined_matrix.set_frustum(left_near, -left_near, bottom_near, top_near, z_near + z_shift, z_far + z_shift); - - // and finally move our camera back - Transform apply_z_shift; - apply_z_shift.origin = Vector3(0.0, 0.0, z_shift); // z negative is forward so this moves it backwards - mono_transform *= apply_z_shift; - - // now prepare our scene with our adjusted transform projection matrix - _prepare_scene(mono_transform, combined_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); - } else if (p_eye == XRInterface::EYE_MONO) { - // For mono render, prepare as per usual - _prepare_scene(cam_transform, camera_matrix, false, false, p_render_buffers, environment, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), p_screen_lod_threshold); - } - - // And render our scene... - _render_scene(p_render_buffers, cam_transform, camera_matrix, false, environment, camera->effects, p_scenario, p_shadow_atlas, RID(), -1, p_screen_lod_threshold); -#endif -}; + int range_check = _visibility_range_check(vd, cull_data.camera_position, cull_data.viewport_mask); + + if (range_check == -1) { + idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + } else if (range_check == 1) { + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; + idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + } else { + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + } + } +} + +int RendererSceneCull::_visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask) { + float dist = p_camera_pos.distance_to(r_vis_data.position); -void RendererSceneCull::_frustum_cull_threaded(uint32_t p_thread, CullData *cull_data) { + bool in_range_last_frame = p_viewport_mask & r_vis_data.viewport_state; + float begin_offset = in_range_last_frame ? -r_vis_data.range_begin_margin : r_vis_data.range_begin_margin; + float end_offset = in_range_last_frame ? r_vis_data.range_end_margin : -r_vis_data.range_end_margin; + + if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end + end_offset) { + r_vis_data.viewport_state &= ~p_viewport_mask; + return -1; + } else if (r_vis_data.range_begin > 0.0f && dist < r_vis_data.range_begin + begin_offset) { + r_vis_data.viewport_state &= ~p_viewport_mask; + return 1; + } else { + r_vis_data.viewport_state |= p_viewport_mask; + return 0; + } +} + +void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_data) { uint32_t cull_total = cull_data->scenario->instance_data.size(); uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); uint32_t cull_from = p_thread * cull_total / total_threads; uint32_t cull_to = (p_thread + 1 == total_threads) ? cull_total : ((p_thread + 1) * cull_total / total_threads); - _frustum_cull(*cull_data, frustum_cull_result_threads[p_thread], cull_from, cull_to); + _scene_cull(*cull_data, scene_cull_result_threads[p_thread], cull_from, cull_to); } -void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to) { +void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to) { uint64_t frame_number = RSG::rasterizer->get_frame_number(); float lightmap_probe_update_speed = RSG::storage->lightmap_get_probe_capture_update_speed() * RSG::rasterizer->get_frame_delta_time(); @@ -2341,183 +2535,207 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; - Transform inv_cam_transform = cull_data.cam_transform.inverse(); + Transform3D inv_cam_transform = cull_data.cam_transform.inverse(); float z_near = cull_data.camera_matrix->get_z_near(); for (uint64_t i = p_from; i < p_to; i++) { bool mesh_visible = false; - if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->frustum) && (cull_data.occlusion_buffer == nullptr || cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING || - !cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))) { - InstanceData &idata = cull_data.scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - - if ((cull_data.visible_layers & idata.layer_mask) == 0) { - //failure - } else if (base_type == RS::INSTANCE_LIGHT) { - cull_result.lights.push_back(idata.instance); - cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid)); - if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { - scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later - } + InstanceData &idata = cull_data.scenario->instance_data[i]; + uint32_t visibility_flags = idata.flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN); + int32_t visibility_check = -1; - } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { - if (cull_data.render_reflection_probe != idata.instance) { - //avoid entering The Matrix +#define HIDDEN_BY_VISIBILITY_CHECKS (visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE || visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) +#define LAYER_CHECK (cull_data.visible_layers & idata.layer_mask) +#define IN_FRUSTUM(f) (cull_data.scenario->instance_aabbs[i].in_frustum(f)) +#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0) +#define VIS_PARENT_CHECK ((idata.parent_array_index == -1) || ((cull_data.scenario->instance_data[idata.parent_array_index].flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK) == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE)) +#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check) +#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near)) - if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data); - cull_data.cull->lock.lock(); - if (!reflection_probe->update_list.in_list()) { - reflection_probe->render_step = 0; - reflection_probe_render_list.add_last(&reflection_probe->update_list); - } - cull_data.cull->lock.unlock(); - - idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); + if (!HIDDEN_BY_VISIBILITY_CHECKS) { + if (LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) { + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + if (base_type == RS::INSTANCE_LIGHT) { + cull_result.lights.push_back(idata.instance); + cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid)); + if (cull_data.shadow_atlas.is_valid() && RSG::storage->light_has_shadow(idata.base_rid)) { + scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later } - if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) { - cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid)); - } - } - } else if (base_type == RS::INSTANCE_DECAL) { - cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid)); - - } else if (base_type == RS::INSTANCE_GI_PROBE) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(idata.instance->base_data); - cull_data.cull->lock.lock(); - if (!gi_probe->update_element.in_list()) { - gi_probe_update_list.add(&gi_probe->update_element); - } - cull_data.cull->lock.unlock(); - cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (base_type == RS::INSTANCE_REFLECTION_PROBE) { + if (cull_data.render_reflection_probe != idata.instance) { + //avoid entering The Matrix - } else if (base_type == RS::INSTANCE_LIGHTMAP) { - cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid)); - } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { - bool keep = true; + if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!reflection_probe->update_list.in_list()) { + reflection_probe->render_step = 0; + reflection_probe_render_list.add_last(&reflection_probe->update_list); + } + cull_data.cull->lock.unlock(); - if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) { - RenderingServerDefault::redraw_request(); - } + idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY); + } - if (base_type == RS::INSTANCE_MESH) { - mesh_visible = true; - } else if (base_type == RS::INSTANCE_PARTICLES) { - //particles visible? process them - if (RSG::storage->particles_is_inactive(idata.base_rid)) { - //but if nothing is going on, don't do it. - keep = false; - } else { - cull_data.cull->lock.lock(); - RSG::storage->particles_request_process(idata.base_rid); - cull_data.cull->lock.unlock(); - RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized()); - //particles visible? request redraw - RenderingServerDefault::redraw_request(); + if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) { + cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid)); + } } - } + } else if (base_type == RS::INSTANCE_DECAL) { + cull_result.decals.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_VOXEL_GI) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(idata.instance->base_data); + cull_data.cull->lock.lock(); + if (!voxel_gi->update_element.in_list()) { + voxel_gi_update_list.add(&voxel_gi->update_element); + } + cull_data.cull->lock.unlock(); + cull_result.voxel_gi_instances.push_back(RID::from_uint64(idata.instance_data_rid)); + + } else if (base_type == RS::INSTANCE_LIGHTMAP) { + cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) { + InstanceVisibilityNotifierData *vnd = idata.visibility_notifier; + if (!vnd->list_element.in_list()) { + visible_notifier_list_lock.lock(); + visible_notifier_list.add(&vnd->list_element); + visible_notifier_list_lock.unlock(); + vnd->just_visible = true; + } + vnd->visible_in_frame = RSG::rasterizer->get_frame_number(); + } else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) { + bool keep = true; - if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - uint32_t idx = 0; + if (idata.flags & InstanceData::FLAG_REDRAW_IF_VISIBLE) { + RenderingServerDefault::redraw_request(); + } - for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { - InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - instance_pair_buffer[idx++] = light->instance; - if (idx == MAX_INSTANCE_PAIRS) { - break; + if (base_type == RS::INSTANCE_MESH) { + mesh_visible = true; + } else if (base_type == RS::INSTANCE_PARTICLES) { + //particles visible? process them + if (RSG::storage->particles_is_inactive(idata.base_rid)) { + //but if nothing is going on, don't do it. + keep = false; + } else { + cull_data.cull->lock.lock(); + RSG::storage->particles_request_process(idata.base_rid); + cull_data.cull->lock.unlock(); + RSG::storage->particles_set_view_axis(idata.base_rid, -cull_data.cam_transform.basis.get_axis(2).normalized(), cull_data.cam_transform.basis.get_axis(1).normalized()); + //particles visible? request redraw + RenderingServerDefault::redraw_request(); } } - scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx); - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY); - } + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + + for (Set<Instance *>::Element *E = geom->lights.front(); E; E = E->next()) { + InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); + instance_pair_buffer[idx++] = light->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } + } + + scene_render->geometry_instance_pair_light_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_LIGHTING_DIRTY); + } - if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - uint32_t idx = 0; + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_REFLECTION_PROBE) && (idata.flags & InstanceData::FLAG_GEOM_REFLECTION_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; - for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { - InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); + for (Set<Instance *>::Element *E = geom->reflection_probes.front(); E; E = E->next()) { + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); - instance_pair_buffer[idx++] = reflection_probe->instance; - if (idx == MAX_INSTANCE_PAIRS) { - break; + instance_pair_buffer[idx++] = reflection_probe->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } - } - scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY); - } + scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_REFLECTION_DIRTY); + } - if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - uint32_t idx = 0; + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_DECAL) && (idata.flags & InstanceData::FLAG_GEOM_DECAL_DIRTY)) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; - for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) { - InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data); + for (Set<Instance *>::Element *E = geom->decals.front(); E; E = E->next()) { + InstanceDecalData *decal = static_cast<InstanceDecalData *>(E->get()->base_data); - instance_pair_buffer[idx++] = decal->instance; - if (idx == MAX_INSTANCE_PAIRS) { - break; + instance_pair_buffer[idx++] = decal->instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } + scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); } - scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, instance_pair_buffer, idx); - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_DECAL_DIRTY); - } - if (idata.flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - uint32_t idx = 0; - for (Set<Instance *>::Element *E = geom->gi_probes.front(); E; E = E->next()) { - InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); + if (idata.flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + uint32_t idx = 0; + for (Set<Instance *>::Element *E = geom->voxel_gi_instances.front(); E; E = E->next()) { + InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(E->get()->base_data); - instance_pair_buffer[idx++] = gi_probe->probe_instance; - if (idx == MAX_INSTANCE_PAIRS) { - break; + instance_pair_buffer[idx++] = voxel_gi->probe_instance; + if (idx == MAX_INSTANCE_PAIRS) { + break; + } } - } - scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); - idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); - } + scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx); + idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY); + } - if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); - Color *sh = idata.instance->lightmap_sh.ptrw(); - const Color *target_sh = idata.instance->lightmap_target_sh.ptr(); - for (uint32_t j = 0; j < 9; j++) { - sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); + if ((idata.flags & InstanceData::FLAG_LIGHTMAP_CAPTURE) && idata.instance->last_frame_pass != frame_number && !idata.instance->lightmap_target_sh.is_empty() && !idata.instance->lightmap_sh.is_empty()) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); + Color *sh = idata.instance->lightmap_sh.ptrw(); + const Color *target_sh = idata.instance->lightmap_target_sh.ptr(); + for (uint32_t j = 0; j < 9; j++) { + sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed)); + } + scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh); + idata.instance->last_frame_pass = frame_number; } - scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, sh); - idata.instance->last_frame_pass = frame_number; - } - if (keep) { - cull_result.geometry_instances.push_back(idata.instance_geometry); + if (keep) { + cull_result.geometry_instances.push_back(idata.instance_geometry); + } } } - } - for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) { - for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) { - if (cull_data.scenario->instance_aabbs[i].in_frustum(cull_data.cull->shadows[j].cascades[k].frustum)) { - InstanceData &idata = cull_data.scenario->instance_data[i]; - uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; + for (uint32_t j = 0; j < cull_data.cull->shadow_count; j++) { + for (uint32_t k = 0; k < cull_data.cull->shadows[j].cascade_count; k++) { + if (IN_FRUSTUM(cull_data.cull->shadows[j].cascades[k].frustum) && VIS_CHECK) { + uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; - if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { - cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); - mesh_visible = true; + if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && idata.flags & InstanceData::FLAG_CAST_SHADOWS) { + cull_result.directional_shadows[j].cascade_geometry_instances[k].push_back(idata.instance_geometry); + mesh_visible = true; + } } } } } +#undef HIDDEN_BY_VISIBILITY_CHECKS +#undef LAYER_CHECK +#undef IN_FRUSTUM +#undef VIS_RANGE_CHECK +#undef VIS_PARENT_CHECK +#undef VIS_CHECK +#undef OCCLUSION_CULLED + for (uint32_t j = 0; j < cull_data.cull->sdfgi.region_count; j++) { if (cull_data.scenario->instance_aabbs[i].in_aabb(cull_data.cull->sdfgi.region_aabb[j])) { - InstanceData &idata = cull_data.scenario->instance_data[i]; uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; if (base_type == RS::INSTANCE_LIGHT) { @@ -2544,11 +2762,7 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu } } -void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows) { - // Note, in stereo rendering: - // - p_cam_transform will be a transform in the middle of our two eyes - // - p_cam_projection is a wider frustrum that encompasses both eyes - +void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) { Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it Scenario *scenario = scenario_owner.getornull(p_scenario); @@ -2559,16 +2773,44 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca if (p_render_buffers.is_valid()) { //no rendering code here, this is only to set up what needs to be done, request regions, etc. - scene_render->sdfgi_update(p_render_buffers, p_environment, p_cam_transform.origin); //update conditions for SDFGI (whether its used or not) + scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not) + } + + RENDER_TIMESTAMP("Visibility Dependencies"); + + if (scenario->instance_visibility.get_bin_count() > 0) { + if (!scenario->viewport_visibility_masks.has(p_viewport)) { + scenario_add_viewport_visibility_mask(scenario->self, p_viewport); + } + + VisibilityCullData visibility_cull_data; + visibility_cull_data.scenario = scenario; + visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport]; + visibility_cull_data.camera_position = p_camera_data->main_transform.origin; + + for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0 + visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i); + visibility_cull_data.cull_count = scenario->instance_visibility.get_bin_size(i); + + if (visibility_cull_data.cull_count == 0) { + continue; + } + + if (visibility_cull_data.cull_count > thread_cull_threshold) { + RendererThreadPool::singleton->thread_work_pool.do_work(RendererThreadPool::singleton->thread_work_pool.get_thread_count(), this, &RendererSceneCull::_visibility_cull_threaded, &visibility_cull_data); + } else { + _visibility_cull(visibility_cull_data, visibility_cull_data.cull_offset, visibility_cull_data.cull_offset + visibility_cull_data.cull_count); + } + } } - RENDER_TIMESTAMP("Frustum Culling"); + RENDER_TIMESTAMP("Culling"); - //rasterizer->set_camera(camera->transform, camera_matrix,ortho); + //rasterizer->set_camera(p_camera_data->main_transform, p_camera_data.main_projection, p_camera_data.is_ortogonal); - Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); + Vector<Plane> planes = p_camera_data->main_projection.get_projection_planes(p_camera_data->main_transform); - Plane near_plane(p_cam_transform.origin, -p_cam_transform.basis.get_axis(2).normalized()); + Plane near_plane(p_camera_data->main_transform.origin, -p_camera_data->main_transform.basis.get_axis(2).normalized()); /* STEP 2 - CULL */ @@ -2606,7 +2848,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca scene_render->set_directional_shadow_count(lights_with_shadow.size()); for (int i = 0; i < lights_with_shadow.size(); i++) { - _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect); + _light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect); } } @@ -2635,7 +2877,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca } } - frustum_cull_result.clear(); + scene_cull_result.clear(); { uint64_t cull_from = 0; @@ -2647,30 +2889,31 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca cull_data.cull = &cull; cull_data.scenario = scenario; cull_data.shadow_atlas = p_shadow_atlas; - cull_data.cam_transform = p_cam_transform; + cull_data.cam_transform = p_camera_data->main_transform; cull_data.visible_layers = p_visible_layers; cull_data.render_reflection_probe = render_reflection_probe; cull_data.occlusion_buffer = RendererSceneOcclusionCull::get_singleton()->buffer_get_ptr(p_viewport); - cull_data.camera_matrix = &p_cam_projection; + cull_data.camera_matrix = &p_camera_data->main_projection; + cull_data.visibility_viewport_mask = scenario->viewport_visibility_masks.has(p_viewport) ? scenario->viewport_visibility_masks[p_viewport] : 0; //#define DEBUG_CULL_TIME #ifdef DEBUG_CULL_TIME uint64_t time_from = OS::get_singleton()->get_ticks_usec(); #endif if (cull_to > thread_cull_threshold) { //multiple threads - for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { - frustum_cull_result_threads[i].clear(); + for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { + scene_cull_result_threads[i].clear(); } - RendererThreadPool::singleton->thread_work_pool.do_work(frustum_cull_result_threads.size(), this, &RendererSceneCull::_frustum_cull_threaded, &cull_data); + RendererThreadPool::singleton->thread_work_pool.do_work(scene_cull_result_threads.size(), this, &RendererSceneCull::_scene_cull_threaded, &cull_data); - for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { - frustum_cull_result.append_from(frustum_cull_result_threads[i]); + for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { + scene_cull_result.append_from(scene_cull_result_threads[i]); } } else { //single threaded - _frustum_cull(cull_data, frustum_cull_result, cull_from, cull_to); + _scene_cull(cull_data, scene_cull_result, cull_from, cull_to); } #ifdef DEBUG_CULL_TIME @@ -2681,9 +2924,9 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca print_line("time taken: " + rtos(time_avg / time_count)); #endif - if (frustum_cull_result.mesh_instances.size()) { - for (uint64_t i = 0; i < frustum_cull_result.mesh_instances.size(); i++) { - RSG::storage->mesh_instance_check_for_update(frustum_cull_result.mesh_instances[i]); + if (scene_cull_result.mesh_instances.size()) { + for (uint64_t i = 0; i < scene_cull_result.mesh_instances.size(); i++) { + RSG::storage->mesh_instance_check_for_update(scene_cull_result.mesh_instances[i]); } RSG::storage->update_mesh_instances(); } @@ -2707,14 +2950,14 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca } render_shadow_data[max_shadows_used].light = cull.shadows[i].light_instance; render_shadow_data[max_shadows_used].pass = j; - render_shadow_data[max_shadows_used].instances.merge_unordered(frustum_cull_result.directional_shadows[i].cascade_geometry_instances[j]); + render_shadow_data[max_shadows_used].instances.merge_unordered(scene_cull_result.directional_shadows[i].cascade_geometry_instances[j]); max_shadows_used++; } } // Positional Shadowss - for (uint32_t i = 0; i < (uint32_t)frustum_cull_result.lights.size(); i++) { - Instance *ins = frustum_cull_result.lights[i]; + for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) { + Instance *ins = scene_cull_result.lights[i]; if (!p_shadow_atlas.is_valid() || !RSG::storage->light_has_shadow(ins->base)) { continue; @@ -2726,12 +2969,12 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca { //compute coverage - Transform cam_xf = p_cam_transform; - float zn = p_cam_projection.get_z_near(); + Transform3D cam_xf = p_camera_data->main_transform; + float zn = p_camera_data->main_projection.get_z_near(); Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane // near plane half width and height - Vector2 vp_half_extents = p_cam_projection.get_viewport_half_extents(); + Vector2 vp_half_extents = p_camera_data->main_projection.get_viewport_half_extents(); switch (RSG::storage->light_get_type(ins->base)) { case RS::LIGHT_OMNI: { @@ -2743,7 +2986,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca ins->transform.origin + cam_xf.basis.get_axis(0) * radius }; - if (!p_cam_orthogonal) { + if (!p_camera_data->is_ortogonal) { //if using perspetive, map them to near plane for (int j = 0; j < 2; j++) { if (p.distance_to(points[j]) < 0) { @@ -2771,7 +3014,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca base + cam_xf.basis.get_axis(0) * w }; - if (!p_cam_orthogonal) { + if (!p_camera_data->is_ortogonal) { //if using perspetive, map them to near plane for (int j = 0; j < 2; j++) { if (p.distance_to(points[j]) < 0) { @@ -2802,7 +3045,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) { //must redraw! RENDER_TIMESTAMP(">Rendering Light " + itos(i)); - light->shadow_dirty = _light_instance_update_shadow(ins, p_cam_transform, p_cam_projection, p_cam_orthogonal, p_cam_vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); + light->shadow_dirty = _light_instance_update_shadow(ins, p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_ortogonal, p_camera_data->vaspect, p_shadow_atlas, scenario, p_screen_lod_threshold); RENDER_TIMESTAMP("<Rendering Light " + itos(i)); } else { light->shadow_dirty = redraw; @@ -2818,13 +3061,13 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca if (cull.sdfgi.region_count > 0) { //update regions for (uint32_t i = 0; i < cull.sdfgi.region_count; i++) { - render_sdfgi_data[i].instances.merge_unordered(frustum_cull_result.sdfgi_region_geometry_instances[i]); + render_sdfgi_data[i].instances.merge_unordered(scene_cull_result.sdfgi_region_geometry_instances[i]); render_sdfgi_data[i].region = i; } //check if static lights were culled bool static_lights_culled = false; for (uint32_t i = 0; i < cull.sdfgi.cascade_light_count; i++) { - if (frustum_cull_result.sdfgi_cascade_lights[i].size()) { + if (scene_cull_result.sdfgi_cascade_lights[i].size()) { static_lights_culled = true; break; } @@ -2833,7 +3076,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca if (static_lights_culled) { sdfgi_update_data.static_cascade_count = cull.sdfgi.cascade_light_count; sdfgi_update_data.static_cascade_indices = cull.sdfgi.cascade_light_index; - sdfgi_update_data.static_positional_lights = frustum_cull_result.sdfgi_cascade_lights; + sdfgi_update_data.static_positional_lights = scene_cull_result.sdfgi_cascade_lights; sdfgi_update_data.update_static = true; } } @@ -2847,7 +3090,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca //append the directional lights to the lights culled for (int i = 0; i < directional_lights.size(); i++) { - frustum_cull_result.light_instances.push_back(directional_lights[i]); + scene_cull_result.light_instances.push_back(directional_lights[i]); } RID camera_effects; @@ -2864,7 +3107,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca } RENDER_TIMESTAMP("Render Scene "); - scene_render->render_scene(p_render_buffers, p_cam_transform, p_cam_projection, p_cam_orthogonal, frustum_cull_result.geometry_instances, frustum_cull_result.light_instances, frustum_cull_result.reflections, frustum_cull_result.gi_probes, frustum_cull_result.decals, frustum_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data); + scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info); for (uint32_t i = 0; i < max_shadows_used; i++) { render_shadow_data[i].instances.clear(); @@ -2875,7 +3118,7 @@ void RendererSceneCull::_render_scene(const Transform &p_cam_transform, const Ca render_sdfgi_data[i].instances.clear(); } - // virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0; + // virtual void render_scene(RID p_render_buffers, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold,const RenderShadowData *p_render_shadows,int p_render_shadow_count,const RenderSDFGIData *p_render_sdfgi_regions,int p_render_sdfgi_region_count,const RenderSDFGIStaticLightData *p_render_sdfgi_static_lights=nullptr) = 0; } RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { @@ -2901,7 +3144,6 @@ RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { #ifndef _3D_DISABLED - Scenario *scenario = scenario_owner.getornull(p_scenario); RID environment; @@ -2911,7 +3153,11 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, environment = scenario->fallback_environment; } RENDER_TIMESTAMP("Render Empty Scene "); - scene_render->render_scene(p_render_buffers, Transform(), CameraMatrix(), true, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); + + RendererSceneRender::CameraData camera_data; + camera_data.set_camera(Transform3D(), CameraMatrix(), true, false); + + scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif } @@ -2961,10 +3207,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int CameraMatrix cm; cm.set_perspective(90, 1, 0.01, max_distance); - Transform local_view; + Transform3D local_view; local_view.set_look_at(origin_offset, origin_offset + view_normals[p_step], view_up[p_step]); - Transform xform = p_instance->transform * local_view; + Transform3D xform = p_instance->transform * local_view; RID shadow_atlas; @@ -2981,7 +3227,10 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int } RENDER_TIMESTAMP("Render Reflection Probe, Step " + itos(p_step)); - _render_scene(xform, cm, false, false, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows); + RendererSceneRender::CameraData camera_data; + camera_data.set_camera(xform, cm, false, false); + + _render_scene(&camera_data, RID(), environment, RID(), RSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, lod_threshold, use_shadows); } else { //do roughness postprocess step until it believes it's done @@ -3033,18 +3282,18 @@ void RendererSceneCull::render_probes() { ref_probe = next; } - /* GI PROBES */ + /* VOXEL GIS */ - SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first(); + SelfList<InstanceVoxelGIData> *voxel_gi = voxel_gi_update_list.first(); - if (gi_probe) { + if (voxel_gi) { RENDER_TIMESTAMP("Render GI Probes"); } - while (gi_probe) { - SelfList<InstanceGIProbeData> *next = gi_probe->next(); + while (voxel_gi) { + SelfList<InstanceVoxelGIData> *next = voxel_gi->next(); - InstanceGIProbeData *probe = gi_probe->self(); + InstanceVoxelGIData *probe = voxel_gi->self(); //Instance *instance_probe = probe->owner; //check if probe must be setup, but don't do if on the lighting thread @@ -3053,7 +3302,7 @@ void RendererSceneCull::render_probes() { int cache_count = 0; { int light_cache_size = probe->light_cache.size(); - const InstanceGIProbeData::LightCache *caches = probe->light_cache.ptr(); + const InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptr(); const RID *instance_caches = probe->light_instances.ptr(); int idx = 0; //must count visible lights @@ -3068,7 +3317,7 @@ void RendererSceneCull::render_probes() { } else if (idx >= light_cache_size) { cache_dirty = true; } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; + const InstanceVoxelGIData::LightCache *cache = &caches[idx]; if ( instance_caches[idx] != instance_light->instance || @@ -3100,7 +3349,7 @@ void RendererSceneCull::render_probes() { } else if (idx >= light_cache_size) { cache_dirty = true; } else { - const InstanceGIProbeData::LightCache *cache = &caches[idx]; + const InstanceVoxelGIData::LightCache *cache = &caches[idx]; if ( instance_caches[idx] != instance_light->instance || @@ -3129,14 +3378,14 @@ void RendererSceneCull::render_probes() { cache_count = idx; } - bool update_lights = scene_render->gi_probe_needs_update(probe->probe_instance); + bool update_lights = scene_render->voxel_gi_needs_update(probe->probe_instance); if (cache_dirty) { probe->light_cache.resize(cache_count); probe->light_instances.resize(cache_count); if (cache_count) { - InstanceGIProbeData::LightCache *caches = probe->light_cache.ptrw(); + InstanceVoxelGIData::LightCache *caches = probe->light_cache.ptrw(); RID *instance_caches = probe->light_instances.ptrw(); int idx = 0; //must count visible lights @@ -3147,7 +3396,7 @@ void RendererSceneCull::render_probes() { continue; } - InstanceGIProbeData::LightCache *cache = &caches[idx]; + InstanceVoxelGIData::LightCache *cache = &caches[idx]; instance_caches[idx] = instance_light->instance; cache->has_shadow = RSG::storage->light_has_shadow(instance->base); @@ -3170,7 +3419,7 @@ void RendererSceneCull::render_probes() { continue; } - InstanceGIProbeData::LightCache *cache = &caches[idx]; + InstanceVoxelGIData::LightCache *cache = &caches[idx]; instance_caches[idx] = instance_light->instance; cache->has_shadow = RSG::storage->light_has_shadow(instance->base); @@ -3192,7 +3441,7 @@ void RendererSceneCull::render_probes() { update_lights = true; } - frustum_cull_result.geometry_instances.clear(); + scene_cull_result.geometry_instances.clear(); RID instance_pair_buffer[MAX_INSTANCE_PAIRS]; @@ -3203,30 +3452,30 @@ void RendererSceneCull::render_probes() { } InstanceGeometryData *geom = (InstanceGeometryData *)ins->base_data; - if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_GI_PROBE_DIRTY)) { + if (ins->scenario && ins->array_index >= 0 && (ins->scenario->instance_data[ins->array_index].flags & InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY)) { uint32_t idx = 0; - for (Set<Instance *>::Element *F = geom->gi_probes.front(); F; F = F->next()) { - InstanceGIProbeData *gi_probe2 = static_cast<InstanceGIProbeData *>(F->get()->base_data); + for (Set<Instance *>::Element *F = geom->voxel_gi_instances.front(); F; F = F->next()) { + InstanceVoxelGIData *voxel_gi2 = static_cast<InstanceVoxelGIData *>(F->get()->base_data); - instance_pair_buffer[idx++] = gi_probe2->probe_instance; + instance_pair_buffer[idx++] = voxel_gi2->probe_instance; if (idx == MAX_INSTANCE_PAIRS) { break; } } - scene_render->geometry_instance_pair_gi_probe_instances(geom->geometry_instance, instance_pair_buffer, idx); + scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, instance_pair_buffer, idx); - ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_GI_PROBE_DIRTY); + ins->scenario->instance_data[ins->array_index].flags &= ~uint32_t(InstanceData::FLAG_GEOM_VOXEL_GI_DIRTY); } - frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); + scene_cull_result.geometry_instances.push_back(geom->geometry_instance); } - scene_render->gi_probe_update(probe->probe_instance, update_lights, probe->light_instances, frustum_cull_result.geometry_instances); + scene_render->voxel_gi_update(probe->probe_instance, update_lights, probe->light_instances, scene_cull_result.geometry_instances); - gi_probe_update_list.remove(gi_probe); + voxel_gi_update_list.remove(voxel_gi); - gi_probe = next; + voxel_gi = next; } } @@ -3237,7 +3486,7 @@ void RendererSceneCull::render_particle_colliders() { if (hfpc->scenario && hfpc->base_type == RS::INSTANCE_PARTICLES_COLLISION && RSG::storage->particles_collision_is_heightfield(hfpc->base)) { //update heightfield instance_cull_result.clear(); - frustum_cull_result.geometry_instances.clear(); + scene_cull_result.geometry_instances.clear(); struct CullAABB { PagedArray<Instance *> *result; @@ -3259,10 +3508,10 @@ void RendererSceneCull::render_particle_colliders() { continue; } InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); - frustum_cull_result.geometry_instances.push_back(geom->geometry_instance); + scene_cull_result.geometry_instances.push_back(geom->geometry_instance); } - scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, frustum_cull_result.geometry_instances); + scene_render->render_particle_collider_heightfield(hfpc->base, hfpc->transform, scene_cull_result.geometry_instances); } heightfield_particle_colliders_update_list.erase(heightfield_particle_colliders_update_list.front()); } @@ -3402,25 +3651,6 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { RSG::storage->base_update_dependency(mesh, &p_instance->dependency_tracker); } - } else if (p_instance->base_type == RS::INSTANCE_IMMEDIATE) { - RID mat = RSG::storage->immediate_get_material(p_instance->base); - - if (!(!mat.is_valid() || RSG::storage->material_casts_shadows(mat))) { - can_cast_shadows = false; - } - - if (mat.is_valid() && RSG::storage->material_is_animated(mat)) { - is_animated = true; - } - - if (mat.is_valid()) { - _update_instance_shader_parameters_from_material(isparams, p_instance->instance_shader_parameters, mat); - } - - if (mat.is_valid()) { - RSG::storage->material_update_dependency(mat, &p_instance->dependency_tracker); - } - } else if (p_instance->base_type == RS::INSTANCE_PARTICLES) { bool cast_shadows = false; @@ -3538,10 +3768,7 @@ bool RendererSceneCull::free(RID p_rid) { } if (camera_owner.owns(p_rid)) { - Camera *camera = camera_owner.getornull(p_rid); - camera_owner.free(p_rid); - memdelete(camera); } else if (scenario_owner.owns(p_rid)) { Scenario *scenario = scenario_owner.getornull(p_rid); @@ -3551,12 +3778,12 @@ bool RendererSceneCull::free(RID p_rid) { } scenario->instance_aabbs.reset(); scenario->instance_data.reset(); + scenario->instance_visibility.reset(); scene_render->free(scenario->reflection_probe_shadow_atlas); scene_render->free(scenario->reflection_atlas); scenario_owner.free(p_rid); RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid); - memdelete(scenario); } else if (RendererSceneOcclusionCull::get_singleton()->is_occluder(p_rid)) { RendererSceneOcclusionCull::get_singleton()->free_occluder(p_rid); @@ -3580,7 +3807,6 @@ bool RendererSceneCull::free(RID p_rid) { update_dirty_instances(); //in case something changed this instance_owner.free(p_rid); - memdelete(instance); } else { return false; } @@ -3592,6 +3818,28 @@ TypedArray<Image> RendererSceneCull::bake_render_uv2(RID p_base, const Vector<RI return scene_render->bake_render_uv2(p_base, p_material_overrides, p_image_size); } +void RendererSceneCull::update_visibility_notifiers() { + SelfList<InstanceVisibilityNotifierData> *E = visible_notifier_list.first(); + while (E) { + SelfList<InstanceVisibilityNotifierData> *N = E->next(); + + InstanceVisibilityNotifierData *visibility_notifier = E->self(); + if (visibility_notifier->just_visible) { + visibility_notifier->just_visible = false; + + RSG::storage->visibility_notifier_call(visibility_notifier->base, true, RSG::threaded); + } else { + if (visibility_notifier->visible_in_frame != RSG::rasterizer->get_frame_number()) { + visible_notifier_list.remove(E); + + RSG::storage->visibility_notifier_call(visibility_notifier->base, false, RSG::threaded); + } + } + + E = N; + } +} + /*******************************/ /* Passthrough to Scene Render */ /*******************************/ @@ -3619,10 +3867,10 @@ RendererSceneCull::RendererSceneCull() { render_sdfgi_data[i].instances.set_page_pool(&geometry_instance_cull_page_pool); } - frustum_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); - frustum_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); - for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { - frustum_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + scene_cull_result.init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); + scene_cull_result_threads.resize(RendererThreadPool::singleton->thread_work_pool.get_thread_count()); + for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { + scene_cull_result_threads[i].init(&rid_cull_page_pool, &geometry_instance_cull_page_pool, &instance_cull_page_pool); } indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); @@ -3643,11 +3891,11 @@ RendererSceneCull::~RendererSceneCull() { render_sdfgi_data[i].instances.reset(); } - frustum_cull_result.reset(); - for (uint32_t i = 0; i < frustum_cull_result_threads.size(); i++) { - frustum_cull_result_threads[i].reset(); + scene_cull_result.reset(); + for (uint32_t i = 0; i < scene_cull_result_threads.size(); i++) { + scene_cull_result_threads[i].reset(); } - frustum_cull_result_threads.clear(); + scene_cull_result_threads.clear(); if (dummy_occlusion_culling) { memdelete(dummy_occlusion_culling); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 930ac0df70..d586fb531f 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -31,6 +31,7 @@ #ifndef RENDERING_SERVER_SCENE_CULL_H #define RENDERING_SERVER_SCENE_CULL_H +#include "core/templates/bin_sorted_array.h" #include "core/templates/pass_func.h" #include "servers/rendering/renderer_compositor.h" @@ -82,7 +83,7 @@ public: RID env; RID effects; - Transform transform; + Transform3D transform; Camera() { visible_layers = 0xFFFFFFFF; @@ -96,7 +97,7 @@ public: } }; - mutable RID_PtrOwner<Camera, true> camera_owner; + mutable RID_Owner<Camera, true> camera_owner; virtual RID camera_allocate(); virtual void camera_initialize(RID p_rid); @@ -104,7 +105,7 @@ public: virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far); virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far); virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far); - virtual void camera_set_transform(RID p_camera, const Transform &p_transform); + virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform); virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers); virtual void camera_set_environment(RID p_camera, RID p_env); virtual void camera_set_camera_effects(RID p_camera, RID p_fx); @@ -117,6 +118,8 @@ public: virtual void occluder_initialize(RID p_occluder); virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); + /* VISIBILITY NOTIFIER API */ + RendererSceneOcclusionCull *dummy_occlusion_culling; /* SCENARIO API */ @@ -242,6 +245,8 @@ public: } }; + struct InstanceVisibilityNotifierData; + struct InstanceData { // Store instance pointer as well as common instance processing information, // to make processing more cache friendly. @@ -253,12 +258,15 @@ public: FLAG_GEOM_LIGHTING_DIRTY = (1 << 11), FLAG_GEOM_REFLECTION_DIRTY = (1 << 12), FLAG_GEOM_DECAL_DIRTY = (1 << 13), - FLAG_GEOM_GI_PROBE_DIRTY = (1 << 14), + FLAG_GEOM_VOXEL_GI_DIRTY = (1 << 14), FLAG_LIGHTMAP_CAPTURE = (1 << 15), FLAG_USES_BAKED_LIGHT = (1 << 16), FLAG_USES_MESH_INSTANCE = (1 << 17), FLAG_REFLECTION_PROBE_DIRTY = (1 << 18), FLAG_IGNORE_OCCLUSION_CULLING = (1 << 19), + FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK = (3 << 20), // 2 bits, overlaps with the other vis. dependency flags + FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE = (1 << 20), + FLAG_VISIBILITY_DEPENDENCY_HIDDEN = (1 << 21), }; uint32_t flags = 0; @@ -267,12 +275,36 @@ public: union { uint64_t instance_data_rid; RendererSceneRender::GeometryInstance *instance_geometry; + InstanceVisibilityNotifierData *visibility_notifier; }; Instance *instance = nullptr; + int32_t parent_array_index = -1; + int32_t visibility_index = -1; + }; + + struct InstanceVisibilityData { + uint64_t viewport_state = 0; + int32_t array_index = -1; + Vector3 position; + Instance *instance = nullptr; + float range_begin = 0.0f; + float range_end = 0.0f; + float range_begin_margin = 0.0f; + float range_end_margin = 0.0f; + }; + + class VisibilityArray : public BinSortedArray<InstanceVisibilityData> { + _FORCE_INLINE_ virtual void _update_idx(InstanceVisibilityData &r_element, uint64_t p_idx) { + r_element.instance->visibility_index = p_idx; + if (r_element.instance->scenario && r_element.instance->array_index != -1) { + r_element.instance->scenario->instance_data[r_element.instance->array_index].visibility_index = p_idx; + } + } }; PagedArrayPool<InstanceBounds> instance_aabb_page_pool; PagedArrayPool<InstanceData> instance_data_page_pool; + PagedArrayPool<InstanceVisibilityData> instance_visibility_data_page_pool; struct Scenario { enum IndexerType { @@ -283,7 +315,6 @@ public: DynamicBVH indexers[INDEXER_MAX]; - RS::ScenarioDebugMode debug; RID self; List<Instance *> directional_lights; @@ -292,6 +323,8 @@ public: RID camera_effects; RID reflection_probe_shadow_atlas; RID reflection_atlas; + uint64_t used_viewport_visibility_bits; + Map<RID, uint64_t> viewport_visibility_masks; SelfList<Instance>::List instances; @@ -299,17 +332,18 @@ public: PagedArray<InstanceBounds> instance_aabbs; PagedArray<InstanceData> instance_data; + VisibilityArray instance_visibility; Scenario() { indexers[INDEXER_GEOMETRY].set_index(INDEXER_GEOMETRY); indexers[INDEXER_VOLUMES].set_index(INDEXER_VOLUMES); - debug = RS::SCENARIO_DEBUG_DISABLED; + used_viewport_visibility_bits = 0; } }; int indexer_update_iterations = 0; - mutable RID_PtrOwner<Scenario, true> scenario_owner; + mutable RID_Owner<Scenario, true> scenario_owner; static void _instance_pair(Instance *p_A, Instance *p_B); static void _instance_unpair(Instance *p_A, Instance *p_B); @@ -319,13 +353,14 @@ public: virtual RID scenario_allocate(); virtual void scenario_initialize(RID p_rid); - virtual void scenario_set_debug(RID p_scenario, RS::ScenarioDebugMode p_debug_mode); virtual void scenario_set_environment(RID p_scenario, RID p_environment); virtual void scenario_set_camera_effects(RID p_scenario, RID p_fx); virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count); virtual bool is_scenario(RID p_scenario) const; virtual RID scenario_get_environment(RID p_scenario); + virtual void scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport); + virtual void scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport); /* INSTANCING API */ @@ -353,7 +388,7 @@ public: RID mesh_instance; //only used for meshes and when skeleton/blendshapes exist - Transform transform; + Transform3D transform; float lod_bias; @@ -399,6 +434,12 @@ public: //scenario stuff DynamicBVH::ID indexer_id; int32_t array_index; + int32_t visibility_index = -1; + float visibility_range_begin; + float visibility_range_end; + float visibility_range_begin_margin; + float visibility_range_end_margin; + Instance *visibility_parent = nullptr; Scenario *scenario; SelfList<Instance> scenario_item; @@ -412,12 +453,6 @@ public: float extra_margin; ObjectID object_id; - float lod_begin; - float lod_end; - float lod_begin_hysteresis; - float lod_end_hysteresis; - RID lod_instance; - Vector<Color> lightmap_target_sh; //target is used for incrementally changing the SH over time, this avoids pops in some corner cases and when going interior <-> exterior uint64_t last_frame_pass; @@ -495,10 +530,10 @@ public: visible = true; - lod_begin = 0; - lod_end = 0; - lod_begin_hysteresis = 0; - lod_end_hysteresis = 0; + visibility_range_begin = 0; + visibility_range_end = 0; + visibility_range_begin_margin = 0; + visibility_range_end_margin = 0; last_frame_pass = 0; version = 1; @@ -535,8 +570,10 @@ public: Set<Instance *> decals; Set<Instance *> reflection_probes; - Set<Instance *> gi_probes; + Set<Instance *> voxel_gi_instances; Set<Instance *> lightmap_captures; + Set<Instance *> visibility_dependencies; + uint32_t visibility_dependencies_depth = 0; InstanceGeometryData() { can_cast_shadows = true; @@ -576,6 +613,18 @@ public: RID instance; }; + struct InstanceVisibilityNotifierData : public InstanceBaseData { + bool just_visible = false; + uint64_t visible_in_frame = 0; + RID base; + SelfList<InstanceVisibilityNotifierData> list_element; + InstanceVisibilityNotifierData() : + list_element(this) {} + }; + + SpinLock visible_notifier_list_lock; + SelfList<InstanceVisibilityNotifierData>::List visible_notifier_list; + struct InstanceLightData : public InstanceBaseData { RID instance; uint64_t last_version; @@ -599,7 +648,7 @@ public: } }; - struct InstanceGIProbeData : public InstanceBaseData { + struct InstanceVoxelGIData : public InstanceBaseData { Instance *owner; Set<Instance *> geometries; @@ -609,7 +658,7 @@ public: struct LightCache { RS::LightType type; - Transform transform; + Transform3D transform; Color color; float energy; float bake_energy; @@ -629,16 +678,16 @@ public: bool invalid; uint32_t base_version; - SelfList<InstanceGIProbeData> update_element; + SelfList<InstanceVoxelGIData> update_element; - InstanceGIProbeData() : + InstanceVoxelGIData() : update_element(this) { invalid = true; base_version = 0; } }; - SelfList<InstanceGIProbeData>::List gi_probe_update_list; + SelfList<InstanceVoxelGIData>::List voxel_gi_update_list; struct InstanceLightmapData : public InstanceBaseData { RID instance; @@ -717,14 +766,14 @@ public: PagedArray<Instance *> instance_cull_result; PagedArray<Instance *> instance_shadow_cull_result; - struct FrustumCullResult { + struct InstanceCullResult { PagedArray<RendererSceneRender::GeometryInstance *> geometry_instances; PagedArray<Instance *> lights; PagedArray<RID> light_instances; PagedArray<RID> lightmaps; PagedArray<RID> reflections; PagedArray<RID> decals; - PagedArray<RID> gi_probes; + PagedArray<RID> voxel_gi_instances; PagedArray<RID> mesh_instances; struct DirectionalShadow { @@ -741,7 +790,7 @@ public: lightmaps.clear(); reflections.clear(); decals.clear(); - gi_probes.clear(); + voxel_gi_instances.clear(); mesh_instances.clear(); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { @@ -765,7 +814,7 @@ public: lightmaps.reset(); reflections.reset(); decals.reset(); - gi_probes.reset(); + voxel_gi_instances.reset(); mesh_instances.reset(); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { @@ -782,14 +831,14 @@ public: } } - void append_from(FrustumCullResult &p_cull_result) { + void append_from(InstanceCullResult &p_cull_result) { geometry_instances.merge_unordered(p_cull_result.geometry_instances); lights.merge_unordered(p_cull_result.lights); light_instances.merge_unordered(p_cull_result.light_instances); lightmaps.merge_unordered(p_cull_result.lightmaps); reflections.merge_unordered(p_cull_result.reflections); decals.merge_unordered(p_cull_result.decals); - gi_probes.merge_unordered(p_cull_result.gi_probes); + voxel_gi_instances.merge_unordered(p_cull_result.voxel_gi_instances); mesh_instances.merge_unordered(p_cull_result.mesh_instances); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { @@ -814,7 +863,7 @@ public: lightmaps.set_page_pool(p_rid_pool); reflections.set_page_pool(p_rid_pool); decals.set_page_pool(p_rid_pool); - gi_probes.set_page_pool(p_rid_pool); + voxel_gi_instances.set_page_pool(p_rid_pool); mesh_instances.set_page_pool(p_rid_pool); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { @@ -832,8 +881,8 @@ public: } }; - FrustumCullResult frustum_cull_result; - LocalVector<FrustumCullResult> frustum_cull_result_threads; + InstanceCullResult scene_cull_result; + LocalVector<InstanceCullResult> scene_cull_result_threads; RendererSceneRender::RenderShadowData render_shadow_data[MAX_UPDATE_SHADOWS]; uint32_t max_shadows_used = 0; @@ -843,7 +892,7 @@ public: uint32_t thread_cull_threshold = 200; - RID_PtrOwner<Instance, true> instance_owner; + RID_Owner<Instance, true> instance_owner; uint32_t geometry_instance_pair_mask; // used in traditional forward, unnecessary on clustered @@ -853,7 +902,7 @@ public: virtual void instance_set_base(RID p_instance, RID p_base); virtual void instance_set_scenario(RID p_instance, RID p_scenario); virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask); - virtual void instance_set_transform(RID p_instance, const Transform &p_transform); + virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform); virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id); virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material); @@ -862,10 +911,14 @@ public: virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); - virtual void instance_set_exterior(RID p_instance, bool p_enabled); virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin); + virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance); + + void _update_instance_visibility_depth(Instance *p_instance); + void _update_instance_visibility_dependencies(Instance *p_instance); + // don't use these in a game! virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const; virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const; @@ -875,8 +928,8 @@ public: virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); - virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); - virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance); + virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); + virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias); @@ -893,9 +946,9 @@ public: _FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance); void _unpair_instance(Instance *p_instance); - void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect); + void _light_instance_setup_directional_shadow(int p_shadow_index, Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect); - _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold); + _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform3D p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_shadow_atlas, Scenario *p_scenario, float p_scren_lod_threshold); RID _render_get_environment(RID p_camera, RID p_scenario); @@ -906,7 +959,7 @@ public: Frustum frustum; CameraMatrix projection; - Transform transform; + Transform3D transform; real_t zfar; real_t split; real_t shadow_texel_size; @@ -937,26 +990,39 @@ public: Frustum frustum; } cull; + struct VisibilityCullData { + uint64_t viewport_mask; + Scenario *scenario; + Vector3 camera_position; + uint32_t cull_offset; + uint32_t cull_count; + }; + + void _visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data); + void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to); + _FORCE_INLINE_ void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_idx); + _FORCE_INLINE_ int _visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask); + struct CullData { Cull *cull; Scenario *scenario; RID shadow_atlas; - Transform cam_transform; + Transform3D cam_transform; uint32_t visible_layers; Instance *render_reflection_probe; const RendererSceneOcclusionCull::HZBuffer *occlusion_buffer; const CameraMatrix *camera_matrix; + uint64_t visibility_viewport_mask; }; - void _frustum_cull_threaded(uint32_t p_thread, CullData *cull_data); - void _frustum_cull(CullData &cull_data, FrustumCullResult &cull_result, uint64_t p_from, uint64_t p_to); + void _scene_cull_threaded(uint32_t p_thread, CullData *cull_data); + void _scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to); bool _render_reflection_probe_step(Instance *p_instance, int p_step); - void _render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, bool p_cam_vaspect, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true); + void _render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr); void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, Ref<XRInterface> &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RendererScene::RenderInfo *r_render_info = nullptr); void update_dirty_instances(); void render_particle_colliders(); @@ -975,7 +1041,7 @@ public: #define PASSBASE scene_render PASS2(directional_shadow_atlas_set_size, int, bool) - PASS1(gi_probe_set_quality, RS::GIProbeQuality) + PASS1(voxel_gi_set_quality, RS::VoxelGIQuality) /* SKY API */ @@ -1054,7 +1120,7 @@ public: /* Render Buffers */ PASS0R(RID, render_buffers_create) - PASS7(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool) + PASS8(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t) PASS1(gi_set_use_half_resolution, bool) /* Shadow Atlas */ @@ -1070,6 +1136,8 @@ public: void set_scene_render(RendererSceneRender *p_scene_render); + virtual void update_visibility_notifiers(); + RendererSceneCull(); virtual ~RendererSceneCull(); }; diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp index c491ccbe7a..1b8aea36d7 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.cpp +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -172,7 +172,7 @@ RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() { } if (debug_image.is_null()) { - debug_image.instance(); + debug_image.instantiate(); } unsigned char *ptrw = debug_data.ptrw(); @@ -185,7 +185,7 @@ RID RendererSceneOcclusionCull::HZBuffer::get_debug_texture() { if (debug_texture.is_null()) { debug_texture = RS::get_singleton()->texture_2d_create(debug_image); } else { - RenderingServer::get_singleton()->texture_2d_update_immediate(debug_texture, debug_image); + RenderingServer::get_singleton()->texture_2d_update(debug_texture, debug_image); } return debug_texture; diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index 390bbaa64b..1d0f53c0bf 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -60,7 +60,7 @@ public: void update_mips(); - _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const { + _FORCE_INLINE_ bool is_occluded(const float p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const CameraMatrix &p_cam_projection, float p_near) const { if (is_empty()) { return false; } @@ -171,7 +171,7 @@ public: virtual void add_scenario(RID p_scenario) {} virtual void remove_scenario(RID p_scenario) {} - virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform &p_xform, bool p_enabled) { _print_warining(); } + virtual void scenario_set_instance(RID p_scenario, RID p_instance, RID p_occluder, const Transform3D &p_xform, bool p_enabled) { _print_warining(); } virtual void scenario_remove_instance(RID p_scenario, RID p_instance) { _print_warining(); } virtual void add_buffer(RID p_buffer) { _print_warining(); } @@ -181,7 +181,7 @@ public: } virtual void buffer_set_scenario(RID p_buffer, RID p_scenario) { _print_warining(); } virtual void buffer_set_size(RID p_buffer, const Vector2i &p_size) { _print_warining(); } - virtual void buffer_update(RID p_buffer, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {} + virtual void buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_pool) {} virtual RID buffer_get_debug_texture(RID p_buffer) { _print_warining(); return RID(); diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index f27bdc6798..3a230ac89d 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -29,3 +29,153 @@ /*************************************************************************/ #include "renderer_scene_render.h" + +void RendererSceneRender::CameraData::set_camera(const Transform3D p_transform, const CameraMatrix p_projection, bool p_is_ortogonal, bool p_vaspect) { + view_count = 1; + is_ortogonal = p_is_ortogonal; + vaspect = p_vaspect; + + main_transform = p_transform; + main_projection = p_projection; + + view_offset[0] = Transform3D(); + view_projection[0] = p_projection; +} + +void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect) { + ERR_FAIL_COND_MSG(p_view_count != 2, "Incorrect view count for stereoscopic view"); + + view_count = p_view_count; + is_ortogonal = p_is_ortogonal; + vaspect = p_vaspect; + Vector<Plane> planes[2]; + + ///////////////////////////////////////////////////////////////////////////// + // Figure out our center transform + + // 1. obtain our planes + for (uint32_t v = 0; v < view_count; v++) { + planes[v] = p_projections[v].get_projection_planes(p_transforms[v]); + } + + // 2. average and normalize plane normals to obtain z vector, cross them to obtain y vector, and from there the x vector for combined camera basis. + Vector3 n0 = planes[0][CameraMatrix::PLANE_LEFT].normal; + Vector3 n1 = planes[1][CameraMatrix::PLANE_RIGHT].normal; + Vector3 z = (n0 + n1).normalized(); + Vector3 y = n0.cross(n1).normalized(); + Vector3 x = y.cross(z).normalized(); + y = z.cross(x).normalized(); + main_transform.basis.set(x, y, z); + + // 3. create a horizon plane with one of the eyes and the up vector as normal. + Plane horizon(p_transforms[0].origin, y); + + // 4. Intersect horizon, left and right to obtain the combined camera origin. + ERR_FAIL_COND_MSG( + !horizon.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_RIGHT], &main_transform.origin), "Can't determine camera origin"); + + // handy to have the inverse of the transform we just build + Transform3D main_transform_inv = main_transform.inverse(); + + // 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters + Vector3 far_center = (planes[0][CameraMatrix::PLANE_FAR].center() + planes[1][CameraMatrix::PLANE_FAR].center()) * 0.5; + Plane far(far_center, -z); + + ///////////////////////////////////////////////////////////////////////////// + // Figure out our top/bottom planes + + // 6. Intersect far and left planes with top planes from both eyes, save the point with highest y as top_left. + Vector3 top_left, other; + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[0][CameraMatrix::PLANE_TOP], &top_left), "Can't determine left camera far/left/top vector"); + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[1][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_TOP], &other), "Can't determine right camera far/left/top vector"); + if (y.dot(top_left) < y.dot(other)) { + top_left = other; + } + + // 7. Intersect far and left planes with bottom planes from both eyes, save the point with lowest y as bottom_left. + Vector3 bottom_left; + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[0][CameraMatrix::PLANE_LEFT], planes[0][CameraMatrix::PLANE_BOTTOM], &bottom_left), "Can't determine left camera far/left/bottom vector"); + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[1][CameraMatrix::PLANE_LEFT], planes[1][CameraMatrix::PLANE_BOTTOM], &other), "Can't determine right camera far/left/bottom vector"); + if (y.dot(other) < y.dot(bottom_left)) { + bottom_left = other; + } + + // 8. Intersect far and right planes with top planes from both eyes, save the point with highest y as top_right. + Vector3 top_right; + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[0][CameraMatrix::PLANE_RIGHT], planes[0][CameraMatrix::PLANE_TOP], &top_right), "Can't determine left camera far/right/top vector"); + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[1][CameraMatrix::PLANE_RIGHT], planes[1][CameraMatrix::PLANE_TOP], &other), "Can't determine right camera far/right/top vector"); + if (y.dot(top_right) < y.dot(other)) { + top_right = other; + } + + // 9. Intersect far and right planes with bottom planes from both eyes, save the point with lowest y as bottom_right. + Vector3 bottom_right; + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[0][CameraMatrix::PLANE_RIGHT], planes[0][CameraMatrix::PLANE_BOTTOM], &bottom_right), "Can't determine left camera far/right/bottom vector"); + ERR_FAIL_COND_MSG( + !far.intersect_3(planes[1][CameraMatrix::PLANE_RIGHT], planes[1][CameraMatrix::PLANE_BOTTOM], &other), "Can't determine right camera far/right/bottom vector"); + if (y.dot(other) < y.dot(bottom_right)) { + bottom_right = other; + } + + // 10. Create top plane with these points: camera origin, top_left, top_right + Plane top(main_transform.origin, top_left, top_right); + + // 11. Create bottom plane with these points: camera origin, bottom_left, bottom_right + Plane bottom(main_transform.origin, bottom_left, bottom_right); + + ///////////////////////////////////////////////////////////////////////////// + // Figure out our near plane points + + // 12. Create a near plane using -camera z and the eye further along in that axis. + Plane near; + Vector3 neg_z = -z; + if (neg_z.dot(p_transforms[1].origin) < neg_z.dot(p_transforms[0].origin)) { + near = Plane(p_transforms[0].origin, neg_z); + } else { + near = Plane(p_transforms[1].origin, neg_z); + } + + // 13. Intersect near plane with bottm/left planes, to obtain min_vec then top/right to obtain max_vec + Vector3 min_vec; + ERR_FAIL_COND_MSG( + !near.intersect_3(bottom, planes[0][CameraMatrix::PLANE_LEFT], &min_vec), "Can't determine left camera near/left/bottom vector"); + ERR_FAIL_COND_MSG( + !near.intersect_3(bottom, planes[1][CameraMatrix::PLANE_LEFT], &other), "Can't determine right camera near/left/bottom vector"); + if (x.dot(other) < x.dot(min_vec)) { + min_vec = other; + } + + Vector3 max_vec; + ERR_FAIL_COND_MSG( + !near.intersect_3(top, planes[0][CameraMatrix::PLANE_RIGHT], &max_vec), "Can't determine left camera near/right/top vector"); + ERR_FAIL_COND_MSG( + !near.intersect_3(top, planes[1][CameraMatrix::PLANE_RIGHT], &other), "Can't determine right camera near/right/top vector"); + if (x.dot(max_vec) < x.dot(other)) { + max_vec = other; + } + + // 14. transform these points by the inverse camera to obtain local_min_vec and local_max_vec + Vector3 local_min_vec = main_transform_inv.xform(min_vec); + Vector3 local_max_vec = main_transform_inv.xform(max_vec); + + // 15. get x and y from these to obtain left, top, right bottom for the frustum. Get the distance from near plane to camera origin to obtain near, and the distance from the far plane to the camer origin to obtain far. + float z_near = -near.distance_to(main_transform.origin); + float z_far = -far.distance_to(main_transform.origin); + + // 16. Use this to build the combined camera matrix. + main_projection.set_frustum(local_min_vec.x, local_max_vec.x, local_min_vec.y, local_max_vec.y, z_near, z_far); + + ///////////////////////////////////////////////////////////////////////////// + // 3. Copy our view data + for (uint32_t v = 0; v < view_count; v++) { + view_offset[v] = main_transform_inv * p_transforms[v]; + view_projection[v] = p_projections[v] * CameraMatrix(view_offset[v].inverse()); + } +} diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 3f28fac549..ff0fea16d0 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -33,13 +33,15 @@ #include "core/math/camera_matrix.h" #include "core/templates/paged_array.h" +#include "servers/rendering/renderer_scene.h" #include "servers/rendering/renderer_storage.h" class RendererSceneRender { public: enum { MAX_DIRECTIONAL_LIGHTS = 8, - MAX_DIRECTIONAL_LIGHT_CASCADES = 4 + MAX_DIRECTIONAL_LIGHT_CASCADES = 4, + MAX_RENDER_VIEWS = 2 }; struct GeometryInstance { @@ -51,7 +53,7 @@ public: virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) = 0; virtual void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) = 0; virtual void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) = 0; - virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; + virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0; virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0; virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0; @@ -65,7 +67,7 @@ public: virtual void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) = 0; virtual void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) = 0; virtual void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) = 0; - virtual void geometry_instance_pair_gi_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_gi_probe_instances, uint32_t p_gi_probe_instance_count) = 0; + virtual void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) = 0; virtual void geometry_instance_free(GeometryInstance *p_geometry_instance) = 0; @@ -161,9 +163,9 @@ public: virtual void directional_shadow_quality_set(RS::ShadowQuality p_quality) = 0; virtual RID light_instance_create(RID p_light) = 0; - virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform) = 0; + virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) = 0; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0; - virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; + virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0; virtual void light_instance_mark_visible(RID p_light_instance) = 0; virtual bool light_instances_can_render_shadow_cube() const { return true; @@ -174,7 +176,7 @@ public: virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0; virtual RID reflection_probe_instance_create(RID p_probe) = 0; - virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; @@ -182,17 +184,17 @@ public: virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0; virtual RID decal_instance_create(RID p_decal) = 0; - virtual void decal_instance_set_transform(RID p_decal, const Transform &p_transform) = 0; + virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) = 0; virtual RID lightmap_instance_create(RID p_lightmap) = 0; - virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform &p_transform) = 0; + virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) = 0; - virtual RID gi_probe_instance_create(RID p_gi_probe) = 0; - virtual void gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) = 0; - virtual bool gi_probe_needs_update(RID p_probe) const = 0; - virtual void gi_probe_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0; + virtual RID voxel_gi_instance_create(RID p_voxel_gi) = 0; + virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) = 0; + virtual bool voxel_gi_needs_update(RID p_probe) const = 0; + virtual void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<GeometryInstance *> &p_dynamic_objects) = 0; - virtual void gi_probe_set_quality(RS::GIProbeQuality) = 0; + virtual void voxel_gi_set_quality(RS::VoxelGIQuality) = 0; struct RenderShadowData { RID light; @@ -216,17 +218,34 @@ public: uint32_t positional_light_count; }; - virtual void render_scene(RID p_render_buffers, const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_gi_probes, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr) = 0; + struct CameraData { + // flags + uint32_t view_count; + bool is_ortogonal; + bool vaspect; - virtual void render_material(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; - virtual void render_particle_collider_heightfield(RID p_collider, const Transform &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0; + // Main/center projection + Transform3D main_transform; + CameraMatrix main_projection; + + Transform3D view_offset[RendererSceneRender::MAX_RENDER_VIEWS]; + CameraMatrix view_projection[RendererSceneRender::MAX_RENDER_VIEWS]; + + void set_camera(const Transform3D p_transform, const CameraMatrix p_projection, bool p_is_ortogonal, bool p_vaspect); + void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect); + }; + + virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0; + + virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; + virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0; virtual void set_scene_pass(uint64_t p_pass) = 0; virtual void set_time(double p_time, double p_step) = 0; virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index 75975e909d..b2aa0d27d3 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -130,7 +130,6 @@ public: virtual void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; virtual void texture_proxy_initialize(RID p_texture, RID p_base) = 0; //all slices, then all the mipmaps, must be coherent - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; virtual void texture_proxy_update(RID p_proxy, RID p_base) = 0; @@ -230,7 +229,9 @@ public: virtual void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) = 0; virtual RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0; - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; @@ -268,14 +269,14 @@ public: virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; - virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0; + virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0; virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0; virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; - virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; + virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; @@ -288,24 +289,6 @@ public: virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; - /* IMMEDIATE API */ - - virtual RID immediate_allocate() = 0; - virtual void immediate_initialize(RID p_rid) = 0; - - virtual void immediate_begin(RID p_immediate, RS::PrimitiveType p_rimitive, RID p_texture = RID()) = 0; - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0; - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0; - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0; - virtual void immediate_color(RID p_immediate, const Color &p_color) = 0; - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_end(RID p_immediate) = 0; - virtual void immediate_clear(RID p_immediate) = 0; - virtual void immediate_set_material(RID p_immediate, RID p_material) = 0; - virtual RID immediate_get_material(RID p_immediate) const = 0; - virtual AABB immediate_get_aabb(RID p_immediate) const = 0; - /* SKELETON API */ virtual RID skeleton_allocate() = 0; @@ -313,8 +296,8 @@ public: virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; - virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; - virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0; + virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; @@ -348,8 +331,6 @@ public: virtual bool light_directional_get_blend_splits(RID p_light) const = 0; virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; virtual bool light_directional_is_sky_only(RID p_light) const = 0; - virtual void light_directional_set_shadow_depth_range_mode(RID p_light, RS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0; - virtual RS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0; virtual RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0; virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0; @@ -413,53 +394,47 @@ public: virtual AABB decal_get_aabb(RID p_decal) const = 0; - /* GI PROBE API */ - - virtual RID gi_probe_allocate() = 0; - virtual void gi_probe_initialize(RID p_rid) = 0; + /* VOXEL GI API */ - virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; + virtual RID voxel_gi_allocate() = 0; + virtual void voxel_gi_initialize(RID p_rid) = 0; - virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; - virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; + virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; - virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; - virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; + virtual AABB voxel_gi_get_bounds(RID p_voxel_gi) const = 0; + virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const = 0; + virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const = 0; + virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const = 0; + virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0; + virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const = 0; + virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) = 0; + virtual float voxel_gi_get_dynamic_range(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0; - virtual float gi_probe_get_energy(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) = 0; + virtual float voxel_gi_get_propagation(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0; - virtual float gi_probe_get_ao(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0; + virtual float voxel_gi_get_energy(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0; + virtual float voxel_gi_get_bias(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0; - virtual float gi_probe_get_bias(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) = 0; + virtual float voxel_gi_get_normal_bias(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) = 0; + virtual bool voxel_gi_is_interior(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) = 0; + virtual bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) = 0; + virtual float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0; - - virtual uint32_t gi_probe_get_version(RID p_probe) = 0; + virtual uint32_t voxel_gi_get_version(RID p_probe) = 0; /* LIGHTMAP */ @@ -507,10 +482,10 @@ public: virtual void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) = 0; virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length) = 0; - virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0; + virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) = 0; virtual void particles_restart(RID p_particles) = 0; - virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; + virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; virtual void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) = 0; virtual bool particles_is_inactive(RID p_particles) const = 0; @@ -524,7 +499,7 @@ public: virtual AABB particles_get_current_aabb(RID p_particles) = 0; virtual AABB particles_get_aabb(RID p_particles) const = 0; - virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; + virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0; virtual int particles_get_draw_passes(RID p_particles) const = 0; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const = 0; @@ -557,9 +532,17 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; + virtual RID visibility_notifier_allocate() = 0; + virtual void visibility_notifier_initialize(RID p_notifier) = 0; + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0; + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0; + + virtual AABB visibility_notifier_get_aabb(RID p_notifier) const = 0; + virtual void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) = 0; + //used from 2D and 3D virtual RID particles_collision_instance_create(RID p_collision) = 0; - virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform &p_transform) = 0; + virtual void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) = 0; virtual void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) = 0; /* GLOBAL VARIABLES */ @@ -590,7 +573,7 @@ public: virtual RID render_target_create() = 0; virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0; - virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0; + virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0; virtual RID render_target_get_texture(RID p_render_target) = 0; virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0; virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0; @@ -616,11 +599,9 @@ public: virtual void set_debug_generate_wireframes(bool p_generate) = 0; - virtual void render_info_begin_capture() = 0; - virtual void render_info_end_capture() = 0; - virtual int get_captured_render_info(RS::RenderInfo p_info) = 0; + virtual void update_memory_info() = 0; - virtual uint64_t get_render_info(RS::RenderInfo p_info) = 0; + virtual uint64_t get_rendering_info(RS::RenderingInfo p_info) = 0; virtual String get_video_adapter_name() const = 0; virtual String get_video_adapter_vendor() const = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index f97e24947d..15ce1dbe63 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -71,11 +71,11 @@ static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, return xf; } -void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { +void RendererViewport::_draw_3d(Viewport *p_viewport) { RENDER_TIMESTAMP(">Begin Rendering 3D Scene"); Ref<XRInterface> xr_interface; - if (XRServer::get_singleton() != nullptr) { + if (p_viewport->use_xr && XRServer::get_singleton() != nullptr) { xr_interface = XRServer::get_singleton()->get_primary_interface(); } @@ -95,15 +95,12 @@ void RendererViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { } float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width); - if (p_viewport->use_xr && xr_interface.is_valid()) { - RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); - } else { - RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas); - } + RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); + RENDER_TIMESTAMP("<End Rendering 3D Scene"); } -void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye) { +void RendererViewport::_draw_viewport(Viewport *p_viewport, uint32_t p_view_count) { if (p_viewport->measure_render_time) { String rt_id = "vp_begin_" + itos(p_viewport->self.get_id()); RSG::storage->capture_timestamp(rt_id); @@ -115,9 +112,15 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_ bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front int scenario_canvas_max_layer = 0; + for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_TYPE_MAX; i++) { + for (int j = 0; j < RS::VIEWPORT_RENDER_INFO_MAX; j++) { + p_viewport->render_info.info[i][j] = 0; + } + } + Color bgcolor = RSG::storage->get_default_clear_color(); - if (!p_viewport->hide_canvas && !p_viewport->disable_environment && RSG::scene->is_scenario(p_viewport->scenario)) { + if (!p_viewport->disable_2d && !p_viewport->disable_environment && RSG::scene->is_scenario(p_viewport->scenario)) { RID environment = RSG::scene->scenario_get_environment(p_viewport->scenario); if (RSG::scene->is_environment(environment)) { scenario_draw_canvas_bg = RSG::scene->environment_get_background(environment) == RS::ENV_BG_CANVAS; @@ -125,7 +128,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_ } } - bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera); + bool can_draw_3d = RSG::scene->is_camera(p_viewport->camera) && !p_viewport->disable_3d; if (p_viewport->clear_mode != RS::VIEWPORT_CLEAR_NEVER) { if (p_viewport->transparent_bg) { @@ -139,16 +142,16 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_ if ((scenario_draw_canvas_bg || can_draw_3d) && !p_viewport->render_buffers.is_valid()) { //wants to draw 3D but there is no render buffer, create p_viewport->render_buffers = RSG::scene->render_buffers_create(); - RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding); + RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, p_viewport->size.width, p_viewport->size.height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_view_count); } RSG::storage->render_target_request_clear(p_viewport->render_target, bgcolor); if (!scenario_draw_canvas_bg && can_draw_3d) { - _draw_3d(p_viewport, p_eye); + _draw_3d(p_viewport); } - if (!p_viewport->hide_canvas) { + if (!p_viewport->disable_2d) { int i = 0; Map<Viewport::CanvasKey, Viewport::CanvasData *> canvas_map; @@ -392,7 +395,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_ if (!can_draw_3d) { RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { - _draw_3d(p_viewport, p_eye); + _draw_3d(p_viewport); } scenario_draw_canvas_bg = false; } @@ -433,7 +436,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_ if (!can_draw_3d) { RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { - _draw_3d(p_viewport, p_eye); + _draw_3d(p_viewport); } scenario_draw_canvas_bg = false; @@ -444,7 +447,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_ if (!can_draw_3d) { RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { - _draw_3d(p_viewport, p_eye); + _draw_3d(p_viewport); } } } @@ -481,7 +484,7 @@ void RendererViewport::draw_viewports() { //sort viewports active_viewports.sort_custom<ViewportSort>(); - Map<DisplayServer::WindowID, Vector<RendererCompositor::BlitToScreen>> blit_to_screen_list; + Map<DisplayServer::WindowID, Vector<BlitToScreen>> blit_to_screen_list; //draw viewports RENDER_TIMESTAMP(">Render Viewports"); @@ -525,6 +528,10 @@ void RendererViewport::draw_viewports() { } } + int vertices_drawn = 0; + int objects_drawn = 0; + int draw_calls_used = 0; + for (int i = 0; i < active_viewports.size(); i++) { Viewport *vp = active_viewports[i]; @@ -535,64 +542,49 @@ void RendererViewport::draw_viewports() { RENDER_TIMESTAMP(">Rendering Viewport " + itos(i)); RSG::storage->render_target_set_as_unused(vp->render_target); -#if 0 - // TODO fix up this code after we change our commit_for_eye to accept our new render targets - if (vp->use_xr && xr_interface.is_valid()) { - // override our size, make sure it matches our required size + // override our size, make sure it matches our required size and is created as a stereo target vp->size = xr_interface->get_render_targetsize(); - RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y); + uint32_t view_count = xr_interface->get_view_count(); + RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); - // render mono or left eye first - XRInterface::Eyes leftOrMono = xr_interface->is_stereo() ? XRInterface::EYE_LEFT : XRInterface::EYE_MONO; - - // check for an external texture destination for our left eye/mono - // TODO investigate how we're going to make external textures work - RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono)); + // check for an external texture destination (disabled for now, not yet supported) + // RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono)); + RSG::storage->render_target_set_external_texture(vp->render_target, 0); - // set our render target as current - RSG::rasterizer->set_current_render_target(vp->render_target); + // render... + RSG::scene->set_debug_draw_mode(vp->debug_draw); - // and draw left eye/mono - _draw_viewport(vp, leftOrMono); - xr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect); + // and draw viewport + _draw_viewport(vp, view_count); - // render right eye - if (leftOrMono == XRInterface::EYE_LEFT) { - // check for an external texture destination for our right eye - RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(XRInterface::EYE_RIGHT)); + // measure - // commit for eye may have changed the render target - RSG::rasterizer->set_current_render_target(vp->render_target); + // commit our eyes + Vector<BlitToScreen> blits = xr_interface->commit_views(vp->render_target, vp->viewport_to_screen_rect); + if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) { + if (!blit_to_screen_list.has(vp->viewport_to_screen)) { + blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); + } - _draw_viewport(vp, XRInterface::EYE_RIGHT); - xr_interface->commit_for_eye(XRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect); + for (int b = 0; b < blits.size(); b++) { + blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]); + } } // and for our frame timing, mark when we've finished committing our eyes XRServer::get_singleton()->_mark_commit(); } else { -#endif - { RSG::storage->render_target_set_external_texture(vp->render_target, 0); RSG::scene->set_debug_draw_mode(vp->debug_draw); - RSG::storage->render_info_begin_capture(); // render standard mono camera - _draw_viewport(vp); - - RSG::storage->render_info_end_capture(); - vp->render_info[RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_OBJECTS_IN_FRAME); - vp->render_info[RS::VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_VERTICES_IN_FRAME); - vp->render_info[RS::VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_MATERIAL_CHANGES_IN_FRAME); - vp->render_info[RS::VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_SHADER_CHANGES_IN_FRAME); - vp->render_info[RS::VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_SURFACE_CHANGES_IN_FRAME); - vp->render_info[RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = RSG::storage->get_captured_render_info(RS::INFO_DRAW_CALLS_IN_FRAME); + _draw_viewport(vp, 1); if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && (!vp->viewport_render_direct_to_screen || !RSG::rasterizer->is_low_end())) { //copy to screen if set as such - RendererCompositor::BlitToScreen blit; + BlitToScreen blit; blit.render_target = vp->render_target; if (vp->viewport_to_screen_rect != Rect2()) { blit.rect = vp->viewport_to_screen_rect; @@ -602,7 +594,7 @@ void RendererViewport::draw_viewports() { } if (!blit_to_screen_list.has(vp->viewport_to_screen)) { - blit_to_screen_list[vp->viewport_to_screen] = Vector<RendererCompositor::BlitToScreen>(); + blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>(); } blit_to_screen_list[vp->viewport_to_screen].push_back(blit); @@ -614,14 +606,22 @@ void RendererViewport::draw_viewports() { } RENDER_TIMESTAMP("<Rendering Viewport " + itos(i)); + + objects_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME]; + vertices_drawn += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME]; + draw_calls_used += vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] + vp->render_info.info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME]; } RSG::scene->set_debug_draw_mode(RS::VIEWPORT_DEBUG_DRAW_DISABLED); + total_objects_drawn = objects_drawn; + total_vertices_drawn = vertices_drawn; + total_draw_calls_used = draw_calls_used; + RENDER_TIMESTAMP("<Render Viewports"); //this needs to be called to make screen swapping more efficient RSG::rasterizer->prepare_for_blitting_render_targets(); - for (Map<int, Vector<RendererCompositor::BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { + for (Map<int, Vector<BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { RSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size()); } } @@ -631,22 +631,41 @@ RID RendererViewport::viewport_allocate() { } void RendererViewport::viewport_initialize(RID p_rid) { - Viewport *viewport = memnew(Viewport); + viewport_owner.initialize_rid(p_rid); + Viewport *viewport = viewport_owner.getornull(p_rid); viewport->self = p_rid; - viewport->hide_scenario = false; - viewport->hide_canvas = false; viewport->render_target = RSG::storage->render_target_create(); viewport->shadow_atlas = RSG::scene->shadow_atlas_create(); viewport->viewport_render_direct_to_screen = false; - - viewport_owner.initialize_rid(p_rid, viewport); } void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); + if (viewport->use_xr == p_use_xr) { + return; + } + viewport->use_xr = p_use_xr; + if (viewport->render_buffers.is_valid()) { + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding, viewport->get_view_count()); + } +} + +uint32_t RendererViewport::Viewport::get_view_count() { + uint32_t view_count = 1; + + if (use_xr && XRServer::get_singleton() != nullptr) { + Ref<XRInterface> xr_interface; + + xr_interface = XRServer::get_singleton()->get_primary_interface(); + if (xr_interface.is_valid()) { + view_count = xr_interface->get_view_count(); + } + } + + return view_count; } void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { @@ -656,13 +675,14 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig ERR_FAIL_COND(!viewport); viewport->size = Size2(p_width, p_height); - RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height); + uint32_t view_count = viewport->get_view_count(); + RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count); if (viewport->render_buffers.is_valid()) { if (p_width == 0 || p_height == 0) { RSG::scene->free(viewport->render_buffers); viewport->render_buffers = RID(); } else { - RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, viewport->use_debanding, view_count); } } @@ -674,7 +694,7 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { ERR_FAIL_COND(!viewport); if (p_active) { - ERR_FAIL_COND(active_viewports.find(viewport) != -1); //already active + ERR_FAIL_COND_MSG(active_viewports.find(viewport) != -1, "Can't make active a Viewport that is already active."); viewport->occlusion_buffer_dirty = true; active_viewports.push_back(viewport); } else { @@ -704,7 +724,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ // If using GLES2 we can optimize this operation by rendering directly to system_fbo // instead of rendering to fbo and copying to system_fbo after if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { - RSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y); + RSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count()); RSG::storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y); } @@ -714,7 +734,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ // if render_direct_to_screen was used, reset size and position if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { RSG::storage->render_target_set_position(viewport->render_target, 0, 0); - RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y); + RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); } viewport->viewport_to_screen_rect = Rect2(); @@ -733,7 +753,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool // if disabled, reset render_target size and position if (!p_enable) { RSG::storage->render_target_set_position(viewport->render_target, 0, 0); - RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y); + RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); } RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN, p_enable); @@ -741,7 +761,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool // if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) { - RSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y); + RSG::storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count()); RSG::storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y); } } @@ -770,25 +790,25 @@ RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const return RID(); } -void RendererViewport::viewport_set_hide_scenario(RID p_viewport, bool p_hide) { +void RendererViewport::viewport_set_disable_2d(RID p_viewport, bool p_disable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - viewport->hide_scenario = p_hide; + viewport->disable_2d = p_disable; } -void RendererViewport::viewport_set_hide_canvas(RID p_viewport, bool p_hide) { +void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - viewport->hide_canvas = p_hide; + viewport->disable_environment = p_disable; } -void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { +void RendererViewport::viewport_set_disable_3d(RID p_viewport, bool p_disable) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - viewport->disable_environment = p_disable; + viewport->disable_3d = p_disable; } void RendererViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { @@ -802,6 +822,10 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); + if (viewport->scenario.is_valid()) { + RSG::scene->scenario_remove_viewport_visibility_mask(viewport->scenario, p_viewport); + } + viewport->scenario = p_scenario; if (viewport->use_occlusion_culling) { RendererSceneOcclusionCull::get_singleton()->buffer_set_scenario(p_viewport, p_scenario); @@ -892,7 +916,7 @@ void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa } viewport->msaa = p_msaa; if (viewport->render_buffers.is_valid()) { - RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, p_msaa, viewport->screen_space_aa, viewport->use_debanding, viewport->get_view_count()); } } @@ -905,7 +929,7 @@ void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::Viewport } viewport->screen_space_aa = p_mode; if (viewport->render_buffers.is_valid()) { - RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, p_mode, viewport->use_debanding, viewport->get_view_count()); } } @@ -918,7 +942,7 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb } viewport->use_debanding = p_use_debanding; if (viewport->render_buffers.is_valid()) { - RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding); + RSG::scene->render_buffers_configure(viewport->render_buffers, viewport->render_target, viewport->size.width, viewport->size.height, viewport->msaa, viewport->screen_space_aa, p_use_debanding, viewport->get_view_count()); } } @@ -964,7 +988,7 @@ void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels viewport->lod_threshold = p_pixels; } -int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info) { +int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfoType p_type, RS::ViewportRenderInfo p_info) { ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1); Viewport *viewport = viewport_owner.getornull(p_viewport); @@ -972,7 +996,7 @@ int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRende return 0; //there should be a lock here.. } - return viewport->render_info[p_info]; + return viewport->render_info.info[p_type][p_info]; } void RendererViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) { @@ -1059,7 +1083,6 @@ bool RendererViewport::free(RID p_rid) { } viewport_owner.free(p_rid); - memdelete(viewport); return true; } @@ -1093,9 +1116,19 @@ void RendererViewport::set_default_clear_color(const Color &p_color) { RSG::storage->set_default_clear_color(p_color); } -//workaround for setting this on thread -void RendererViewport::call_set_use_vsync(bool p_enable) { - DisplayServer::get_singleton()->_set_use_vsync(p_enable); +// Workaround for setting this on thread. +void RendererViewport::call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) { + DisplayServer::get_singleton()->window_set_vsync_mode(p_mode, p_window); +} + +int RendererViewport::get_total_objects_drawn() const { + return total_objects_drawn; +} +int RendererViewport::get_total_vertices_drawn() const { + return total_vertices_drawn; +} +int RendererViewport::get_total_draw_calls_used() const { + return total_draw_calls_used; } RendererViewport::RendererViewport() { diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 5c372e8c9a..ac7a35f97d 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -34,6 +34,7 @@ #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" #include "core/templates/self_list.h" +#include "servers/rendering/renderer_scene.h" #include "servers/rendering_server.h" #include "servers/xr/xr_interface.h" @@ -68,9 +69,9 @@ public: Rect2 viewport_to_screen_rect; bool viewport_render_direct_to_screen; - bool hide_scenario; - bool hide_canvas; - bool disable_environment; + bool disable_2d = false; + bool disable_environment = false; + bool disable_3d = false; bool measure_render_time; bool snap_2d_transforms_to_pixel; @@ -92,7 +93,6 @@ public: uint64_t last_pass = 0; - int render_info[RS::VIEWPORT_RENDER_INFO_MAX]; RS::ViewportDebugDraw debug_draw; RS::ViewportClearMode clear_mode; @@ -133,11 +133,13 @@ public: Map<RID, CanvasData> canvas_map; + RendererScene::RenderInfo render_info; + Viewport() { update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE; clear_mode = RS::VIEWPORT_CLEAR_ALWAYS; transparent_bg = false; - disable_environment = false; + viewport_to_screen = DisplayServer::INVALID_WINDOW_ID; shadow_atlas_size = 0; measure_render_time = false; @@ -152,9 +154,6 @@ public: snap_2d_transforms_to_pixel = false; snap_2d_vertices_to_pixel = false; - for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) { - render_info[i] = 0; - } use_xr = false; sdf_active = false; @@ -164,13 +163,15 @@ public: time_gpu_begin = 0; time_gpu_end = 0; } + + uint32_t get_view_count(); }; HashMap<String, RID> timestamp_vp_map; uint64_t draw_viewports_pass = 0; - mutable RID_PtrOwner<Viewport, true> viewport_owner; + mutable RID_Owner<Viewport, true> viewport_owner; struct ViewportSort { _FORCE_INLINE_ bool operator()(const Viewport *p_left, const Viewport *p_right) const { @@ -186,9 +187,13 @@ public: Vector<Viewport *> active_viewports; + int total_objects_drawn = 0; + int total_vertices_drawn = 0; + int total_draw_calls_used = 0; + private: - void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye); - void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO); + void _draw_3d(Viewport *p_viewport); + void _draw_viewport(Viewport *p_viewport, uint32_t p_view_count = 1); int occlusion_rays_per_thread = 512; @@ -215,9 +220,9 @@ public: RID viewport_get_texture(RID p_viewport) const; RID viewport_get_occluder_debug_texture(RID p_viewport) const; - void viewport_set_hide_scenario(RID p_viewport, bool p_hide); - void viewport_set_hide_canvas(RID p_viewport, bool p_hide); + void viewport_set_disable_2d(RID p_viewport, bool p_disable); void viewport_set_disable_environment(RID p_viewport, bool p_disable); + void viewport_set_disable_3d(RID p_viewport, bool p_disable); void viewport_attach_camera(RID p_viewport, RID p_camera); void viewport_set_scenario(RID p_viewport, RID p_scenario); @@ -240,7 +245,7 @@ public: void viewport_set_occlusion_culling_build_quality(RS::ViewportOcclusionCullingBuildQuality p_quality); void viewport_set_lod_threshold(RID p_viewport, float p_pixels); - virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfo p_info); + virtual int viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfoType p_type, RS::ViewportRenderInfo p_info); virtual void viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw); void viewport_set_measure_render_time(RID p_viewport, bool p_enable); @@ -262,8 +267,12 @@ public: bool free(RID p_rid); - //workaround for setting this on thread - void call_set_use_vsync(bool p_enable); + int get_total_objects_drawn() const; + int get_total_vertices_drawn() const; + int get_total_draw_calls_used() const; + + // Workaround for setting this on thread. + void call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window); RendererViewport(); virtual ~RendererViewport() {} diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 056cec4c1f..3594939362 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -98,7 +98,7 @@ RID RenderingDevice::_texture_create_shared_from_slice(const Ref<RDTextureView> return texture_create_shared_from_slice(p_view->base, p_with_texture, p_layer, p_mipmap, p_slice_type); } -RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments) { +RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count) { Vector<AttachmentFormat> attachments; attachments.resize(p_attachments.size()); @@ -107,12 +107,43 @@ RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID); attachments.write[i] = af->base; } - return framebuffer_format_create(attachments); + return framebuffer_format_create(attachments, p_view_count); } -RID RenderingDevice::_framebuffer_create(const Array &p_textures, FramebufferFormatID p_format_check) { +RenderingDevice::FramebufferFormatID RenderingDevice::_framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count) { + Vector<AttachmentFormat> attachments; + attachments.resize(p_attachments.size()); + + for (int i = 0; i < p_attachments.size(); i++) { + Ref<RDAttachmentFormat> af = p_attachments[i]; + ERR_FAIL_COND_V(af.is_null(), INVALID_FORMAT_ID); + attachments.write[i] = af->base; + } + + Vector<FramebufferPass> passes; + for (int i = 0; i < p_passes.size(); i++) { + Ref<RDFramebufferPass> pass = p_passes[i]; + ERR_CONTINUE(pass.is_null()); + passes.push_back(pass->base); + } + + return framebuffer_format_create_multipass(attachments, passes, p_view_count); +} + +RID RenderingDevice::_framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check, uint32_t p_view_count) { + Vector<RID> textures = Variant(p_textures); + return framebuffer_create(textures, p_format_check, p_view_count); +} + +RID RenderingDevice::_framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check, uint32_t p_view_count) { Vector<RID> textures = Variant(p_textures); - return framebuffer_create(textures, p_format_check); + Vector<FramebufferPass> passes; + for (int i = 0; i < p_passes.size(); i++) { + Ref<RDFramebufferPass> pass = p_passes[i]; + ERR_CONTINUE(pass.is_null()); + passes.push_back(pass->base); + } + return framebuffer_create_multipass(textures, passes, p_format_check, p_view_count); } RID RenderingDevice::_sampler_create(const Ref<RDSamplerState> &p_state) { @@ -143,7 +174,7 @@ Ref<RDShaderBytecode> RenderingDevice::_shader_compile_from_source(const Ref<RDS ERR_FAIL_COND_V(p_source.is_null(), Ref<RDShaderBytecode>()); Ref<RDShaderBytecode> bytecode; - bytecode.instance(); + bytecode.instantiate(); for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { String error; @@ -190,7 +221,36 @@ Error RenderingDevice::_buffer_update(RID p_buffer, uint32_t p_offset, uint32_t return buffer_update(p_buffer, p_offset, p_size, p_data.ptr(), p_post_barrier); } -RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags) { +static Vector<RenderingDevice::PipelineSpecializationConstant> _get_spec_constants(const TypedArray<RDPipelineSpecializationConstant> &p_constants) { + Vector<RenderingDevice::PipelineSpecializationConstant> ret; + ret.resize(p_constants.size()); + for (int i = 0; i < p_constants.size(); i++) { + Ref<RDPipelineSpecializationConstant> c = p_constants[i]; + ERR_CONTINUE(c.is_null()); + RenderingDevice::PipelineSpecializationConstant &sc = ret.write[i]; + Variant value = c->get_value(); + switch (value.get_type()) { + case Variant::BOOL: { + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sc.bool_value = value; + } break; + case Variant::INT: { + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + sc.int_value = value; + } break; + case Variant::FLOAT: { + sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; + sc.float_value = value; + } break; + default: { + } + } + + sc.constant_id = c->get_constant_id(); + } + return ret; +} +RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants) { PipelineRasterizationState rasterization_state; if (p_rasterization_state.is_valid()) { rasterization_state = p_rasterization_state->base; @@ -221,7 +281,11 @@ RID RenderingDevice::_render_pipeline_create(RID p_shader, FramebufferFormatID p } } - return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags); + return render_pipeline_create(p_shader, p_framebuffer_format, p_vertex_format, p_render_primitive, rasterization_state, multisample_state, depth_stencil_state, color_blend_state, p_dynamic_state_flags, p_for_render_pass, _get_spec_constants(p_specialization_constants)); +} + +RID RenderingDevice::_compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants = TypedArray<RDPipelineSpecializationConstant>()) { + return compute_pipeline_create(p_shader, _get_spec_constants(p_specialization_constants)); } Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values, float p_clear_depth, uint32_t p_clear_stencil, const Rect2 &p_region, const TypedArray<RID> &p_storage_textures) { @@ -242,6 +306,22 @@ Vector<int64_t> RenderingDevice::_draw_list_begin_split(RID p_framebuffer, uint3 return split_ids; } +Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p_splits) { + Vector<DrawListID> splits; + splits.resize(p_splits); + + Error err = draw_list_switch_to_next_pass_split(p_splits, splits.ptrw()); + ERR_FAIL_COND_V(err != OK, Vector<int64_t>()); + + Vector<int64_t> split_ids; + split_ids.resize(splits.size()); + for (int i = 0; i < splits.size(); i++) { + split_ids.write[i] = splits[i]; + } + + return split_ids; +} + void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) { ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size); @@ -269,10 +349,12 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("texture_clear", "texture", "color", "base_mipmap", "mipmap_count", "base_layer", "layer_count", "post_barrier"), &RenderingDevice::texture_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("texture_resolve_multisample", "from_texture", "to_texture", "post_barrier"), &RenderingDevice::texture_resolve_multisample, DEFVAL(BARRIER_MASK_ALL)); - ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments"), &RenderingDevice::_framebuffer_format_create); + ClassDB::bind_method(D_METHOD("framebuffer_format_create", "attachments", "view_count"), &RenderingDevice::_framebuffer_format_create, DEFVAL(1)); + ClassDB::bind_method(D_METHOD("framebuffer_format_create_multipass", "attachments", "passes", "view_count"), &RenderingDevice::_framebuffer_format_create_multipass, DEFVAL(1)); ClassDB::bind_method(D_METHOD("framebuffer_format_create_empty", "samples"), &RenderingDevice::framebuffer_format_create_empty, DEFVAL(TEXTURE_SAMPLES_1)); - ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format"), &RenderingDevice::framebuffer_format_get_texture_samples); - ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID)); + ClassDB::bind_method(D_METHOD("framebuffer_format_get_texture_samples", "format", "render_pass"), &RenderingDevice::framebuffer_format_get_texture_samples, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("framebuffer_create", "textures", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1)); + ClassDB::bind_method(D_METHOD("framebuffer_create_multipass", "textures", "passes", "validate_with_format", "view_count"), &RenderingDevice::_framebuffer_create_multipass, DEFVAL(INVALID_FORMAT_ID), DEFVAL(1)); ClassDB::bind_method(D_METHOD("framebuffer_create_empty", "size", "samples", "validate_with_format"), &RenderingDevice::framebuffer_create_empty, DEFVAL(TEXTURE_SAMPLES_1), DEFVAL(INVALID_FORMAT_ID)); ClassDB::bind_method(D_METHOD("framebuffer_get_format", "framebuffer"), &RenderingDevice::framebuffer_get_format); @@ -299,10 +381,10 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("buffer_clear", "buffer", "offset", "size_bytes", "post_barrier"), &RenderingDevice::buffer_clear, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("buffer_get_data", "buffer"), &RenderingDevice::buffer_get_data); - ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags"), &RenderingDevice::_render_pipeline_create, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("render_pipeline_create", "shader", "framebuffer_format", "vertex_format", "primitive", "rasterization_state", "multisample_state", "stencil_state", "color_blend_state", "dynamic_state_flags", "for_render_pass", "specialization_constants"), &RenderingDevice::_render_pipeline_create, DEFVAL(0), DEFVAL(0), DEFVAL(TypedArray<RDPipelineSpecializationConstant>())); ClassDB::bind_method(D_METHOD("render_pipeline_is_valid", "render_pipeline"), &RenderingDevice::render_pipeline_is_valid); - ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader"), &RenderingDevice::compute_pipeline_create); + ClassDB::bind_method(D_METHOD("compute_pipeline_create", "shader", "specialization_constants"), &RenderingDevice::_compute_pipeline_create, DEFVAL(TypedArray<RDPipelineSpecializationConstant>())); ClassDB::bind_method(D_METHOD("compute_pipeline_is_valid", "compute_pieline"), &RenderingDevice::compute_pipeline_is_valid); ClassDB::bind_method(D_METHOD("screen_get_width", "screen"), &RenderingDevice::screen_get_width, DEFVAL(DisplayServer::MAIN_WINDOW_ID)); @@ -325,6 +407,9 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2i())); ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor); + ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass"), &RenderingDevice::draw_list_switch_to_next_pass); + ClassDB::bind_method(D_METHOD("draw_list_switch_to_next_pass_split", "splits"), &RenderingDevice::_draw_list_switch_to_next_pass_split); + ClassDB::bind_method(D_METHOD("draw_list_end", "post_barrier"), &RenderingDevice::draw_list_end, DEFVAL(BARRIER_MASK_ALL)); ClassDB::bind_method(D_METHOD("compute_list_begin", "allow_draw_overlap"), &RenderingDevice::compute_list_begin, DEFVAL(false)); @@ -364,6 +449,8 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device_name"), &RenderingDevice::get_device_name); ClassDB::bind_method(D_METHOD("get_device_pipeline_cache_uuid"), &RenderingDevice::get_device_pipeline_cache_uuid); + ClassDB::bind_method(D_METHOD("get_memory_usage"), &RenderingDevice::get_memory_usage); + BIND_CONSTANT(BARRIER_MASK_RASTER); BIND_CONSTANT(BARRIER_MASK_COMPUTE); BIND_CONSTANT(BARRIER_MASK_TRANSFER); @@ -799,6 +886,10 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(SHADER_LANGUAGE_GLSL); BIND_ENUM_CONSTANT(SHADER_LANGUAGE_HLSL); + BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL); + BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT); + BIND_ENUM_CONSTANT(PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT); + BIND_ENUM_CONSTANT(LIMIT_MAX_BOUND_UNIFORM_SETS); BIND_ENUM_CONSTANT(LIMIT_MAX_FRAMEBUFFER_COLOR_ATTACHMENTS); BIND_ENUM_CONSTANT(LIMIT_MAX_TEXTURES_PER_UNIFORM_SET); @@ -835,6 +926,10 @@ void RenderingDevice::_bind_methods() { BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Y); BIND_ENUM_CONSTANT(LIMIT_MAX_COMPUTE_WORKGROUP_SIZE_Z); + BIND_ENUM_CONSTANT(MEMORY_TEXTURES); + BIND_ENUM_CONSTANT(MEMORY_BUFFERS); + BIND_ENUM_CONSTANT(MEMORY_TOTAL); + BIND_CONSTANT(INVALID_ID); BIND_CONSTANT(INVALID_FORMAT_ID); } diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 4dcb9b963e..9a154ef7e9 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -47,6 +47,8 @@ class RDPipelineRasterizationState; class RDPipelineMultisampleState; class RDPipelineDepthStencilState; class RDPipelineColorBlendState; +class RDFramebufferPass; +class RDPipelineSpecializationConstant; class RenderingDevice : public Object { GDCLASS(RenderingDevice, Object) @@ -516,11 +518,24 @@ public: typedef int64_t FramebufferFormatID; // This ID is warranted to be unique for the same formats, does not need to be freed - virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format) = 0; + virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1) = 0; + struct FramebufferPass { + enum { + ATTACHMENT_UNUSED = -1 + }; + Vector<int32_t> color_attachments; + Vector<int32_t> input_attachments; + Vector<int32_t> resolve_attachments; + Vector<int32_t> preserve_attachments; + int32_t depth_attachment = ATTACHMENT_UNUSED; + }; + + virtual FramebufferFormatID framebuffer_format_create_multipass(const Vector<AttachmentFormat> &p_attachments, Vector<FramebufferPass> &p_passes, uint32_t p_view_count = 1) = 0; virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1) = 0; - virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format) = 0; + virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format, uint32_t p_pass = 0) = 0; - virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID) = 0; + virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0; + virtual RID framebuffer_create_multipass(const Vector<RID> &p_texture_attachments, Vector<FramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1) = 0; virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID) = 0; virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer) = 0; @@ -701,11 +716,39 @@ public: virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0; virtual bool uniform_set_is_valid(RID p_uniform_set) = 0; + typedef void (*UniformSetInvalidatedCallback)(const RID &, void *); + virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) = 0; virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; virtual Vector<uint8_t> buffer_get_data(RID p_buffer) = 0; //this causes stall, only use to retrieve large buffers for saving + /******************************************/ + /**** PIPELINE SPECIALIZATION CONSTANT ****/ + /******************************************/ + + enum PipelineSpecializationConstantType { + PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL, + PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT, + PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT, + }; + + struct PipelineSpecializationConstant { + PipelineSpecializationConstantType type; + uint32_t constant_id; + union { + uint32_t int_value; + float float_value; + bool bool_value; + }; + + PipelineSpecializationConstant() { + type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + constant_id = 0; + int_value = 0; + } + }; + /*************************/ /**** RENDER PIPELINE ****/ /*************************/ @@ -962,13 +1005,13 @@ public: }; virtual bool render_pipeline_is_valid(RID p_pipeline) = 0; - virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0) = 0; + virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0; /**************************/ /**** COMPUTE PIPELINE ****/ /**************************/ - virtual RID compute_pipeline_create(RID p_shader) = 0; + virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()) = 0; virtual bool compute_pipeline_is_valid(RID p_pipeline) = 0; /****************/ @@ -1018,6 +1061,9 @@ public: virtual void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) = 0; virtual void draw_list_disable_scissor(DrawListID p_list) = 0; + virtual DrawListID draw_list_switch_to_next_pass() = 0; + virtual Error draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) = 0; + virtual void draw_list_end(uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0; /***********************/ @@ -1111,7 +1157,13 @@ public: virtual void submit() = 0; virtual void sync() = 0; - virtual uint64_t get_memory_usage() const = 0; + enum MemoryType { + MEMORY_TEXTURES, + MEMORY_BUFFERS, + MEMORY_TOTAL + }; + + virtual uint64_t get_memory_usage(MemoryType p_type) const = 0; virtual RenderingDevice *create_local_device() = 0; @@ -1134,8 +1186,10 @@ protected: RID _texture_create_shared(const Ref<RDTextureView> &p_view, RID p_with_texture); RID _texture_create_shared_from_slice(const Ref<RDTextureView> &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, TextureSliceType p_slice_type = TEXTURE_SLICE_2D); - FramebufferFormatID _framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments); - RID _framebuffer_create(const Array &p_textures, FramebufferFormatID p_format_check = INVALID_ID); + FramebufferFormatID _framebuffer_format_create(const TypedArray<RDAttachmentFormat> &p_attachments, uint32_t p_view_count); + FramebufferFormatID _framebuffer_format_create_multipass(const TypedArray<RDAttachmentFormat> &p_attachments, const TypedArray<RDFramebufferPass> &p_passes, uint32_t p_view_count); + RID _framebuffer_create(const TypedArray<RID> &p_textures, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); + RID _framebuffer_create_multipass(const TypedArray<RID> &p_textures, const TypedArray<RDFramebufferPass> &p_passes, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1); RID _sampler_create(const Ref<RDSamplerState> &p_state); VertexFormatID _vertex_format_create(const TypedArray<RDVertexAttribute> &p_vertex_formats); RID _vertex_array_create(uint32_t p_vertex_count, VertexFormatID p_vertex_format, const TypedArray<RID> &p_src_buffers); @@ -1146,11 +1200,13 @@ protected: Error _buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); - RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags = 0); + RID _render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const Ref<RDPipelineRasterizationState> &p_rasterization_state, const Ref<RDPipelineMultisampleState> &p_multisample_state, const Ref<RDPipelineDepthStencilState> &p_depth_stencil_state, const Ref<RDPipelineColorBlendState> &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); + RID _compute_pipeline_create(RID p_shader, const TypedArray<RDPipelineSpecializationConstant> &p_specialization_constants); Vector<int64_t> _draw_list_begin_split(RID p_framebuffer, uint32_t p_splits, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2(), const TypedArray<RID> &p_storage_textures = TypedArray<RID>()); void _draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size); void _compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size); + Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits); }; VARIANT_ENUM_CAST(RenderingDevice::ShaderStage) @@ -1177,9 +1233,11 @@ VARIANT_ENUM_CAST(RenderingDevice::LogicOperation) VARIANT_ENUM_CAST(RenderingDevice::BlendFactor) VARIANT_ENUM_CAST(RenderingDevice::BlendOperation) VARIANT_ENUM_CAST(RenderingDevice::PipelineDynamicStateFlags) +VARIANT_ENUM_CAST(RenderingDevice::PipelineSpecializationConstantType) VARIANT_ENUM_CAST(RenderingDevice::InitialAction) VARIANT_ENUM_CAST(RenderingDevice::FinalAction) VARIANT_ENUM_CAST(RenderingDevice::Limit) +VARIANT_ENUM_CAST(RenderingDevice::MemoryType) typedef RenderingDevice RD; diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index 2f11360364..2652edb1bc 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -156,7 +156,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String } Ref<RDShaderFile> shader_file; - shader_file.instance(); + shader_file.instantiate(); if (base_error == "") { if (stage_found[RD::SHADER_STAGE_COMPUTE] && stages_found > 1) { @@ -173,7 +173,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String for (Map<StringName, String>::Element *E = version_texts.front(); E; E = E->next()) { Ref<RDShaderBytecode> bytecode; - bytecode.instance(); + bytecode.instantiate(); for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { String code = stage_code[i]; diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index e43c3669b5..1af427b356 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -51,8 +51,8 @@ ClassDB::bind_method(D_METHOD("get_" _MKSTR(m_sub) "_" _MKSTR(m_member)), &m_class::get_##m_sub##_##m_member); \ ADD_PROPERTY(PropertyInfo(m_variant_type, _MKSTR(m_sub) "_" _MKSTR(m_member)), "set_" _MKSTR(m_sub) "_" _MKSTR(m_member), "get_" _MKSTR(m_sub) "_" _MKSTR(m_member)) -class RDTextureFormat : public Reference { - GDCLASS(RDTextureFormat, Reference) +class RDTextureFormat : public RefCounted { + GDCLASS(RDTextureFormat, RefCounted) friend class RenderingDevice; RD::TextureFormat base; @@ -87,8 +87,8 @@ protected: } }; -class RDTextureView : public Reference { - GDCLASS(RDTextureView, Reference) +class RDTextureView : public RefCounted { + GDCLASS(RDTextureView, RefCounted) friend class RenderingDevice; @@ -110,8 +110,8 @@ protected: } }; -class RDAttachmentFormat : public Reference { - GDCLASS(RDAttachmentFormat, Reference) +class RDAttachmentFormat : public RefCounted { + GDCLASS(RDAttachmentFormat, RefCounted) friend class RenderingDevice; RD::AttachmentFormat base; @@ -128,8 +128,36 @@ protected: } }; -class RDSamplerState : public Reference { - GDCLASS(RDSamplerState, Reference) +class RDFramebufferPass : public RefCounted { + GDCLASS(RDFramebufferPass, RefCounted) + friend class RenderingDevice; + + RD::FramebufferPass base; + +public: + RD_SETGET(PackedInt32Array, color_attachments) + RD_SETGET(PackedInt32Array, input_attachments) + RD_SETGET(PackedInt32Array, resolve_attachments) + RD_SETGET(PackedInt32Array, preserve_attachments) + RD_SETGET(int32_t, depth_attachment) +protected: + enum { + ATTACHMENT_UNUSED = -1 + }; + + static void _bind_methods() { + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, color_attachments); + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, input_attachments); + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, resolve_attachments); + RD_BIND(Variant::PACKED_INT32_ARRAY, RDFramebufferPass, preserve_attachments); + RD_BIND(Variant::INT, RDFramebufferPass, depth_attachment); + + BIND_CONSTANT(ATTACHMENT_UNUSED); + } +}; + +class RDSamplerState : public RefCounted { + GDCLASS(RDSamplerState, RefCounted) friend class RenderingDevice; RD::SamplerState base; @@ -171,8 +199,8 @@ protected: } }; -class RDVertexAttribute : public Reference { - GDCLASS(RDVertexAttribute, Reference) +class RDVertexAttribute : public RefCounted { + GDCLASS(RDVertexAttribute, RefCounted) friend class RenderingDevice; RD::VertexAttribute base; @@ -192,8 +220,8 @@ protected: RD_BIND(Variant::INT, RDVertexAttribute, frequency); } }; -class RDShaderSource : public Reference { - GDCLASS(RDShaderSource, Reference) +class RDShaderSource : public RefCounted { + GDCLASS(RDShaderSource, RefCounted) String source[RD::SHADER_STAGE_MAX]; RD::ShaderLanguage language = RD::SHADER_LANGUAGE_GLSL; @@ -386,8 +414,8 @@ protected: } }; -class RDUniform : public Reference { - GDCLASS(RDUniform, Reference) +class RDUniform : public RefCounted { + GDCLASS(RDUniform, RefCounted) friend class RenderingDevice; RD::Uniform base; @@ -424,8 +452,43 @@ protected: ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_ids", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "_set_ids", "get_ids"); } }; -class RDPipelineRasterizationState : public Reference { - GDCLASS(RDPipelineRasterizationState, Reference) + +class RDPipelineSpecializationConstant : public RefCounted { + GDCLASS(RDPipelineSpecializationConstant, RefCounted) + friend class RenderingDevice; + + Variant value = false; + uint32_t constant_id; + +public: + void set_value(const Variant &p_value) { + ERR_FAIL_COND(p_value.get_type() != Variant::BOOL && p_value.get_type() != Variant::INT && p_value.get_type() != Variant::FLOAT); + value = p_value; + } + Variant get_value() const { return value; } + + void set_constant_id(uint32_t p_id) { + constant_id = p_id; + } + uint32_t get_constant_id() const { + return constant_id; + } + +protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("set_value", "value"), &RDPipelineSpecializationConstant::set_value); + ClassDB::bind_method(D_METHOD("get_value"), &RDPipelineSpecializationConstant::get_value); + + ClassDB::bind_method(D_METHOD("set_constant_id", "constant_id"), &RDPipelineSpecializationConstant::set_constant_id); + ClassDB::bind_method(D_METHOD("get_constant_id"), &RDPipelineSpecializationConstant::get_constant_id); + + ADD_PROPERTY(PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT), "set_value", "get_value"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "constant_id", PROPERTY_HINT_RANGE, "0,65535,0"), "set_constant_id", "get_constant_id"); + } +}; + +class RDPipelineRasterizationState : public RefCounted { + GDCLASS(RDPipelineRasterizationState, RefCounted) friend class RenderingDevice; RD::PipelineRasterizationState base; @@ -459,8 +522,8 @@ protected: } }; -class RDPipelineMultisampleState : public Reference { - GDCLASS(RDPipelineMultisampleState, Reference) +class RDPipelineMultisampleState : public RefCounted { + GDCLASS(RDPipelineMultisampleState, RefCounted) friend class RenderingDevice; RD::PipelineMultisampleState base; @@ -490,8 +553,8 @@ protected: } }; -class RDPipelineDepthStencilState : public Reference { - GDCLASS(RDPipelineDepthStencilState, Reference) +class RDPipelineDepthStencilState : public RefCounted { + GDCLASS(RDPipelineDepthStencilState, RefCounted) friend class RenderingDevice; RD::PipelineDepthStencilState base; @@ -549,8 +612,8 @@ protected: } }; -class RDPipelineColorBlendStateAttachment : public Reference { - GDCLASS(RDPipelineColorBlendStateAttachment, Reference) +class RDPipelineColorBlendStateAttachment : public RefCounted { + GDCLASS(RDPipelineColorBlendStateAttachment, RefCounted) friend class RenderingDevice; RD::PipelineColorBlendState::Attachment base; @@ -594,8 +657,8 @@ protected: } }; -class RDPipelineColorBlendState : public Reference { - GDCLASS(RDPipelineColorBlendState, Reference) +class RDPipelineColorBlendState : public RefCounted { + GDCLASS(RDPipelineColorBlendState, RefCounted) friend class RenderingDevice; RD::PipelineColorBlendState base; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index c6fe6a07e0..e3ebebca86 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -42,26 +42,6 @@ int RenderingServerDefault::changes = 0; -/* BLACK BARS */ - -void RenderingServerDefault::black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) { - black_margin[SIDE_LEFT] = p_left; - black_margin[SIDE_TOP] = p_top; - black_margin[SIDE_RIGHT] = p_right; - black_margin[SIDE_BOTTOM] = p_bottom; -} - -void RenderingServerDefault::black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) { - black_image[SIDE_LEFT] = p_left; - black_image[SIDE_TOP] = p_top; - black_image[SIDE_RIGHT] = p_right; - black_image[SIDE_BOTTOM] = p_bottom; -} - -void RenderingServerDefault::_draw_margins() { - RSG::canvas_render->draw_window_margins(black_margin, black_image); -}; - /* FREE */ void RenderingServerDefault::_free(RID p_rid) { @@ -114,9 +94,11 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::viewport->draw_viewports(); RSG::canvas_render->update(); - _draw_margins(); RSG::rasterizer->end_frame(p_swap_buffers); + RSG::canvas->update_visibility_notifiers(); + RSG::scene->update_visibility_notifiers(); + while (frame_drawn_callbacks.front()) { Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object); if (obj) { @@ -207,6 +189,8 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { print_frame_profile_frame_count = 0; } } + + RSG::storage->update_memory_info(); } float RenderingServerDefault::get_frame_setup_time_cpu() const { @@ -257,8 +241,15 @@ void RenderingServerDefault::finish() { /* STATUS INFORMATION */ -uint64_t RenderingServerDefault::get_render_info(RenderInfo p_info) { - return RSG::storage->get_render_info(p_info); +uint64_t RenderingServerDefault::get_rendering_info(RenderingInfo p_info) { + if (p_info == RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME) { + return RSG::viewport->get_total_objects_drawn(); + } else if (p_info == RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME) { + return RSG::viewport->get_total_vertices_drawn(); + } else if (p_info == RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME) { + return RSG::viewport->get_total_draw_calls_used(); + } + return RSG::storage->get_rendering_info(p_info); } String RenderingServerDefault::get_video_adapter_name() const { @@ -358,7 +349,7 @@ void RenderingServerDefault::_thread_loop() { draw_thread_up.set(); while (!exit.is_set()) { // flush commands one by one, until exit is requested - command_queue.wait_and_flush_one(); + command_queue.wait_and_flush(); } command_queue.flush_all(); // flush all @@ -396,6 +387,7 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) : server_thread = 0; } + RSG::threaded = p_create_thread; RSG::canvas = memnew(RendererCanvasCull); RSG::viewport = memnew(RendererViewport); RendererSceneCull *sr = memnew(RendererSceneCull); @@ -406,11 +398,6 @@ RenderingServerDefault::RenderingServerDefault(bool p_create_thread) : sr->set_scene_render(RSG::rasterizer->get_scene()); frame_profile_frame = 0; - - for (int i = 0; i < 4; i++) { - black_margin[i] = 0; - black_image[i] = RID(); - } } RenderingServerDefault::~RenderingServerDefault() { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index bf47d497b6..79665dcdd2 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -58,9 +58,6 @@ class RenderingServerDefault : public RenderingServer { static int changes; RID test_cube; - int black_margin[4]; - RID black_image[4]; - struct FrameDrawnCallbacks { ObjectID object; StringName method; @@ -69,7 +66,6 @@ class RenderingServerDefault : public RenderingServer { List<FrameDrawnCallbacks> frame_drawn_callbacks; - void _draw_margins(); static void _changes_changed() {} uint64_t frame_profile_frame; @@ -192,8 +188,6 @@ public: FUNCRIDTEX6(texture_3d, Image::Format, int, int, int, bool, const Vector<Ref<Image>> &) FUNCRIDTEX1(texture_proxy, RID) - //goes pass-through - FUNC3(texture_2d_update_immediate, RID, const Ref<Image> &, int) //these go through command queue if they are in another thread FUNC3(texture_2d_update, RID, const Ref<Image> &, int) FUNC2(texture_3d_update, RID, const Vector<Ref<Image>> &) @@ -290,7 +284,9 @@ public: FUNC2(mesh_set_blend_shape_mode, RID, BlendShapeMode) FUNC1RC(BlendShapeMode, mesh_get_blend_shape_mode, RID) - FUNC4(mesh_surface_update_region, RID, int, int, const Vector<uint8_t> &) + FUNC4(mesh_surface_update_vertex_region, RID, int, int, const Vector<uint8_t> &) + FUNC4(mesh_surface_update_attribute_region, RID, int, int, const Vector<uint8_t> &) + FUNC4(mesh_surface_update_skin_region, RID, int, int, const Vector<uint8_t> &) FUNC3(mesh_surface_set_material, RID, int, RID) FUNC2RC(RID, mesh_surface_get_material, RID, int) @@ -314,7 +310,7 @@ public: FUNC1RC(int, multimesh_get_instance_count, RID) FUNC2(multimesh_set_mesh, RID, RID) - FUNC3(multimesh_instance_set_transform, RID, int, const Transform &) + FUNC3(multimesh_instance_set_transform, RID, int, const Transform3D &) FUNC3(multimesh_instance_set_transform_2d, RID, int, const Transform2D &) FUNC3(multimesh_instance_set_color, RID, int, const Color &) FUNC3(multimesh_instance_set_custom_data, RID, int, const Color &) @@ -322,7 +318,7 @@ public: FUNC1RC(RID, multimesh_get_mesh, RID) FUNC1RC(AABB, multimesh_get_aabb, RID) - FUNC2RC(Transform, multimesh_instance_get_transform, RID, int) + FUNC2RC(Transform3D, multimesh_instance_get_transform, RID, int) FUNC2RC(Transform2D, multimesh_instance_get_transform_2d, RID, int) FUNC2RC(Color, multimesh_instance_get_color, RID, int) FUNC2RC(Color, multimesh_instance_get_custom_data, RID, int) @@ -333,28 +329,13 @@ public: FUNC2(multimesh_set_visible_instances, RID, int) FUNC1RC(int, multimesh_get_visible_instances, RID) - /* IMMEDIATE API */ - - FUNCRIDSPLIT(immediate) - FUNC3(immediate_begin, RID, PrimitiveType, RID) - FUNC2(immediate_vertex, RID, const Vector3 &) - FUNC2(immediate_normal, RID, const Vector3 &) - FUNC2(immediate_tangent, RID, const Plane &) - FUNC2(immediate_color, RID, const Color &) - FUNC2(immediate_uv, RID, const Vector2 &) - FUNC2(immediate_uv2, RID, const Vector2 &) - FUNC1(immediate_end, RID) - FUNC1(immediate_clear, RID) - FUNC2(immediate_set_material, RID, RID) - FUNC1RC(RID, immediate_get_material, RID) - /* SKELETON API */ FUNCRIDSPLIT(skeleton) FUNC3(skeleton_allocate_data, RID, int, bool) FUNC1RC(int, skeleton_get_bone_count, RID) - FUNC3(skeleton_bone_set_transform, RID, int, const Transform &) - FUNC2RC(Transform, skeleton_bone_get_transform, RID, int) + FUNC3(skeleton_bone_set_transform, RID, int, const Transform3D &) + FUNC2RC(Transform3D, skeleton_bone_get_transform, RID, int) FUNC3(skeleton_bone_set_transform_2d, RID, int, const Transform2D &) FUNC2RC(Transform2D, skeleton_bone_get_transform_2d, RID, int) FUNC2(skeleton_set_base_transform_2d, RID, const Transform2D &) @@ -381,7 +362,6 @@ public: FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) FUNC2(light_directional_set_blend_splits, RID, bool) FUNC2(light_directional_set_sky_only, RID, bool) - FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) /* PROBE API */ @@ -418,47 +398,25 @@ public: /* BAKED LIGHT API */ - FUNCRIDSPLIT(gi_probe) - - FUNC8(gi_probe_allocate_data, RID, const Transform &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &) - - FUNC1RC(AABB, gi_probe_get_bounds, RID) - FUNC1RC(Vector3i, gi_probe_get_octree_size, RID) - FUNC1RC(Vector<uint8_t>, gi_probe_get_octree_cells, RID) - FUNC1RC(Vector<uint8_t>, gi_probe_get_data_cells, RID) - FUNC1RC(Vector<uint8_t>, gi_probe_get_distance_field, RID) - FUNC1RC(Vector<int>, gi_probe_get_level_counts, RID) - FUNC1RC(Transform, gi_probe_get_to_cell_xform, RID) - - FUNC2(gi_probe_set_dynamic_range, RID, float) - FUNC1RC(float, gi_probe_get_dynamic_range, RID) - - FUNC2(gi_probe_set_propagation, RID, float) - FUNC1RC(float, gi_probe_get_propagation, RID) - - FUNC2(gi_probe_set_energy, RID, float) - FUNC1RC(float, gi_probe_get_energy, RID) - - FUNC2(gi_probe_set_ao, RID, float) - FUNC1RC(float, gi_probe_get_ao, RID) - - FUNC2(gi_probe_set_ao_size, RID, float) - FUNC1RC(float, gi_probe_get_ao_size, RID) + FUNCRIDSPLIT(voxel_gi) - FUNC2(gi_probe_set_bias, RID, float) - FUNC1RC(float, gi_probe_get_bias, RID) + FUNC8(voxel_gi_allocate_data, RID, const Transform3D &, const AABB &, const Vector3i &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<uint8_t> &, const Vector<int> &) - FUNC2(gi_probe_set_normal_bias, RID, float) - FUNC1RC(float, gi_probe_get_normal_bias, RID) + FUNC1RC(AABB, voxel_gi_get_bounds, RID) + FUNC1RC(Vector3i, voxel_gi_get_octree_size, RID) + FUNC1RC(Vector<uint8_t>, voxel_gi_get_octree_cells, RID) + FUNC1RC(Vector<uint8_t>, voxel_gi_get_data_cells, RID) + FUNC1RC(Vector<uint8_t>, voxel_gi_get_distance_field, RID) + FUNC1RC(Vector<int>, voxel_gi_get_level_counts, RID) + FUNC1RC(Transform3D, voxel_gi_get_to_cell_xform, RID) - FUNC2(gi_probe_set_interior, RID, bool) - FUNC1RC(bool, gi_probe_is_interior, RID) - - FUNC2(gi_probe_set_use_two_bounces, RID, bool) - FUNC1RC(bool, gi_probe_is_using_two_bounces, RID) - - FUNC2(gi_probe_set_anisotropy_strength, RID, float) - FUNC1RC(float, gi_probe_get_anisotropy_strength, RID) + FUNC2(voxel_gi_set_dynamic_range, RID, float) + FUNC2(voxel_gi_set_propagation, RID, float) + FUNC2(voxel_gi_set_energy, RID, float) + FUNC2(voxel_gi_set_bias, RID, float) + FUNC2(voxel_gi_set_normal_bias, RID, float) + FUNC2(voxel_gi_set_interior, RID, bool) + FUNC2(voxel_gi_set_use_two_bounces, RID, bool) /* LIGHTMAP */ @@ -496,11 +454,11 @@ public: FUNC2(particles_set_fractional_delta, RID, bool) FUNC1R(bool, particles_is_inactive, RID) FUNC3(particles_set_trails, RID, bool, float) - FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform> &) + FUNC2(particles_set_trail_bind_poses, RID, const Vector<Transform3D> &) FUNC1(particles_request_process, RID) FUNC1(particles_restart, RID) - FUNC6(particles_emit, RID, const Transform &, const Vector3 &, const Color &, const Color &, uint32_t) + FUNC6(particles_emit, RID, const Transform3D &, const Vector3 &, const Color &, const Color &, uint32_t) FUNC2(particles_set_subemitter, RID, RID) FUNC2(particles_set_collision_base_size, RID, float) @@ -512,7 +470,7 @@ public: FUNC3(particles_set_draw_pass_mesh, RID, int, RID) FUNC1R(AABB, particles_get_current_aabb, RID) - FUNC2(particles_set_emission_transform, RID, const Transform &) + FUNC2(particles_set_emission_transform, RID, const Transform3D &) /* PARTICLES COLLISION */ @@ -529,6 +487,12 @@ public: FUNC1(particles_collision_height_field_update, RID) FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution) + /* VISIBILITY_NOTIFIER */ + + FUNCRIDSPLIT(visibility_notifier) + FUNC2(visibility_notifier_set_aabb, RID, const AABB &) + FUNC3(visibility_notifier_set_callbacks, RID, const Callable &, const Callable &) + #undef server_name #undef ServerName //from now on, calls forwarded to this singleton @@ -541,7 +505,7 @@ public: FUNC4(camera_set_perspective, RID, float, float, float) FUNC4(camera_set_orthogonal, RID, float, float, float) FUNC5(camera_set_frustum, RID, float, Vector2, float, float) - FUNC2(camera_set_transform, RID, const Transform &) + FUNC2(camera_set_transform, RID, const Transform3D &) FUNC2(camera_set_cull_mask, RID, uint32_t) FUNC2(camera_set_environment, RID, RID) FUNC2(camera_set_camera_effects, RID, RID) @@ -549,7 +513,7 @@ public: /* OCCLUDER */ FUNCRIDSPLIT(occluder) - FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &); + FUNC3(occluder_set_mesh, RID, const PackedVector3Array &, const PackedInt32Array &) #undef server_name #undef ServerName @@ -576,9 +540,9 @@ public: FUNC1RC(RID, viewport_get_texture, RID) - FUNC2(viewport_set_hide_scenario, RID, bool) - FUNC2(viewport_set_hide_canvas, RID, bool) + FUNC2(viewport_set_disable_2d, RID, bool) FUNC2(viewport_set_disable_environment, RID, bool) + FUNC2(viewport_set_disable_3d, RID, bool) FUNC2(viewport_attach_camera, RID, RID) FUNC2(viewport_set_scenario, RID, RID) @@ -606,14 +570,14 @@ public: FUNC1(viewport_set_occlusion_culling_build_quality, ViewportOcclusionCullingBuildQuality) FUNC2(viewport_set_lod_threshold, RID, float) - FUNC2R(int, viewport_get_render_info, RID, ViewportRenderInfo) + FUNC3R(int, viewport_get_render_info, RID, ViewportRenderInfoType, ViewportRenderInfo) FUNC2(viewport_set_debug_draw, RID, ViewportDebugDraw) FUNC2(viewport_set_measure_render_time, RID, bool) FUNC1RC(float, viewport_get_measured_render_time_cpu, RID) FUNC1RC(float, viewport_get_measured_render_time_gpu, RID) - FUNC1(call_set_use_vsync, bool) + FUNC2(call_set_vsync_mode, DisplayServer::VSyncMode, DisplayServer::WindowID) /* ENVIRONMENT API */ @@ -624,7 +588,7 @@ public: #define server_name RSG::scene FUNC2(directional_shadow_atlas_set_size, int, bool) - FUNC1(gi_probe_set_quality, GIProbeQuality) + FUNC1(voxel_gi_set_quality, VoxelGIQuality) /* SKY API */ @@ -703,7 +667,6 @@ public: FUNCRIDSPLIT(scenario) - FUNC2(scenario_set_debug, RID, ScenarioDebugMode) FUNC2(scenario_set_environment, RID, RID) FUNC2(scenario_set_camera_effects, RID, RID) FUNC2(scenario_set_fallback_environment, RID, RID) @@ -714,7 +677,7 @@ public: FUNC2(instance_set_base, RID, RID) FUNC2(instance_set_scenario, RID, RID) FUNC2(instance_set_layer_mask, RID, uint32_t) - FUNC2(instance_set_transform, RID, const Transform &) + FUNC2(instance_set_transform, RID, const Transform3D &) FUNC2(instance_attach_object_instance_id, RID, ObjectID) FUNC3(instance_set_blend_shape_weight, RID, int, float) FUNC3(instance_set_surface_override_material, RID, int, RID) @@ -723,9 +686,9 @@ public: FUNC2(instance_set_custom_aabb, RID, AABB) FUNC2(instance_attach_skeleton, RID, RID) - FUNC2(instance_set_exterior, RID, bool) FUNC2(instance_set_extra_visibility_margin, RID, real_t) + FUNC2(instance_set_visibility_parent, RID, RID) // don't use these in a game! FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID) @@ -736,8 +699,7 @@ public: FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting) FUNC2(instance_geometry_set_material_override, RID, RID) - FUNC5(instance_geometry_set_draw_range, RID, float, float, float, float) - FUNC2(instance_geometry_set_as_instance_lod, RID, RID) + FUNC5(instance_geometry_set_visibility_range, RID, float, float, float, float) FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) FUNC2(instance_geometry_set_lod_bias, RID, float) @@ -807,6 +769,8 @@ public: FUNC3(canvas_item_add_particles, RID, RID, RID) FUNC2(canvas_item_add_set_transform, RID, const Transform2D &) FUNC2(canvas_item_add_clip_ignore, RID, bool) + FUNC5(canvas_item_add_animation_slice, RID, double, double, double, double) + FUNC2(canvas_item_set_sort_children_by_y, RID, bool) FUNC2(canvas_item_set_z_index, RID, int) FUNC2(canvas_item_set_z_as_relative_to_parent, RID, bool) @@ -820,6 +784,8 @@ public: FUNC2(canvas_item_set_use_parent_material, RID, bool) + FUNC5(canvas_item_set_visibility_notifier, RID, bool, const Rect2 &, const Callable &, const Callable &) + FUNC6(canvas_item_set_canvas_group_mode, RID, CanvasGroupMode, float, bool, float, bool) FUNCRIDSPLIT(canvas_light) @@ -887,11 +853,6 @@ public: #undef WRITE_ACTION #undef SYNC_DEBUG - /* BLACK BARS */ - - virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) override; - virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) override; - /* FREE */ virtual void free(RID p_rid) override { @@ -915,7 +876,7 @@ public: /* STATUS INFORMATION */ - virtual uint64_t get_render_info(RenderInfo p_info) override; + virtual uint64_t get_rendering_info(RenderingInfo p_info) override; virtual String get_video_adapter_name() const override; virtual String get_video_adapter_vendor() const override; diff --git a/servers/rendering/rendering_server_globals.cpp b/servers/rendering/rendering_server_globals.cpp index c0d9988e85..2dda506bac 100644 --- a/servers/rendering/rendering_server_globals.cpp +++ b/servers/rendering/rendering_server_globals.cpp @@ -30,6 +30,8 @@ #include "rendering_server_globals.h" +bool RenderingServerGlobals::threaded = false; + RendererStorage *RenderingServerGlobals::storage = nullptr; RendererCanvasRender *RenderingServerGlobals::canvas_render = nullptr; RendererCompositor *RenderingServerGlobals::rasterizer = nullptr; diff --git a/servers/rendering/rendering_server_globals.h b/servers/rendering/rendering_server_globals.h index a28a0f5180..63755e6125 100644 --- a/servers/rendering/rendering_server_globals.h +++ b/servers/rendering/rendering_server_globals.h @@ -41,6 +41,8 @@ class RendererScene; class RenderingServerGlobals { public: + static bool threaded; + static RendererStorage *storage; static RendererCanvasRender *canvas_render; static RendererCompositor *rasterizer; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 14b21e1f42..9b2ba36358 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -631,7 +631,7 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { if (!_is_number(last_char)) { return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); } - if (!str.is_valid_integer()) { + if (!str.is_valid_int()) { return _make_token(TK_ERROR, "Invalid numeric constant"); } } @@ -2941,7 +2941,7 @@ Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::C p[2][0] = p_value[8].real; p[2][1] = p_value[9].real; p[2][2] = p_value[10].real; - Transform t = Transform(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real)); + Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real)); value = Variant(t); break; } @@ -3040,7 +3040,7 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.type = Variant::BASIS; break; case ShaderLanguage::TYPE_MAT4: - pi.type = Variant::TRANSFORM; + pi.type = Variant::TRANSFORM3D; break; case ShaderLanguage::TYPE_SAMPLER2D: case ShaderLanguage::TYPE_ISAMPLER2D: @@ -6375,13 +6375,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } pass_array = false; - bool array_size_incorrect = false; - - if (b->parent_function->return_array_size > 0 && b->parent_function->return_array_size != expr->get_array_size()) { - array_size_incorrect = true; - } - - if (b->parent_function->return_type != expr->get_datatype() || array_size_incorrect || return_struct_name != expr->get_datatype_name()) { + if (b->parent_function->return_type != expr->get_datatype() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) { _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); return ERR_PARSE_ERROR; } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index af66e32e06..4120e04ee1 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -447,7 +447,7 @@ public: virtual DataType get_datatype() const override { return datatype_cache; } virtual String get_datatype_name() const override { return String(struct_name); } - virtual int get_array_size() const override { return array_size; } + virtual int get_array_size() const override { return (index_expression || call_expression) ? 0 : array_size; } virtual bool is_indexed() const override { return index_expression != nullptr; } ArrayNode() : diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index a1e892498b..376d23ccb3 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -92,6 +92,10 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEWPORT_SIZE"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_SPATIAL].functions["vertex"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VERTEX"] = constt(ShaderLanguage::TYPE_VEC3); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["FRAGCOORD"] = constt(ShaderLanguage::TYPE_VEC4); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["FRONT_FACING"] = constt(ShaderLanguage::TYPE_BOOL); @@ -118,7 +122,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_STRENGTH"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_COLOR"] = ShaderLanguage::TYPE_VEC4; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_DEPTH"] = ShaderLanguage::TYPE_FLOAT; - shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_CURVE"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SSS_TRANSMITTANCE_BOOST"] = ShaderLanguage::TYPE_FLOAT; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["BACKLIGHT"] = ShaderLanguage::TYPE_VEC3; shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT; @@ -131,6 +134,10 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_INDEX"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_MONO_LEFT"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["VIEW_RIGHT"] = constt(ShaderLanguage::TYPE_INT); + shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["OUTPUT_IS_SRGB"] = constt(ShaderLanguage::TYPE_BOOL); shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["WORLD_MATRIX"] = constt(ShaderLanguage::TYPE_MAT4); @@ -204,7 +211,6 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_lambert_wrap"); - shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_oren_nayar"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_burley"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("diffuse_toon"); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 4741e90a81..748b372c62 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -31,7 +31,7 @@ #include "rendering_server.h" #include "core/config/project_settings.h" - +#include "servers/rendering/rendering_server_globals.h" RenderingServer *RenderingServer::singleton = nullptr; RenderingServer *(*RenderingServer::create_func)() = nullptr; @@ -67,12 +67,6 @@ Array RenderingServer::_texture_debug_usage_bind() { return arr; } -Array RenderingServer::_shader_get_param_list_bind(RID p_shader) const { - List<PropertyInfo> l; - shader_get_param_list(p_shader, &l); - return convert_property_list(&l); -} - static Array to_array(const Vector<ObjectID> &ids) { Array a; a.resize(ids.size()); @@ -83,16 +77,25 @@ static Array to_array(const Vector<ObjectID> &ids) { } Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const { + if (RSG::threaded) { + WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); + } Vector<ObjectID> ids = instances_cull_aabb(p_aabb, p_scenario); return to_array(ids); } Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { + if (RSG::threaded) { + WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); + } Vector<ObjectID> ids = instances_cull_ray(p_from, p_to, p_scenario); return to_array(ids); } Array RenderingServer::_instances_cull_convex_bind(const Array &p_convex, RID p_scenario) const { + if (RSG::threaded) { + WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); + } Vector<Plane> planes; for (int i = 0; i < p_convex.size(); ++i) { Variant v = p_convex[i]; @@ -422,7 +425,9 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint value |= CLAMP(int((src[i * 4 + 0] * 0.5 + 0.5) * 1023.0), 0, 1023); value |= CLAMP(int((src[i * 4 + 1] * 0.5 + 0.5) * 1023.0), 0, 1023) << 10; value |= CLAMP(int((src[i * 4 + 2] * 0.5 + 0.5) * 1023.0), 0, 1023) << 20; - value |= CLAMP(int((src[i * 4 + 3] * 0.5 + 0.5) * 1023.0), 0, 1023) << 30; + if (src[i * 4 + 3] > 0) { + value |= 3 << 30; + } memcpy(&vw[p_offsets[ai] + i * p_vertex_stride], &value, 4); } @@ -436,13 +441,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(array.size() != p_vertex_array_len, ERR_INVALID_PARAMETER); const Color *src = array.ptr(); - uint16_t color16[4]; for (int i = 0; i < p_vertex_array_len; i++) { - color16[0] = Math::make_half_float(src[i].r); - color16[1] = Math::make_half_float(src[i].g); - color16[2] = Math::make_half_float(src[i].b); - color16[3] = Math::make_half_float(src[i].a); - memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], color16, 8); + uint8_t color8[4] = { + uint8_t(CLAMP(src[i].r * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(src[i].g * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(src[i].b * 255.0, 0.0, 255.0)), + uint8_t(CLAMP(src[i].a * 255.0, 0.0, 255.0)) + }; + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], color8, 4); } } break; case RS::ARRAY_TEX_UV: { @@ -759,7 +765,7 @@ void RenderingServer::mesh_surface_make_offsets_from_format(uint32_t p_format, i elem_size = 4; } break; case RS::ARRAY_COLOR: { - elem_size = 8; + elem_size = 4; } break; case RS::ARRAY_TEX_UV: { elem_size = 8; @@ -1121,8 +1127,9 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t Color *w = arr.ptrw(); for (int32_t j = 0; j < p_vertex_len; j++) { - const uint16_t *v = (const uint16_t *)&ar[j * attrib_elem_size + offsets[i]]; - w[j] = Color(Math::half_to_float(v[0]), Math::half_to_float(v[1]), Math::half_to_float(v[2]), Math::half_to_float(v[3])); + const uint8_t *v = (const uint8_t *)&ar[j * attrib_elem_size + offsets[i]]; + + w[j] = Color(v[0] / 255.0, v[1] / 255.0, v[2] / 255.0, v[3] / 255.0); } ret[i] = arr; @@ -1439,29 +1446,247 @@ RenderingDevice *RenderingServer::create_local_rendering_device() const { return RenderingDevice::get_singleton()->create_local_device(); } +static Vector<Ref<Image>> _get_imgvec(const TypedArray<Image> &p_layers) { + Vector<Ref<Image>> images; + images.resize(p_layers.size()); + for (int i = 0; i < p_layers.size(); i++) { + images.write[i] = p_layers[i]; + } + return images; +} +RID RenderingServer::_texture_2d_layered_create(const TypedArray<Image> &p_layers, TextureLayeredType p_layered_type) { + return texture_2d_layered_create(_get_imgvec(p_layers), p_layered_type); +} +RID RenderingServer::_texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data) { + return texture_3d_create(p_format, p_width, p_height, p_depth, p_mipmaps, _get_imgvec(p_data)); +} + +void RenderingServer::_texture_3d_update(RID p_texture, const TypedArray<Image> &p_data) { + texture_3d_update(p_texture, _get_imgvec(p_data)); +} + +TypedArray<Image> RenderingServer::_texture_3d_get(RID p_texture) const { + Vector<Ref<Image>> images = texture_3d_get(p_texture); + TypedArray<Image> ret; + ret.resize(images.size()); + for (int i = 0; i < images.size(); i++) { + ret[i] = images[i]; + } + return ret; +} + +TypedArray<Dictionary> RenderingServer::_shader_get_param_list(RID p_shader) const { + List<PropertyInfo> l; + shader_get_param_list(p_shader, &l); + return convert_property_list(&l); +} + +static RS::SurfaceData _dict_to_surf(const Dictionary &p_dictionary) { + ERR_FAIL_COND_V(!p_dictionary.has("primitive"), RS::SurfaceData()); + ERR_FAIL_COND_V(!p_dictionary.has("format"), RS::SurfaceData()); + ERR_FAIL_COND_V(!p_dictionary.has("vertex_data"), RS::SurfaceData()); + ERR_FAIL_COND_V(!p_dictionary.has("vertex_count"), RS::SurfaceData()); + ERR_FAIL_COND_V(!p_dictionary.has("aabb"), RS::SurfaceData()); + + RS::SurfaceData sd; + + sd.primitive = RS::PrimitiveType(int(p_dictionary["primitive"])); + sd.format = p_dictionary["format"]; + sd.vertex_data = p_dictionary["vertex_data"]; + if (p_dictionary.has("attribute_data")) { + sd.attribute_data = p_dictionary["attribute_data"]; + } + if (p_dictionary.has("skin_data")) { + sd.skin_data = p_dictionary["skin_data"]; + } + + sd.vertex_count = p_dictionary["vertex_count"]; + + if (p_dictionary.has("index_data")) { + sd.index_data = p_dictionary["index_data"]; + ERR_FAIL_COND_V(!p_dictionary.has("index_count"), RS::SurfaceData()); + sd.index_count = p_dictionary["index_count"]; + } + + sd.aabb = p_dictionary["aabb"]; + + if (p_dictionary.has("lods")) { + Array lods = p_dictionary["lods"]; + for (int i = 0; i < lods.size(); i++) { + Dictionary lod = lods[i]; + ERR_CONTINUE(!lod.has("edge_length")); + ERR_CONTINUE(!lod.has("index_data")); + RS::SurfaceData::LOD l; + l.edge_length = lod["edge_length"]; + l.index_data = lod["index_data"]; + sd.lods.push_back(l); + } + } + + if (p_dictionary.has("bone_aabbs")) { + Array aabbs = p_dictionary["bone_aabbs"]; + for (int i = 0; i < aabbs.size(); i++) { + AABB aabb = aabbs[i]; + sd.bone_aabbs.push_back(aabb); + } + } + + if (p_dictionary.has("blend_shape_data")) { + sd.blend_shape_data = p_dictionary["blend_shape_data"]; + } + + if (p_dictionary.has("material")) { + sd.material = p_dictionary["material"]; + } + + return sd; +} +RID RenderingServer::_mesh_create_from_surfaces(const TypedArray<Dictionary> &p_surfaces, int p_blend_shape_count) { + Vector<RS::SurfaceData> surfaces; + for (int i = 0; i < p_surfaces.size(); i++) { + surfaces.push_back(_dict_to_surf(p_surfaces[i])); + } + return mesh_create_from_surfaces(surfaces); +} +void RenderingServer::_mesh_add_surface(RID p_mesh, const Dictionary &p_surface) { + mesh_add_surface(p_mesh, _dict_to_surf(p_surface)); +} +Dictionary RenderingServer::_mesh_get_surface(RID p_mesh, int p_idx) { + RS::SurfaceData sd = mesh_get_surface(p_mesh, p_idx); + + Dictionary d; + d["primitive"] = sd.primitive; + d["format"] = sd.format; + d["vertex_data"] = sd.vertex_data; + if (sd.attribute_data.size()) { + d["attribute_data"] = sd.attribute_data; + } + if (sd.skin_data.size()) { + d["skin_data"] = sd.skin_data; + } + d["vertex_count"] = sd.vertex_count; + if (sd.index_count) { + d["index_data"] = sd.index_data; + d["index_count"] = sd.index_count; + } + d["aabb"] = sd.aabb; + + if (sd.lods.size()) { + Array lods; + for (int i = 0; i < sd.lods.size(); i++) { + Dictionary ld; + ld["edge_length"] = sd.lods[i].edge_length; + ld["index_data"] = sd.lods[i].index_data; + lods.push_back(lods); + } + d["lods"] = lods; + } + + if (sd.bone_aabbs.size()) { + Array aabbs; + for (int i = 0; i < sd.bone_aabbs.size(); i++) { + aabbs.push_back(sd.bone_aabbs[i]); + } + d["bone_aabbs"] = aabbs; + } + + if (sd.blend_shape_data.size()) { + d["blend_shape_data"] = sd.blend_shape_data; + } + + if (sd.material.is_valid()) { + d["material"] = sd.material; + } + return d; +} + +Array RenderingServer::_instance_geometry_get_shader_parameter_list(RID p_instance) const { + List<PropertyInfo> params; + instance_geometry_get_shader_parameter_list(p_instance, ¶ms); + return convert_property_list(¶ms); +} + +TypedArray<Image> RenderingServer::_bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size) { + Vector<RID> mat_overrides; + for (int i = 0; i < p_material_overrides.size(); i++) { + mat_overrides.push_back(p_material_overrides[i]); + } + return bake_render_uv2(p_base, mat_overrides, p_image_size); +} + +void RenderingServer::_particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses) { + Vector<Transform3D> tbposes; + tbposes.resize(p_bind_poses.size()); + for (int i = 0; i < p_bind_poses.size(); i++) { + tbposes.write[i] = p_bind_poses[i]; + } + particles_set_trail_bind_poses(p_particles, tbposes); +} + void RenderingServer::_bind_methods() { - ClassDB::bind_method(D_METHOD("force_sync"), &RenderingServer::sync); - ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &RenderingServer::draw, DEFVAL(true), DEFVAL(0.0)); - ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device); + BIND_CONSTANT(NO_INDEX_ARRAY); + BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); + BIND_CONSTANT(CANVAS_ITEM_Z_MIN); + BIND_CONSTANT(CANVAS_ITEM_Z_MAX); + BIND_CONSTANT(MAX_GLOW_LEVELS); + BIND_CONSTANT(MAX_CURSORS); + BIND_CONSTANT(MAX_2D_DIRECTIONAL_LIGHTS); -#ifndef _MSC_VER -#warning TODO all texture methods need re-binding -#endif + /* TEXTURE */ ClassDB::bind_method(D_METHOD("texture_2d_create", "image"), &RenderingServer::texture_2d_create); + ClassDB::bind_method(D_METHOD("texture_2d_layered_create", "layers", "layered_type"), &RenderingServer::_texture_2d_layered_create); + ClassDB::bind_method(D_METHOD("texture_3d_create", "format", "width", "height", "depth", "mipmaps", "data"), &RenderingServer::_texture_3d_create); + ClassDB::bind_method(D_METHOD("texture_proxy_create", "base"), &RenderingServer::texture_proxy_create); + + ClassDB::bind_method(D_METHOD("texture_2d_update", "texture", "image", "layer"), &RenderingServer::texture_2d_update); + ClassDB::bind_method(D_METHOD("texture_3d_update", "texture", "data"), &RenderingServer::_texture_3d_update); + ClassDB::bind_method(D_METHOD("texture_proxy_update", "texture", "proxy_to"), &RenderingServer::texture_proxy_update); + + ClassDB::bind_method(D_METHOD("texture_2d_placeholder_create"), &RenderingServer::texture_2d_placeholder_create); + ClassDB::bind_method(D_METHOD("texture_2d_layered_placeholder_create", "layered_type"), &RenderingServer::texture_2d_layered_placeholder_create); + ClassDB::bind_method(D_METHOD("texture_3d_placeholder_create"), &RenderingServer::texture_3d_placeholder_create); + ClassDB::bind_method(D_METHOD("texture_2d_get", "texture"), &RenderingServer::texture_2d_get); + ClassDB::bind_method(D_METHOD("texture_2d_layer_get", "texture", "layer"), &RenderingServer::texture_2d_layer_get); + ClassDB::bind_method(D_METHOD("texture_3d_get", "texture"), &RenderingServer::_texture_3d_get); + + ClassDB::bind_method(D_METHOD("texture_replace", "texture", "by_texture"), &RenderingServer::texture_replace); + ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height"), &RenderingServer::texture_set_size_override); + + ClassDB::bind_method(D_METHOD("texture_set_path", "texture", "path"), &RenderingServer::texture_set_path); + ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &RenderingServer::texture_get_path); + + ClassDB::bind_method(D_METHOD("texture_set_force_redraw_if_visible", "texture", "enable"), &RenderingServer::texture_set_force_redraw_if_visible); + + BIND_ENUM_CONSTANT(TEXTURE_LAYERED_2D_ARRAY); + BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP); + BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP_ARRAY); + + BIND_ENUM_CONSTANT(CUBEMAP_LAYER_LEFT); + BIND_ENUM_CONSTANT(CUBEMAP_LAYER_RIGHT); + BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BOTTOM); + BIND_ENUM_CONSTANT(CUBEMAP_LAYER_TOP); + BIND_ENUM_CONSTANT(CUBEMAP_LAYER_FRONT); + BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BACK); + + /* SHADER */ -#ifndef _3D_DISABLED - ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create); - ClassDB::bind_method(D_METHOD("sky_set_material", "sky", "material"), &RenderingServer::sky_set_material); -#endif ClassDB::bind_method(D_METHOD("shader_create"), &RenderingServer::shader_create); - ClassDB::bind_method(D_METHOD("shader_set_code", "shader", "code"), &RenderingServer::shader_set_code); ClassDB::bind_method(D_METHOD("shader_get_code", "shader"), &RenderingServer::shader_get_code); - ClassDB::bind_method(D_METHOD("shader_get_param_list", "shader"), &RenderingServer::_shader_get_param_list_bind); - ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "name", "texture"), &RenderingServer::shader_set_default_texture_param); - ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "name"), &RenderingServer::shader_get_default_texture_param); - ClassDB::bind_method(D_METHOD("shader_get_param_default", "material", "parameter"), &RenderingServer::shader_get_param_default); + ClassDB::bind_method(D_METHOD("shader_get_param_list", "shader"), &RenderingServer::_shader_get_param_list); + ClassDB::bind_method(D_METHOD("shader_get_param_default", "shader", "param"), &RenderingServer::shader_get_param_default); + + ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "param", "texture"), &RenderingServer::shader_set_default_texture_param); + ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "param"), &RenderingServer::shader_get_default_texture_param); + + BIND_ENUM_CONSTANT(SHADER_SPATIAL); + BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM); + BIND_ENUM_CONSTANT(SHADER_PARTICLES); + BIND_ENUM_CONSTANT(SHADER_SKY); + BIND_ENUM_CONSTANT(SHADER_MAX); + + /* MATERIAL */ ClassDB::bind_method(D_METHOD("material_create"), &RenderingServer::material_create); ClassDB::bind_method(D_METHOD("material_set_shader", "shader_material", "shader"), &RenderingServer::material_set_shader); @@ -1471,18 +1696,26 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &RenderingServer::material_set_next_pass); + BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MIN); + BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MAX); + + /* MESH API */ + + ClassDB::bind_method(D_METHOD("mesh_create_from_surfaces", "surfaces", "blend_shape_count"), &RenderingServer::_mesh_create_from_surfaces, DEFVAL(0)); ClassDB::bind_method(D_METHOD("mesh_create"), &RenderingServer::mesh_create); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_count", "array_index"), &RenderingServer::mesh_surface_get_format_offset); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_vertex_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_vertex_stride); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_attribute_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_attribute_stride); ClassDB::bind_method(D_METHOD("mesh_surface_get_format_skin_stride", "format", "vertex_count"), &RenderingServer::mesh_surface_get_format_skin_stride); - //ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); + ClassDB::bind_method(D_METHOD("mesh_add_surface", "mesh", "surface"), &RenderingServer::_mesh_add_surface); + ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primitive", "arrays", "blend_shapes", "lods", "compress_format"), &RenderingServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0)); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &RenderingServer::mesh_get_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &RenderingServer::mesh_set_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &RenderingServer::mesh_get_blend_shape_mode); - ClassDB::bind_method(D_METHOD("mesh_surface_update_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_region); + ClassDB::bind_method(D_METHOD("mesh_surface_set_material", "mesh", "surface", "material"), &RenderingServer::mesh_surface_set_material); ClassDB::bind_method(D_METHOD("mesh_surface_get_material", "mesh", "surface"), &RenderingServer::mesh_surface_get_material); + ClassDB::bind_method(D_METHOD("mesh_get_surface", "mesh", "surface"), &RenderingServer::_mesh_get_surface); ClassDB::bind_method(D_METHOD("mesh_surface_get_arrays", "mesh", "surface"), &RenderingServer::mesh_surface_get_arrays); ClassDB::bind_method(D_METHOD("mesh_surface_get_blend_shape_arrays", "mesh", "surface"), &RenderingServer::mesh_surface_get_blend_shape_arrays); ClassDB::bind_method(D_METHOD("mesh_get_surface_count", "mesh"), &RenderingServer::mesh_get_surface_count); @@ -1490,6 +1723,81 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("mesh_get_custom_aabb", "mesh"), &RenderingServer::mesh_get_custom_aabb); ClassDB::bind_method(D_METHOD("mesh_clear", "mesh"), &RenderingServer::mesh_clear); + ClassDB::bind_method(D_METHOD("mesh_surface_update_vertex_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_vertex_region); + ClassDB::bind_method(D_METHOD("mesh_surface_update_attribute_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_attribute_region); + ClassDB::bind_method(D_METHOD("mesh_surface_update_skin_region", "mesh", "surface", "offset", "data"), &RenderingServer::mesh_surface_update_skin_region); + + ClassDB::bind_method(D_METHOD("mesh_set_shadow_mesh", "mesh", "shadow_mesh"), &RenderingServer::mesh_set_shadow_mesh); + + BIND_ENUM_CONSTANT(ARRAY_VERTEX); + BIND_ENUM_CONSTANT(ARRAY_NORMAL); + BIND_ENUM_CONSTANT(ARRAY_TANGENT); + BIND_ENUM_CONSTANT(ARRAY_COLOR); + BIND_ENUM_CONSTANT(ARRAY_TEX_UV); + BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM3); + BIND_ENUM_CONSTANT(ARRAY_BONES); + BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); + BIND_ENUM_CONSTANT(ARRAY_INDEX); + BIND_ENUM_CONSTANT(ARRAY_MAX); + + BIND_CONSTANT(ARRAY_CUSTOM_COUNT); + + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_UNORM); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA8_SNORM); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_HALF); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_HALF); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_R_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RG_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGB_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_RGBA_FLOAT); + BIND_ENUM_CONSTANT(ARRAY_CUSTOM_MAX); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BITS); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT); + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT); + + BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK); + BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE); + + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE); + BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS); + + BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); + BIND_ENUM_CONSTANT(PRIMITIVE_LINES); + BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); + BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); + BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); + BIND_ENUM_CONSTANT(PRIMITIVE_MAX); + + BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); + BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); + + /* MULTIMESH API */ + ClassDB::bind_method(D_METHOD("multimesh_create"), &RenderingServer::multimesh_create); ClassDB::bind_method(D_METHOD("multimesh_allocate_data", "multimesh", "instances", "transform_format", "color_format", "custom_data_format"), &RenderingServer::multimesh_allocate_data, DEFVAL(false), DEFVAL(false)); ClassDB::bind_method(D_METHOD("multimesh_get_instance_count", "multimesh"), &RenderingServer::multimesh_get_instance_count); @@ -1508,21 +1816,11 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("multimesh_get_visible_instances", "multimesh"), &RenderingServer::multimesh_get_visible_instances); ClassDB::bind_method(D_METHOD("multimesh_set_buffer", "multimesh", "buffer"), &RenderingServer::multimesh_set_buffer); ClassDB::bind_method(D_METHOD("multimesh_get_buffer", "multimesh"), &RenderingServer::multimesh_get_buffer); -#ifndef _3D_DISABLED - ClassDB::bind_method(D_METHOD("immediate_create"), &RenderingServer::immediate_create); - ClassDB::bind_method(D_METHOD("immediate_begin", "immediate", "primitive", "texture"), &RenderingServer::immediate_begin, DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("immediate_vertex", "immediate", "vertex"), &RenderingServer::immediate_vertex); - ClassDB::bind_method(D_METHOD("immediate_vertex_2d", "immediate", "vertex"), &RenderingServer::immediate_vertex_2d); - ClassDB::bind_method(D_METHOD("immediate_normal", "immediate", "normal"), &RenderingServer::immediate_normal); - ClassDB::bind_method(D_METHOD("immediate_tangent", "immediate", "tangent"), &RenderingServer::immediate_tangent); - ClassDB::bind_method(D_METHOD("immediate_color", "immediate", "color"), &RenderingServer::immediate_color); - ClassDB::bind_method(D_METHOD("immediate_uv", "immediate", "tex_uv"), &RenderingServer::immediate_uv); - ClassDB::bind_method(D_METHOD("immediate_uv2", "immediate", "tex_uv"), &RenderingServer::immediate_uv2); - ClassDB::bind_method(D_METHOD("immediate_end", "immediate"), &RenderingServer::immediate_end); - ClassDB::bind_method(D_METHOD("immediate_clear", "immediate"), &RenderingServer::immediate_clear); - ClassDB::bind_method(D_METHOD("immediate_set_material", "immediate", "material"), &RenderingServer::immediate_set_material); - ClassDB::bind_method(D_METHOD("immediate_get_material", "immediate"), &RenderingServer::immediate_get_material); -#endif + + BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_2D); + BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_3D); + + /* SKELETON API */ ClassDB::bind_method(D_METHOD("skeleton_create"), &RenderingServer::skeleton_create); ClassDB::bind_method(D_METHOD("skeleton_allocate_data", "skeleton", "bones", "is_2d_skeleton"), &RenderingServer::skeleton_allocate_data, DEFVAL(false)); @@ -1531,8 +1829,10 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform", "skeleton", "bone"), &RenderingServer::skeleton_bone_get_transform); ClassDB::bind_method(D_METHOD("skeleton_bone_set_transform_2d", "skeleton", "bone", "transform"), &RenderingServer::skeleton_bone_set_transform_2d); ClassDB::bind_method(D_METHOD("skeleton_bone_get_transform_2d", "skeleton", "bone"), &RenderingServer::skeleton_bone_get_transform_2d); + ClassDB::bind_method(D_METHOD("skeleton_set_base_transform_2d", "skeleton", "base_transform"), &RenderingServer::skeleton_set_base_transform_2d); + + /* Light API */ -#ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("directional_light_create"), &RenderingServer::directional_light_create); ClassDB::bind_method(D_METHOD("omni_light_create"), &RenderingServer::omni_light_create); ClassDB::bind_method(D_METHOD("spot_light_create"), &RenderingServer::spot_light_create); @@ -1546,13 +1846,62 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &RenderingServer::light_set_cull_mask); ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &RenderingServer::light_set_reverse_cull_face_mode); ClassDB::bind_method(D_METHOD("light_set_bake_mode", "light", "bake_mode"), &RenderingServer::light_set_bake_mode); + ClassDB::bind_method(D_METHOD("light_set_max_sdfgi_cascade", "light", "cascade"), &RenderingServer::light_set_max_sdfgi_cascade); ClassDB::bind_method(D_METHOD("light_omni_set_shadow_mode", "light", "mode"), &RenderingServer::light_omni_set_shadow_mode); ClassDB::bind_method(D_METHOD("light_directional_set_shadow_mode", "light", "mode"), &RenderingServer::light_directional_set_shadow_mode); ClassDB::bind_method(D_METHOD("light_directional_set_blend_splits", "light", "enable"), &RenderingServer::light_directional_set_blend_splits); ClassDB::bind_method(D_METHOD("light_directional_set_sky_only", "light", "enable"), &RenderingServer::light_directional_set_sky_only); - ClassDB::bind_method(D_METHOD("light_directional_set_shadow_depth_range_mode", "light", "range_mode"), &RenderingServer::light_directional_set_shadow_depth_range_mode); + + BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL); + BIND_ENUM_CONSTANT(LIGHT_OMNI); + BIND_ENUM_CONSTANT(LIGHT_SPOT); + + BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY); + BIND_ENUM_CONSTANT(LIGHT_PARAM_INDIRECT_ENERGY); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SPECULAR); + BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SIZE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ANGLE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ATTENUATION); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_MAX_DISTANCE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_FADE_START); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_PANCAKE_SIZE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BLUR); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_TRANSMITTANCE_BIAS); + BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX); + + BIND_ENUM_CONSTANT(LIGHT_BAKE_DISABLED); + BIND_ENUM_CONSTANT(LIGHT_BAKE_DYNAMIC); + BIND_ENUM_CONSTANT(LIGHT_BAKE_STATIC); + + BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID); + BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE); + + BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); + BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS); + BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS); + + ClassDB::bind_method(D_METHOD("shadows_quality_set", "quality"), &RenderingServer::shadows_quality_set); + ClassDB::bind_method(D_METHOD("directional_shadow_quality_set", "quality"), &RenderingServer::directional_shadow_quality_set); + ClassDB::bind_method(D_METHOD("directional_shadow_atlas_set_size", "size", "is_16bits"), &RenderingServer::directional_shadow_atlas_set_size); + + BIND_ENUM_CONSTANT(SHADOW_QUALITY_HARD); + BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_LOW); + BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_MEDIUM); + BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_HIGH); + BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_ULTRA); + BIND_ENUM_CONSTANT(SHADOW_QUALITY_MAX); + + /* REFLECTION PROBE */ ClassDB::bind_method(D_METHOD("reflection_probe_create"), &RenderingServer::reflection_probe_create); ClassDB::bind_method(D_METHOD("reflection_probe_set_update_mode", "probe", "mode"), &RenderingServer::reflection_probe_set_update_mode); @@ -1567,54 +1916,77 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_box_projection", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_box_projection); ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_shadows); ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_cull_mask); + ClassDB::bind_method(D_METHOD("reflection_probe_set_resolution", "probe", "resolution"), &RenderingServer::reflection_probe_set_resolution); + ClassDB::bind_method(D_METHOD("reflection_probe_set_lod_threshold", "probe", "pixels"), &RenderingServer::reflection_probe_set_lod_threshold); -#ifndef _MSC_VER -#warning TODO all giprobe methods need re-binding -#endif -#if 0 - ClassDB::bind_method(D_METHOD("gi_probe_create"), &RenderingServer::gi_probe_create); - ClassDB::bind_method(D_METHOD("gi_probe_set_bounds", "probe", "bounds"), &RenderingServer::gi_probe_set_bounds); - ClassDB::bind_method(D_METHOD("gi_probe_get_bounds", "probe"), &RenderingServer::gi_probe_get_bounds); - ClassDB::bind_method(D_METHOD("gi_probe_set_cell_size", "probe", "range"), &RenderingServer::gi_probe_set_cell_size); - ClassDB::bind_method(D_METHOD("gi_probe_get_cell_size", "probe"), &RenderingServer::gi_probe_get_cell_size); - ClassDB::bind_method(D_METHOD("gi_probe_set_to_cell_xform", "probe", "xform"), &RenderingServer::gi_probe_set_to_cell_xform); - ClassDB::bind_method(D_METHOD("gi_probe_get_to_cell_xform", "probe"), &RenderingServer::gi_probe_get_to_cell_xform); - ClassDB::bind_method(D_METHOD("gi_probe_set_dynamic_data", "probe", "data"), &RenderingServer::gi_probe_set_dynamic_data); - ClassDB::bind_method(D_METHOD("gi_probe_get_dynamic_data", "probe"), &RenderingServer::gi_probe_get_dynamic_data); - ClassDB::bind_method(D_METHOD("gi_probe_set_dynamic_range", "probe", "range"), &RenderingServer::gi_probe_set_dynamic_range); - ClassDB::bind_method(D_METHOD("gi_probe_get_dynamic_range", "probe"), &RenderingServer::gi_probe_get_dynamic_range); - ClassDB::bind_method(D_METHOD("gi_probe_set_energy", "probe", "energy"), &RenderingServer::gi_probe_set_energy); - ClassDB::bind_method(D_METHOD("gi_probe_get_energy", "probe"), &RenderingServer::gi_probe_get_energy); - ClassDB::bind_method(D_METHOD("gi_probe_set_bias", "probe", "bias"), &RenderingServer::gi_probe_set_bias); - ClassDB::bind_method(D_METHOD("gi_probe_get_bias", "probe"), &RenderingServer::gi_probe_get_bias); - ClassDB::bind_method(D_METHOD("gi_probe_set_normal_bias", "probe", "bias"), &RenderingServer::gi_probe_set_normal_bias); - ClassDB::bind_method(D_METHOD("gi_probe_get_normal_bias", "probe"), &RenderingServer::gi_probe_get_normal_bias); - ClassDB::bind_method(D_METHOD("gi_probe_set_propagation", "probe", "propagation"), &RenderingServer::gi_probe_set_propagation); - ClassDB::bind_method(D_METHOD("gi_probe_get_propagation", "probe"), &RenderingServer::gi_probe_get_propagation); - ClassDB::bind_method(D_METHOD("gi_probe_set_interior", "probe", "enable"), &RenderingServer::gi_probe_set_interior); - ClassDB::bind_method(D_METHOD("gi_probe_is_interior", "probe"), &RenderingServer::gi_probe_is_interior); - ClassDB::bind_method(D_METHOD("gi_probe_set_compress", "probe", "enable"), &RenderingServer::gi_probe_set_compress); - ClassDB::bind_method(D_METHOD("gi_probe_is_compressed", "probe"), &RenderingServer::gi_probe_is_compressed); -#endif - /* - ClassDB::bind_method(D_METHOD("lightmap_create()"), &RenderingServer::lightmap_capture_create); - ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &RenderingServer::lightmap_capture_set_bounds); - ClassDB::bind_method(D_METHOD("lightmap_capture_get_bounds", "capture"), &RenderingServer::lightmap_capture_get_bounds); - ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree", "capture", "octree"), &RenderingServer::lightmap_capture_set_octree); - ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_transform", "capture", "xform"), &RenderingServer::lightmap_capture_set_octree_cell_transform); - ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_transform", "capture"), &RenderingServer::lightmap_capture_get_octree_cell_transform); - ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_subdiv", "capture", "subdiv"), &RenderingServer::lightmap_capture_set_octree_cell_subdiv); - ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_subdiv", "capture"), &RenderingServer::lightmap_capture_get_octree_cell_subdiv); - ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &RenderingServer::lightmap_capture_get_octree); - ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &RenderingServer::lightmap_capture_set_energy); - ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &RenderingServer::lightmap_capture_get_energy); -*/ + BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE); + BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS); - ClassDB::bind_method(D_METHOD("occluder_create"), &RenderingServer::occluder_create); - ClassDB::bind_method(D_METHOD("occluder_set_mesh"), &RenderingServer::occluder_set_mesh); + BIND_ENUM_CONSTANT(REFLECTION_PROBE_AMBIENT_DISABLED); + BIND_ENUM_CONSTANT(REFLECTION_PROBE_AMBIENT_ENVIRONMENT); + BIND_ENUM_CONSTANT(REFLECTION_PROBE_AMBIENT_COLOR); + + /* DECAL */ + + ClassDB::bind_method(D_METHOD("decal_create"), &RenderingServer::decal_create); + ClassDB::bind_method(D_METHOD("decal_set_extents", "decal", "extents"), &RenderingServer::decal_set_extents); + ClassDB::bind_method(D_METHOD("decal_set_texture", "decal", "type", "texture"), &RenderingServer::decal_set_texture); + ClassDB::bind_method(D_METHOD("decal_set_emission_energy", "decal", "energy"), &RenderingServer::decal_set_emission_energy); + ClassDB::bind_method(D_METHOD("decal_set_albedo_mix", "decal", "albedo_mix"), &RenderingServer::decal_set_albedo_mix); + ClassDB::bind_method(D_METHOD("decal_set_modulate", "decal", "color"), &RenderingServer::decal_set_modulate); + ClassDB::bind_method(D_METHOD("decal_set_cull_mask", "decal", "mask"), &RenderingServer::decal_set_cull_mask); + ClassDB::bind_method(D_METHOD("decal_set_distance_fade", "decal", "enabled", "begin", "length"), &RenderingServer::decal_set_distance_fade); + ClassDB::bind_method(D_METHOD("decal_set_fade", "decal", "above", "below"), &RenderingServer::decal_set_fade); + ClassDB::bind_method(D_METHOD("decal_set_normal_fade", "decal", "fade"), &RenderingServer::decal_set_normal_fade); + + BIND_ENUM_CONSTANT(DECAL_TEXTURE_ALBEDO); + BIND_ENUM_CONSTANT(DECAL_TEXTURE_NORMAL); + BIND_ENUM_CONSTANT(DECAL_TEXTURE_ORM); + BIND_ENUM_CONSTANT(DECAL_TEXTURE_EMISSION); + BIND_ENUM_CONSTANT(DECAL_TEXTURE_MAX); + + /* VOXEL GI API */ + + ClassDB::bind_method(D_METHOD("voxel_gi_create"), &RenderingServer::voxel_gi_create); + ClassDB::bind_method(D_METHOD("voxel_gi_allocate_data", "voxel_gi", "to_cell_xform", "aabb", "octree_size", "octree_cells", "data_cells", "distance_field", "level_counts"), &RenderingServer::voxel_gi_allocate_data); + ClassDB::bind_method(D_METHOD("voxel_gi_get_octree_size", "voxel_gi"), &RenderingServer::voxel_gi_get_octree_size); + ClassDB::bind_method(D_METHOD("voxel_gi_get_octree_cells", "voxel_gi"), &RenderingServer::voxel_gi_get_octree_cells); + ClassDB::bind_method(D_METHOD("voxel_gi_get_data_cells", "voxel_gi"), &RenderingServer::voxel_gi_get_data_cells); + ClassDB::bind_method(D_METHOD("voxel_gi_get_distance_field", "voxel_gi"), &RenderingServer::voxel_gi_get_distance_field); + ClassDB::bind_method(D_METHOD("voxel_gi_get_level_counts", "voxel_gi"), &RenderingServer::voxel_gi_get_level_counts); + ClassDB::bind_method(D_METHOD("voxel_gi_get_to_cell_xform", "voxel_gi"), &RenderingServer::voxel_gi_get_to_cell_xform); + + ClassDB::bind_method(D_METHOD("voxel_gi_set_dynamic_range", "voxel_gi", "range"), &RenderingServer::voxel_gi_set_dynamic_range); + ClassDB::bind_method(D_METHOD("voxel_gi_set_propagation", "voxel_gi", "amount"), &RenderingServer::voxel_gi_set_propagation); + ClassDB::bind_method(D_METHOD("voxel_gi_set_energy", "voxel_gi", "energy"), &RenderingServer::voxel_gi_set_energy); + ClassDB::bind_method(D_METHOD("voxel_gi_set_bias", "voxel_gi", "bias"), &RenderingServer::voxel_gi_set_bias); + ClassDB::bind_method(D_METHOD("voxel_gi_set_normal_bias", "voxel_gi", "bias"), &RenderingServer::voxel_gi_set_normal_bias); + ClassDB::bind_method(D_METHOD("voxel_gi_set_interior", "voxel_gi", "enable"), &RenderingServer::voxel_gi_set_interior); + ClassDB::bind_method(D_METHOD("voxel_gi_set_use_two_bounces", "voxel_gi", "enable"), &RenderingServer::voxel_gi_set_use_two_bounces); + + ClassDB::bind_method(D_METHOD("voxel_gi_set_quality", "quality"), &RenderingServer::voxel_gi_set_quality); + + BIND_ENUM_CONSTANT(VOXEL_GI_QUALITY_LOW); + BIND_ENUM_CONSTANT(VOXEL_GI_QUALITY_HIGH); + + /* LIGHTMAP */ + + ClassDB::bind_method(D_METHOD("lightmap_create"), &RenderingServer::lightmap_create); + ClassDB::bind_method(D_METHOD("lightmap_set_textures", "lightmap", "light", "uses_sh"), &RenderingServer::lightmap_set_textures); + ClassDB::bind_method(D_METHOD("lightmap_set_probe_bounds", "lightmap", "bounds"), &RenderingServer::lightmap_set_probe_bounds); + ClassDB::bind_method(D_METHOD("lightmap_set_probe_interior", "lightmap", "interior"), &RenderingServer::lightmap_set_probe_interior); + ClassDB::bind_method(D_METHOD("lightmap_set_probe_capture_data", "lightmap", "points", "point_sh", "tetrahedra", "bsp_tree"), &RenderingServer::lightmap_set_probe_capture_data); + ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_points", "lightmap"), &RenderingServer::lightmap_get_probe_capture_points); + ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_sh", "lightmap"), &RenderingServer::lightmap_get_probe_capture_sh); + ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_tetrahedra", "lightmap"), &RenderingServer::lightmap_get_probe_capture_tetrahedra); + ClassDB::bind_method(D_METHOD("lightmap_get_probe_capture_bsp_tree", "lightmap"), &RenderingServer::lightmap_get_probe_capture_bsp_tree); + + ClassDB::bind_method(D_METHOD("lightmap_set_probe_capture_update_speed", "speed"), &RenderingServer::lightmap_set_probe_capture_update_speed); + + /* PARTICLES API */ -#endif ClassDB::bind_method(D_METHOD("particles_create"), &RenderingServer::particles_create); + ClassDB::bind_method(D_METHOD("particles_set_mode", "particles", "mode"), &RenderingServer::particles_set_mode); ClassDB::bind_method(D_METHOD("particles_set_emitting", "particles", "emitting"), &RenderingServer::particles_set_emitting); ClassDB::bind_method(D_METHOD("particles_get_emitting", "particles"), &RenderingServer::particles_get_emitting); ClassDB::bind_method(D_METHOD("particles_set_amount", "particles", "amount"), &RenderingServer::particles_set_amount); @@ -1628,16 +2000,89 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("particles_set_use_local_coordinates", "particles", "enable"), &RenderingServer::particles_set_use_local_coordinates); ClassDB::bind_method(D_METHOD("particles_set_process_material", "particles", "material"), &RenderingServer::particles_set_process_material); ClassDB::bind_method(D_METHOD("particles_set_fixed_fps", "particles", "fps"), &RenderingServer::particles_set_fixed_fps); + ClassDB::bind_method(D_METHOD("particles_set_interpolate", "particles", "enable"), &RenderingServer::particles_set_interpolate); ClassDB::bind_method(D_METHOD("particles_set_fractional_delta", "particles", "enable"), &RenderingServer::particles_set_fractional_delta); + ClassDB::bind_method(D_METHOD("particles_set_collision_base_size", "particles", "size"), &RenderingServer::particles_set_collision_base_size); + ClassDB::bind_method(D_METHOD("particles_set_transform_align", "particles", "align"), &RenderingServer::particles_set_transform_align); + ClassDB::bind_method(D_METHOD("particles_set_trails", "particles", "enable", "length_sec"), &RenderingServer::particles_set_trails); + ClassDB::bind_method(D_METHOD("particles_set_trail_bind_poses", "particles", "bind_poses"), &RenderingServer::_particles_set_trail_bind_poses); + ClassDB::bind_method(D_METHOD("particles_is_inactive", "particles"), &RenderingServer::particles_is_inactive); ClassDB::bind_method(D_METHOD("particles_request_process", "particles"), &RenderingServer::particles_request_process); ClassDB::bind_method(D_METHOD("particles_restart", "particles"), &RenderingServer::particles_restart); + + ClassDB::bind_method(D_METHOD("particles_set_subemitter", "particles", "subemitter_particles"), &RenderingServer::particles_set_subemitter); + ClassDB::bind_method(D_METHOD("particles_emit", "particles", "transform", "velocity", "color", "custom", "emit_flags"), &RenderingServer::particles_emit); + ClassDB::bind_method(D_METHOD("particles_set_draw_order", "particles", "order"), &RenderingServer::particles_set_draw_order); ClassDB::bind_method(D_METHOD("particles_set_draw_passes", "particles", "count"), &RenderingServer::particles_set_draw_passes); ClassDB::bind_method(D_METHOD("particles_set_draw_pass_mesh", "particles", "pass", "mesh"), &RenderingServer::particles_set_draw_pass_mesh); ClassDB::bind_method(D_METHOD("particles_get_current_aabb", "particles"), &RenderingServer::particles_get_current_aabb); ClassDB::bind_method(D_METHOD("particles_set_emission_transform", "particles", "transform"), &RenderingServer::particles_set_emission_transform); + BIND_ENUM_CONSTANT(PARTICLES_MODE_2D); + BIND_ENUM_CONSTANT(PARTICLES_MODE_3D); + + BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_DISABLED); + BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD); + BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_Y_TO_VELOCITY); + BIND_ENUM_CONSTANT(PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY); + + BIND_CONSTANT(PARTICLES_EMIT_FLAG_POSITION); + BIND_CONSTANT(PARTICLES_EMIT_FLAG_ROTATION_SCALE); + BIND_CONSTANT(PARTICLES_EMIT_FLAG_VELOCITY); + BIND_CONSTANT(PARTICLES_EMIT_FLAG_COLOR); + BIND_CONSTANT(PARTICLES_EMIT_FLAG_CUSTOM); + + BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_INDEX); + BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_LIFETIME); + BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_REVERSE_LIFETIME); + BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_VIEW_DEPTH); + + /* PARTICLES COLLISION */ + + ClassDB::bind_method(D_METHOD("particles_collision_create"), &RenderingServer::particles_collision_create); + ClassDB::bind_method(D_METHOD("particles_collision_set_collision_type", "particles_collision", "type"), &RenderingServer::particles_collision_set_collision_type); + ClassDB::bind_method(D_METHOD("particles_collision_set_cull_mask", "particles_collision", "mask"), &RenderingServer::particles_collision_set_cull_mask); + ClassDB::bind_method(D_METHOD("particles_collision_set_sphere_radius", "particles_collision", "radius"), &RenderingServer::particles_collision_set_sphere_radius); + ClassDB::bind_method(D_METHOD("particles_collision_set_box_extents", "particles_collision", "extents"), &RenderingServer::particles_collision_set_box_extents); + ClassDB::bind_method(D_METHOD("particles_collision_set_attractor_strength", "particles_collision", "setrngth"), &RenderingServer::particles_collision_set_attractor_strength); + ClassDB::bind_method(D_METHOD("particles_collision_set_attractor_directionality", "particles_collision", "amount"), &RenderingServer::particles_collision_set_attractor_directionality); + ClassDB::bind_method(D_METHOD("particles_collision_set_attractor_attenuation", "particles_collision", "curve"), &RenderingServer::particles_collision_set_attractor_attenuation); + ClassDB::bind_method(D_METHOD("particles_collision_set_field_texture", "particles_collision", "texture"), &RenderingServer::particles_collision_set_field_texture); + + ClassDB::bind_method(D_METHOD("particles_collision_height_field_update", "particles_collision"), &RenderingServer::particles_collision_height_field_update); + ClassDB::bind_method(D_METHOD("particles_collision_set_height_field_resolution", "particles_collision", "resolution"), &RenderingServer::particles_collision_set_height_field_resolution); + + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_BOX_ATTRACT); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_VECTOR_FIELD_ATTRACT); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_SPHERE_COLLIDE); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_BOX_COLLIDE); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_SDF_COLLIDE); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE); + + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_256); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_512); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_1024); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_2048); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_4096); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_8192); + BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX); + + /* VISIBILITY NOTIFIER */ + + ClassDB::bind_method(D_METHOD("visibility_notifier_create"), &RenderingServer::visibility_notifier_create); + ClassDB::bind_method(D_METHOD("visibility_notifier_set_aabb", "notifier", "aabb"), &RenderingServer::visibility_notifier_set_aabb); + ClassDB::bind_method(D_METHOD("visibility_notifier_set_callbacks", "notifier", "enter_callable", "exit_callable"), &RenderingServer::visibility_notifier_set_callbacks); + + /* OCCLUDER */ + + ClassDB::bind_method(D_METHOD("occluder_create"), &RenderingServer::occluder_create); + ClassDB::bind_method(D_METHOD("occluder_set_mesh", "occluder", "vertices", "indices"), &RenderingServer::occluder_set_mesh); + + /* CAMERA */ + ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create); ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &RenderingServer::camera_set_perspective); ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &RenderingServer::camera_set_orthogonal); @@ -1645,8 +2090,11 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &RenderingServer::camera_set_transform); ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &RenderingServer::camera_set_cull_mask); ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &RenderingServer::camera_set_environment); + ClassDB::bind_method(D_METHOD("camera_set_camera_effects", "camera", "effects"), &RenderingServer::camera_set_camera_effects); ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &RenderingServer::camera_set_use_vertical_aspect); + /* VIEWPORT */ + ClassDB::bind_method(D_METHOD("viewport_create"), &RenderingServer::viewport_create); ClassDB::bind_method(D_METHOD("viewport_set_use_xr", "viewport", "use_xr"), &RenderingServer::viewport_set_use_xr); ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &RenderingServer::viewport_set_size); @@ -1658,338 +2106,47 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &RenderingServer::viewport_set_update_mode); ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &RenderingServer::viewport_set_clear_mode); ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture); - ClassDB::bind_method(D_METHOD("viewport_set_hide_scenario", "viewport", "hidden"), &RenderingServer::viewport_set_hide_scenario); - ClassDB::bind_method(D_METHOD("viewport_set_hide_canvas", "viewport", "hidden"), &RenderingServer::viewport_set_hide_canvas); + ClassDB::bind_method(D_METHOD("viewport_set_disable_3d", "viewport", "disable"), &RenderingServer::viewport_set_disable_3d); + ClassDB::bind_method(D_METHOD("viewport_set_disable_2d", "viewport", "disable"), &RenderingServer::viewport_set_disable_2d); ClassDB::bind_method(D_METHOD("viewport_set_disable_environment", "viewport", "disabled"), &RenderingServer::viewport_set_disable_environment); ClassDB::bind_method(D_METHOD("viewport_attach_camera", "viewport", "camera"), &RenderingServer::viewport_attach_camera); ClassDB::bind_method(D_METHOD("viewport_set_scenario", "viewport", "scenario"), &RenderingServer::viewport_set_scenario); ClassDB::bind_method(D_METHOD("viewport_attach_canvas", "viewport", "canvas"), &RenderingServer::viewport_attach_canvas); ClassDB::bind_method(D_METHOD("viewport_remove_canvas", "viewport", "canvas"), &RenderingServer::viewport_remove_canvas); + ClassDB::bind_method(D_METHOD("viewport_set_snap_2d_transforms_to_pixel", "viewport", "enabled"), &RenderingServer::viewport_set_snap_2d_transforms_to_pixel); + ClassDB::bind_method(D_METHOD("viewport_set_snap_2d_vertices_to_pixel", "viewport", "enabled"), &RenderingServer::viewport_set_snap_2d_vertices_to_pixel); + + ClassDB::bind_method(D_METHOD("viewport_set_default_canvas_item_texture_filter", "viewport", "filter"), &RenderingServer::viewport_set_default_canvas_item_texture_filter); + ClassDB::bind_method(D_METHOD("viewport_set_default_canvas_item_texture_repeat", "viewport", "repeat"), &RenderingServer::viewport_set_default_canvas_item_texture_repeat); + ClassDB::bind_method(D_METHOD("viewport_set_canvas_transform", "viewport", "canvas", "offset"), &RenderingServer::viewport_set_canvas_transform); + ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &RenderingServer::viewport_set_canvas_stacking); + ClassDB::bind_method(D_METHOD("viewport_set_transparent_background", "viewport", "enabled"), &RenderingServer::viewport_set_transparent_background); ClassDB::bind_method(D_METHOD("viewport_set_global_canvas_transform", "viewport", "transform"), &RenderingServer::viewport_set_global_canvas_transform); - ClassDB::bind_method(D_METHOD("viewport_set_canvas_stacking", "viewport", "canvas", "layer", "sublayer"), &RenderingServer::viewport_set_canvas_stacking); + + ClassDB::bind_method(D_METHOD("viewport_set_sdf_oversize_and_scale", "viewport", "oversize", "scale"), &RenderingServer::viewport_set_sdf_oversize_and_scale); + ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_size", "viewport", "size", "use_16_bits"), &RenderingServer::viewport_set_shadow_atlas_size, DEFVAL(false)); ClassDB::bind_method(D_METHOD("viewport_set_shadow_atlas_quadrant_subdivision", "viewport", "quadrant", "subdivision"), &RenderingServer::viewport_set_shadow_atlas_quadrant_subdivision); ClassDB::bind_method(D_METHOD("viewport_set_msaa", "viewport", "msaa"), &RenderingServer::viewport_set_msaa); + ClassDB::bind_method(D_METHOD("viewport_set_screen_space_aa", "viewport", "mode"), &RenderingServer::viewport_set_screen_space_aa); ClassDB::bind_method(D_METHOD("viewport_set_use_debanding", "viewport", "enable"), &RenderingServer::viewport_set_use_debanding); ClassDB::bind_method(D_METHOD("viewport_set_use_occlusion_culling", "viewport", "enable"), &RenderingServer::viewport_set_use_occlusion_culling); ClassDB::bind_method(D_METHOD("viewport_set_occlusion_rays_per_thread", "rays_per_thread"), &RenderingServer::viewport_set_occlusion_rays_per_thread); ClassDB::bind_method(D_METHOD("viewport_set_occlusion_culling_build_quality", "quality"), &RenderingServer::viewport_set_occlusion_culling_build_quality); - ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "info"), &RenderingServer::viewport_get_render_info); + ClassDB::bind_method(D_METHOD("viewport_get_render_info", "viewport", "type", "info"), &RenderingServer::viewport_get_render_info); ClassDB::bind_method(D_METHOD("viewport_set_debug_draw", "viewport", "draw"), &RenderingServer::viewport_set_debug_draw); ClassDB::bind_method(D_METHOD("viewport_set_measure_render_time", "viewport", "enable"), &RenderingServer::viewport_set_measure_render_time); ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_cpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_cpu); - ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); - - ClassDB::bind_method(D_METHOD("environment_create"), &RenderingServer::environment_create); - ClassDB::bind_method(D_METHOD("environment_set_background", "env", "bg"), &RenderingServer::environment_set_background); - ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &RenderingServer::environment_set_sky); - ClassDB::bind_method(D_METHOD("environment_set_sky_custom_fov", "env", "scale"), &RenderingServer::environment_set_sky_custom_fov); - ClassDB::bind_method(D_METHOD("environment_set_sky_orientation", "env", "orientation"), &RenderingServer::environment_set_sky_orientation); - ClassDB::bind_method(D_METHOD("environment_set_bg_color", "env", "color"), &RenderingServer::environment_set_bg_color); - ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy); - ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer); - ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color())); - ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); - ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); - ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); - ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); - ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); - ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog); - - ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create); - ClassDB::bind_method(D_METHOD("scenario_set_debug", "scenario", "debug_mode"), &RenderingServer::scenario_set_debug); - ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &RenderingServer::scenario_set_environment); - ClassDB::bind_method(D_METHOD("scenario_set_camera_effects", "scenario", "effects"), &RenderingServer::scenario_set_camera_effects); - ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment); - -#ifndef _3D_DISABLED - - ClassDB::bind_method(D_METHOD("instance_create2", "base", "scenario"), &RenderingServer::instance_create2); - ClassDB::bind_method(D_METHOD("instance_create"), &RenderingServer::instance_create); - ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &RenderingServer::instance_set_base); - ClassDB::bind_method(D_METHOD("instance_set_scenario", "instance", "scenario"), &RenderingServer::instance_set_scenario); - ClassDB::bind_method(D_METHOD("instance_set_layer_mask", "instance", "mask"), &RenderingServer::instance_set_layer_mask); - ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform); - ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id); - ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight); - ClassDB::bind_method(D_METHOD("instance_set_surface_override_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_override_material); - ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible); - // ClassDB::bind_method(D_METHOD("instance_set_use_lightmap", "instance", "lightmap_instance", "lightmap"), &RenderingServer::instance_set_use_lightmap); - ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb); - ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton); - ClassDB::bind_method(D_METHOD("instance_set_exterior", "instance", "enabled"), &RenderingServer::instance_set_exterior); - ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &RenderingServer::instance_set_extra_visibility_margin); - ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag); - ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting); - ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &RenderingServer::instance_geometry_set_material_override); - ClassDB::bind_method(D_METHOD("instance_geometry_set_draw_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_draw_range); - ClassDB::bind_method(D_METHOD("instance_geometry_set_as_instance_lod", "instance", "as_lod_of_instance"), &RenderingServer::instance_geometry_set_as_instance_lod); - - ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &RenderingServer::_instances_cull_aabb_bind, DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &RenderingServer::_instances_cull_ray_bind, DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("instances_cull_convex", "convex", "scenario"), &RenderingServer::_instances_cull_convex_bind, DEFVAL(RID())); -#endif - ClassDB::bind_method(D_METHOD("canvas_create"), &RenderingServer::canvas_create); - ClassDB::bind_method(D_METHOD("canvas_set_item_mirroring", "canvas", "item", "mirroring"), &RenderingServer::canvas_set_item_mirroring); - ClassDB::bind_method(D_METHOD("canvas_set_modulate", "canvas", "color"), &RenderingServer::canvas_set_modulate); -#ifndef _MSC_VER -#warning TODO method bindings need to be fixed -#endif -#if 0 - - ClassDB::bind_method(D_METHOD("canvas_item_create"), &RenderingServer::canvas_item_create); - ClassDB::bind_method(D_METHOD("canvas_item_set_parent", "item", "parent"), &RenderingServer::canvas_item_set_parent); - ClassDB::bind_method(D_METHOD("canvas_item_set_visible", "item", "visible"), &RenderingServer::canvas_item_set_visible); - ClassDB::bind_method(D_METHOD("canvas_item_set_light_mask", "item", "mask"), &RenderingServer::canvas_item_set_light_mask); - ClassDB::bind_method(D_METHOD("canvas_item_set_transform", "item", "transform"), &RenderingServer::canvas_item_set_transform); - ClassDB::bind_method(D_METHOD("canvas_item_set_clip", "item", "clip"), &RenderingServer::canvas_item_set_clip); - ClassDB::bind_method(D_METHOD("canvas_item_set_distance_field_mode", "item", "enabled"), &RenderingServer::canvas_item_set_distance_field_mode); - ClassDB::bind_method(D_METHOD("canvas_item_set_custom_rect", "item", "use_custom_rect", "rect"), &RenderingServer::canvas_item_set_custom_rect, DEFVAL(Rect2())); - ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &RenderingServer::canvas_item_set_modulate); - ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &RenderingServer::canvas_item_set_self_modulate); - ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &RenderingServer::canvas_item_set_draw_behind_parent); - ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); - ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); - ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose", "normal_map"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(RID()), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate", "normal_map"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)), DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width", "normal_map"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0), DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture", "normal_map", "antialiased"), &RenderingServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID()), DEFVAL(RID()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count", "normal_map", "antialiased"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1), DEFVAL(RID()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture", "normal_map"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()), DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture", "normal_map"), &RenderingServer::canvas_item_add_multimesh, DEFVAL(RID())); - ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture", "normal_map"), &RenderingServer::canvas_item_add_particles); - ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &RenderingServer::canvas_item_add_set_transform); - ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &RenderingServer::canvas_item_add_clip_ignore); - ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &RenderingServer::canvas_item_set_sort_children_by_y); -#endif - ClassDB::bind_method(D_METHOD("canvas_item_set_z_index", "item", "z_index"), &RenderingServer::canvas_item_set_z_index); - ClassDB::bind_method(D_METHOD("canvas_item_set_z_as_relative_to_parent", "item", "enabled"), &RenderingServer::canvas_item_set_z_as_relative_to_parent); - ClassDB::bind_method(D_METHOD("canvas_item_set_copy_to_backbuffer", "item", "enabled", "rect"), &RenderingServer::canvas_item_set_copy_to_backbuffer); - ClassDB::bind_method(D_METHOD("canvas_item_clear", "item"), &RenderingServer::canvas_item_clear); - ClassDB::bind_method(D_METHOD("canvas_item_set_draw_index", "item", "index"), &RenderingServer::canvas_item_set_draw_index); - ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &RenderingServer::canvas_item_set_material); - ClassDB::bind_method(D_METHOD("canvas_item_set_use_parent_material", "item", "enabled"), &RenderingServer::canvas_item_set_use_parent_material); - ClassDB::bind_method(D_METHOD("canvas_light_create"), &RenderingServer::canvas_light_create); - ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &RenderingServer::canvas_light_attach_to_canvas); - ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_enabled); - ClassDB::bind_method(D_METHOD("canvas_light_set_texture_scale", "light", "scale"), &RenderingServer::canvas_light_set_texture_scale); - ClassDB::bind_method(D_METHOD("canvas_light_set_transform", "light", "transform"), &RenderingServer::canvas_light_set_transform); - ClassDB::bind_method(D_METHOD("canvas_light_set_texture", "light", "texture"), &RenderingServer::canvas_light_set_texture); - ClassDB::bind_method(D_METHOD("canvas_light_set_texture_offset", "light", "offset"), &RenderingServer::canvas_light_set_texture_offset); - ClassDB::bind_method(D_METHOD("canvas_light_set_color", "light", "color"), &RenderingServer::canvas_light_set_color); - ClassDB::bind_method(D_METHOD("canvas_light_set_height", "light", "height"), &RenderingServer::canvas_light_set_height); - ClassDB::bind_method(D_METHOD("canvas_light_set_energy", "light", "energy"), &RenderingServer::canvas_light_set_energy); - ClassDB::bind_method(D_METHOD("canvas_light_set_z_range", "light", "min_z", "max_z"), &RenderingServer::canvas_light_set_z_range); - ClassDB::bind_method(D_METHOD("canvas_light_set_layer_range", "light", "min_layer", "max_layer"), &RenderingServer::canvas_light_set_layer_range); - ClassDB::bind_method(D_METHOD("canvas_light_set_item_cull_mask", "light", "mask"), &RenderingServer::canvas_light_set_item_cull_mask); - ClassDB::bind_method(D_METHOD("canvas_light_set_item_shadow_cull_mask", "light", "mask"), &RenderingServer::canvas_light_set_item_shadow_cull_mask); - ClassDB::bind_method(D_METHOD("canvas_light_set_mode", "light", "mode"), &RenderingServer::canvas_light_set_mode); - ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_shadow_enabled); - ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_filter", "light", "filter"), &RenderingServer::canvas_light_set_shadow_filter); - ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color); - ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth); - - ClassDB::bind_method(D_METHOD("canvas_light_occluder_create"), &RenderingServer::canvas_light_occluder_create); - ClassDB::bind_method(D_METHOD("canvas_light_occluder_attach_to_canvas", "occluder", "canvas"), &RenderingServer::canvas_light_occluder_attach_to_canvas); - ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_enabled", "occluder", "enabled"), &RenderingServer::canvas_light_occluder_set_enabled); - ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_polygon", "occluder", "polygon"), &RenderingServer::canvas_light_occluder_set_polygon); - ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform); - ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask); - - ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &RenderingServer::canvas_occluder_polygon_create); - ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &RenderingServer::canvas_occluder_polygon_set_shape); - ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_cull_mode", "occluder_polygon", "mode"), &RenderingServer::canvas_occluder_polygon_set_cull_mode); - - ClassDB::bind_method(D_METHOD("global_variable_add", "name", "type", "default_value"), &RenderingServer::global_variable_add); - ClassDB::bind_method(D_METHOD("global_variable_remove", "name"), &RenderingServer::global_variable_remove); - ClassDB::bind_method(D_METHOD("global_variable_get_list"), &RenderingServer::global_variable_get_list); - ClassDB::bind_method(D_METHOD("global_variable_set", "name", "value"), &RenderingServer::global_variable_set); - ClassDB::bind_method(D_METHOD("global_variable_get", "name"), &RenderingServer::global_variable_get); - ClassDB::bind_method(D_METHOD("global_variable_get_type", "name"), &RenderingServer::global_variable_get_type); - - ClassDB::bind_method(D_METHOD("black_bars_set_margins", "left", "top", "right", "bottom"), &RenderingServer::black_bars_set_margins); - ClassDB::bind_method(D_METHOD("black_bars_set_images", "left", "top", "right", "bottom"), &RenderingServer::black_bars_set_images); - - ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingServer::free); // shouldn't conflict with Object::free() - - ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &RenderingServer::request_frame_drawn_callback); - ClassDB::bind_method(D_METHOD("has_changed"), &RenderingServer::has_changed); - ClassDB::bind_method(D_METHOD("init"), &RenderingServer::init); - ClassDB::bind_method(D_METHOD("finish"), &RenderingServer::finish); - ClassDB::bind_method(D_METHOD("get_render_info", "info"), &RenderingServer::get_render_info); - ClassDB::bind_method(D_METHOD("get_video_adapter_name"), &RenderingServer::get_video_adapter_name); - ClassDB::bind_method(D_METHOD("get_video_adapter_vendor"), &RenderingServer::get_video_adapter_vendor); -#ifndef _3D_DISABLED - - ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &RenderingServer::make_sphere_mesh); - ClassDB::bind_method(D_METHOD("get_test_cube"), &RenderingServer::get_test_cube); -#endif - ClassDB::bind_method(D_METHOD("get_test_texture"), &RenderingServer::get_test_texture); - ClassDB::bind_method(D_METHOD("get_white_texture"), &RenderingServer::get_white_texture); - - ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "use_filter"), &RenderingServer::set_boot_image, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color); - - ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); - ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &RenderingServer::has_os_feature); - ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &RenderingServer::set_debug_generate_wireframes); - - ClassDB::bind_method(D_METHOD("is_render_loop_enabled"), &RenderingServer::is_render_loop_enabled); - ClassDB::bind_method(D_METHOD("set_render_loop_enabled", "enabled"), &RenderingServer::set_render_loop_enabled); - ClassDB::bind_method(D_METHOD("get_frame_setup_time_cpu"), &RenderingServer::get_frame_setup_time_cpu); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_loop_enabled"), "set_render_loop_enabled", "is_render_loop_enabled"); - - BIND_CONSTANT(NO_INDEX_ARRAY); - BIND_CONSTANT(ARRAY_WEIGHTS_SIZE); - BIND_CONSTANT(CANVAS_ITEM_Z_MIN); - BIND_CONSTANT(CANVAS_ITEM_Z_MAX); - BIND_CONSTANT(MAX_GLOW_LEVELS); - BIND_CONSTANT(MAX_CURSORS); - - BIND_ENUM_CONSTANT(TEXTURE_LAYERED_2D_ARRAY); - BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP); - BIND_ENUM_CONSTANT(TEXTURE_LAYERED_CUBEMAP_ARRAY); - - BIND_ENUM_CONSTANT(CUBEMAP_LAYER_LEFT); - BIND_ENUM_CONSTANT(CUBEMAP_LAYER_RIGHT); - BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BOTTOM); - BIND_ENUM_CONSTANT(CUBEMAP_LAYER_TOP); - BIND_ENUM_CONSTANT(CUBEMAP_LAYER_FRONT); - BIND_ENUM_CONSTANT(CUBEMAP_LAYER_BACK); - - BIND_ENUM_CONSTANT(SHADER_SPATIAL); - BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM); - BIND_ENUM_CONSTANT(SHADER_PARTICLES); - BIND_ENUM_CONSTANT(SHADER_SKY); - BIND_ENUM_CONSTANT(SHADER_MAX); - - BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MIN); - BIND_CONSTANT(MATERIAL_RENDER_PRIORITY_MAX); - - BIND_ENUM_CONSTANT(ARRAY_VERTEX); - BIND_ENUM_CONSTANT(ARRAY_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_COLOR); - BIND_ENUM_CONSTANT(ARRAY_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_CUSTOM0); - BIND_ENUM_CONSTANT(ARRAY_CUSTOM1); - BIND_ENUM_CONSTANT(ARRAY_CUSTOM2); - BIND_ENUM_CONSTANT(ARRAY_CUSTOM3); - BIND_ENUM_CONSTANT(ARRAY_BONES); - BIND_ENUM_CONSTANT(ARRAY_WEIGHTS); - BIND_ENUM_CONSTANT(ARRAY_INDEX); - BIND_ENUM_CONSTANT(ARRAY_MAX); - - BIND_ENUM_CONSTANT(ARRAY_FORMAT_VERTEX); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_NORMAL); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_TANGENT); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_COLOR); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_TEX_UV2); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_BONES); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_WEIGHTS); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_INDEX); - - BIND_ENUM_CONSTANT(ARRAY_FORMAT_BLEND_SHAPE_MASK); - - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_BASE); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM0_SHIFT); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM1_SHIFT); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM2_SHIFT); - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM3_SHIFT); - - BIND_ENUM_CONSTANT(ARRAY_FORMAT_CUSTOM_MASK); - BIND_ENUM_CONSTANT(ARRAY_COMPRESS_FLAGS_BASE); - - BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_2D_VERTICES); - BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_DYNAMIC_UPDATE); - BIND_ENUM_CONSTANT(ARRAY_FLAG_USE_8_BONE_WEIGHTS); - - BIND_ENUM_CONSTANT(PRIMITIVE_POINTS); - BIND_ENUM_CONSTANT(PRIMITIVE_LINES); - BIND_ENUM_CONSTANT(PRIMITIVE_LINE_STRIP); - BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLES); - BIND_ENUM_CONSTANT(PRIMITIVE_TRIANGLE_STRIP); - BIND_ENUM_CONSTANT(PRIMITIVE_MAX); - - BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED); - BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE); - - BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_2D); - BIND_ENUM_CONSTANT(MULTIMESH_TRANSFORM_3D); - - BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL); - BIND_ENUM_CONSTANT(LIGHT_OMNI); - BIND_ENUM_CONSTANT(LIGHT_SPOT); - - BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY); - BIND_ENUM_CONSTANT(LIGHT_PARAM_INDIRECT_ENERGY); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SPECULAR); - BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SIZE); - BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ANGLE); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SPOT_ATTENUATION); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_MAX_DISTANCE); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_FADE_START); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_PANCAKE_SIZE); - BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BLUR); - BIND_ENUM_CONSTANT(LIGHT_PARAM_TRANSMITTANCE_BIAS); - BIND_ENUM_CONSTANT(LIGHT_PARAM_MAX); - - BIND_ENUM_CONSTANT(LIGHT_BAKE_DISABLED); - BIND_ENUM_CONSTANT(LIGHT_BAKE_DYNAMIC); - BIND_ENUM_CONSTANT(LIGHT_BAKE_STATIC); - - BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_DUAL_PARABOLOID); - BIND_ENUM_CONSTANT(LIGHT_OMNI_SHADOW_CUBE); - - BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); - BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS); - BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS); - - BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); - BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED); - - BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ONCE); - BIND_ENUM_CONSTANT(REFLECTION_PROBE_UPDATE_ALWAYS); - - BIND_ENUM_CONSTANT(REFLECTION_PROBE_AMBIENT_DISABLED); - BIND_ENUM_CONSTANT(REFLECTION_PROBE_AMBIENT_ENVIRONMENT); - BIND_ENUM_CONSTANT(REFLECTION_PROBE_AMBIENT_COLOR); - - BIND_ENUM_CONSTANT(DECAL_TEXTURE_ALBEDO); - BIND_ENUM_CONSTANT(DECAL_TEXTURE_NORMAL); - BIND_ENUM_CONSTANT(DECAL_TEXTURE_ORM); - BIND_ENUM_CONSTANT(DECAL_TEXTURE_EMISSION); - BIND_ENUM_CONSTANT(DECAL_TEXTURE_MAX); - - BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_INDEX); - BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_LIFETIME); - BIND_ENUM_CONSTANT(PARTICLES_DRAW_ORDER_VIEW_DEPTH); + ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); - BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); - BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); + BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); //then goes to disabled); must be manually updated + BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); // default BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ALWAYS); @@ -1997,6 +2154,17 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_NEVER); BIND_ENUM_CONSTANT(VIEWPORT_CLEAR_ONLY_NEXT_FRAME); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_OVERSIZE_100_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_OVERSIZE_120_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_OVERSIZE_150_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_OVERSIZE_200_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_OVERSIZE_MAX); + + BIND_ENUM_CONSTANT(VIEWPORT_SDF_SCALE_100_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_SCALE_50_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_SCALE_25_PERCENT); + BIND_ENUM_CONSTANT(VIEWPORT_SDF_SCALE_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_MSAA_DISABLED); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_2X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_4X); @@ -2008,23 +2176,28 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_FXAA); BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW); + BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM); + BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH); + BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME); - BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME); - BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME); + BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME); BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_VISIBLE); + BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_SHADOW); + BIND_ENUM_CONSTANT(VIEWPORT_RENDER_INFO_TYPE_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DISABLED); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_UNSHADED); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_LIGHTING); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OVERDRAW); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_WIREFRAME); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER); - BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO); - BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING); - BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE); @@ -2034,11 +2207,62 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_SDFGI_PROBES); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_GI_BUFFER); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_DISABLE_LOD); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_CLUSTER_OMNI_LIGHTS); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_CLUSTER_SPOT_LIGHTS); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_CLUSTER_DECALS); + BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS); + /* SKY API */ + + ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create); + ClassDB::bind_method(D_METHOD("sky_set_radiance_size", "sky", "radiance_size"), &RenderingServer::sky_set_radiance_size); + ClassDB::bind_method(D_METHOD("sky_set_mode", "sky", "mode"), &RenderingServer::sky_set_mode); + ClassDB::bind_method(D_METHOD("sky_set_material", "sky", "material"), &RenderingServer::sky_set_material); + ClassDB::bind_method(D_METHOD("sky_bake_panorama", "sky", "energy", "bake_irradiance", "size"), &RenderingServer::sky_bake_panorama); + + BIND_ENUM_CONSTANT(SKY_MODE_AUTOMATIC); BIND_ENUM_CONSTANT(SKY_MODE_QUALITY); + BIND_ENUM_CONSTANT(SKY_MODE_INCREMENTAL); BIND_ENUM_CONSTANT(SKY_MODE_REALTIME); + /* ENVIRONMENT */ + + ClassDB::bind_method(D_METHOD("environment_create"), &RenderingServer::environment_create); + ClassDB::bind_method(D_METHOD("environment_set_background", "env", "bg"), &RenderingServer::environment_set_background); + ClassDB::bind_method(D_METHOD("environment_set_sky", "env", "sky"), &RenderingServer::environment_set_sky); + ClassDB::bind_method(D_METHOD("environment_set_sky_custom_fov", "env", "scale"), &RenderingServer::environment_set_sky_custom_fov); + ClassDB::bind_method(D_METHOD("environment_set_sky_orientation", "env", "orientation"), &RenderingServer::environment_set_sky_orientation); + ClassDB::bind_method(D_METHOD("environment_set_bg_color", "env", "color"), &RenderingServer::environment_set_bg_color); + ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy); + ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer); + ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color())); + ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); + ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); + ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); + ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); + ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); + ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog); + ClassDB::bind_method(D_METHOD("environment_set_sdfgi", "env", "enable", "cascades", "min_cell_size", "y_scale", "use_occlusion", "bounce_feedback", "read_sky", "energy", "normal_bias", "probe_bias"), &RenderingServer::environment_set_sdfgi); + ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "light", "light_energy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount"), &RenderingServer::environment_set_volumetric_fog); + + ClassDB::bind_method(D_METHOD("environment_glow_set_use_bicubic_upscale", "enable"), &RenderingServer::environment_glow_set_use_bicubic_upscale); + ClassDB::bind_method(D_METHOD("environment_glow_set_use_high_quality", "enable"), &RenderingServer::environment_glow_set_use_high_quality); + ClassDB::bind_method(D_METHOD("environment_set_ssr_roughness_quality", "quality"), &RenderingServer::environment_set_ssr_roughness_quality); + ClassDB::bind_method(D_METHOD("environment_set_ssao_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssao_quality); + ClassDB::bind_method(D_METHOD("environment_set_sdfgi_ray_count", "ray_count"), &RenderingServer::environment_set_sdfgi_ray_count); + ClassDB::bind_method(D_METHOD("environment_set_sdfgi_frames_to_converge", "frames"), &RenderingServer::environment_set_sdfgi_frames_to_converge); + ClassDB::bind_method(D_METHOD("environment_set_sdfgi_frames_to_update_light", "frames"), &RenderingServer::environment_set_sdfgi_frames_to_update_light); + ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog_volume_size", "size", "depth"), &RenderingServer::environment_set_volumetric_fog_volume_size); + ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog_filter_active", "active"), &RenderingServer::environment_set_volumetric_fog_filter_active); + + ClassDB::bind_method(D_METHOD("environment_bake_panorama", "environment", "bake_irradiance", "size"), &RenderingServer::environment_bake_panorama); + + ClassDB::bind_method(D_METHOD("screen_space_roughness_limiter_set_active", "enable", "amount", "limit"), &RenderingServer::screen_space_roughness_limiter_set_active); + ClassDB::bind_method(D_METHOD("sub_surface_scattering_set_quality", "quality"), &RenderingServer::sub_surface_scattering_set_quality); + ClassDB::bind_method(D_METHOD("sub_surface_scattering_set_scale", "scale", "depth_scale"), &RenderingServer::sub_surface_scattering_set_scale); + BIND_ENUM_CONSTANT(ENV_BG_CLEAR_COLOR); BIND_ENUM_CONSTANT(ENV_BG_COLOR); BIND_ENUM_CONSTANT(ENV_BG_SKY); @@ -2078,49 +2302,118 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_HIGH); BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_ULTRA); + BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_4); + BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_6); + BIND_ENUM_CONSTANT(ENV_SDFGI_CASCADES_8); + + BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_DISABLED); + BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_75_PERCENT); + BIND_ENUM_CONSTANT(ENV_SDFGI_Y_SCALE_50_PERCENT); + + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_4); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_8); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_16); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_32); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_64); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_96); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_128); + BIND_ENUM_CONSTANT(ENV_SDFGI_RAY_COUNT_MAX); + + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_IN_5_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_IN_10_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_IN_15_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_IN_20_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_IN_25_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_IN_30_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_CONVERGE_MAX); + + BIND_ENUM_CONSTANT(ENV_SDFGI_UPDATE_LIGHT_IN_1_FRAME); + BIND_ENUM_CONSTANT(ENV_SDFGI_UPDATE_LIGHT_IN_2_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_UPDATE_LIGHT_IN_4_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_UPDATE_LIGHT_IN_8_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_UPDATE_LIGHT_IN_16_FRAMES); + BIND_ENUM_CONSTANT(ENV_SDFGI_UPDATE_LIGHT_MAX); + BIND_ENUM_CONSTANT(SUB_SURFACE_SCATTERING_QUALITY_DISABLED); BIND_ENUM_CONSTANT(SUB_SURFACE_SCATTERING_QUALITY_LOW); BIND_ENUM_CONSTANT(SUB_SURFACE_SCATTERING_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(SUB_SURFACE_SCATTERING_QUALITY_HIGH); + /* CAMERA EFFECTS */ + + ClassDB::bind_method(D_METHOD("camera_effects_create"), &RenderingServer::camera_effects_create); + + ClassDB::bind_method(D_METHOD("camera_effects_set_dof_blur_quality", "quality", "use_jitter"), &RenderingServer::camera_effects_set_dof_blur_quality); + ClassDB::bind_method(D_METHOD("camera_effects_set_dof_blur_bokeh_shape", "shape"), &RenderingServer::camera_effects_set_dof_blur_bokeh_shape); + + ClassDB::bind_method(D_METHOD("camera_effects_set_dof_blur", "camera_effects", "far_enable", "far_distance", "far_transition", "near_enable", "near_distance", "near_transition", "amount"), &RenderingServer::camera_effects_set_dof_blur); + ClassDB::bind_method(D_METHOD("camera_effects_set_custom_exposure", "camera_effects", "enable", "exposure"), &RenderingServer::camera_effects_set_custom_exposure); + + BIND_ENUM_CONSTANT(DOF_BOKEH_BOX); + BIND_ENUM_CONSTANT(DOF_BOKEH_HEXAGON); + BIND_ENUM_CONSTANT(DOF_BOKEH_CIRCLE); + BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_VERY_LOW); BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_LOW); BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_MEDIUM); BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_HIGH); - BIND_ENUM_CONSTANT(DOF_BOKEH_BOX); - BIND_ENUM_CONSTANT(DOF_BOKEH_HEXAGON); - BIND_ENUM_CONSTANT(DOF_BOKEH_CIRCLE); + /* SCENARIO */ - BIND_ENUM_CONSTANT(SHADOW_QUALITY_HARD); - BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_LOW); - BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_MEDIUM); - BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_HIGH); - BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_ULTRA); - BIND_ENUM_CONSTANT(SHADOW_QUALITY_MAX); + ClassDB::bind_method(D_METHOD("scenario_create"), &RenderingServer::scenario_create); + ClassDB::bind_method(D_METHOD("scenario_set_environment", "scenario", "environment"), &RenderingServer::scenario_set_environment); + ClassDB::bind_method(D_METHOD("scenario_set_fallback_environment", "scenario", "environment"), &RenderingServer::scenario_set_fallback_environment); + ClassDB::bind_method(D_METHOD("scenario_set_camera_effects", "scenario", "effects"), &RenderingServer::scenario_set_camera_effects); - BIND_ENUM_CONSTANT(SCENARIO_DEBUG_DISABLED); - BIND_ENUM_CONSTANT(SCENARIO_DEBUG_WIREFRAME); - BIND_ENUM_CONSTANT(SCENARIO_DEBUG_OVERDRAW); - BIND_ENUM_CONSTANT(SCENARIO_DEBUG_SHADELESS); + /* INSTANCE */ - BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_LOW); - BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_MEDIUM); - BIND_ENUM_CONSTANT(VIEWPORT_OCCLUSION_BUILD_QUALITY_HIGH); + ClassDB::bind_method(D_METHOD("instance_create2", "base", "scenario"), &RenderingServer::instance_create2); + ClassDB::bind_method(D_METHOD("instance_create"), &RenderingServer::instance_create); + ClassDB::bind_method(D_METHOD("instance_set_base", "instance", "base"), &RenderingServer::instance_set_base); + ClassDB::bind_method(D_METHOD("instance_set_scenario", "instance", "scenario"), &RenderingServer::instance_set_scenario); + ClassDB::bind_method(D_METHOD("instance_set_layer_mask", "instance", "mask"), &RenderingServer::instance_set_layer_mask); + ClassDB::bind_method(D_METHOD("instance_set_transform", "instance", "transform"), &RenderingServer::instance_set_transform); + ClassDB::bind_method(D_METHOD("instance_attach_object_instance_id", "instance", "id"), &RenderingServer::instance_attach_object_instance_id); + ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight); + ClassDB::bind_method(D_METHOD("instance_set_surface_override_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_override_material); + ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible); + + ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb); + + ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton); + ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &RenderingServer::instance_set_extra_visibility_margin); + ClassDB::bind_method(D_METHOD("instance_set_visibility_parent", "instance", "parent"), &RenderingServer::instance_set_visibility_parent); + + ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag); + ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting); + ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &RenderingServer::instance_geometry_set_material_override); + ClassDB::bind_method(D_METHOD("instance_geometry_set_visibility_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_visibility_range); + ClassDB::bind_method(D_METHOD("instance_geometry_set_lightmap", "instance", "lightmap", "lightmap_uv_scale", "lightmap_slice"), &RenderingServer::instance_geometry_set_lightmap); + ClassDB::bind_method(D_METHOD("instance_geometry_set_lod_bias", "instance", "lod_bias"), &RenderingServer::instance_geometry_set_lod_bias); + + ClassDB::bind_method(D_METHOD("instance_geometry_set_shader_parameter", "instance", "parameter", "value"), &RenderingServer::instance_geometry_set_shader_parameter); + ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_parameter", "instance", "parameter"), &RenderingServer::instance_geometry_get_shader_parameter); + ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_parameter_default_value", "instance", "parameter"), &RenderingServer::instance_geometry_get_shader_parameter_default_value); + ClassDB::bind_method(D_METHOD("instance_geometry_get_shader_parameter_list", "instance"), &RenderingServer::_instance_geometry_get_shader_parameter_list); + + ClassDB::bind_method(D_METHOD("instances_cull_aabb", "aabb", "scenario"), &RenderingServer::_instances_cull_aabb_bind, DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("instances_cull_ray", "from", "to", "scenario"), &RenderingServer::_instances_cull_ray_bind, DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("instances_cull_convex", "convex", "scenario"), &RenderingServer::_instances_cull_convex_bind, DEFVAL(RID())); BIND_ENUM_CONSTANT(INSTANCE_NONE); BIND_ENUM_CONSTANT(INSTANCE_MESH); BIND_ENUM_CONSTANT(INSTANCE_MULTIMESH); - BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE); BIND_ENUM_CONSTANT(INSTANCE_PARTICLES); BIND_ENUM_CONSTANT(INSTANCE_PARTICLES_COLLISION); BIND_ENUM_CONSTANT(INSTANCE_LIGHT); BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE); BIND_ENUM_CONSTANT(INSTANCE_DECAL); - BIND_ENUM_CONSTANT(INSTANCE_GI_PROBE); + BIND_ENUM_CONSTANT(INSTANCE_VOXEL_GI); BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP); BIND_ENUM_CONSTANT(INSTANCE_OCCLUDER); + BIND_ENUM_CONSTANT(INSTANCE_VISIBLITY_NOTIFIER); BIND_ENUM_CONSTANT(INSTANCE_MAX); + BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK); BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT); @@ -2134,6 +2427,80 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); + /* Bake 3D Object */ + + ClassDB::bind_method(D_METHOD("bake_render_uv2", "base", "material_overrides", "image_size"), &RenderingServer::bake_render_uv2); + + BIND_ENUM_CONSTANT(BAKE_CHANNEL_ALBEDO_ALPHA); + BIND_ENUM_CONSTANT(BAKE_CHANNEL_NORMAL); + BIND_ENUM_CONSTANT(BAKE_CHANNEL_ORM); + BIND_ENUM_CONSTANT(BAKE_CHANNEL_EMISSION); + + /* CANVAS (2D) */ + + ClassDB::bind_method(D_METHOD("canvas_create"), &RenderingServer::canvas_create); + ClassDB::bind_method(D_METHOD("canvas_set_item_mirroring", "canvas", "item", "mirroring"), &RenderingServer::canvas_set_item_mirroring); + ClassDB::bind_method(D_METHOD("canvas_set_modulate", "canvas", "color"), &RenderingServer::canvas_set_modulate); + ClassDB::bind_method(D_METHOD("canvas_set_disable_scale", "disable"), &RenderingServer::canvas_set_disable_scale); + + /* CANVAS TEXTURE */ + + ClassDB::bind_method(D_METHOD("canvas_texture_create"), &RenderingServer::canvas_texture_create); + ClassDB::bind_method(D_METHOD("canvas_texture_set_channel", "canvas_texture", "channel", "texture"), &RenderingServer::canvas_texture_set_channel); + ClassDB::bind_method(D_METHOD("canvas_texture_set_shading_parameters", "canvas_texture", "base_color", "shininess"), &RenderingServer::canvas_texture_set_shading_parameters); + + ClassDB::bind_method(D_METHOD("canvas_texture_set_texture_filter", "canvas_texture", "filter"), &RenderingServer::canvas_texture_set_texture_filter); + ClassDB::bind_method(D_METHOD("canvas_texture_set_texture_repeat", "canvas_texture", "repeat"), &RenderingServer::canvas_texture_set_texture_repeat); + + BIND_ENUM_CONSTANT(CANVAS_TEXTURE_CHANNEL_DIFFUSE); + BIND_ENUM_CONSTANT(CANVAS_TEXTURE_CHANNEL_NORMAL); + BIND_ENUM_CONSTANT(CANVAS_TEXTURE_CHANNEL_SPECULAR); + + /* CANVAS ITEM */ + + ClassDB::bind_method(D_METHOD("canvas_item_create"), &RenderingServer::canvas_item_create); + ClassDB::bind_method(D_METHOD("canvas_item_set_parent", "item", "parent"), &RenderingServer::canvas_item_set_parent); + ClassDB::bind_method(D_METHOD("canvas_item_set_default_texture_filter", "item", "filter"), &RenderingServer::canvas_item_set_default_texture_filter); + ClassDB::bind_method(D_METHOD("canvas_item_set_default_texture_repeat", "item", "repeat"), &RenderingServer::canvas_item_set_default_texture_repeat); + ClassDB::bind_method(D_METHOD("canvas_item_set_visible", "item", "visible"), &RenderingServer::canvas_item_set_visible); + ClassDB::bind_method(D_METHOD("canvas_item_set_light_mask", "item", "mask"), &RenderingServer::canvas_item_set_light_mask); + ClassDB::bind_method(D_METHOD("canvas_item_set_transform", "item", "transform"), &RenderingServer::canvas_item_set_transform); + ClassDB::bind_method(D_METHOD("canvas_item_set_clip", "item", "clip"), &RenderingServer::canvas_item_set_clip); + ClassDB::bind_method(D_METHOD("canvas_item_set_distance_field_mode", "item", "enabled"), &RenderingServer::canvas_item_set_distance_field_mode); + ClassDB::bind_method(D_METHOD("canvas_item_set_custom_rect", "item", "use_custom_rect", "rect"), &RenderingServer::canvas_item_set_custom_rect, DEFVAL(Rect2())); + ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &RenderingServer::canvas_item_set_modulate); + ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &RenderingServer::canvas_item_set_self_modulate); + ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &RenderingServer::canvas_item_set_draw_behind_parent); + //primitives + + ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); + ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); + ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0)); + ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("canvas_item_add_multimesh", "item", "mesh", "texture"), &RenderingServer::canvas_item_add_multimesh, DEFVAL(RID())); + ClassDB::bind_method(D_METHOD("canvas_item_add_particles", "item", "particles", "texture"), &RenderingServer::canvas_item_add_particles); + ClassDB::bind_method(D_METHOD("canvas_item_add_set_transform", "item", "transform"), &RenderingServer::canvas_item_add_set_transform); + ClassDB::bind_method(D_METHOD("canvas_item_add_clip_ignore", "item", "ignore"), &RenderingServer::canvas_item_add_clip_ignore); + ClassDB::bind_method(D_METHOD("canvas_item_set_sort_children_by_y", "item", "enabled"), &RenderingServer::canvas_item_set_sort_children_by_y); + ClassDB::bind_method(D_METHOD("canvas_item_set_z_index", "item", "z_index"), &RenderingServer::canvas_item_set_z_index); + ClassDB::bind_method(D_METHOD("canvas_item_set_z_as_relative_to_parent", "item", "enabled"), &RenderingServer::canvas_item_set_z_as_relative_to_parent); + ClassDB::bind_method(D_METHOD("canvas_item_set_copy_to_backbuffer", "item", "enabled", "rect"), &RenderingServer::canvas_item_set_copy_to_backbuffer); + + ClassDB::bind_method(D_METHOD("canvas_item_clear", "item"), &RenderingServer::canvas_item_clear); + ClassDB::bind_method(D_METHOD("canvas_item_set_draw_index", "item", "index"), &RenderingServer::canvas_item_set_draw_index); + ClassDB::bind_method(D_METHOD("canvas_item_set_material", "item", "material"), &RenderingServer::canvas_item_set_material); + ClassDB::bind_method(D_METHOD("canvas_item_set_use_parent_material", "item", "enabled"), &RenderingServer::canvas_item_set_use_parent_material); + + ClassDB::bind_method(D_METHOD("canvas_item_set_visibility_notifier", "item", "enable", "area", "enter_callable", "exit_callable"), &RenderingServer::canvas_item_set_visibility_notifier); + ClassDB::bind_method(D_METHOD("canvas_item_set_canvas_group_mode", "item", "mode", "clear_margin", "fit_empty", "fit_margin", "blur_mipmaps"), &RenderingServer::canvas_item_set_canvas_group_mode, DEFVAL(5.0), DEFVAL(false), DEFVAL(0.0), DEFVAL(false)); + BIND_ENUM_CONSTANT(NINE_PATCH_STRETCH); BIND_ENUM_CONSTANT(NINE_PATCH_TILE); BIND_ENUM_CONSTANT(NINE_PATCH_TILE_FIT); @@ -2157,6 +2524,28 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_OPAQUE); BIND_ENUM_CONSTANT(CANVAS_GROUP_MODE_TRANSPARENT); + /* CANVAS LIGHT */ + + ClassDB::bind_method(D_METHOD("canvas_light_create"), &RenderingServer::canvas_light_create); + ClassDB::bind_method(D_METHOD("canvas_light_attach_to_canvas", "light", "canvas"), &RenderingServer::canvas_light_attach_to_canvas); + ClassDB::bind_method(D_METHOD("canvas_light_set_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_enabled); + ClassDB::bind_method(D_METHOD("canvas_light_set_texture_scale", "light", "scale"), &RenderingServer::canvas_light_set_texture_scale); + ClassDB::bind_method(D_METHOD("canvas_light_set_transform", "light", "transform"), &RenderingServer::canvas_light_set_transform); + ClassDB::bind_method(D_METHOD("canvas_light_set_texture", "light", "texture"), &RenderingServer::canvas_light_set_texture); + ClassDB::bind_method(D_METHOD("canvas_light_set_texture_offset", "light", "offset"), &RenderingServer::canvas_light_set_texture_offset); + ClassDB::bind_method(D_METHOD("canvas_light_set_color", "light", "color"), &RenderingServer::canvas_light_set_color); + ClassDB::bind_method(D_METHOD("canvas_light_set_height", "light", "height"), &RenderingServer::canvas_light_set_height); + ClassDB::bind_method(D_METHOD("canvas_light_set_energy", "light", "energy"), &RenderingServer::canvas_light_set_energy); + ClassDB::bind_method(D_METHOD("canvas_light_set_z_range", "light", "min_z", "max_z"), &RenderingServer::canvas_light_set_z_range); + ClassDB::bind_method(D_METHOD("canvas_light_set_layer_range", "light", "min_layer", "max_layer"), &RenderingServer::canvas_light_set_layer_range); + ClassDB::bind_method(D_METHOD("canvas_light_set_item_cull_mask", "light", "mask"), &RenderingServer::canvas_light_set_item_cull_mask); + ClassDB::bind_method(D_METHOD("canvas_light_set_item_shadow_cull_mask", "light", "mask"), &RenderingServer::canvas_light_set_item_shadow_cull_mask); + ClassDB::bind_method(D_METHOD("canvas_light_set_mode", "light", "mode"), &RenderingServer::canvas_light_set_mode); + ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_enabled", "light", "enabled"), &RenderingServer::canvas_light_set_shadow_enabled); + ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_filter", "light", "filter"), &RenderingServer::canvas_light_set_shadow_filter); + ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color); + ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth); + BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_POINT); BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_DIRECTIONAL); @@ -2169,10 +2558,38 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_PCF13); BIND_ENUM_CONSTANT(CANVAS_LIGHT_FILTER_MAX); + /* CANVAS OCCLUDER */ + + ClassDB::bind_method(D_METHOD("canvas_light_occluder_create"), &RenderingServer::canvas_light_occluder_create); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_attach_to_canvas", "occluder", "canvas"), &RenderingServer::canvas_light_occluder_attach_to_canvas); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_enabled", "occluder", "enabled"), &RenderingServer::canvas_light_occluder_set_enabled); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_polygon", "occluder", "polygon"), &RenderingServer::canvas_light_occluder_set_polygon); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_as_sdf_collision", "occluder", "enable"), &RenderingServer::canvas_light_occluder_set_as_sdf_collision); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask); + + /* CANVAS LIGHT OCCLUDER POLYGON */ + + ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_create"), &RenderingServer::canvas_occluder_polygon_create); + ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_shape", "occluder_polygon", "shape", "closed"), &RenderingServer::canvas_occluder_polygon_set_shape); + ClassDB::bind_method(D_METHOD("canvas_occluder_polygon_set_cull_mode", "occluder_polygon", "mode"), &RenderingServer::canvas_occluder_polygon_set_cull_mode); + + ClassDB::bind_method(D_METHOD("canvas_set_shadow_texture_size", "size"), &RenderingServer::canvas_set_shadow_texture_size); + BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_DISABLED); BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE); BIND_ENUM_CONSTANT(CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE); + /* GLOBAL VARIABLES */ + + ClassDB::bind_method(D_METHOD("global_variable_add", "name", "type", "default_value"), &RenderingServer::global_variable_add); + ClassDB::bind_method(D_METHOD("global_variable_remove", "name"), &RenderingServer::global_variable_remove); + ClassDB::bind_method(D_METHOD("global_variable_get_list"), &RenderingServer::global_variable_get_list); + ClassDB::bind_method(D_METHOD("global_variable_set", "name", "value"), &RenderingServer::global_variable_set); + ClassDB::bind_method(D_METHOD("global_variable_set_override", "name", "value"), &RenderingServer::global_variable_set_override); + ClassDB::bind_method(D_METHOD("global_variable_get", "name"), &RenderingServer::global_variable_get); + ClassDB::bind_method(D_METHOD("global_variable_get_type", "name"), &RenderingServer::global_variable_get_type); + BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_BOOL); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_BVEC2); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_BVEC3); @@ -2203,22 +2620,53 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_SAMPLERCUBE); BIND_ENUM_CONSTANT(GLOBAL_VAR_TYPE_MAX); - BIND_ENUM_CONSTANT(INFO_OBJECTS_IN_FRAME); - BIND_ENUM_CONSTANT(INFO_VERTICES_IN_FRAME); - BIND_ENUM_CONSTANT(INFO_MATERIAL_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(INFO_SHADER_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(INFO_SURFACE_CHANGES_IN_FRAME); - BIND_ENUM_CONSTANT(INFO_DRAW_CALLS_IN_FRAME); - BIND_ENUM_CONSTANT(INFO_USAGE_VIDEO_MEM_TOTAL); - BIND_ENUM_CONSTANT(INFO_VIDEO_MEM_USED); - BIND_ENUM_CONSTANT(INFO_TEXTURE_MEM_USED); - BIND_ENUM_CONSTANT(INFO_VERTEX_MEM_USED); + /* Free */ + ClassDB::bind_method(D_METHOD("free_rid", "rid"), &RenderingServer::free); // shouldn't conflict with Object::free() + + /* Misc */ + + ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &RenderingServer::request_frame_drawn_callback); + ClassDB::bind_method(D_METHOD("has_changed"), &RenderingServer::has_changed); + ClassDB::bind_method(D_METHOD("get_rendering_info", "info"), &RenderingServer::get_rendering_info); + ClassDB::bind_method(D_METHOD("get_video_adapter_name"), &RenderingServer::get_video_adapter_name); + ClassDB::bind_method(D_METHOD("get_video_adapter_vendor"), &RenderingServer::get_video_adapter_vendor); + + ClassDB::bind_method(D_METHOD("make_sphere_mesh", "latitudes", "longitudes", "radius"), &RenderingServer::make_sphere_mesh); + ClassDB::bind_method(D_METHOD("get_test_cube"), &RenderingServer::get_test_cube); + + ClassDB::bind_method(D_METHOD("get_test_texture"), &RenderingServer::get_test_texture); + ClassDB::bind_method(D_METHOD("get_white_texture"), &RenderingServer::get_white_texture); + + ClassDB::bind_method(D_METHOD("set_boot_image", "image", "color", "scale", "use_filter"), &RenderingServer::set_boot_image, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_default_clear_color", "color"), &RenderingServer::set_default_clear_color); + + ClassDB::bind_method(D_METHOD("has_feature", "feature"), &RenderingServer::has_feature); + ClassDB::bind_method(D_METHOD("has_os_feature", "feature"), &RenderingServer::has_os_feature); + ClassDB::bind_method(D_METHOD("set_debug_generate_wireframes", "generate"), &RenderingServer::set_debug_generate_wireframes); + + ClassDB::bind_method(D_METHOD("is_render_loop_enabled"), &RenderingServer::is_render_loop_enabled); + ClassDB::bind_method(D_METHOD("set_render_loop_enabled", "enabled"), &RenderingServer::set_render_loop_enabled); + + ClassDB::bind_method(D_METHOD("get_frame_setup_time_cpu"), &RenderingServer::get_frame_setup_time_cpu); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "render_loop_enabled"), "set_render_loop_enabled", "is_render_loop_enabled"); + + BIND_ENUM_CONSTANT(RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME); + BIND_ENUM_CONSTANT(RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME); + BIND_ENUM_CONSTANT(RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME); + BIND_ENUM_CONSTANT(RENDERING_INFO_TEXTURE_MEM_USED); + BIND_ENUM_CONSTANT(RENDERING_INFO_BUFFER_MEM_USED); + BIND_ENUM_CONSTANT(RENDERING_INFO_VIDEO_MEM_USED); BIND_ENUM_CONSTANT(FEATURE_SHADERS); BIND_ENUM_CONSTANT(FEATURE_MULTITHREADED); ADD_SIGNAL(MethodInfo("frame_pre_draw")); ADD_SIGNAL(MethodInfo("frame_post_draw")); + + ClassDB::bind_method(D_METHOD("force_sync"), &RenderingServer::sync); + ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &RenderingServer::draw, DEFVAL(true), DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device); } void RenderingServer::mesh_add_surface_from_mesh_data(RID p_mesh, const Geometry3D::MeshData &p_mesh_data) { @@ -2251,10 +2699,6 @@ void RenderingServer::mesh_add_surface_from_planes(RID p_mesh, const Vector<Plan mesh_add_surface_from_mesh_data(p_mesh, mdata); } -void RenderingServer::immediate_vertex_2d(RID p_immediate, const Vector2 &p_vertex) { - immediate_vertex(p_immediate, Vector3(p_vertex.x, p_vertex.y, 0)); -} - RID RenderingServer::instance_create2(RID p_base, RID p_scenario) { RID instance = instance_create(); instance_set_base(instance, p_base); @@ -2282,6 +2726,10 @@ RenderingServer::RenderingServer() { GLOBAL_DEF_RST("rendering/textures/vram_compression/import_etc2", true); GLOBAL_DEF_RST("rendering/textures/vram_compression/import_pvrtc", false); + GLOBAL_DEF("rendering/textures/lossless_compression/force_png", false); + GLOBAL_DEF("rendering/textures/lossless_compression/webp_compression_level", 2); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/lossless_compression/webp_compression_level", PropertyInfo(Variant::INT, "rendering/textures/lossless_compression/webp_compression_level", PROPERTY_HINT_RANGE, "0,9,1")); + GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600); ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::FLOAT, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); @@ -2324,9 +2772,8 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false); - GLOBAL_DEF("rendering/global_illumination/gi_probes/anisotropic", false); - GLOBAL_DEF("rendering/global_illumination/gi_probes/quality", 1); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/gi_probes/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/gi_probes/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)")); + GLOBAL_DEF("rendering/global_illumination/voxel_gi/quality", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/global_illumination/voxel_gi/quality", PropertyInfo(Variant::INT, "rendering/global_illumination/voxel_gi/quality", PROPERTY_HINT_ENUM, "Low (4 Cones - Fast),High (6 Cones - Slow)")); GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading", false); GLOBAL_DEF("rendering/shading/overrides/force_vertex_shading.mobile", true); @@ -2414,6 +2861,8 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512); ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1")); + + GLOBAL_DEF_RST("rendering/xr/enabled", false); } RenderingServer::~RenderingServer() { diff --git a/servers/rendering_server.h b/servers/rendering_server.h index a9ab4928c4..0d01d4a2bd 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -103,7 +103,6 @@ public: virtual RID texture_3d_create(Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector<Ref<Image>> &p_data) = 0; //all slices, then all the mipmaps, must be coherent virtual RID texture_proxy_create(RID p_base) = 0; - virtual void texture_2d_update_immediate(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; //mostly used for video and streaming virtual void texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; virtual void texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) = 0; virtual void texture_proxy_update(RID p_texture, RID p_proxy_to) = 0; @@ -119,10 +118,6 @@ public: virtual void texture_replace(RID p_texture, RID p_by_texture) = 0; virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - virtual void texture_bind(RID p_texture, uint32_t p_texture_no) = 0; -#endif virtual void texture_set_path(RID p_texture, const String &p_path) = 0; virtual String texture_get_path(RID p_texture) const = 0; @@ -173,7 +168,6 @@ public: virtual void shader_set_code(RID p_shader, const String &p_code) = 0; virtual String shader_get_code(RID p_shader) const = 0; virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; - Array _shader_get_param_list_bind(RID p_shader) const; virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const = 0; virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; @@ -214,9 +208,9 @@ public: enum ArrayType { ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit) - ARRAY_NORMAL = 1, // A2B10G10R10 + ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal - ARRAY_COLOR = 3, // RGBA16F + ARRAY_COLOR = 3, // RGBA8 ARRAY_TEX_UV = 4, // RG32F ARRAY_TEX_UV2 = 5, // RG32F ARRAY_CUSTOM0 = 6, // depends on ArrayCustomFormat @@ -342,7 +336,9 @@ public: virtual void mesh_set_blend_shape_mode(RID p_mesh, BlendShapeMode p_mode) = 0; virtual BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const = 0; - virtual void mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + virtual void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + virtual void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; + virtual void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) = 0; virtual void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) = 0; virtual RID mesh_surface_get_material(RID p_mesh, int p_surface) const = 0; @@ -371,7 +367,7 @@ public: virtual int multimesh_get_instance_count(RID p_multimesh) const = 0; virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh) = 0; - virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) = 0; + virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) = 0; virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) = 0; virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) = 0; virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) = 0; @@ -379,7 +375,7 @@ public: virtual RID multimesh_get_mesh(RID p_multimesh) const = 0; virtual AABB multimesh_get_aabb(RID p_multimesh) const = 0; - virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; + virtual Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const = 0; virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const = 0; virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const = 0; @@ -390,29 +386,13 @@ public: virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible) = 0; virtual int multimesh_get_visible_instances(RID p_multimesh) const = 0; - /* IMMEDIATE API */ - - virtual RID immediate_create() = 0; - virtual void immediate_begin(RID p_immediate, PrimitiveType p_rimitive, RID p_texture = RID()) = 0; - virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex) = 0; - virtual void immediate_vertex_2d(RID p_immediate, const Vector2 &p_vertex); - virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal) = 0; - virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent) = 0; - virtual void immediate_color(RID p_immediate, const Color &p_color) = 0; - virtual void immediate_uv(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_uv2(RID p_immediate, const Vector2 &tex_uv) = 0; - virtual void immediate_end(RID p_immediate) = 0; - virtual void immediate_clear(RID p_immediate) = 0; - virtual void immediate_set_material(RID p_immediate, RID p_material) = 0; - virtual RID immediate_get_material(RID p_immediate) const = 0; - /* SKELETON API */ virtual RID skeleton_create() = 0; virtual void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) = 0; virtual int skeleton_get_bone_count(RID p_skeleton) const = 0; - virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) = 0; - virtual Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; + virtual void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) = 0; + virtual Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) = 0; virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const = 0; virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) = 0; @@ -489,13 +469,19 @@ public: virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; virtual void light_directional_set_sky_only(RID p_light, bool p_sky_only) = 0; - enum LightDirectionalShadowDepthRangeMode { - LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE, - LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED, - }; + virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; - virtual void light_directional_set_shadow_depth_range_mode(RID p_light, LightDirectionalShadowDepthRangeMode p_range_mode) = 0; + enum ShadowQuality { + SHADOW_QUALITY_HARD, + SHADOW_QUALITY_SOFT_LOW, + SHADOW_QUALITY_SOFT_MEDIUM, + SHADOW_QUALITY_SOFT_HIGH, + SHADOW_QUALITY_SOFT_ULTRA, + SHADOW_QUALITY_MAX + }; + virtual void shadows_quality_set(ShadowQuality p_quality) = 0; + virtual void directional_shadow_quality_set(ShadowQuality p_quality) = 0; /* PROBE API */ virtual RID reflection_probe_create() = 0; @@ -548,56 +534,34 @@ public: virtual void decal_set_fade(RID p_decal, float p_above, float p_below) = 0; virtual void decal_set_normal_fade(RID p_decal, float p_fade) = 0; - /* GI PROBE API */ - - virtual RID gi_probe_create() = 0; - - virtual void gi_probe_allocate_data(RID p_gi_probe, const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; - - virtual AABB gi_probe_get_bounds(RID p_gi_probe) const = 0; - virtual Vector3i gi_probe_get_octree_size(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_octree_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_data_cells(RID p_gi_probe) const = 0; - virtual Vector<uint8_t> gi_probe_get_distance_field(RID p_gi_probe) const = 0; - virtual Vector<int> gi_probe_get_level_counts(RID p_gi_probe) const = 0; - virtual Transform gi_probe_get_to_cell_xform(RID p_gi_probe) const = 0; + /* VOXEL GI API */ - virtual void gi_probe_set_dynamic_range(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_dynamic_range(RID p_gi_probe) const = 0; + virtual RID voxel_gi_create() = 0; - virtual void gi_probe_set_propagation(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_propagation(RID p_gi_probe) const = 0; + virtual void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) = 0; - virtual void gi_probe_set_energy(RID p_gi_probe, float p_energy) = 0; - virtual float gi_probe_get_energy(RID p_gi_probe) const = 0; + virtual AABB voxel_gi_get_bounds(RID p_voxel_gi) const = 0; + virtual Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const = 0; + virtual Vector<uint8_t> voxel_gi_get_octree_cells(RID p_voxel_gi) const = 0; + virtual Vector<uint8_t> voxel_gi_get_data_cells(RID p_voxel_gi) const = 0; + virtual Vector<uint8_t> voxel_gi_get_distance_field(RID p_voxel_gi) const = 0; + virtual Vector<int> voxel_gi_get_level_counts(RID p_voxel_gi) const = 0; + virtual Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const = 0; - virtual void gi_probe_set_ao(RID p_gi_probe, float p_ao) = 0; - virtual float gi_probe_get_ao(RID p_gi_probe) const = 0; + virtual void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) = 0; + virtual void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) = 0; + virtual void voxel_gi_set_energy(RID p_voxel_gi, float p_energy) = 0; + virtual void voxel_gi_set_bias(RID p_voxel_gi, float p_bias) = 0; + virtual void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) = 0; + virtual void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) = 0; + virtual void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) = 0; - virtual void gi_probe_set_ao_size(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_ao_size(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_bias(RID p_gi_probe, float p_bias) = 0; - virtual float gi_probe_get_bias(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_normal_bias(RID p_gi_probe, float p_range) = 0; - virtual float gi_probe_get_normal_bias(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_interior(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_interior(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_use_two_bounces(RID p_gi_probe, bool p_enable) = 0; - virtual bool gi_probe_is_using_two_bounces(RID p_gi_probe) const = 0; - - virtual void gi_probe_set_anisotropy_strength(RID p_gi_probe, float p_strength) = 0; - virtual float gi_probe_get_anisotropy_strength(RID p_gi_probe) const = 0; - - enum GIProbeQuality { - GI_PROBE_QUALITY_LOW, - GI_PROBE_QUALITY_HIGH, + enum VoxelGIQuality { + VOXEL_GI_QUALITY_LOW, + VOXEL_GI_QUALITY_HIGH, }; - virtual void gi_probe_set_quality(GIProbeQuality) = 0; + virtual void voxel_gi_set_quality(VoxelGIQuality) = 0; /* LIGHTMAP */ @@ -651,7 +615,7 @@ public: virtual void particles_set_transform_align(RID p_particles, ParticlesTransformAlign p_transform_align) = 0; virtual void particles_set_trails(RID p_particles, bool p_enable, float p_length_sec) = 0; - virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform> &p_bind_poses) = 0; + virtual void particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) = 0; virtual bool particles_is_inactive(RID p_particles) = 0; virtual void particles_request_process(RID p_particles) = 0; @@ -667,7 +631,7 @@ public: PARTICLES_EMIT_FLAG_CUSTOM = 16 }; - virtual void particles_emit(RID p_particles, const Transform &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; + virtual void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) = 0; enum ParticlesDrawOrder { PARTICLES_DRAW_ORDER_INDEX, @@ -683,7 +647,7 @@ public: virtual AABB particles_get_current_aabb(RID p_particles) = 0; - virtual void particles_set_emission_transform(RID p_particles, const Transform &p_transform) = 0; //this is only used for 2D, in 3D it's automatic + virtual void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) = 0; //this is only used for 2D, in 3D it's automatic /* PARTICLES COLLISION API */ @@ -722,24 +686,30 @@ public: virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field + /* VISIBILITY NOTIFIER API */ + + virtual RID visibility_notifier_create() = 0; + virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0; + virtual void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0; + + /* OCCLUDER API */ + + virtual RID occluder_create() = 0; + virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0; + /* CAMERA API */ virtual RID camera_create() = 0; virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0; virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0; virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0; - virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0; + virtual void camera_set_transform(RID p_camera, const Transform3D &p_transform) = 0; virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0; virtual void camera_set_environment(RID p_camera, RID p_env) = 0; virtual void camera_set_camera_effects(RID p_camera, RID p_camera_effects) = 0; virtual void camera_set_use_vertical_aspect(RID p_camera, bool p_enable) = 0; - /* OCCLUDER API */ - - virtual RID occluder_create() = 0; - virtual void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) = 0; - - /* VIEWPORT TARGET API */ + /* VIEWPORT API */ enum CanvasItemTextureFilter { CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, //uses canvas item setting for draw command, uses global setting for canvas item @@ -790,9 +760,9 @@ public: virtual RID viewport_get_texture(RID p_viewport) const = 0; - virtual void viewport_set_hide_scenario(RID p_viewport, bool p_hide) = 0; - virtual void viewport_set_hide_canvas(RID p_viewport, bool p_hide) = 0; virtual void viewport_set_disable_environment(RID p_viewport, bool p_disable) = 0; + virtual void viewport_set_disable_3d(RID p_viewport, bool p_disable) = 0; + virtual void viewport_set_disable_2d(RID p_viewport, bool p_disable) = 0; virtual void viewport_attach_camera(RID p_viewport, RID p_camera) = 0; virtual void viewport_set_scenario(RID p_viewport, RID p_scenario) = 0; @@ -865,15 +835,18 @@ public: enum ViewportRenderInfo { VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME, - VIEWPORT_RENDER_INFO_VERTICES_IN_FRAME, - VIEWPORT_RENDER_INFO_MATERIAL_CHANGES_IN_FRAME, - VIEWPORT_RENDER_INFO_SHADER_CHANGES_IN_FRAME, - VIEWPORT_RENDER_INFO_SURFACE_CHANGES_IN_FRAME, + VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME, VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME, VIEWPORT_RENDER_INFO_MAX, }; - virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfo p_info) = 0; + enum ViewportRenderInfoType { + VIEWPORT_RENDER_INFO_TYPE_VISIBLE, + VIEWPORT_RENDER_INFO_TYPE_SHADOW, + VIEWPORT_RENDER_INFO_TYPE_MAX + }; + + virtual int viewport_get_render_info(RID p_viewport, ViewportRenderInfoType p_type, ViewportRenderInfo p_info) = 0; enum ViewportDebugDraw { VIEWPORT_DEBUG_DRAW_DISABLED, @@ -882,9 +855,9 @@ public: VIEWPORT_DEBUG_DRAW_OVERDRAW, VIEWPORT_DEBUG_DRAW_WIREFRAME, VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER, - VIEWPORT_DEBUG_DRAW_GI_PROBE_ALBEDO, - VIEWPORT_DEBUG_DRAW_GI_PROBE_LIGHTING, - VIEWPORT_DEBUG_DRAW_GI_PROBE_EMISSION, + VIEWPORT_DEBUG_DRAW_VOXEL_GI_ALBEDO, + VIEWPORT_DEBUG_DRAW_VOXEL_GI_LIGHTING, + VIEWPORT_DEBUG_DRAW_VOXEL_GI_EMISSION, VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS, VIEWPORT_DEBUG_DRAW_DIRECTIONAL_SHADOW_ATLAS, VIEWPORT_DEBUG_DRAW_SCENE_LUMINANCE, @@ -908,8 +881,6 @@ public: virtual float viewport_get_measured_render_time_cpu(RID p_viewport) const = 0; virtual float viewport_get_measured_render_time_gpu(RID p_viewport) const = 0; - virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) = 0; - /* SKY API */ enum SkyMode { @@ -960,10 +931,6 @@ public: virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; virtual void environment_set_ambient_light(RID p_env, const Color &p_color, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; -// FIXME: Disabled during Vulkan refactoring, should be ported. -#if 0 - virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; -#endif enum EnvironmentGlowBlendMode { ENV_GLOW_BLEND_MODE_ADDITIVE, @@ -1105,30 +1072,10 @@ public: virtual void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) = 0; virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) = 0; - enum ShadowQuality { - SHADOW_QUALITY_HARD, - SHADOW_QUALITY_SOFT_LOW, - SHADOW_QUALITY_SOFT_MEDIUM, - SHADOW_QUALITY_SOFT_HIGH, - SHADOW_QUALITY_SOFT_ULTRA, - SHADOW_QUALITY_MAX - }; - - virtual void shadows_quality_set(ShadowQuality p_quality) = 0; - virtual void directional_shadow_quality_set(ShadowQuality p_quality) = 0; - /* SCENARIO API */ virtual RID scenario_create() = 0; - enum ScenarioDebugMode { - SCENARIO_DEBUG_DISABLED, - SCENARIO_DEBUG_WIREFRAME, - SCENARIO_DEBUG_OVERDRAW, - SCENARIO_DEBUG_SHADELESS, - }; - - virtual void scenario_set_debug(RID p_scenario, ScenarioDebugMode p_debug_mode) = 0; virtual void scenario_set_environment(RID p_scenario, RID p_environment) = 0; virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment) = 0; virtual void scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) = 0; @@ -1139,18 +1086,18 @@ public: INSTANCE_NONE, INSTANCE_MESH, INSTANCE_MULTIMESH, - INSTANCE_IMMEDIATE, INSTANCE_PARTICLES, INSTANCE_PARTICLES_COLLISION, INSTANCE_LIGHT, INSTANCE_REFLECTION_PROBE, INSTANCE_DECAL, - INSTANCE_GI_PROBE, + INSTANCE_VOXEL_GI, INSTANCE_LIGHTMAP, INSTANCE_OCCLUDER, + INSTANCE_VISIBLITY_NOTIFIER, INSTANCE_MAX, - INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) | (1 << INSTANCE_PARTICLES) + INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_PARTICLES) }; virtual RID instance_create2(RID p_base, RID p_scenario); @@ -1160,7 +1107,7 @@ public: virtual void instance_set_base(RID p_instance, RID p_base) = 0; virtual void instance_set_scenario(RID p_instance, RID p_scenario) = 0; virtual void instance_set_layer_mask(RID p_instance, uint32_t p_mask) = 0; - virtual void instance_set_transform(RID p_instance, const Transform &p_transform) = 0; + virtual void instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; virtual void instance_attach_object_instance_id(RID p_instance, ObjectID p_id) = 0; virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0; @@ -1169,9 +1116,9 @@ public: virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0; virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; - virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0; virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0; + virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0; // don't use these in a game! virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0; @@ -1200,9 +1147,7 @@ public: virtual void instance_geometry_set_flag(RID p_instance, InstanceFlags p_flags, bool p_enabled) = 0; virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) = 0; virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; - - virtual void instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; - virtual void instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) = 0; + virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0; virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; @@ -1231,6 +1176,7 @@ public: virtual void canvas_set_disable_scale(bool p_disable) = 0; + /* CANVAS TEXTURE */ virtual RID canvas_texture_create() = 0; enum CanvasTextureChannel { @@ -1245,6 +1191,8 @@ public: virtual void canvas_texture_set_texture_filter(RID p_canvas_texture, CanvasItemTextureFilter p_filter) = 0; virtual void canvas_texture_set_texture_repeat(RID p_canvas_texture, CanvasItemTextureRepeat p_repeat) = 0; + /* CANVAS ITEM */ + virtual RID canvas_item_create() = 0; virtual void canvas_item_set_parent(RID p_item, RID p_parent) = 0; @@ -1287,6 +1235,8 @@ public: virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) = 0; virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0; virtual void canvas_item_add_clip_ignore(RID p_item, bool p_ignore) = 0; + virtual void canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) = 0; + virtual void canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) = 0; virtual void canvas_item_set_z_index(RID p_item, int p_z) = 0; virtual void canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) = 0; @@ -1301,6 +1251,8 @@ public: virtual void canvas_item_set_use_parent_material(RID p_item, bool p_enable) = 0; + virtual void canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callbable, const Callable &p_exit_callable) = 0; + enum CanvasGroupMode { CANVAS_GROUP_MODE_DISABLED, CANVAS_GROUP_MODE_OPAQUE, @@ -1309,6 +1261,7 @@ public: virtual void canvas_item_set_canvas_group_mode(RID p_item, CanvasGroupMode p_mode, float p_clear_margin = 5.0, bool p_fit_empty = false, float p_fit_margin = 0.0, bool p_blur_mipmaps = false) = 0; + /* CANVAS LIGHT */ virtual RID canvas_light_create() = 0; enum CanvasLightMode { @@ -1355,6 +1308,8 @@ public: virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0; virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0; + /* CANVAS LIGHT OCCLUDER */ + virtual RID canvas_light_occluder_create() = 0; virtual void canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) = 0; virtual void canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) = 0; @@ -1363,6 +1318,8 @@ public: virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0; virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0; + /* CANVAS LIGHT OCCLUDER POLYGON */ + virtual RID canvas_occluder_polygon_create() = 0; virtual void canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) = 0; @@ -1425,11 +1382,6 @@ public: static ShaderLanguage::DataType global_variable_type_get_shader_datatype(GlobalVariableType p_type); - /* BLACK BARS */ - - virtual void black_bars_set_margins(int p_left, int p_top, int p_right, int p_bottom) = 0; - virtual void black_bars_set_images(RID p_left, RID p_top, RID p_right, RID p_bottom) = 0; - /* FREE */ virtual void free(RID p_rid) = 0; ///< free RIDs associated with the visual server @@ -1446,20 +1398,17 @@ public: /* STATUS INFORMATION */ - enum RenderInfo { - INFO_OBJECTS_IN_FRAME, - INFO_VERTICES_IN_FRAME, - INFO_MATERIAL_CHANGES_IN_FRAME, - INFO_SHADER_CHANGES_IN_FRAME, - INFO_SURFACE_CHANGES_IN_FRAME, - INFO_DRAW_CALLS_IN_FRAME, - INFO_USAGE_VIDEO_MEM_TOTAL, - INFO_VIDEO_MEM_USED, - INFO_TEXTURE_MEM_USED, - INFO_VERTEX_MEM_USED, + enum RenderingInfo { + RENDERING_INFO_TOTAL_OBJECTS_IN_FRAME, + RENDERING_INFO_TOTAL_PRIMITIVES_IN_FRAME, + RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME, + RENDERING_INFO_TEXTURE_MEM_USED, + RENDERING_INFO_BUFFER_MEM_USED, + RENDERING_INFO_VIDEO_MEM_USED, + RENDERING_INFO_MAX }; - virtual uint64_t get_render_info(RenderInfo p_info) = 0; + virtual uint64_t get_rendering_info(RenderingInfo p_info) = 0; virtual String get_video_adapter_name() const = 0; virtual String get_video_adapter_vendor() const = 0; @@ -1505,7 +1454,7 @@ public: virtual void set_debug_generate_wireframes(bool p_generate) = 0; - virtual void call_set_use_vsync(bool p_enable) = 0; + virtual void call_set_vsync_mode(DisplayServer::VSyncMode p_mode, DisplayServer::WindowID p_window) = 0; virtual bool is_low_end() const = 0; @@ -1518,6 +1467,20 @@ public: RenderingServer(); virtual ~RenderingServer(); + +private: + //binder helpers + RID _texture_2d_layered_create(const TypedArray<Image> &p_layers, TextureLayeredType p_layered_type); + RID _texture_3d_create(Image::Format p_format, int p_width, int p_height, int p_depth, bool p_mipmaps, const TypedArray<Image> &p_data); + void _texture_3d_update(RID p_texture, const TypedArray<Image> &p_data); + TypedArray<Image> _texture_3d_get(RID p_texture) const; + TypedArray<Dictionary> _shader_get_param_list(RID p_shader) const; + RID _mesh_create_from_surfaces(const TypedArray<Dictionary> &p_surfaces, int p_blend_shape_count); + void _mesh_add_surface(RID p_mesh, const Dictionary &p_surface); + Dictionary _mesh_get_surface(RID p_mesh, int p_idx); + Array _instance_geometry_get_shader_parameter_list(RID p_instance) const; + TypedArray<Image> _bake_render_uv2(RID p_base, const TypedArray<RID> &p_material_overrides, const Size2i &p_image_size); + void _particles_set_trail_bind_poses(RID p_particles, const TypedArray<Transform3D> &p_bind_poses); }; // make variant understand the enums @@ -1526,6 +1489,7 @@ VARIANT_ENUM_CAST(RenderingServer::CubeMapLayer); VARIANT_ENUM_CAST(RenderingServer::ShaderMode); VARIANT_ENUM_CAST(RenderingServer::ArrayType); VARIANT_ENUM_CAST(RenderingServer::ArrayFormat); +VARIANT_ENUM_CAST(RenderingServer::ArrayCustomFormat); VARIANT_ENUM_CAST(RenderingServer::PrimitiveType); VARIANT_ENUM_CAST(RenderingServer::BlendShapeMode); VARIANT_ENUM_CAST(RenderingServer::MultimeshTransformFormat); @@ -1534,18 +1498,26 @@ VARIANT_ENUM_CAST(RenderingServer::LightParam); VARIANT_ENUM_CAST(RenderingServer::LightBakeMode); VARIANT_ENUM_CAST(RenderingServer::LightOmniShadowMode); VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowMode); -VARIANT_ENUM_CAST(RenderingServer::LightDirectionalShadowDepthRangeMode); VARIANT_ENUM_CAST(RenderingServer::ReflectionProbeUpdateMode); VARIANT_ENUM_CAST(RenderingServer::ReflectionProbeAmbientMode); +VARIANT_ENUM_CAST(RenderingServer::VoxelGIQuality); VARIANT_ENUM_CAST(RenderingServer::DecalTexture); +VARIANT_ENUM_CAST(RenderingServer::ParticlesMode); +VARIANT_ENUM_CAST(RenderingServer::ParticlesTransformAlign); VARIANT_ENUM_CAST(RenderingServer::ParticlesDrawOrder); +VARIANT_ENUM_CAST(RenderingServer::ParticlesEmitFlags); +VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionType); +VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionHeightfieldResolution); VARIANT_ENUM_CAST(RenderingServer::ViewportUpdateMode); VARIANT_ENUM_CAST(RenderingServer::ViewportClearMode); VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA); VARIANT_ENUM_CAST(RenderingServer::ViewportScreenSpaceAA); VARIANT_ENUM_CAST(RenderingServer::ViewportRenderInfo); +VARIANT_ENUM_CAST(RenderingServer::ViewportRenderInfoType); VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw); VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality); +VARIANT_ENUM_CAST(RenderingServer::ViewportSDFOversize); +VARIANT_ENUM_CAST(RenderingServer::ViewportSDFScale); VARIANT_ENUM_CAST(RenderingServer::SkyMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG); VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource); @@ -1554,11 +1526,15 @@ VARIANT_ENUM_CAST(RenderingServer::EnvironmentGlowBlendMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSRRoughnessQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGICascades); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIFramesToConverge); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIRayCount); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIFramesToUpdateLight); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIYScale); VARIANT_ENUM_CAST(RenderingServer::SubSurfaceScatteringQuality); VARIANT_ENUM_CAST(RenderingServer::DOFBlurQuality); VARIANT_ENUM_CAST(RenderingServer::DOFBokehShape); VARIANT_ENUM_CAST(RenderingServer::ShadowQuality); -VARIANT_ENUM_CAST(RenderingServer::ScenarioDebugMode); VARIANT_ENUM_CAST(RenderingServer::InstanceType); VARIANT_ENUM_CAST(RenderingServer::InstanceFlags); VARIANT_ENUM_CAST(RenderingServer::ShadowCastingSetting); @@ -1571,8 +1547,10 @@ VARIANT_ENUM_CAST(RenderingServer::CanvasLightBlendMode); VARIANT_ENUM_CAST(RenderingServer::CanvasLightShadowFilter); VARIANT_ENUM_CAST(RenderingServer::CanvasOccluderPolygonCullMode); VARIANT_ENUM_CAST(RenderingServer::GlobalVariableType); -VARIANT_ENUM_CAST(RenderingServer::RenderInfo); +VARIANT_ENUM_CAST(RenderingServer::RenderingInfo); VARIANT_ENUM_CAST(RenderingServer::Features); +VARIANT_ENUM_CAST(RenderingServer::CanvasTextureChannel); +VARIANT_ENUM_CAST(RenderingServer::BakeChannels); // Alias to make it easier to use. #define RS RenderingServer diff --git a/servers/text_server.cpp b/servers/text_server.cpp index daed612b02..6f48148cab 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -466,16 +466,16 @@ void TextServer::initialize_hex_code_box_fonts() { Vector<uint8_t> hex_box_data; Ref<Image> image; - image.instance(); + image.instantiate(); Ref<ImageTexture> hex_code_image_tex[2]; hex_box_data.resize(tamsyn5x9_png_len); memcpy(hex_box_data.ptrw(), tamsyn5x9_png, tamsyn5x9_png_len); image->load_png_from_buffer(hex_box_data); - hex_code_image_tex[0].instance(); + hex_code_image_tex[0].instantiate(); hex_code_image_tex[0]->create_from_image(image); - hex_code_box_font_tex[0].instance(); + hex_code_box_font_tex[0].instantiate(); hex_code_box_font_tex[0]->set_diffuse_texture(hex_code_image_tex[0]); hex_code_box_font_tex[0]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); hex_box_data.clear(); @@ -483,9 +483,9 @@ void TextServer::initialize_hex_code_box_fonts() { hex_box_data.resize(tamsyn10x20_png_len); memcpy(hex_box_data.ptrw(), tamsyn10x20_png, tamsyn10x20_png_len); image->load_png_from_buffer(hex_box_data); - hex_code_image_tex[1].instance(); + hex_code_image_tex[1].instantiate(); hex_code_image_tex[1]->create_from_image(image); - hex_code_box_font_tex[1].instance(); + hex_code_box_font_tex[1].instantiate(); hex_code_box_font_tex[1]->set_diffuse_texture(hex_code_image_tex[1]); hex_code_box_font_tex[1]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); hex_box_data.clear(); diff --git a/servers/text_server.h b/servers/text_server.h index 7fcfb91151..138ceb9356 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -31,7 +31,7 @@ #ifndef TEXT_SERVER_H #define TEXT_SERVER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/templates/rid.h" #include "core/variant/variant.h" diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index 9148631899..09e8e12f8b 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "xr_interface.h" +#include "servers/rendering/renderer_compositor.h" void XRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name); @@ -45,7 +46,7 @@ void XRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tracking_status"), &XRInterface::get_tracking_status); ClassDB::bind_method(D_METHOD("get_render_targetsize"), &XRInterface::get_render_targetsize); - ClassDB::bind_method(D_METHOD("is_stereo"), &XRInterface::is_stereo); + ClassDB::bind_method(D_METHOD("get_view_count"), &XRInterface::get_view_count); ADD_GROUP("Interface", "interface_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_is_primary", "is_primary"); diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 8039018f35..6031bd7003 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -35,6 +35,9 @@ #include "core/os/thread_safe.h" #include "servers/xr_server.h" +// forward declaration +struct BlitToScreen; + /** @author Bastiaan Olij <mux213@gmail.com> @@ -47,8 +50,8 @@ Note that we may make this into a fully instantiable class for GDNative support. */ -class XRInterface : public Reference { - GDCLASS(XRInterface, Reference); +class XRInterface : public RefCounted { + GDCLASS(XRInterface, RefCounted); public: enum Capabilities { /* purely meta data, provides some info about what this interface supports */ @@ -105,17 +108,22 @@ public: /** rendering and internal **/ virtual Size2 get_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */ - virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */ - virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */ - virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */ - virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye); /* if applicable return external texture to render to */ - virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */ + virtual uint32_t get_view_count() = 0; /* returns the view count we need (1 is monoscopic, 2 is stereoscopic but can be more) */ + virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */ + virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */ + virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each view projection matrix */ + + virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */ virtual void process() = 0; virtual void notification(int p_what) = 0; XRInterface(); ~XRInterface(); + + // deprecated + virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye); /* if applicable return external texture to render to */ + virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */ }; VARIANT_ENUM_CAST(XRInterface::Capabilities); diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index 5341390045..e9383db941 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -194,8 +194,8 @@ void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHan }; }; -Transform XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const { - Transform new_transform; +Transform3D XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const { + Transform3D new_transform; new_transform.basis = get_orientation(); new_transform.origin = get_position(); diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index a5c6459471..5577582929 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -43,8 +43,8 @@ This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking. */ -class XRPositionalTracker : public Reference { - GDCLASS(XRPositionalTracker, Reference); +class XRPositionalTracker : public RefCounted { + GDCLASS(XRPositionalTracker, RefCounted); _THREAD_SAFE_CLASS_ public: @@ -93,7 +93,7 @@ public: void set_mesh(const Ref<Mesh> &p_mesh); Ref<Mesh> get_mesh() const; - Transform get_transform(bool p_adjust_by_reference_frame) const; + Transform3D get_transform(bool p_adjust_by_reference_frame) const; XRPositionalTracker(); ~XRPositionalTracker() {} diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 5678071857..b12fff319d 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -101,25 +101,25 @@ void XRServer::set_world_scale(real_t p_world_scale) { world_scale = p_world_scale; }; -Transform XRServer::get_world_origin() const { +Transform3D XRServer::get_world_origin() const { return world_origin; }; -void XRServer::set_world_origin(const Transform &p_world_origin) { +void XRServer::set_world_origin(const Transform3D &p_world_origin) { world_origin = p_world_origin; }; -Transform XRServer::get_reference_frame() const { +Transform3D XRServer::get_reference_frame() const { return reference_frame; }; void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) { if (primary_interface != nullptr) { // clear our current reference frame or we'll end up double adjusting it - reference_frame = Transform(); + reference_frame = Transform3D(); // requesting our EYE_MONO transform should return our current HMD position - Transform new_reference_frame = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform()); + Transform3D new_reference_frame = primary_interface->get_camera_transform(); // remove our tilt if (p_rotation_mode == 1) { @@ -145,10 +145,10 @@ void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) { }; }; -Transform XRServer::get_hmd_transform() { - Transform hmd_transform; +Transform3D XRServer::get_hmd_transform() { + Transform3D hmd_transform; if (primary_interface != nullptr) { - hmd_transform = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, hmd_transform); + hmd_transform = primary_interface->get_camera_transform(); }; return hmd_transform; }; diff --git a/servers/xr_server.h b/servers/xr_server.h index 46243d7fd0..25431844c2 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -31,7 +31,7 @@ #ifndef XR_SERVER_H #define XR_SERVER_H -#include "core/object/reference.h" +#include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/os/thread_safe.h" #include "core/templates/rid.h" @@ -82,8 +82,8 @@ private: Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ real_t world_scale; /* scale by which we multiply our tracker positions */ - Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ - Transform reference_frame; /* our reference frame */ + Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ + Transform3D reference_frame; /* our reference frame */ uint64_t last_process_usec; /* for frame timing, usec when we did our processing */ uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */ @@ -122,8 +122,8 @@ public: Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world and in the virtual world out of sync */ - Transform get_world_origin() const; - void set_world_origin(const Transform &p_world_origin); + Transform3D get_world_origin() const; + void set_world_origin(const Transform3D &p_world_origin); /* center_on_hmd calculates a new reference frame. This ensures the HMD is positioned to 0,0,0 facing 0,0,-1 (need to verify this direction) @@ -135,13 +135,13 @@ public: Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world and in the virtual world out of sync */ - Transform get_reference_frame() const; + Transform3D get_reference_frame() const; void center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height); /* get_hmd_transform gets our hmd transform (centered between eyes) with most up to date tracking, relative to the origin */ - Transform get_hmd_transform(); + Transform3D get_hmd_transform(); /* Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc. diff --git a/tests/test_aabb.h b/tests/test_aabb.h index 517c4dcefd..c4daa56e5a 100644 --- a/tests/test_aabb.h +++ b/tests/test_aabb.h @@ -50,8 +50,8 @@ TEST_CASE("[AABB] Constructor methods") { TEST_CASE("[AABB] String conversion") { CHECK_MESSAGE( - String(AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6))) == "-1.5, 2, -2.5 - 4, 5, 6", - "The string representation shouild match the expected value."); + String(AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6))) == "[P: (-1.5, 2, -2.5), S: (4, 5, 6)]", + "The string representation should match the expected value."); } TEST_CASE("[AABB] Basic getters") { @@ -278,24 +278,24 @@ TEST_CASE("[AABB] Get endpoints") { TEST_CASE("[AABB] Get longest/shortest axis") { const AABB aabb = AABB(Vector3(-1.5, 2, -2.5), Vector3(4, 5, 6)); CHECK_MESSAGE( - aabb.get_longest_axis().is_equal_approx(Vector3(0, 0, 1)), + aabb.get_longest_axis() == Vector3(0, 0, 1), "get_longest_axis() should return the expected value."); CHECK_MESSAGE( aabb.get_longest_axis_index() == Vector3::AXIS_Z, - "get_longest_axis() should return the expected value."); + "get_longest_axis_index() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_longest_axis_size(), 6), - "get_longest_axis() should return the expected value."); + aabb.get_longest_axis_size() == 6, + "get_longest_axis_size() should return the expected value."); CHECK_MESSAGE( - aabb.get_shortest_axis().is_equal_approx(Vector3(1, 0, 0)), + aabb.get_shortest_axis() == Vector3(1, 0, 0), "get_shortest_axis() should return the expected value."); CHECK_MESSAGE( aabb.get_shortest_axis_index() == Vector3::AXIS_X, - "get_shortest_axis() should return the expected value."); + "get_shortest_axis_index() should return the expected value."); CHECK_MESSAGE( - Math::is_equal_approx(aabb.get_shortest_axis_size(), 4), - "get_shortest_axis() should return the expected value."); + aabb.get_shortest_axis_size() == 4, + "get_shortest_axis_size() should return the expected value."); } #ifndef _MSC_VER diff --git a/tests/test_class_db.h b/tests/test_class_db.h index 9ef4569c14..29edf5a4a0 100644 --- a/tests/test_class_db.h +++ b/tests/test_class_db.h @@ -97,7 +97,7 @@ struct ExposedClass { bool is_singleton = false; bool is_instantiable = false; - bool is_reference = false; + bool is_ref_counted = false; ClassDB::APIType api_type; @@ -131,7 +131,7 @@ struct ExposedClass { struct NamesCache { StringName variant_type = StaticCString::create("Variant"); StringName object_class = StaticCString::create("Object"); - StringName reference_class = StaticCString::create("Reference"); + StringName ref_counted_class = StaticCString::create("RefCounted"); StringName string_type = StaticCString::create("String"); StringName string_name_type = StaticCString::create("StringName"); StringName node_path_type = StaticCString::create("NodePath"); @@ -240,10 +240,10 @@ bool arg_default_value_is_assignable_to_type(const Context &p_context, const Var p_arg_type.name == p_context.names_cache.node_path_type; case Variant::NODE_PATH: return p_arg_type.name == p_context.names_cache.node_path_type; - case Variant::TRANSFORM: + case Variant::TRANSFORM3D: case Variant::TRANSFORM2D: case Variant::BASIS: - case Variant::QUAT: + case Variant::QUATERNION: case Variant::PLANE: case Variant::AABB: case Variant::COLOR: @@ -516,7 +516,7 @@ void add_exposed_classes(Context &r_context) { exposed_class.api_type = api_type; exposed_class.is_singleton = Engine::get_singleton()->has_singleton(class_name); exposed_class.is_instantiable = class_info->creation_func && !exposed_class.is_singleton; - exposed_class.is_reference = ClassDB::is_parent_class(class_name, "Reference"); + exposed_class.is_ref_counted = ClassDB::is_parent_class(class_name, "RefCounted"); exposed_class.base = ClassDB::get_parent_class(class_name); // Add properties @@ -611,7 +611,7 @@ void add_exposed_classes(Context &r_context) { method.return_type.name = return_info.class_name; bool bad_reference_hint = !method.is_virtual && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE && - ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.reference_class); + ClassDB::is_parent_class(return_info.class_name, r_context.names_cache.ref_counted_class); TEST_COND(bad_reference_hint, "Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'.", " Are you returning a reference type by pointer? Method: '", exposed_class.name, ".", method.name, "'."); } else if (return_info.hint == PROPERTY_HINT_RESOURCE_TYPE) { @@ -665,7 +665,7 @@ void add_exposed_classes(Context &r_context) { TEST_COND(exposed_class.find_property_by_name(method.name), "Method name conflicts with property: '", String(class_name), ".", String(method.name), "'."); - // Classes starting with an underscore are ignored unless they're used as a property setter or getter + // Methods starting with an underscore are ignored unless they're virtual or used as a property setter or getter. if (!method.is_virtual && String(method.name)[0] == '_') { for (const List<PropertyData>::Element *F = exposed_class.properties.front(); F; F = F->next()) { const PropertyData &prop = F->get(); @@ -678,6 +678,10 @@ void add_exposed_classes(Context &r_context) { } else { exposed_class.methods.push_back(method); } + + if (method.is_virtual) { + TEST_COND(String(method.name)[0] != '_', "Virtual method ", String(method.name), " does not start with underscore."); + } } // Add signals @@ -750,6 +754,9 @@ void add_exposed_classes(Context &r_context) { const List<StringName> &enum_constants = enum_map.get(*k); for (const List<StringName>::Element *E = enum_constants.front(); E; E = E->next()) { const StringName &constant_name = E->get(); + TEST_FAIL_COND(String(constant_name).find("::") != -1, + "Enum constant contains '::', check bindings to remove the scope: '", + String(class_name), ".", String(enum_.name), ".", String(constant_name), "'."); int *value = class_info->constant_map.getptr(constant_name); TEST_FAIL_COND(!value, "Missing enum constant value: '", String(class_name), ".", String(enum_.name), ".", String(constant_name), "'."); @@ -769,8 +776,11 @@ void add_exposed_classes(Context &r_context) { for (const List<String>::Element *E = constants.front(); E; E = E->next()) { const String &constant_name = E->get(); + TEST_FAIL_COND(constant_name.find("::") != -1, + "Constant contains '::', check bindings to remove the scope: '", + String(class_name), ".", constant_name, "'."); int *value = class_info->constant_map.getptr(StringName(E->get())); - TEST_FAIL_COND(!value, "Missing enum constant value: '", String(class_name), ".", String(constant_name), "'."); + TEST_FAIL_COND(!value, "Missing constant value: '", String(class_name), ".", String(constant_name), "'."); ConstantData constant; constant.name = constant_name; diff --git a/tests/test_color.h b/tests/test_color.h index ad4a7cd3f2..bffa890ae2 100644 --- a/tests/test_color.h +++ b/tests/test_color.h @@ -140,7 +140,7 @@ TEST_CASE("[Color] Conversion methods") { cyan.to_rgba64() == 0x0000'ffff'ffff'ffff, "The returned 64-bit BGR number should match the expected value."); CHECK_MESSAGE( - String(cyan) == "0, 1, 1, 1", + String(cyan) == "(0, 1, 1, 1)", "The string representation should match the expected value."); } diff --git a/tests/test_command_queue.h b/tests/test_command_queue.h index 2f0f62f5c8..f0d4569942 100644 --- a/tests/test_command_queue.h +++ b/tests/test_command_queue.h @@ -127,20 +127,20 @@ public: int func1_count = 0; - void func1(Transform t) { + void func1(Transform3D t) { func1_count++; } - void func2(Transform t, float f) { + void func2(Transform3D t, float f) { func1_count++; } - void func3(Transform t1, Transform t2, Transform t3, Transform t4, Transform t5, Transform t6) { + void func3(Transform3D t1, Transform3D t2, Transform3D t3, Transform3D t4, Transform3D t5, Transform3D t6) { func1_count++; } - Transform func1r(Transform t) { + Transform3D func1r(Transform3D t) { func1_count++; return t; } - Transform func2r(Transform t, float f) { + Transform3D func2r(Transform3D t, float f) { func1_count++; return t; } @@ -156,7 +156,7 @@ public: command_queue.flush_all(); } for (int i = 0; i < message_count_to_read; i++) { - command_queue.wait_and_flush_one(); + command_queue.wait_and_flush(); } message_count_to_read = 0; @@ -175,8 +175,8 @@ public: during_writing = false; writer_threadwork.thread_wait_for_work(); while (!exit_threads) { - Transform tr; - Transform otr; + Transform3D tr; + Transform3D otr; float f = 1; during_writing = true; for (int i = 0; i < message_types_to_write.size(); i++) { @@ -276,50 +276,6 @@ TEST_CASE("[CommandQueue] Test Queue Basics") { ProjectSettings::get_singleton()->property_get_revert(COMMAND_QUEUE_SETTING)); } -TEST_CASE("[CommandQueue] Test Waiting at Queue Full") { - const char *COMMAND_QUEUE_SETTING = "memory/limits/command_queue/multithreading_queue_size_kb"; - ProjectSettings::get_singleton()->set_setting(COMMAND_QUEUE_SETTING, 1); - SharedThreadState sts; - sts.init_threads(); - - int msgs_to_add = 24; // a queue of size 1kB fundamentally cannot fit 24 matrices. - for (int i = 0; i < msgs_to_add; i++) { - sts.add_msg_to_write(SharedThreadState::TEST_MSG_FUNC1_TRANSFORM); - } - sts.writer_threadwork.main_start_work(); - // If we call main_wait_for_done, we will deadlock. So instead... - sts.message_count_to_read = 1; - sts.reader_threadwork.main_start_work(); - sts.reader_threadwork.main_wait_for_done(); - CHECK_MESSAGE(sts.func1_count == 1, - "Reader should have read one message"); - CHECK_MESSAGE(sts.during_writing, - "Writer thread should still be blocked on writing."); - sts.message_count_to_read = msgs_to_add - 3; - sts.reader_threadwork.main_start_work(); - sts.reader_threadwork.main_wait_for_done(); - CHECK_MESSAGE(sts.func1_count >= msgs_to_add - 3, - "Reader should have read most messages"); - sts.writer_threadwork.main_wait_for_done(); - CHECK_MESSAGE(sts.during_writing == false, - "Writer thread should no longer be blocked on writing."); - sts.message_count_to_read = 2; - sts.reader_threadwork.main_start_work(); - sts.reader_threadwork.main_wait_for_done(); - sts.message_count_to_read = -1; - sts.reader_threadwork.main_start_work(); - sts.reader_threadwork.main_wait_for_done(); - CHECK_MESSAGE(sts.func1_count == msgs_to_add, - "Reader should have read all messages"); - - sts.destroy_threads(); - - CHECK_MESSAGE(sts.func1_count == msgs_to_add, - "Reader should have read no additional messages after join"); - ProjectSettings::get_singleton()->set_setting(COMMAND_QUEUE_SETTING, - ProjectSettings::get_singleton()->property_get_revert(COMMAND_QUEUE_SETTING)); -} - TEST_CASE("[CommandQueue] Test Queue Wrapping to same spot.") { const char *COMMAND_QUEUE_SETTING = "memory/limits/command_queue/multithreading_queue_size_kb"; ProjectSettings::get_singleton()->set_setting(COMMAND_QUEUE_SETTING, 1); diff --git a/tests/test_config_file.h b/tests/test_config_file.h index 958341018b..33fd30ffa1 100644 --- a/tests/test_config_file.h +++ b/tests/test_config_file.h @@ -138,8 +138,8 @@ name="Unnamed Player" tagline="Waiting for Godot" -color=Color( 0, 0.5, 1, 1 ) -position=Vector2( 3, 4 ) +color=Color(0, 0.5, 1, 1) +position=Vector2(3, 4) [graphics] diff --git a/tests/test_curve.h b/tests/test_curve.h index 3055cfd97b..7eeee86f32 100644 --- a/tests/test_curve.h +++ b/tests/test_curve.h @@ -80,7 +80,7 @@ TEST_CASE("[Curve] Custom curve with free tangents") { "Custom free curve should contain the expected number of points."); CHECK_MESSAGE( - Math::is_equal_approx(curve->interpolate(-0.1), 0), + Math::is_zero_approx(curve->interpolate(-0.1)), "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( Math::is_equal_approx(curve->interpolate(0.1), (real_t)0.352), @@ -99,7 +99,7 @@ TEST_CASE("[Curve] Custom curve with free tangents") { "Custom free curve should return the expected value at offset 0.1."); CHECK_MESSAGE( - Math::is_equal_approx(curve->interpolate_baked(-0.1), 0), + Math::is_zero_approx(curve->interpolate_baked(-0.1)), "Custom free curve should return the expected baked value at offset 0.1."); CHECK_MESSAGE( Math::is_equal_approx(curve->interpolate_baked(0.1), (real_t)0.352), @@ -169,7 +169,7 @@ TEST_CASE("[Curve] Custom curve with linear tangents") { "Custom linear curve should contain the expected number of points."); CHECK_MESSAGE( - Math::is_equal_approx(curve->interpolate(-0.1), 0), + Math::is_zero_approx(curve->interpolate(-0.1)), "Custom linear curve should return the expected value at offset -0.1."); CHECK_MESSAGE( Math::is_equal_approx(curve->interpolate(0.1), (real_t)0.4), @@ -188,7 +188,7 @@ TEST_CASE("[Curve] Custom curve with linear tangents") { "Custom linear curve should return the expected value at offset 2.0."); CHECK_MESSAGE( - Math::is_equal_approx(curve->interpolate_baked(-0.1), 0), + Math::is_zero_approx(curve->interpolate_baked(-0.1)), "Custom linear curve should return the expected baked value at offset -0.1."); CHECK_MESSAGE( Math::is_equal_approx(curve->interpolate_baked(0.1), (real_t)0.4), diff --git a/tests/test_file_access.h b/tests/test_file_access.h index 00a314644c..cb74e08a0d 100644 --- a/tests/test_file_access.h +++ b/tests/test_file_access.h @@ -31,7 +31,7 @@ #ifndef TEST_FILE_ACCESS_H #define TEST_FILE_ACCESS_H -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "test_utils.h" namespace TestFileAccess { diff --git a/tests/test_json.h b/tests/test_json.h index f1cb4799dc..3af58dfa1c 100644 --- a/tests/test_json.h +++ b/tests/test_json.h @@ -45,75 +45,65 @@ TEST_CASE("[JSON] Parsing single data types") { // Parsing a single data type as JSON is valid per the JSON specification. JSON json; - Variant result; - String err_str; - int err_line; - json.parse("null", result, err_str, err_line); + json.parse("null"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing `null` as JSON should parse successfully."); CHECK_MESSAGE( - result == Variant(), + json.get_data() == Variant(), "Parsing a double quoted string as JSON should return the expected value."); - json.parse("true", result, err_str, err_line); + json.parse("true"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing boolean `true` as JSON should parse successfully."); CHECK_MESSAGE( - result, + json.get_data(), "Parsing boolean `true` as JSON should return the expected value."); - json.parse("false", result, err_str, err_line); + json.parse("false"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing boolean `false` as JSON should parse successfully."); CHECK_MESSAGE( - !result, + !json.get_data(), "Parsing boolean `false` as JSON should return the expected value."); - // JSON only has a floating-point number type, no integer type. - // This is why we use `is_equal_approx()` for the comparison. - json.parse("123456", result, err_str, err_line); + json.parse("123456"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing an integer number as JSON should parse successfully."); CHECK_MESSAGE( - (int)result == 123'456, + (int)(json.get_data()) == 123456, "Parsing an integer number as JSON should return the expected value."); - json.parse("0.123456", result, err_str, err_line); + json.parse("0.123456"); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing a floating-point number as JSON should parse successfully."); CHECK_MESSAGE( - Math::is_equal_approx(result, 0.123456), + Math::is_equal_approx(double(json.get_data()), 0.123456), "Parsing a floating-point number as JSON should return the expected value."); - json.parse("\"hello\"", result, err_str, err_line); + json.parse("\"hello\""); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing a double quoted string as JSON should parse successfully."); CHECK_MESSAGE( - result == "hello", + json.get_data() == "hello", "Parsing a double quoted string as JSON should return the expected value."); } TEST_CASE("[JSON] Parsing arrays") { JSON json; - Variant result; - String err_str; - int err_line; // JSON parsing fails if it's split over several lines (even if leading indentation is removed). - json.parse( - R"(["Hello", "world.", "This is",["a","json","array.",[]], "Empty arrays ahoy:", [[["Gotcha!"]]]])", - result, err_str, err_line); + json.parse(R"(["Hello", "world.", "This is",["a","json","array.",[]], "Empty arrays ahoy:", [[["Gotcha!"]]]])"); - const Array array = result; + const Array array = json.get_data(); CHECK_MESSAGE( - err_line == 0, + json.get_error_line() == 0, "Parsing a JSON array should parse successfully."); CHECK_MESSAGE( array[0] == "Hello", @@ -136,15 +126,10 @@ TEST_CASE("[JSON] Parsing arrays") { TEST_CASE("[JSON] Parsing objects (dictionaries)") { JSON json; - Variant result; - String err_str; - int err_line; - json.parse( - R"({"name": "Godot Engine", "is_free": true, "bugs": null, "apples": {"red": 500, "green": 0, "blue": -20}, "empty_object": {}})", - result, err_str, err_line); + json.parse(R"({"name": "Godot Engine", "is_free": true, "bugs": null, "apples": {"red": 500, "green": 0, "blue": -20}, "empty_object": {}})"); - const Dictionary dictionary = result; + const Dictionary dictionary = json.get_data(); CHECK_MESSAGE( dictionary["name"] == "Godot Engine", "The parsed JSON should contain the expected values."); diff --git a/tests/test_macros.h b/tests/test_macros.h index a13f3abbe7..a1f1932db4 100644 --- a/tests/test_macros.h +++ b/tests/test_macros.h @@ -91,10 +91,10 @@ DOCTEST_STRINGIFY_VARIANT(Vector3); DOCTEST_STRINGIFY_VARIANT(Vector3i); DOCTEST_STRINGIFY_VARIANT(Transform2D); DOCTEST_STRINGIFY_VARIANT(Plane); -DOCTEST_STRINGIFY_VARIANT(Quat); +DOCTEST_STRINGIFY_VARIANT(Quaternion); DOCTEST_STRINGIFY_VARIANT(AABB); DOCTEST_STRINGIFY_VARIANT(Basis); -DOCTEST_STRINGIFY_VARIANT(Transform); +DOCTEST_STRINGIFY_VARIANT(Transform3D); DOCTEST_STRINGIFY_VARIANT(::Color); // Disambiguate from `doctest::Color`. DOCTEST_STRINGIFY_VARIANT(StringName); diff --git a/tests/test_main.cpp b/tests/test_main.cpp index 54327caf3d..d0466d1e2d 100644 --- a/tests/test_main.cpp +++ b/tests/test_main.cpp @@ -74,6 +74,7 @@ #include "test_shader_lang.h" #include "test_string.h" #include "test_text_server.h" +#include "test_time.h" #include "test_translation.h" #include "test_validate_testing.h" #include "test_variant.h" diff --git a/tests/test_math.cpp b/tests/test_math.cpp index 88c32713ed..67d9a52539 100644 --- a/tests/test_math.cpp +++ b/tests/test_math.cpp @@ -30,13 +30,13 @@ #include "test_math.h" +#include "core/io/file_access.h" #include "core/math/basis.h" #include "core/math/camera_matrix.h" #include "core/math/delaunay_3d.h" #include "core/math/geometry_2d.h" #include "core/math/math_funcs.h" -#include "core/math/transform.h" -#include "core/os/file_access.h" +#include "core/math/transform_3d.h" #include "core/os/keyboard.h" #include "core/os/os.h" #include "core/string/print_string.h" @@ -599,13 +599,13 @@ MainLoop *test() { Basis m2(v2, a2); - Quat q = m; - Quat q2 = m2; + Quaternion q = m; + Quaternion q2 = m2; Basis m3 = m.inverse() * m2; - Quat q3 = (q.inverse() * q2); //.normalized(); + Quaternion q3 = (q.inverse() * q2); //.normalized(); - print_line(Quat(m3)); + print_line(Quaternion(m3)); print_line(q3); print_line("before v: " + v + " a: " + rtos(a)); diff --git a/tests/test_object.h b/tests/test_object.h index 142d76553d..b7eedc2670 100644 --- a/tests/test_object.h +++ b/tests/test_object.h @@ -93,35 +93,8 @@ public: Ref<Script> get_script() const override { return Ref<Script>(); } - Vector<ScriptNetData> get_rpc_methods() const override { - return Vector<ScriptNetData>(); - } - uint16_t get_rpc_method_id(const StringName &p_method) const override { - return 0; - } - StringName get_rpc_method(uint16_t p_id) const override { - return StringName(); - } - MultiplayerAPI::RPCMode get_rpc_mode_by_id(uint16_t p_id) const override { - return MultiplayerAPI::RPC_MODE_PUPPET; - } - MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const override { - return MultiplayerAPI::RPC_MODE_PUPPET; - } - Vector<ScriptNetData> get_rset_properties() const override { - return Vector<ScriptNetData>(); - } - uint16_t get_rset_property_id(const StringName &p_variable) const override { - return 0; - } - StringName get_rset_property(uint16_t p_id) const override { - return StringName(); - } - MultiplayerAPI::RPCMode get_rset_mode_by_id(uint16_t p_id) const override { - return MultiplayerAPI::RPC_MODE_PUPPET; - } - MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const override { - return MultiplayerAPI::RPC_MODE_PUPPET; + const Vector<MultiplayerAPI::RPCConfig> get_rpc_methods() const override { + return Vector<MultiplayerAPI::RPCConfig>(); } ScriptLanguage *get_language() override { return nullptr; @@ -192,8 +165,8 @@ TEST_CASE("[Object] Construction") { Object object; CHECK_MESSAGE( - !object.is_reference(), - "Object is not a Reference."); + !object.is_ref_counted(), + "Object is not a RefCounted."); Object *p_db = ObjectDB::get_instance(object.get_instance_id()); CHECK_MESSAGE( diff --git a/tests/test_physics_3d.cpp b/tests/test_physics_3d.cpp index 727c44b3ac..4488e4bf64 100644 --- a/tests/test_physics_3d.cpp +++ b/tests/test_physics_3d.cpp @@ -70,14 +70,14 @@ class TestPhysics3DMainLoop : public MainLoop { void body_changed_transform(Object *p_state, RID p_visual_instance) { PhysicsDirectBodyState3D *state = (PhysicsDirectBodyState3D *)p_state; RenderingServer *vs = RenderingServer::get_singleton(); - Transform t = state->get_transform(); + Transform3D t = state->get_transform(); vs->instance_set_transform(p_visual_instance, t); } bool quit; protected: - RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform p_location, bool p_active_default = true, const Transform &p_shape_xform = Transform()) { + RID create_body(PhysicsServer3D::ShapeType p_shape, PhysicsServer3D::BodyMode p_body, const Transform3D p_location, bool p_active_default = true, const Transform3D &p_shape_xform = Transform3D()) { RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); @@ -179,7 +179,7 @@ protected: type_shape_map[PhysicsServer3D::SHAPE_CONVEX_POLYGON] = convex_shape; } - void make_trimesh(Vector<Vector3> p_faces, const Transform &p_xform = Transform()) { + void make_trimesh(Vector<Vector3> p_faces, const Transform3D &p_xform = Transform3D()) { RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); RID trimesh_shape = ps->shape_create(PhysicsServer3D::SHAPE_CONCAVE_POLYGON); @@ -209,12 +209,12 @@ protected: ps->body_set_space(tribody, space); //todo set space ps->body_add_shape(tribody, trimesh_shape); - Transform tritrans = p_xform; + Transform3D tritrans = p_xform; ps->body_set_state(tribody, PhysicsServer3D::BODY_STATE_TRANSFORM, tritrans); vs->instance_set_transform(triins, tritrans); } - void make_grid(int p_width, int p_height, real_t p_cellsize, real_t p_cellheight, const Transform &p_xform = Transform()) { + void make_grid(int p_width, int p_height, real_t p_cellsize, real_t p_cellheight, const Transform3D &p_xform = Transform3D()) { Vector<Vector<real_t>> grid; grid.resize(p_width); @@ -261,7 +261,7 @@ public: if (mover.is_valid()) { PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); + Transform3D t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); t.origin += Vector3(x, y, 0); ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); @@ -287,7 +287,7 @@ public: scenario = vs->scenario_create(); vs->light_set_shadow(lightaux, true); light = vs->instance_create2(lightaux, scenario); - Transform t; + Transform3D t; t.rotate(Vector3(1.0, 0, 0), 0.6); vs->instance_set_transform(light, t); @@ -304,9 +304,9 @@ public: vs->viewport_set_scenario(viewport, scenario); vs->camera_set_perspective(camera, 60, 0.1, 40.0); - vs->camera_set_transform(camera, Transform(Basis(), Vector3(0, 9, 12))); + vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 9, 12))); - Transform gxf; + Transform3D gxf; gxf.basis.scale(Vector3(1.4, 0.4, 1.4)); gxf.origin = Vector3(-2, 1, -2); make_grid(5, 5, 2.5, 1, gxf); @@ -317,12 +317,12 @@ public: if (mover.is_valid()) { static real_t joy_speed = 10; PhysicsServer3D *ps = PhysicsServer3D::get_singleton(); - Transform t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); + Transform3D t = ps->body_get_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM); t.origin += Vector3(joy_speed * joy_direction.x * p_time, -joy_speed * joy_direction.y * p_time, 0); ps->body_set_state(mover, PhysicsServer3D::BODY_STATE_TRANSFORM, t); }; - Transform cameratr; + Transform3D cameratr; cameratr.rotate(Vector3(0, 1, 0), ofs_x); cameratr.rotate(Vector3(1, 0, 0), -ofs_y); cameratr.translate(Vector3(0, 2, 8)); @@ -355,20 +355,20 @@ public: Dictionary capsule_params; capsule_params["radius"] = 0.5; capsule_params["height"] = 1; - Transform shape_xform; + Transform3D shape_xform; shape_xform.rotate(Vector3(1, 0, 0), Math_PI / 2.0); //shape_xform.origin=Vector3(1,1,1); ps->shape_set_data(capsule_shape, capsule_params); RID mesh_instance = vs->instance_create2(capsule_mesh, scenario); character = ps->body_create(); - ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_CHARACTER); + ps->body_set_mode(character, PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED); ps->body_set_space(character, space); //todo add space ps->body_add_shape(character, capsule_shape); ps->body_set_force_integration_callback(character, callable_mp(this, &TestPhysics3DMainLoop::body_changed_transform), mesh_instance); - ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform(Basis(), Vector3(-2, 5, -2))); + ps->body_set_state(character, PhysicsServer3D::BODY_STATE_TRANSFORM, Transform3D(Basis(), Vector3(-2, 5, -2))); bodies.push_back(character); } @@ -383,19 +383,19 @@ public: PhysicsServer3D::ShapeType type = shape_idx[i % 4]; - Transform t; + Transform3D t; t.origin = Vector3(0.0 * i, 3.5 + 1.1 * i, 0.7 + 0.0 * i); t.basis.rotate(Vector3(0.2, -1, 0), Math_PI / 2 * 0.6); - create_body(type, PhysicsServer3D::BODY_MODE_RIGID, t); + create_body(type, PhysicsServer3D::BODY_MODE_DYNAMIC, t); } create_static_plane(Plane(Vector3(0, 1, 0), -1)); } void test_activate() { - create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_RIGID, Transform(Basis(), Vector3(0, 2, 0)), true); + create_body(PhysicsServer3D::SHAPE_BOX, PhysicsServer3D::BODY_MODE_DYNAMIC, Transform3D(Basis(), Vector3(0, 2, 0)), true); create_static_plane(Plane(Vector3(0, 1, 0), -1)); } diff --git a/tests/test_rect2.h b/tests/test_rect2.h index 821aa69970..c5740167db 100644 --- a/tests/test_rect2.h +++ b/tests/test_rect2.h @@ -61,7 +61,7 @@ TEST_CASE("[Rect2] Constructor methods") { TEST_CASE("[Rect2] String conversion") { // Note: This also depends on the Vector2 string representation. CHECK_MESSAGE( - String(Rect2(0, 100, 1280, 720)) == "0, 100, 1280, 720", + String(Rect2(0, 100, 1280, 720)) == "[P: (0, 100), S: (1280, 720)]", "The string representation should match the expected value."); } @@ -273,7 +273,7 @@ TEST_CASE("[Rect2i] Constructor methods") { TEST_CASE("[Rect2i] String conversion") { // Note: This also depends on the Vector2 string representation. CHECK_MESSAGE( - String(Rect2i(0, 100, 1280, 720)) == "0, 100, 1280, 720", + String(Rect2i(0, 100, 1280, 720)) == "[P: (0, 100), S: (1280, 720)]", "The string representation should match the expected value."); } diff --git a/tests/test_render.cpp b/tests/test_render.cpp index 9737fd03f3..fe223ca258 100644 --- a/tests/test_render.cpp +++ b/tests/test_render.cpp @@ -53,7 +53,7 @@ class TestMainLoop : public MainLoop { struct InstanceInfo { RID instance; - Transform base; + Transform3D base; Vector3 rot_axis; }; @@ -165,7 +165,7 @@ public: vs->viewport_set_active(viewport, true); vs->viewport_attach_camera(viewport, camera); vs->viewport_set_scenario(viewport, scenario); - vs->camera_set_transform(camera, Transform(Basis(), Vector3(0, 3, 30))); + vs->camera_set_transform(camera, Transform3D(Basis(), Vector3(0, 3, 30))); vs->camera_set_perspective(camera, 60, 0.1, 1000); /* @@ -182,7 +182,7 @@ public: vs->light_set_color(lightaux, Color(1.0, 1.0, 1.0)); //vs->light_set_shadow( lightaux, true ); light = vs->instance_create2(lightaux, scenario); - Transform lla; + Transform3D lla; //lla.set_look_at(Vector3(),Vector3(1, -1, 1)); lla.set_look_at(Vector3(), Vector3(0.0, -0.836026, -0.548690)); @@ -201,7 +201,7 @@ public: } virtual bool iteration(float p_time) { RenderingServer *vs = RenderingServer::get_singleton(); - //Transform t; + //Transform3D t; //t.rotate(Vector3(0, 1, 0), ofs); //t.translate(Vector3(0,0,20 )); //vs->camera_set_transform(camera, t); @@ -211,7 +211,7 @@ public: //return quit; for (List<InstanceInfo>::Element *E = instances.front(); E; E = E->next()) { - Transform pre(Basis(E->get().rot_axis, ofs), Vector3()); + Transform3D pre(Basis(E->get().rot_axis, ofs), Vector3()); vs->instance_set_transform(E->get().instance, pre * E->get().base); /* if( !E->next() ) { diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp index 2169350c02..ad763b344e 100644 --- a/tests/test_shader_lang.cpp +++ b/tests/test_shader_lang.cpp @@ -30,7 +30,7 @@ #include "test_shader_lang.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "core/os/main_loop.h" #include "core/os/os.h" diff --git a/tests/test_string.h b/tests/test_string.h index 6e214574af..1982d8de60 100644 --- a/tests/test_string.h +++ b/tests/test_string.h @@ -1130,7 +1130,7 @@ TEST_CASE("[String] Path functions") { CHECK(String(path[i]).get_basename() == base_name[i]); CHECK(String(path[i]).get_extension() == ext[i]); CHECK(String(path[i]).get_file() == file[i]); - CHECK(String(path[i]).is_abs_path() == abs[i]); + CHECK(String(path[i]).is_absolute_path() == abs[i]); CHECK(String(path[i]).is_rel_path() != abs[i]); CHECK(String(path[i]).simplify_path().get_base_dir().plus_file(file[i]) == String(path[i]).simplify_path()); } @@ -1317,7 +1317,7 @@ TEST_CASE("[String] Is_*") { for (int i = 0; i < 12; i++) { String s = String(data[i]); CHECK(s.is_numeric() == isnum[i]); - CHECK(s.is_valid_integer() == isint[i]); + CHECK(s.is_valid_int() == isint[i]); CHECK(s.is_valid_hex_number(false) == ishex[i]); CHECK(s.is_valid_hex_number(true) == ishex_p[i]); CHECK(s.is_valid_float() == isflt[i]); diff --git a/tests/test_time.h b/tests/test_time.h new file mode 100644 index 0000000000..28f1cb2f20 --- /dev/null +++ b/tests/test_time.h @@ -0,0 +1,145 @@ +/*************************************************************************/ +/* test_time.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#ifndef TEST_TIME_H +#define TEST_TIME_H + +#include "core/os/time.h" + +#include "thirdparty/doctest/doctest.h" + +#define YEAR_KEY "year" +#define MONTH_KEY "month" +#define DAY_KEY "day" +#define WEEKDAY_KEY "weekday" +#define HOUR_KEY "hour" +#define MINUTE_KEY "minute" +#define SECOND_KEY "second" +#define DST_KEY "dst" + +namespace TestTime { + +TEST_CASE("[Time] Unix time conversion to/from datetime string") { + const Time *time = Time::get_singleton(); + + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1970-01-01T00:00:00") == 0, "Time get_unix_time_from_datetime_string: The timestamp for Unix epoch is zero."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1970-01-01 00:00:00") == 0, "Time get_unix_time_from_datetime_string: The timestamp for Unix epoch with space is zero."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1970-01-01") == 0, "Time get_unix_time_from_datetime_string: The timestamp for Unix epoch without time is zero."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("00:00:00") == 0, "Time get_unix_time_from_datetime_string: The timestamp for zero time without date is zero."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1969-12-31T23:59:59") == -1, "Time get_unix_time_from_datetime_string: The timestamp for just before Unix epoch is negative one."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1234-05-06T07:08:09") == -23215049511, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary datetime is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1234-05-06 07:08:09") == -23215049511, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary datetime with space is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1234-05-06") == -23215075200, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary date without time is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("07:08:09") == 25689, "Time get_unix_time_from_datetime_string: The timestamp for an arbitrary time without date is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("2014-02-09T22:10:30") == 1391983830, "Time get_unix_time_from_datetime_string: The timestamp for GODOT IS OPEN SOURCE is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("2014-02-09 22:10:30") == 1391983830, "Time get_unix_time_from_datetime_string: The timestamp for GODOT IS OPEN SOURCE with space is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("2014-02-09") == 1391904000, "Time get_unix_time_from_datetime_string: The date for GODOT IS OPEN SOURCE without time is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("22:10:30") == 79830, "Time get_unix_time_from_datetime_string: The time for GODOT IS OPEN SOURCE without date is as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("-1000000000-01-01T00:00:00") == -31557014167219200, "Time get_unix_time_from_datetime_string: In the year negative a billion, Japan might not have been here."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string("1000000-01-01T00:00:00") == 31494784780800, "Time get_unix_time_from_datetime_string: The timestamp for the year a million is as expected."); + + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(0) == "1970-01-01T00:00:00", "Time get_datetime_string_from_unix_time: The timestamp string for Unix epoch is zero."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(0, true) == "1970-01-01 00:00:00", "Time get_datetime_string_from_unix_time: The timestamp string for Unix epoch with space is zero."); + CHECK_MESSAGE(time->get_date_string_from_unix_time(0) == "1970-01-01", "Time get_date_string_from_unix_time: The date string for zero is Unix epoch date."); + CHECK_MESSAGE(time->get_time_string_from_unix_time(0) == "00:00:00", "Time get_time_string_from_unix_time: The date for zero zero is Unix epoch date."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(-1) == "1969-12-31T23:59:59", "Time get_time_string_from_unix_time: The timestamp string for just before Unix epoch is as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(-23215049511) == "1234-05-06T07:08:09", "Time get_datetime_string_from_unix_time: The timestamp for an arbitrary datetime is as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(-23215049511, true) == "1234-05-06 07:08:09", "Time get_datetime_string_from_unix_time: The timestamp for an arbitrary datetime with space is as expected."); + CHECK_MESSAGE(time->get_date_string_from_unix_time(-23215075200) == "1234-05-06", "Time get_date_string_from_unix_time: The timestamp for an arbitrary date without time is as expected."); + CHECK_MESSAGE(time->get_time_string_from_unix_time(25689) == "07:08:09", "Time get_time_string_from_unix_time: The timestamp for an arbitrary time without date is as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(1391983830) == "2014-02-09T22:10:30", "Time get_datetime_string_from_unix_time: The timestamp for GODOT IS OPEN SOURCE is as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(1391983830, true) == "2014-02-09 22:10:30", "Time get_datetime_string_from_unix_time: The timestamp for GODOT IS OPEN SOURCE with space is as expected."); + CHECK_MESSAGE(time->get_date_string_from_unix_time(1391904000) == "2014-02-09", "Time get_date_string_from_unix_time: The date for GODOT IS OPEN SOURCE without time is as expected."); + CHECK_MESSAGE(time->get_time_string_from_unix_time(79830) == "22:10:30", "Time get_time_string_from_unix_time: The time for GODOT IS OPEN SOURCE without date is as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_unix_time(31494784780800) == "1000000-01-01T00:00:00", "Time get_datetime_string_from_unix_time: The timestamp for the year a million is as expected."); +} + +TEST_CASE("[Time] Datetime dictionary conversion methods") { + const Time *time = Time::get_singleton(); + + Dictionary datetime; + datetime[YEAR_KEY] = 2014; + datetime[MONTH_KEY] = 2; + datetime[DAY_KEY] = 9; + datetime[WEEKDAY_KEY] = Time::Weekday::WEEKDAY_SUNDAY; + datetime[HOUR_KEY] = 22; + datetime[MINUTE_KEY] = 10; + datetime[SECOND_KEY] = 30; + + Dictionary date_only; + date_only[YEAR_KEY] = 2014; + date_only[MONTH_KEY] = 2; + date_only[DAY_KEY] = 9; + date_only[WEEKDAY_KEY] = Time::Weekday::WEEKDAY_SUNDAY; + + Dictionary time_only; + time_only[HOUR_KEY] = 22; + time_only[MINUTE_KEY] = 10; + time_only[SECOND_KEY] = 30; + + CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(datetime) == 1391983830, "Time get_unix_time_from_datetime_dict: The datetime dictionary for GODOT IS OPEN SOURCE is converted to a timestamp as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(date_only) == 1391904000, "Time get_unix_time_from_datetime_dict: The date dictionary for GODOT IS OPEN SOURCE is converted to a timestamp as expected."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time_only) == 79830, "Time get_unix_time_from_datetime_dict: The time dictionary for GODOT IS OPEN SOURCE is converted to a timestamp as expected."); + + CHECK_MESSAGE(time->get_datetime_dict_from_unix_time(1391983830).hash() == datetime.hash(), "Time get_datetime_dict_from_unix_time: The datetime timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected."); + CHECK_MESSAGE(time->get_date_dict_from_unix_time(1391904000).hash() == date_only.hash(), "Time get_date_dict_from_unix_time: The date timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected."); + CHECK_MESSAGE(time->get_time_dict_from_unix_time(79830).hash() == time_only.hash(), "Time get_time_dict_from_unix_time: The time timestamp for GODOT IS OPEN SOURCE is converted to a dictionary as expected."); + + CHECK_MESSAGE((Time::Weekday)(int)time->get_datetime_dict_from_unix_time(0)[WEEKDAY_KEY] == Time::Weekday::WEEKDAY_THURSDAY, "Time get_datetime_dict_from_unix_time: The weekday for the Unix epoch is a Thursday as expected."); + CHECK_MESSAGE((Time::Weekday)(int)time->get_datetime_dict_from_unix_time(1391983830)[WEEKDAY_KEY] == Time::Weekday::WEEKDAY_SUNDAY, "Time get_datetime_dict_from_unix_time: The weekday for GODOT IS OPEN SOURCE is a Sunday as expected."); + + CHECK_MESSAGE(time->get_datetime_dict_from_string("2014-02-09T22:10:30").hash() == datetime.hash(), "Time get_datetime_dict_from_string: The dictionary from string for GODOT IS OPEN SOURCE works as expected."); + CHECK_MESSAGE(!time->get_datetime_dict_from_string("2014-02-09T22:10:30", false).has(WEEKDAY_KEY), "Time get_datetime_dict_from_string: The dictionary from string for GODOT IS OPEN SOURCE without weekday doesn't contain the weekday key as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_dict(datetime) == "2014-02-09T22:10:30", "Time get_datetime_string_from_dict: The string from dictionary for GODOT IS OPEN SOURCE works as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_dict(time->get_datetime_dict_from_string("2014-02-09T22:10:30")) == "2014-02-09T22:10:30", "Time get_datetime_string_from_dict: The round-trip string to dict to string GODOT IS OPEN SOURCE works as expected."); + CHECK_MESSAGE(time->get_datetime_string_from_dict(time->get_datetime_dict_from_string("2014-02-09 22:10:30"), true) == "2014-02-09 22:10:30", "Time get_datetime_string_from_dict: The round-trip string to dict to string GODOT IS OPEN SOURCE with spaces works as expected."); +} + +TEST_CASE("[Time] System time methods") { + const Time *time = Time::get_singleton(); + + const uint64_t ticks_msec = time->get_ticks_msec(); + const uint64_t ticks_usec = time->get_ticks_usec(); + + CHECK_MESSAGE(time->get_unix_time_from_system() > 1000000000, "Time get_unix_time_from_system: The timestamp from system time doesn't fail and is very positive."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time->get_datetime_dict_from_system()) > 1000000000, "Time get_datetime_string_from_system: The timestamp from system time doesn't fail and is very positive."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time->get_date_dict_from_system()) > 1000000000, "Time get_datetime_string_from_system: The date from system time doesn't fail and is very positive."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_dict(time->get_time_dict_from_system()) < 86400, "Time get_datetime_string_from_system: The time from system time doesn't fail and is within the acceptable range."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string(time->get_datetime_string_from_system()) > 1000000000, "Time get_datetime_string_from_system: The timestamp from system time doesn't fail and is very positive."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string(time->get_date_string_from_system()) > 1000000000, "Time get_datetime_string_from_system: The date from system time doesn't fail and is very positive."); + CHECK_MESSAGE(time->get_unix_time_from_datetime_string(time->get_time_string_from_system()) < 86400, "Time get_datetime_string_from_system: The time from system time doesn't fail and is within the acceptable range."); + + CHECK_MESSAGE(time->get_ticks_msec() >= ticks_msec, "Time get_ticks_msec: The value has not decreased."); + CHECK_MESSAGE(time->get_ticks_usec() > ticks_usec, "Time get_ticks_usec: The value has increased."); +} + +} // namespace TestTime + +#endif // TEST_TIME_H diff --git a/tests/test_validate_testing.h b/tests/test_validate_testing.h index 6d3eea724c..f301047509 100644 --- a/tests/test_validate_testing.h +++ b/tests/test_validate_testing.h @@ -84,7 +84,7 @@ TEST_SUITE("Validate tests") { Plane plane(Vector3(1, 1, 1), 1.0); INFO(plane); - Quat quat(Vector3(0.5, 1.0, 2.0)); + Quaternion quat(Vector3(0.5, 1.0, 2.0)); INFO(quat); AABB aabb(Vector3(), Vector3(100, 100, 100)); @@ -93,7 +93,7 @@ TEST_SUITE("Validate tests") { Basis basis(quat); INFO(basis); - Transform trans(basis); + Transform3D trans(basis); INFO(trans); Color color(1, 0.5, 0.2, 0.3); diff --git a/thirdparty/README.md b/thirdparty/README.md index 03a2ddf5e4..31e88180d0 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -616,6 +616,11 @@ Files extracted from upstream source: - `include` folder - `LICENSE` +Some downstream changes have been made and are identified by +`// -- GODOT begin --` and `// -- GODOT end --` comments. +They can be reapplied using the patch included in the `patches` +folder. + ## squish diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp index fd7968204b..f6a56f1f5d 100644 --- a/thirdparty/enet/godot.cpp +++ b/thirdparty/enet/godot.cpp @@ -164,7 +164,7 @@ public: verify = p_verify; for_hostname = p_for_hostname; cert = p_cert; - udp.instance(); + udp.instantiate(); dtls = Ref<PacketPeerDTLS>(PacketPeerDTLS::create()); if (p_base->bound) { uint16_t port; @@ -254,7 +254,7 @@ class ENetDTLSServer : public ENetGodotSocket { public: ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) { - udp_server.instance(); + udp_server.instantiate(); if (p_base->bound) { uint16_t port; p_base->get_socket_address(&local_address, &port); diff --git a/thirdparty/misc/easing_equations.cpp b/thirdparty/misc/easing_equations.cpp index af48aaf079..ce32c1a362 100644 --- a/thirdparty/misc/easing_equations.cpp +++ b/thirdparty/misc/easing_equations.cpp @@ -297,7 +297,7 @@ static real_t out_in(real_t t, real_t b, real_t c, real_t d) { } }; // namespace back -Tween::interpolater Tween::interpolaters[Tween::TRANS_COUNT][Tween::EASE_COUNT] = { +Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = { { &linear::in, &linear::out, &linear::in_out, &linear::out_in }, { &sine::in, &sine::out, &sine::in_out, &sine::out_in }, { &quint::in, &quint::out, &quint::in_out, &quint::out_in }, @@ -311,7 +311,7 @@ Tween::interpolater Tween::interpolaters[Tween::TRANS_COUNT][Tween::EASE_COUNT] { &back::in, &back::out, &back::in_out, &back::out_in }, }; -real_t Tween::_run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d) { +real_t Tween::run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d) { interpolater cb = interpolaters[p_trans_type][p_ease_type]; ERR_FAIL_COND_V(cb == NULL, b); diff --git a/thirdparty/spirv-reflect/patches/specialization-constants.patch b/thirdparty/spirv-reflect/patches/specialization-constants.patch new file mode 100644 index 0000000000..8ff1dcc2e5 --- /dev/null +++ b/thirdparty/spirv-reflect/patches/specialization-constants.patch @@ -0,0 +1,293 @@ +diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c +index 0fc979a8a4..3e3643717a 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.c ++++ b/thirdparty/spirv-reflect/spirv_reflect.c +@@ -124,6 +124,9 @@ typedef struct Decorations { + NumberDecoration location; + NumberDecoration offset; + NumberDecoration uav_counter_buffer; ++// -- GODOT begin -- ++ NumberDecoration specialization_constant; ++// -- GODOT end -- + StringDecoration semantic; + uint32_t array_stride; + uint32_t matrix_stride; +@@ -610,6 +613,9 @@ static SpvReflectResult ParseNodes(Parser* p_parser) + p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; + p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; + p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; ++// -- GODOT begin -- ++ p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE; ++// -- GODOT end -- + } + // Mark source file id node + p_parser->source_file_id = (uint32_t)INVALID_VALUE; +@@ -800,10 +806,16 @@ static SpvReflectResult ParseNodes(Parser* p_parser) + CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); + } + break; +- ++// -- GODOT begin -- + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: +- case SpvOpSpecConstant: ++ case SpvOpSpecConstant: { ++ CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); ++ CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); ++ p_node->is_type = true; ++ } ++ break; ++// -- GODOT end -- + case SpvOpSpecConstantComposite: + case SpvOpSpecConstantOp: { + CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); +@@ -1309,6 +1321,9 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) + skip = true; + } + break; ++// -- GODOT begin -- ++ case SpvDecorationSpecId: ++// -- GODOT end -- + case SpvDecorationBlock: + case SpvDecorationBufferBlock: + case SpvDecorationColMajor: +@@ -1441,7 +1456,14 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) + p_target_decorations->input_attachment_index.word_offset = word_offset; + } + break; +- ++// -- GODOT begin -- ++ case SpvDecorationSpecId: { ++ uint32_t word_offset = p_node->word_offset + member_offset+ 3; ++ CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); ++ p_target_decorations->specialization_constant.word_offset = word_offset; ++ } ++ break; ++// -- GODOT end -- + case SpvReflectDecorationHlslCounterBufferGOOGLE: { + uint32_t word_offset = p_node->word_offset + member_offset+ 3; + CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); +@@ -1731,6 +1753,13 @@ static SpvReflectResult ParseType( + p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; + } + break; ++// -- GODOT begin -- ++ case SpvOpSpecConstantTrue: ++ case SpvOpSpecConstantFalse: ++ case SpvOpSpecConstant: { ++ } ++ break; ++// -- GODOT end -- + } + + if (result == SPV_REFLECT_RESULT_SUCCESS) { +@@ -3187,6 +3216,69 @@ static SpvReflectResult ParseExecutionModes(Parser* p_parser, SpvReflectShaderMo + return SPV_REFLECT_RESULT_SUCCESS; + } + ++// -- GODOT begin -- ++static SpvReflectResult ParseSpecializationConstants(Parser* p_parser, SpvReflectShaderModule* p_module) ++{ ++ p_module->specialization_constant_count = 0; ++ p_module->specialization_constants = NULL; ++ for (size_t i = 0; i < p_parser->node_count; ++i) { ++ Node* p_node = &(p_parser->nodes[i]); ++ if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { ++ p_module->specialization_constant_count++; ++ } ++ } ++ ++ if (p_module->specialization_constant_count == 0) { ++ return SPV_REFLECT_RESULT_SUCCESS; ++ } ++ ++ p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); ++ ++ uint32_t index = 0; ++ ++ for (size_t i = 0; i < p_parser->node_count; ++i) { ++ Node* p_node = &(p_parser->nodes[i]); ++ switch(p_node->op) { ++ default: continue; ++ case SpvOpSpecConstantTrue: { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; ++ p_module->specialization_constants[index].default_value.int_bool_value = 1; ++ } break; ++ case SpvOpSpecConstantFalse: { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; ++ p_module->specialization_constants[index].default_value.int_bool_value = 0; ++ } break; ++ case SpvOpSpecConstant: { ++ SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; ++ uint32_t element_type_id = (uint32_t)INVALID_VALUE; ++ uint32_t default_value = 0; ++ IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); ++ IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); ++ ++ Node* p_next_node = FindNode(p_parser, element_type_id); ++ ++ if (p_next_node->op == SpvOpTypeInt) { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; ++ } else if (p_next_node->op == SpvOpTypeFloat) { ++ p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; ++ } else { ++ return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; ++ } ++ ++ p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float ++ } break; ++ } ++ ++ p_module->specialization_constants[index].name = p_node->name; ++ p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; ++ p_module->specialization_constants[index].spirv_id = p_node->result_id; ++ index++; ++ } ++ ++ return SPV_REFLECT_RESULT_SUCCESS; ++} ++// -- GODOT end -- ++ + static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module) + { + for (size_t i = 0; i < p_parser->node_count; ++i) { +@@ -3562,6 +3654,12 @@ SpvReflectResult spvReflectCreateShaderModule( + result = ParsePushConstantBlocks(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } ++// -- GODOT begin -- ++ if (result == SPV_REFLECT_RESULT_SUCCESS) { ++ result = ParseSpecializationConstants(&parser, p_module); ++ SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); ++ } ++// -- GODOT end -- + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseEntryPoints(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); +@@ -3691,6 +3789,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) + SafeFree(p_entry->used_push_constants); + } + SafeFree(p_module->entry_points); ++// -- GODOT begin -- ++ SafeFree(p_module->specialization_constants); ++// -- GODOT end -- + + // Push constants + for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { +@@ -3959,6 +4060,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( + return SPV_REFLECT_RESULT_SUCCESS; + } + ++// -- GODOT begin -- ++SpvReflectResult spvReflectEnumerateSpecializationConstants( ++ const SpvReflectShaderModule* p_module, ++ uint32_t* p_count, ++ SpvReflectSpecializationConstant** pp_constants ++) ++{ ++ if (IsNull(p_module)) { ++ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; ++ } ++ if (IsNull(p_count)) { ++ return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; ++ } ++ ++ if (IsNotNull(pp_constants)) { ++ if (*p_count != p_module->specialization_constant_count) { ++ return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; ++ } ++ ++ for (uint32_t index = 0; index < *p_count; ++index) { ++ SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; ++ pp_constants[index] = p_const; ++ } ++ } ++ else { ++ *p_count = p_module->specialization_constant_count; ++ } ++ ++ return SPV_REFLECT_RESULT_SUCCESS; ++} ++// -- GODOT end -- ++ + SpvReflectResult spvReflectEnumerateInputVariables( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, +diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h +index a5a956e9e8..21f8160770 100644 +--- a/thirdparty/spirv-reflect/spirv_reflect.h ++++ b/thirdparty/spirv-reflect/spirv_reflect.h +@@ -292,6 +292,28 @@ typedef struct SpvReflectTypeDescription { + struct SpvReflectTypeDescription* members; + } SpvReflectTypeDescription; + ++// -- GODOT begin -- ++/*! @struct SpvReflectSpecializationConstant ++ ++*/ ++ ++typedef enum SpvReflectSpecializationConstantType { ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, ++ SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, ++} SpvReflectSpecializationConstantType; ++ ++typedef struct SpvReflectSpecializationConstant { ++ const char* name; ++ uint32_t spirv_id; ++ uint32_t constant_id; ++ SpvReflectSpecializationConstantType constant_type; ++ union { ++ float float_value; ++ uint32_t int_bool_value; ++ } default_value; ++} SpvReflectSpecializationConstant; ++// -- GODOT end -- + + /*! @struct SpvReflectInterfaceVariable + +@@ -439,6 +461,10 @@ typedef struct SpvReflectShaderModule { + SpvReflectInterfaceVariable* interface_variables; + uint32_t push_constant_block_count; + SpvReflectBlockVariable* push_constant_blocks; ++ // -- GODOT begin -- ++ uint32_t specialization_constant_count; ++ SpvReflectSpecializationConstant* specialization_constants; ++ // -- GODOT end -- + + struct Internal { + size_t spirv_size; +@@ -694,6 +720,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( + SpvReflectInterfaceVariable** pp_variables + ); + ++// -- GOODT begin -- ++/*! @fn spvReflectEnumerateSpecializationConstants ++ @brief If the module contains multiple entry points, this will only get ++ the specialization constants for the first one. ++ @param p_module Pointer to an instance of SpvReflectShaderModule. ++ @param p_count If pp_constants is NULL, the module's specialization constant ++ count will be stored here. ++ If pp_variables is not NULL, *p_count must contain ++ the module's specialization constant count. ++ @param pp_variables If NULL, the module's specialization constant count will be ++ written to *p_count. ++ If non-NULL, pp_constants must point to an array with ++ *p_count entries, where pointers to the module's ++ specialization constants will be written. The caller must not ++ free the specialization constants written to this array. ++ @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. ++ Otherwise, the error code indicates the cause of the ++ failure. ++ ++*/ ++SpvReflectResult spvReflectEnumerateSpecializationConstants( ++ const SpvReflectShaderModule* p_module, ++ uint32_t* p_count, ++ SpvReflectSpecializationConstant** pp_constants ++); ++// -- GODOT end -- ++ + /*! @fn spvReflectEnumerateEntryPointInputVariables + @brief Enumerate the input variables for a given entry point. + @param entry_point The name of the entry point to get the input variables for. diff --git a/thirdparty/spirv-reflect/spirv_reflect.c b/thirdparty/spirv-reflect/spirv_reflect.c index 0fc979a8a4..8f614c8874 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.c +++ b/thirdparty/spirv-reflect/spirv_reflect.c @@ -124,6 +124,9 @@ typedef struct Decorations { NumberDecoration location; NumberDecoration offset; NumberDecoration uav_counter_buffer; +// -- GODOT begin -- + NumberDecoration specialization_constant; +// -- GODOT end -- StringDecoration semantic; uint32_t array_stride; uint32_t matrix_stride; @@ -610,6 +613,9 @@ static SpvReflectResult ParseNodes(Parser* p_parser) p_parser->nodes[i].decorations.offset.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.uav_counter_buffer.value = (uint32_t)INVALID_VALUE; p_parser->nodes[i].decorations.built_in = (SpvBuiltIn)INVALID_VALUE; +// -- GODOT begin -- + p_parser->nodes[i].decorations.specialization_constant.value = (SpvBuiltIn)INVALID_VALUE; +// -- GODOT end -- } // Mark source file id node p_parser->source_file_id = (uint32_t)INVALID_VALUE; @@ -800,10 +806,16 @@ static SpvReflectResult ParseNodes(Parser* p_parser) CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); } break; - +// -- GODOT begin -- case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: - case SpvOpSpecConstant: + case SpvOpSpecConstant: { + CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); + CHECKED_READU32(p_parser, p_node->word_offset + 2, p_node->result_id); + p_node->is_type = true; + } + break; +// -- GODOT end -- case SpvOpSpecConstantComposite: case SpvOpSpecConstantOp: { CHECKED_READU32(p_parser, p_node->word_offset + 1, p_node->result_type_id); @@ -1309,6 +1321,9 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) skip = true; } break; +// -- GODOT begin -- + case SpvDecorationSpecId: +// -- GODOT end -- case SpvDecorationBlock: case SpvDecorationBufferBlock: case SpvDecorationColMajor: @@ -1441,7 +1456,14 @@ static SpvReflectResult ParseDecorations(Parser* p_parser) p_target_decorations->input_attachment_index.word_offset = word_offset; } break; - +// -- GODOT begin -- + case SpvDecorationSpecId: { + uint32_t word_offset = p_node->word_offset + member_offset+ 3; + CHECKED_READU32(p_parser, word_offset, p_target_decorations->specialization_constant.value); + p_target_decorations->specialization_constant.word_offset = word_offset; + } + break; +// -- GODOT end -- case SpvReflectDecorationHlslCounterBufferGOOGLE: { uint32_t word_offset = p_node->word_offset + member_offset+ 3; CHECKED_READU32(p_parser, word_offset, p_target_decorations->uav_counter_buffer.value); @@ -1731,6 +1753,13 @@ static SpvReflectResult ParseType( p_type->type_flags |= SPV_REFLECT_TYPE_FLAG_EXTERNAL_ACCELERATION_STRUCTURE; } break; +// -- GODOT begin -- + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: + case SpvOpSpecConstant: { + } + break; +// -- GODOT end -- } if (result == SPV_REFLECT_RESULT_SUCCESS) { @@ -3187,6 +3216,69 @@ static SpvReflectResult ParseExecutionModes(Parser* p_parser, SpvReflectShaderMo return SPV_REFLECT_RESULT_SUCCESS; } +// -- GODOT begin -- +static SpvReflectResult ParseSpecializationConstants(Parser* p_parser, SpvReflectShaderModule* p_module) +{ + p_module->specialization_constant_count = 0; + p_module->specialization_constants = NULL; + for (size_t i = 0; i < p_parser->node_count; ++i) { + Node* p_node = &(p_parser->nodes[i]); + if (p_node->op == SpvOpSpecConstantTrue || p_node->op == SpvOpSpecConstantFalse || p_node->op == SpvOpSpecConstant) { + p_module->specialization_constant_count++; + } + } + + if (p_module->specialization_constant_count == 0) { + return SPV_REFLECT_RESULT_SUCCESS; + } + + p_module->specialization_constants = (SpvReflectSpecializationConstant*)calloc(p_module->specialization_constant_count, sizeof(SpvReflectSpecializationConstant)); + + uint32_t index = 0; + + for (size_t i = 0; i < p_parser->node_count; ++i) { + Node* p_node = &(p_parser->nodes[i]); + switch(p_node->op) { + default: continue; + case SpvOpSpecConstantTrue: { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; + p_module->specialization_constants[index].default_value.int_bool_value = 1; + } break; + case SpvOpSpecConstantFalse: { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL; + p_module->specialization_constants[index].default_value.int_bool_value = 0; + } break; + case SpvOpSpecConstant: { + SpvReflectResult result = SPV_REFLECT_RESULT_SUCCESS; + uint32_t element_type_id = (uint32_t)INVALID_VALUE; + uint32_t default_value = 0; + IF_READU32(result, p_parser, p_node->word_offset + 1, element_type_id); + IF_READU32(result, p_parser, p_node->word_offset + 3, default_value); + + Node* p_next_node = FindNode(p_parser, element_type_id); + + if (p_next_node->op == SpvOpTypeInt) { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_INT; + } else if (p_next_node->op == SpvOpTypeFloat) { + p_module->specialization_constants[index].constant_type = SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT; + } else { + return SPV_REFLECT_RESULT_ERROR_PARSE_FAILED; + } + + p_module->specialization_constants[index].default_value.int_bool_value = default_value; //bits are the same for int and float + } break; + } + + p_module->specialization_constants[index].name = p_node->name; + p_module->specialization_constants[index].constant_id = p_node->decorations.specialization_constant.value; + p_module->specialization_constants[index].spirv_id = p_node->result_id; + index++; + } + + return SPV_REFLECT_RESULT_SUCCESS; +} +// -- GODOT end -- + static SpvReflectResult ParsePushConstantBlocks(Parser* p_parser, SpvReflectShaderModule* p_module) { for (size_t i = 0; i < p_parser->node_count; ++i) { @@ -3562,6 +3654,12 @@ SpvReflectResult spvReflectCreateShaderModule( result = ParsePushConstantBlocks(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); } +// -- GODOT begin -- + if (result == SPV_REFLECT_RESULT_SUCCESS) { + result = ParseSpecializationConstants(&parser, p_module); + SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); + } +// -- GODOT end -- if (result == SPV_REFLECT_RESULT_SUCCESS) { result = ParseEntryPoints(&parser, p_module); SPV_REFLECT_ASSERT(result == SPV_REFLECT_RESULT_SUCCESS); @@ -3691,6 +3789,9 @@ void spvReflectDestroyShaderModule(SpvReflectShaderModule* p_module) SafeFree(p_entry->used_push_constants); } SafeFree(p_module->entry_points); +// -- GODOT begin -- + SafeFree(p_module->specialization_constants); +// -- GODOT end -- // Push constants for (size_t i = 0; i < p_module->push_constant_block_count; ++i) { @@ -3959,6 +4060,38 @@ SpvReflectResult spvReflectEnumerateEntryPointInterfaceVariables( return SPV_REFLECT_RESULT_SUCCESS; } +// -- GODOT begin -- +SpvReflectResult spvReflectEnumerateSpecializationConstants( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, + SpvReflectSpecializationConstant** pp_constants +) +{ + if (IsNull(p_module)) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + if (IsNull(p_count)) { + return SPV_REFLECT_RESULT_ERROR_NULL_POINTER; + } + + if (IsNotNull(pp_constants)) { + if (*p_count != p_module->specialization_constant_count) { + return SPV_REFLECT_RESULT_ERROR_COUNT_MISMATCH; + } + + for (uint32_t index = 0; index < *p_count; ++index) { + SpvReflectSpecializationConstant *p_const = &p_module->specialization_constants[index]; + pp_constants[index] = p_const; + } + } + else { + *p_count = p_module->specialization_constant_count; + } + + return SPV_REFLECT_RESULT_SUCCESS; +} +// -- GODOT end -- + SpvReflectResult spvReflectEnumerateInputVariables( const SpvReflectShaderModule* p_module, uint32_t* p_count, diff --git a/thirdparty/spirv-reflect/spirv_reflect.h b/thirdparty/spirv-reflect/spirv_reflect.h index a5a956e9e8..21f8160770 100644 --- a/thirdparty/spirv-reflect/spirv_reflect.h +++ b/thirdparty/spirv-reflect/spirv_reflect.h @@ -292,6 +292,28 @@ typedef struct SpvReflectTypeDescription { struct SpvReflectTypeDescription* members; } SpvReflectTypeDescription; +// -- GODOT begin -- +/*! @struct SpvReflectSpecializationConstant + +*/ + +typedef enum SpvReflectSpecializationConstantType { + SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL = 0, + SPV_REFLECT_SPECIALIZATION_CONSTANT_INT = 1, + SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT = 2, +} SpvReflectSpecializationConstantType; + +typedef struct SpvReflectSpecializationConstant { + const char* name; + uint32_t spirv_id; + uint32_t constant_id; + SpvReflectSpecializationConstantType constant_type; + union { + float float_value; + uint32_t int_bool_value; + } default_value; +} SpvReflectSpecializationConstant; +// -- GODOT end -- /*! @struct SpvReflectInterfaceVariable @@ -439,6 +461,10 @@ typedef struct SpvReflectShaderModule { SpvReflectInterfaceVariable* interface_variables; uint32_t push_constant_block_count; SpvReflectBlockVariable* push_constant_blocks; + // -- GODOT begin -- + uint32_t specialization_constant_count; + SpvReflectSpecializationConstant* specialization_constants; + // -- GODOT end -- struct Internal { size_t spirv_size; @@ -694,6 +720,33 @@ SpvReflectResult spvReflectEnumerateInputVariables( SpvReflectInterfaceVariable** pp_variables ); +// -- GOODT begin -- +/*! @fn spvReflectEnumerateSpecializationConstants + @brief If the module contains multiple entry points, this will only get + the specialization constants for the first one. + @param p_module Pointer to an instance of SpvReflectShaderModule. + @param p_count If pp_constants is NULL, the module's specialization constant + count will be stored here. + If pp_variables is not NULL, *p_count must contain + the module's specialization constant count. + @param pp_variables If NULL, the module's specialization constant count will be + written to *p_count. + If non-NULL, pp_constants must point to an array with + *p_count entries, where pointers to the module's + specialization constants will be written. The caller must not + free the specialization constants written to this array. + @return If successful, returns SPV_REFLECT_RESULT_SUCCESS. + Otherwise, the error code indicates the cause of the + failure. + +*/ +SpvReflectResult spvReflectEnumerateSpecializationConstants( + const SpvReflectShaderModule* p_module, + uint32_t* p_count, + SpvReflectSpecializationConstant** pp_constants +); +// -- GODOT end -- + /*! @fn spvReflectEnumerateEntryPointInputVariables @brief Enumerate the input variables for a given entry point. @param entry_point The name of the entry point to get the input variables for. |