diff options
90 files changed, 1222 insertions, 446 deletions
@@ -58,6 +58,7 @@ J08nY <johny@neuromancer.sk> <jancar.jj@gmail.com> J08nY <johny@neuromancer.sk> <J08nY@users.noreply.github.com> Jakub Grzesik <kubecz3k@gmail.com> janglee <merupatel123@gmail.com> +Jean-Michel Bernard <jmb462@gmail.com> Jérôme Gully <jerome.gully0@gmail.com> JFonS <joan.fonssanchez@gmail.com> Juan Linietsky <reduzio@gmail.com> @@ -67,6 +68,9 @@ Juan Linietsky <reduzio@gmail.com> <reduz@Juans-MBP.fibertel.com.ar> Juan Linietsky <reduzio@gmail.com> <red@kyoko> Julian Murgia <the.straton@gmail.com> Kanabenki <lucien.menassol@gmail.com> <18357657+Kanabenki@users.noreply.github.com> +karroffel <therzog@mail.de> +karroffel <therzog@mail.de> <thomas.herzog@mail.com> +karroffel <therzog@mail.de> <thomas.herzog@simedis.com> Kelly Thomas <kelly.thomas@hotmail.com.au> Kongfa Waroros <gongpha@hotmail.com> K. S. Ernest (iFire) Lee <ernest.lee@chibifire.com> @@ -123,11 +127,10 @@ romulox_x <romulox_x@yahoo.com> Ruslan Mustakov <r.mustakov@gmail.com> <ruslan.mustakov@xored.com> Saracen <SaracenOne@gmail.com> sheepandshepherd <sheepandshepherd@hotmail.com> <sheepandshepherd@users.noreply.github.com> +Silc 'Tokage' Renew <tokage.it.lab@gmail.com> +Silc 'Tokage' Renew <tokage.it.lab@gmail.com> <61938263+TokageItLab@users.noreply.github.com> Swarnim Arun <swarnimarun11@gmail.com> Theo Hallenius <redsymbzone@hotmail.com> -Thomas Herzog <therzog@mail.de> -Thomas Herzog <therzog@mail.de> <thomas.herzog@mail.com> -Thomas Herzog <therzog@mail.de> <thomas.herzog@simedis.com> Tomasz Chabora <kobewi4e@gmail.com> Twarit <wtwarit@gmail.com> V.VamsiKrishna <vk@bsb.in> <vamsikrishna.v@gmail.com> diff --git a/AUTHORS.md b/AUTHORS.md index 0a0e3a9c21..a86bc3ffe4 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -122,6 +122,7 @@ name is available. Julien Nguyen (Blackiris) Jummit Justo Delgado (mrcdk) + karroffel Kelly Thomas (KellyThomas) kleonc Kongfa Waroros (gongpha) @@ -179,6 +180,7 @@ name is available. Ralf Hölzemer (rollenrolm) Ramesh Ravone (RameshRavone) raphael10241024 + Raul Santos (raulsntos) Ray Koopa (RayKoopa) Rémi Verschelde (akien-mga) Rhody Lugo (rraallvv) @@ -194,13 +196,13 @@ name is available. Sergey Minakov (naithar) sersoong Shiqing (kawa-yoiko) + Silc 'Tokage' Renew (TokageItLab) Simon Wenner (swenner) Stijn Hinlopen (hinlopen) Swarnim Arun (minraws) Thakee Nathees (ThakeeNathees) thebestnom Theo Hallenius (TheoXD) - Thomas Herzog (karroffel) Timo Schwarzer (timoschwarzer) Timo (toger5) Tomasz Chabora (KoBeWi) @@ -28,6 +28,7 @@ generous deed immortalized in the next stable release of Godot Engine. Ben Nolan Brandon Lamb + Bri Garry Newman Gordon MacPherson Hunter Dickson @@ -41,7 +42,6 @@ generous deed immortalized in the next stable release of Godot Engine. AD Ford alex brown Andrew Bowen - Andrew Dunai Angry Skull anti666 blurp @@ -81,9 +81,7 @@ generous deed immortalized in the next stable release of Godot Engine. Slobodan Milnovic Stephan Lanfermann Steve - Stonesoft io Thomas Krampl - Tristan Pemble Violin Iliev Xwdit @@ -103,7 +101,6 @@ generous deed immortalized in the next stable release of Godot Engine. David Graham David Snopek Ed Morley - Ellen Poe Florian Rämisch Gamejunkey Jacobus Dens @@ -120,12 +117,14 @@ generous deed immortalized in the next stable release of Godot Engine. Maciej Pendolski Manuele Finocchiaro Markus Wiesner + Mathieu Matthew Hillier Michael Mick Monster Vial Officine Pixel S.n.c. Patrick Brock + Paul E Hansen Pedro Silva Petrus Prinsloo Retro Village @@ -147,7 +146,6 @@ generous deed immortalized in the next stable release of Godot Engine. Vagabond Arcade Vitaliy Sapronenko Xeno Coliseum - Zaven Muradyan Adam Nakonieczny Adam Nelson @@ -155,6 +153,7 @@ generous deed immortalized in the next stable release of Godot Engine. Alexander J Maynard Alex Khayrullin alice gambrell + Amar Šahinović Andrew Cunningham Andrew Farr Andriy @@ -211,15 +210,14 @@ generous deed immortalized in the next stable release of Godot Engine. Hunter Barabas Jake Burga James Couzens - James Zahn Jan Sælid Jared Jared White Jennifer Wilcox + Jeremi Biernacki Jesús Chicharro Joel Fivat Johnathan Kupferer - Jonathan Turner Josef Stumpfegger Jose Malheiro Jose Manuel Muñoz Perez @@ -238,6 +236,7 @@ generous deed immortalized in the next stable release of Godot Engine. kinfox Kis Levente Lorand Kos + Lakshaya Goel Laszlo Kiss leetNightshade Leo Fidel R Liban @@ -347,11 +346,11 @@ generous deed immortalized in the next stable release of Godot Engine. Adam Long Adam McCurdy Adam N Webber - Adam R Pope Adam Smeltzer Adam Szymański Adisibio Adrien de Pierres + Agustinus Arya Ahmet Kalyoncu Aidan O'Flannagain Aki Mimoto @@ -377,6 +376,7 @@ generous deed immortalized in the next stable release of Godot Engine. Andrew Groot andrew james morris Andrew Thomas + angrykoala Ano Nim Anthony Avina Anton Bouwer @@ -394,6 +394,7 @@ generous deed immortalized in the next stable release of Godot Engine. Balázs Batári Baptiste Le Bourhis Bartosz Bielecki + bcat Benedikt Benoit Jauvin-Girard Ben Ridley @@ -409,6 +410,7 @@ generous deed immortalized in the next stable release of Godot Engine. Blunderjack Bobby CC Wong Borkzilla + Brad Harms Bram brian Brian Klein @@ -417,6 +419,7 @@ generous deed immortalized in the next stable release of Godot Engine. Bruno Hurth Burney Waring bwhirt + c64cosmin Caleb Gartner Caleb Makela Cameron Meyer @@ -480,11 +483,13 @@ generous deed immortalized in the next stable release of Godot Engine. Eric Stokes Eric Walkingshaw Eric Williams + Erika Sanders Erkki Seppälä Faisal Alkubaisi Fancy Ants Studios fby Fekinox + Felix Adam Felix Bohmann Filip Lundby Forty Doubleu @@ -494,6 +499,7 @@ generous deed immortalized in the next stable release of Godot Engine. FrostMarble Game Endeavor Gary Thomas + gebba George Marques Georgi Petkov Graham Overby @@ -502,6 +508,7 @@ generous deed immortalized in the next stable release of Godot Engine. Greg Olson Greyson Richey Grid + Grok Games Grominet Guillaume Pham Ngoc Guldoman @@ -532,15 +539,16 @@ generous deed immortalized in the next stable release of Godot Engine. Jan Vetulani JARKKO PARVIAINEN Jason Bolton + Jason Evans Jason Malcolm-Herzmark Jason Uechi Jeff Hungerford Jeff Messer Jeffrey Berube Jennifer Graves - JernauGurgeh Jesse Dubay Jim Engstrand + Joe Hurdle Joe Klemmer Joel Höglund John Bruce @@ -577,13 +585,14 @@ generous deed immortalized in the next stable release of Godot Engine. Justin Oaksford Justin Spedding KaDokta - Karol Porzycki Keedong Park + keeganstoybox Keinan Powers Keith Bradner Kenji Kawabata Ken Minardo Kent Jofur + Kerotasma Ketafuki Kevin van Rooijen Kiri Jolly @@ -602,6 +611,7 @@ generous deed immortalized in the next stable release of Godot Engine. Kyle Burnett Kyle Jacobs Kyuppin + La diagonale du poulpe Lasse le Dous Laurent CHEA Laxman Pradhan @@ -627,7 +637,6 @@ generous deed immortalized in the next stable release of Godot Engine. Martin Liška Martin Trbola Martin Zabinski - Mathieu Matt Edwards Matthew Booe Matt Sylvia @@ -657,11 +666,11 @@ generous deed immortalized in the next stable release of Godot Engine. Molinghu Molly Jameson MoltenGears + Moowool MrAZIE Mrjemandem Nathan Fish Nathaniel - nee neighty Neil Blakey-Milner Neil Wang @@ -704,6 +713,7 @@ generous deed immortalized in the next stable release of Godot Engine. Rad Cat Rafa Laguna Raffaele Aramo + Ragnar Pettersson Rainer Amler Rami Hanano Rammeow @@ -728,8 +738,10 @@ generous deed immortalized in the next stable release of Godot Engine. Ryan Groom Sam Caulfield Sam Edson + Samuel Egger Scott Longley Sean Lynch + Sean Wall Sebastian Michailidis SeongWan Kim SeungJong k @@ -744,6 +756,7 @@ generous deed immortalized in the next stable release of Godot Engine. Simon Wenner sirn Skalli + slavfox smbe19 smo1704 Solene Waked @@ -793,6 +806,7 @@ generous deed immortalized in the next stable release of Godot Engine. UltyX Uther v01tech + Vaida Narušė Vaughan Ling Victor Vincent Foulon @@ -800,7 +814,7 @@ generous deed immortalized in the next stable release of Godot Engine. Vladimir Savin Vladislav Smirnov VoxelVisions.com - Vytenis Narušis + Wapiti . werner mendizabal Wiley Thompson William Edwards diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index 57833fe42f..562cbbdd27 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -49,12 +49,11 @@ ProjectSettings *ProjectSettings::get_singleton() { } String ProjectSettings::get_project_data_dir_name() const { - return ".godot"; + return project_data_dir_name; } String ProjectSettings::get_project_data_path() const { - String project_data_dir_name = get_project_data_dir_name(); - return "res://" + project_data_dir_name; + return "res://" + get_project_data_dir_name(); } String ProjectSettings::get_resource_path() const { @@ -520,6 +519,10 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo _load_settings_text(custom_settings); } } + + // Updating the default value after the project settings have loaded. + project_data_dir_name = GLOBAL_GET("application/config/project_data_dir_name"); + // Using GLOBAL_GET on every block for compressing can be slow, so assigning here. Compression::zstd_long_distance_matching = GLOBAL_GET("compression/formats/zstd/long_distance_matching"); Compression::zstd_level = GLOBAL_GET("compression/formats/zstd/compression_level"); @@ -1091,6 +1094,7 @@ ProjectSettings::ProjectSettings() { custom_prop_info["application/run/main_scene"] = PropertyInfo(Variant::STRING, "application/run/main_scene", PROPERTY_HINT_FILE, "*.tscn,*.scn,*.res"); GLOBAL_DEF("application/run/disable_stdout", false); GLOBAL_DEF("application/run/disable_stderr", false); + project_data_dir_name = GLOBAL_DEF_RST("application/config/project_data_dir_name", ".godot"); GLOBAL_DEF("application/config/use_custom_user_dir", false); GLOBAL_DEF("application/config/custom_user_dir_name", ""); GLOBAL_DEF("application/config/project_settings_override", ""); diff --git a/core/config/project_settings.h b/core/config/project_settings.h index b642051402..82f04b94df 100644 --- a/core/config/project_settings.h +++ b/core/config/project_settings.h @@ -93,6 +93,8 @@ protected: OrderedHashMap<StringName, AutoloadInfo> autoloads; + String project_data_dir_name; + 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; diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index e54c947340..df631053b8 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -233,7 +233,7 @@ uint64_t FileAccessCompressed::get_position() const { if (writing) { return write_pos; } else { - return read_block * block_size + read_pos; + return (uint64_t)read_block * block_size + read_pos; } } diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index b5c882e9ce..53bf7456e6 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -99,7 +99,7 @@ static int godot_testerror(voidpf opaque, voidpf stream) { } static voidpf godot_alloc(voidpf opaque, uInt items, uInt size) { - return memalloc(items * size); + return memalloc((size_t)items * size); } static void godot_free(voidpf opaque, voidpf address) { diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp index fb4c76aa7a..24808cc8d6 100644 --- a/core/io/zip_io.cpp +++ b/core/io/zip_io.cpp @@ -100,7 +100,7 @@ int zipio_testerror(voidpf opaque, voidpf stream) { } voidpf zipio_alloc(voidpf opaque, uInt items, uInt size) { - voidpf ptr = memalloc(items * size); + voidpf ptr = memalloc((size_t)items * size); memset(ptr, 0, items * size); return ptr; } diff --git a/core/multiplayer/multiplayer_replicator.cpp b/core/multiplayer/multiplayer_replicator.cpp index a4ea74327c..6604510394 100644 --- a/core/multiplayer/multiplayer_replicator.cpp +++ b/core/multiplayer/multiplayer_replicator.cpp @@ -572,7 +572,7 @@ Error MultiplayerReplicator::_spawn_despawn(ResourceUID::ID p_scene_id, Object * args[0] = p_peer; args[1] = p_scene_id; args[2] = p_obj; - args[3] = true; + args[3] = p_spawn; const Variant *argp[] = { &args[0], &args[1], &args[2], &args[3] }; Callable::CallError ce; Variant ret; diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp index b7d2bac96d..289caf5247 100644 --- a/core/object/undo_redo.cpp +++ b/core/object/undo_redo.cpp @@ -32,6 +32,7 @@ #include "core/io/resource.h" #include "core/os/os.h" +#include "core/templates/local_vector.h" void UndoRedo::_discard_redo() { if (current_action == actions.size() - 1) { @@ -85,10 +86,17 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { current_action = actions.size() - 2; if (p_mode == MERGE_ENDS) { - // Clear all do ops from last action, and delete all object references - List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); + // Clear all do ops from last action if they are not forced kept + LocalVector<List<Operation>::Element *> to_remove; + for (List<Operation>::Element *E = actions.write[current_action + 1].do_ops.front(); E; E = E->next()) { + if (!E->get().force_keep_in_merge_ends) { + to_remove.push_back(E); + } + } - while (E) { + for (unsigned int i = 0; i < to_remove.size(); i++) { + List<Operation>::Element *E = to_remove[i]; + // Delete all object references if (E->get().type == Operation::TYPE_REFERENCE) { Object *obj = ObjectDB::get_instance(E->get().object); @@ -96,27 +104,26 @@ void UndoRedo::create_action(const String &p_name, MergeMode p_mode) { memdelete(obj); } } - - E = E->next(); - actions.write[current_action + 1].do_ops.pop_front(); + E->erase(); } } actions.write[actions.size() - 1].last_tick = ticks; - merge_mode = p_mode; merging = true; } else { Action new_action; new_action.name = p_name; new_action.last_tick = ticks; actions.push_back(new_action); - - merge_mode = MERGE_DISABLE; } + + merge_mode = p_mode; } action_level++; + + force_keep_in_merge_ends = false; } void UndoRedo::add_do_method(Object *p_object, const StringName &p_method, VARIANT_ARG_DECLARE) { @@ -146,7 +153,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -157,6 +164,7 @@ void UndoRedo::add_undo_method(Object *p_object, const StringName &p_method, VAR } undo_op.type = Operation::TYPE_METHOD; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_method; for (int i = 0; i < VARIANT_ARG_MAX; i++) { @@ -187,7 +195,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -198,6 +206,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, } undo_op.type = Operation::TYPE_PROPERTY; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; undo_op.name = p_property; undo_op.args[0] = p_value; actions.write[current_action + 1].undo_ops.push_back(undo_op); @@ -223,7 +232,7 @@ void UndoRedo::add_undo_reference(Object *p_object) { ERR_FAIL_COND((current_action + 1) >= actions.size()); // No undo if the merge mode is MERGE_ENDS - if (merge_mode == MERGE_ENDS) { + if (!force_keep_in_merge_ends && merge_mode == MERGE_ENDS) { return; } @@ -234,9 +243,24 @@ void UndoRedo::add_undo_reference(Object *p_object) { } undo_op.type = Operation::TYPE_REFERENCE; + undo_op.force_keep_in_merge_ends = force_keep_in_merge_ends; actions.write[current_action + 1].undo_ops.push_back(undo_op); } +void UndoRedo::start_force_keep_in_merge_ends() { + ERR_FAIL_COND(action_level <= 0); + ERR_FAIL_COND((current_action + 1) >= actions.size()); + + force_keep_in_merge_ends = true; +} + +void UndoRedo::end_force_keep_in_merge_ends() { + ERR_FAIL_COND(action_level <= 0); + ERR_FAIL_COND((current_action + 1) >= actions.size()); + + force_keep_in_merge_ends = false; +} + void UndoRedo::_pop_history_tail() { _discard_redo(); @@ -538,6 +562,9 @@ void UndoRedo::_bind_methods() { ClassDB::bind_method(D_METHOD("add_do_reference", "object"), &UndoRedo::add_do_reference); ClassDB::bind_method(D_METHOD("add_undo_reference", "object"), &UndoRedo::add_undo_reference); + ClassDB::bind_method(D_METHOD("start_force_keep_in_merge_ends"), &UndoRedo::start_force_keep_in_merge_ends); + ClassDB::bind_method(D_METHOD("end_force_keep_in_merge_ends"), &UndoRedo::end_force_keep_in_merge_ends); + ClassDB::bind_method(D_METHOD("get_history_count"), &UndoRedo::get_history_count); ClassDB::bind_method(D_METHOD("get_current_action"), &UndoRedo::get_current_action); ClassDB::bind_method(D_METHOD("get_action_name", "id"), &UndoRedo::get_action_name); diff --git a/core/object/undo_redo.h b/core/object/undo_redo.h index d1ce252d86..a757d154e2 100644 --- a/core/object/undo_redo.h +++ b/core/object/undo_redo.h @@ -61,6 +61,7 @@ private: }; Type type; + bool force_keep_in_merge_ends; Ref<RefCounted> ref; ObjectID object; StringName name; @@ -76,6 +77,7 @@ private: Vector<Action> actions; int current_action = -1; + bool force_keep_in_merge_ends = false; int action_level = 0; MergeMode merge_mode = MERGE_DISABLE; bool merging = false; @@ -109,6 +111,9 @@ public: void add_do_reference(Object *p_object); void add_undo_reference(Object *p_object); + void start_force_keep_in_merge_ends(); + void end_force_keep_in_merge_ends(); + bool is_committing_action() const; void commit_action(bool p_execute = true); diff --git a/core/variant/variant.h b/core/variant/variant.h index 9ec131a1b8..d3f694e7ca 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -641,6 +641,7 @@ public: static UtilityFunctionType get_utility_function_type(const StringName &p_name); + static MethodInfo get_utility_function_info(const StringName &p_name); static int get_utility_function_argument_count(const StringName &p_name); static Variant::Type get_utility_function_argument_type(const StringName &p_name, int p_arg); static String get_utility_function_argument_name(const StringName &p_name, int p_arg); diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp index 55c1376031..666b582e39 100644 --- a/core/variant/variant_utility.cpp +++ b/core/variant/variant_utility.cpp @@ -1333,6 +1333,28 @@ Variant::UtilityFunctionType Variant::get_utility_function_type(const StringName return bfi->type; } +MethodInfo Variant::get_utility_function_info(const StringName &p_name) { + MethodInfo info; + const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); + if (bfi) { + info.name = p_name; + if (bfi->returns_value && bfi->return_type == Variant::NIL) { + info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + } + info.return_val.type = bfi->return_type; + if (bfi->is_vararg) { + info.flags |= METHOD_FLAG_VARARG; + } + for (int i = 0; i < bfi->argnames.size(); ++i) { + PropertyInfo arg; + arg.type = bfi->get_arg_type(i); + arg.name = bfi->argnames[i]; + info.arguments.push_back(arg); + } + } + return info; +} + int Variant::get_utility_function_argument_count(const StringName &p_name) { const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name); if (!bfi) { diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml index f20f4adcdf..c5a44009d2 100644 --- a/doc/classes/EditorImportPlugin.xml +++ b/doc/classes/EditorImportPlugin.xml @@ -5,7 +5,7 @@ </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 (see [member ProjectSettings.application/config/project_data_dir_name]). Below is an example EditorImportPlugin that imports a [Mesh] from a file with the extension ".special" or ".spec": [codeblocks] [gdscript] @@ -197,7 +197,7 @@ <method name="_get_save_extension" qualifiers="virtual const"> <return type="String" /> <description> - Gets the extension used to save this resource in the [code].godot/imported[/code] directory. + Gets the extension used to save this resource in the [code].godot/imported[/code] directory (see [member ProjectSettings.application/config/project_data_dir_name]). </description> </method> <method name="_get_visible_name" qualifiers="virtual const"> diff --git a/doc/classes/EditorSyntaxHighlighter.xml b/doc/classes/EditorSyntaxHighlighter.xml index 8880ce4d44..462323a067 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 ScriptEditorBase._add_syntax_highlighter (currently not working). 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/Node.xml b/doc/classes/Node.xml index cae74ca553..843db8c174 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -551,6 +551,7 @@ <argument index="0" name="node" type="Node" /> <description> Removes a child node. The node is NOT deleted and must be deleted manually. + [b]Note:[/b] This function may set the [member owner] of the removed Node (or its descendants) to be [code]null[/code], if that [member owner] is no longer a parent or ancestor. </description> </method> <method name="remove_from_group"> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 5403bd48d5..eec06d6f82 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -221,6 +221,11 @@ The project's name. It is used both by the Project Manager and by exporters. The project name can be translated by translating its value in localization files. The window title will be set to match the project name automatically on startup. [b]Note:[/b] Changing this value will also change the user data folder's path if [member application/config/use_custom_user_dir] is [code]false[/code]. After renaming the project, you will no longer be able to access existing data in [code]user://[/code] unless you rename the old folder to match the new project name. See [url=https://docs.godotengine.org/en/latest/tutorials/io/data_paths.html]Data paths[/url] in the documentation for more information. </member> + <member name="application/config/project_data_dir_name" type="String" setter="" getter="" default="".godot""> + The project data directory is used for storing project-specific data (metadata, shader cache, etc.). + [b]Note:[/b] Restart the application after changing this setting. + [b]Note:[/b] Changing this value can help on platforms or with third-party tools where specific directory patterns are disallowed. Only modify this setting if you know that your environment requires it, as changing the default can impact compatibility with some external tools or plugins which expect the default [code].godot[/code] folder. + </member> <member name="application/config/project_settings_override" type="String" setter="" getter="" default=""""> Specifies a file to override project settings. For example: [code]user://custom_settings.cfg[/code]. See "Overriding" in the [ProjectSettings] class description at the top for more information. [b]Note:[/b] Regardless of this setting's value, [code]res://override.cfg[/code] will still be read to override the project settings. @@ -1745,23 +1750,23 @@ </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. + [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 (see [member application/config/project_data_dir_name]). </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. + [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 (see [member application/config/project_data_dir_name]). </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. + [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 (see [member application/config/project_data_dir_name]). </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. + [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 (see [member application/config/project_data_dir_name]). </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. + [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 (see [member application/config/project_data_dir_name]). </member> <member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64"> </member> diff --git a/doc/classes/ScriptEditorBase.xml b/doc/classes/ScriptEditorBase.xml index 1e72fe9090..88adeaf12f 100644 --- a/doc/classes/ScriptEditorBase.xml +++ b/doc/classes/ScriptEditorBase.xml @@ -9,6 +9,13 @@ <tutorials> </tutorials> <methods> + <method name="add_syntax_highlighter"> + <return type="void" /> + <argument index="0" name="highlighter" type="EditorSyntaxHighlighter" /> + <description> + Adds a [EditorSyntaxHighlighter] to the open script. + </description> + </method> <method name="get_base_editor" qualifiers="const"> <return type="Control" /> <description> diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml index def6fe5d1f..044460f569 100644 --- a/doc/classes/UndoRedo.xml +++ b/doc/classes/UndoRedo.xml @@ -134,6 +134,12 @@ The way actions are merged is dictated by the [code]merge_mode[/code] argument. See [enum MergeMode] for details. </description> </method> + <method name="end_force_keep_in_merge_ends"> + <return type="void" /> + <description> + Stops marking operations as to be processed even if the action gets merged with another in the [constant MERGE_ENDS] mode. See [method start_force_keep_in_merge_ends]. + </description> + </method> <method name="get_action_name"> <return type="String" /> <argument index="0" name="id" type="int" /> @@ -190,6 +196,12 @@ Redo the last action. </description> </method> + <method name="start_force_keep_in_merge_ends"> + <return type="void" /> + <description> + Marks the next "do" and "undo" operations to be processed even if the action gets merged with another in the [constant MERGE_ENDS] mode. Return to normal operation using [method end_force_keep_in_merge_ends]. + </description> + </method> <method name="undo"> <return type="bool" /> <description> @@ -209,7 +221,7 @@ Makes "do"/"undo" operations stay in separate actions. </constant> <constant name="MERGE_ENDS" value="1" enum="MergeMode"> - Makes so that the action's "do" operation is from the first action created and the "undo" operation is from the last subsequent action with the same name. + Makes so that the action's "undo" operations are from the first action created and the "do" operations are from the last subsequent action with the same name. </constant> <constant name="MERGE_ALL" value="2" enum="MergeMode"> Makes subsequent actions with the same name be merged into one. diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 26508dc612..39d296e7cf 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -36,7 +36,8 @@ if env["builtin_libpng"]: # Currently .ASM filter_neon.S does not compile on NT. import os - use_neon = "neon_enabled" in env and env["neon_enabled"] and os.name != "nt" + # Enable ARM NEON instructions on 32-bit Android to compile more optimized code. + use_neon = "android_arch" in env and env["android_arch"] == "armv7" and os.name != "nt" if use_neon: env_png.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT", 2)]) else: diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index d32592e81a..42b5bbfaf2 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -110,7 +110,7 @@ void IPUnix::_resolve_hostname(List<IPAddress> &r_addresses, const String &p_hos struct addrinfo *next = result; do { - if (next->ai_addr == NULL) { + if (next->ai_addr == nullptr) { next = next->ai_next; continue; } diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 152efc7807..44fed02f41 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -525,7 +525,7 @@ Error VulkanContext::_check_capabilities() { // check our extended features VkPhysicalDeviceMultiviewFeatures multiview_features; multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - multiview_features.pNext = NULL; + multiview_features.pNext = nullptr; VkPhysicalDeviceFeatures2 device_features; device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index 6fef65c92d..767856f939 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -2163,7 +2163,7 @@ Error EditorFileSystem::_resource_import(const String &p_path) { } bool EditorFileSystem::_should_skip_directory(const String &p_path) { - if (p_path == ProjectSettings::get_singleton()->get_project_data_path()) { + if (p_path.begins_with(ProjectSettings::get_singleton()->get_project_data_path())) { return true; } diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index 71f13c0c2f..5b48cc2638 100644 --- a/editor/editor_paths.cpp +++ b/editor/editor_paths.cpp @@ -200,6 +200,20 @@ EditorPaths::EditorPaths() { paths_valid = false; } } + + // Check that the project data directory '.gdignore' file exists + String project_data_gdignore_file_path = project_data_dir.plus_file(".gdignore"); + if (!FileAccess::exists(project_data_gdignore_file_path)) { + // Add an empty .gdignore file to avoid scan. + FileAccessRef f = FileAccess::open(project_data_gdignore_file_path, FileAccess::WRITE); + if (f) { + f->store_line(""); + f->close(); + } else { + ERR_PRINT("Failed to create file " + project_data_gdignore_file_path); + } + } + Engine::get_singleton()->set_shader_cache_path(project_data_dir); // Editor metadata dir. diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 283496c0f1..b61f6e12eb 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -235,7 +235,7 @@ void FindInFiles::_scan_dir(String path, PackedStringArray &out_folders) { // Ignore special dirs (such as .git and project data directory) String project_data_dir_name = ProjectSettings::get_singleton()->get_project_data_dir_name(); - if (file.begins_with(".") || file == project_data_dir_name) { + if (file.begins_with(".") || file.begins_with(project_data_dir_name)) { continue; } if (dir->current_is_hidden()) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 5df6743f4c..677a5f1f2c 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -214,6 +214,7 @@ Ref<EditorSyntaxHighlighter> EditorPlainTextSyntaxHighlighter::_create() const { void ScriptEditorBase::_bind_methods() { ClassDB::bind_method(D_METHOD("get_base_editor"), &ScriptEditorBase::get_base_editor); + ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &ScriptEditorBase::add_syntax_highlighter); ADD_SIGNAL(MethodInfo("name_changed")); ADD_SIGNAL(MethodInfo("edited_script_changed")); @@ -762,20 +763,24 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tselected); if (current) { - Ref<Script> script = current->get_edited_resource(); - if (p_save && script.is_valid()) { + RES file = current->get_edited_resource(); + if (p_save && file.is_valid()) { // Do not try to save internal scripts, but prompt to save in-memory // scripts which are not saved to disk yet (have empty path). - if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { + if (file->get_path().find("local://") == -1 && file->get_path().find("::") == -1) { save_current_script(); } } - if (script.is_valid()) { - if (!script->get_path().is_empty()) { + if (file.is_valid()) { + if (!file->get_path().is_empty()) { // Only saved scripts can be restored. - previous_scripts.push_back(script->get_path()); + previous_scripts.push_back(file->get_path()); + } + + Ref<Script> script = file; + if (script.is_valid()) { + notify_script_close(script); } - notify_script_close(script); } } @@ -1079,7 +1084,6 @@ void ScriptEditor::_file_dialog_action(String p_file) { memdelete(file); if (EditorFileSystem::get_singleton()) { - const Vector<String> textfile_extensions = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false); if (textfile_extensions.has(p_file.get_extension())) { EditorFileSystem::get_singleton()->update_file(p_file); } @@ -1167,9 +1171,8 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog_option = FILE_NEW_TEXTFILE; file_dialog->clear_filters(); - const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false); - for (int i = 0; i < textfile_ext.size(); i++) { - file_dialog->add_filter("*." + textfile_ext[i] + " ; " + textfile_ext[i].to_upper()); + for (const String &E : textfile_extensions) { + file_dialog->add_filter("*." + E + " ; " + E.to_upper()); } file_dialog->popup_file_dialog(); file_dialog->set_title(TTR("New Text File...")); @@ -1187,9 +1190,8 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); } - const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false); - for (int i = 0; i < textfile_ext.size(); i++) { - file_dialog->add_filter("*." + textfile_ext[i] + " ; " + textfile_ext[i].to_upper()); + for (const String &E : textfile_extensions) { + file_dialog->add_filter("*." + E + " ; " + E.to_upper()); } file_dialog->popup_file_dialog(); @@ -1542,6 +1544,7 @@ void ScriptEditor::_notification(int p_what) { EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &ScriptEditor::_editor_settings_changed)); EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &ScriptEditor::_filesystem_changed)); + _editor_settings_changed(); [[fallthrough]]; } case NOTIFICATION_TRANSLATION_CHANGED: @@ -2117,7 +2120,7 @@ void ScriptEditor::_update_script_connections() { } } -Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error) { +Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error) const { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } @@ -2601,6 +2604,12 @@ void ScriptEditor::_save_layout() { } void ScriptEditor::_editor_settings_changed() { + textfile_extensions.clear(); + const Vector<String> textfile_ext = ((String)(EditorSettings::get_singleton()->get("docks/filesystem/textfile_extensions"))).split(",", false); + for (const String &E : textfile_ext) { + textfile_extensions.insert(E); + } + trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/behavior/files/trim_trailing_whitespace_on_save"); convert_indent_on_save = EditorSettings::get_singleton()->get("text_editor/behavior/files/convert_indent_on_save"); use_space_indentation = EditorSettings::get_singleton()->get("text_editor/behavior/indent/type"); @@ -2807,12 +2816,22 @@ bool ScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data if (file == "" || !FileAccess::exists(file)) { continue; } - Ref<Script> scr = ResourceLoader::load(file); - if (scr.is_valid()) { - return true; + if (ResourceLoader::exists(file, "Script")) { + Ref<Script> scr = ResourceLoader::load(file); + if (scr.is_valid()) { + return true; + } + } + + if (textfile_extensions.has(file.get_extension())) { + Error err; + Ref<TextFile> text_file = _load_text_file(file, &err); + if (text_file.is_valid() && err == OK) { + return true; + } } } - return true; + return false; } return false; @@ -2877,9 +2896,13 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co if (file == "" || !FileAccess::exists(file)) { continue; } - Ref<Script> scr = ResourceLoader::load(file); - if (scr.is_valid()) { - edit(scr); + + if (!ResourceLoader::exists(file, "Script") && !textfile_extensions.has(file.get_extension())) { + continue; + } + + RES res = open_file(file); + if (res.is_valid()) { if (tab_container->get_child_count() > num_tabs_before) { tab_container->move_child(tab_container->get_child(tab_container->get_child_count() - 1), new_index); num_tabs_before = tab_container->get_child_count(); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index ce26699280..8caebc1c8c 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -453,7 +453,8 @@ class ScriptEditor : public PanelContainer { Ref<Script> _get_current_script(); Array _get_open_scripts() const; - Ref<TextFile> _load_text_file(const String &p_path, Error *r_error); + Set<String> textfile_extensions; + Ref<TextFile> _load_text_file(const String &p_path, Error *r_error) const; Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path); void _on_find_in_files_requested(String text); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 1c251075de..2c02389db2 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -1341,8 +1341,6 @@ void ScriptTextEditor::_bind_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(D_METHOD("add_syntax_highlighter", "highlighter"), &ScriptTextEditor::add_syntax_highlighter); } Control *ScriptTextEditor::get_edit_menu() { diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 06ba8a6168..1fc7eb98e0 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -407,10 +407,6 @@ void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { code_editor->convert_case(p_case); } -void TextEditor::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &TextEditor::add_syntax_highlighter); -} - static ScriptEditorBase *create_editor(const RES &p_resource) { if (Object::cast_to<TextFile>(*p_resource)) { return memnew(TextEditor); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 9308fec210..7404557f46 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -87,8 +87,6 @@ private: }; protected: - static void _bind_methods(); - void _edit_option(int p_op); void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position); void _text_edit_gui_input(const Ref<InputEvent> &ev); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index cc5ff90541..c2e86f8b43 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -465,6 +465,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } + _fix_invalid_tiles_in_tile_map_selection(); } break; case DRAG_TYPE_BUCKET: { Vector<Vector2i> line = TileMapEditor::get_line(tile_map, tile_map->world_to_map(drag_last_mouse_pos), tile_map->world_to_map(mpos)); @@ -483,6 +484,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } } } + _fix_invalid_tiles_in_tile_map_selection(); } break; default: break; @@ -508,6 +510,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p drag_start_mouse_pos = mpos; if (tile_map_selection.has(tile_map->world_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) { // Move the selection + _update_selection_pattern_from_tilemap_selection(); // Make sure the pattern is up to date before moving. drag_type = DRAG_TYPE_MOVE; drag_modified.clear(); for (Set<Vector2i>::Element *E = tile_map_selection.front(); E; E = E->next()) { @@ -541,6 +544,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile); } + _fix_invalid_tiles_in_tile_map_selection(); } else if (tool_buttons_group->get_pressed_button() == line_tool_button) { drag_type = DRAG_TYPE_LINE; drag_start_mouse_pos = mpos; @@ -569,6 +573,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p } } } + _fix_invalid_tiles_in_tile_map_selection(); } } } @@ -1323,6 +1328,25 @@ void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() { } } +void TileMapEditorTilesPlugin::_fix_invalid_tiles_in_tile_map_selection() { + TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); + if (!tile_map) { + return; + } + + Set<Vector2i> to_remove; + for (Vector2i selected : tile_map_selection) { + TileMapCell cell = tile_map->get_cell(tile_map_layer, selected); + if (cell.source_id == TileSet::INVALID_SOURCE && cell.get_atlas_coords() == TileSetSource::INVALID_ATLAS_COORDS && cell.alternative_tile == TileSetAtlasSource::INVALID_TILE_ALTERNATIVE) { + to_remove.insert(selected); + } + } + + for (Vector2i cell : to_remove) { + tile_map_selection.erase(cell); + } +} + void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection() { TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id)); if (!tile_map) { @@ -1423,6 +1447,8 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern( } } _update_bottom_panel(); + tile_atlas_control->update(); + alternative_tiles_control->update(); } void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index 6126db59e9..a1ab3db318 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -124,6 +124,7 @@ private: void _update_selection_pattern_from_tileset_selection(); void _update_tileset_selection_from_selection_pattern(); void _update_fix_selected_and_hovered(); + void _fix_invalid_tiles_in_tile_map_selection(); ///// Bottom panel. ////. Label *missing_source_label; diff --git a/main/main.cpp b/main/main.cpp index 5a2a088494..3cc7923cc2 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2488,17 +2488,17 @@ bool Main::iteration() { iterating++; - uint64_t ticks = OS::get_singleton()->get_ticks_usec(); + const uint64_t ticks = OS::get_singleton()->get_ticks_usec(); Engine::get_singleton()->_frame_ticks = ticks; main_timer_sync.set_cpu_ticks_usec(ticks); main_timer_sync.set_fixed_fps(fixed_fps); - uint64_t ticks_elapsed = ticks - last_ticks; + const uint64_t ticks_elapsed = ticks - last_ticks; - int physics_ticks_per_second = Engine::get_singleton()->get_physics_ticks_per_second(); - float physics_step = 1.0 / physics_ticks_per_second; + const int physics_ticks_per_second = Engine::get_singleton()->get_physics_ticks_per_second(); + const double physics_step = 1.0 / physics_ticks_per_second; - float time_scale = Engine::get_singleton()->get_time_scale(); + const double time_scale = Engine::get_singleton()->get_time_scale(); MainFrameTime advance = main_timer_sync.advance(physics_step, physics_ticks_per_second); double process_step = advance.process_step; diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 53694035dc..5ffe644495 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -408,7 +408,7 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b } break; - case OPERATION_SUBSTRACTION: { + case OPERATION_SUBTRACTION: { int face_count = 0; for (int i = 0; i < mesh_merge.faces.size(); i++) { diff --git a/modules/csg/csg.h b/modules/csg/csg.h index c872860486..b1fe933268 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -67,7 +67,7 @@ struct CSGBrushOperation { enum Operation { OPERATION_UNION, OPERATION_INTERSECTION, - OPERATION_SUBSTRACTION, + OPERATION_SUBTRACTION, }; void merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap); diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index e4297a593e..14e7896295 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -192,7 +192,7 @@ CSGBrush *CSGShape3D::_get_brush() { bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap); break; case CSGShape3D::OPERATION_SUBTRACTION: - bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap); + bop.merge_brushes(CSGBrushOperation::OPERATION_SUBTRACTION, *n, *nn2, *nn, snap); break; } memdelete(n); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 2dafc85f45..8bd288cf0f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -470,6 +470,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type); if (container_type.kind != GDScriptParser::DataType::VARIANT) { + container_type.is_meta_type = false; result.set_container_element_type(container_type); } } @@ -875,18 +876,34 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { GDScriptParser::ClassNode *previous_class = parser->current_class; parser->current_class = p_class; - // Do functions now. + // Do functions and properties now. for (int i = 0; i < p_class->members.size(); i++) { GDScriptParser::ClassNode::Member member = p_class->members[i]; - if (member.type != GDScriptParser::ClassNode::Member::FUNCTION) { - continue; - } + if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) { + resolve_function_body(member.function); + + // Apply annotations. + for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { + E->apply(parser, member.function); + } + } else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) { + if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) { + if (member.variable->getter != nullptr) { + member.variable->getter->set_datatype(member.variable->datatype); - resolve_function_body(member.function); + resolve_function_body(member.variable->getter); + } + if (member.variable->setter != nullptr) { + resolve_function_signature(member.variable->setter); + + if (member.variable->setter->parameters.size() > 0) { + member.variable->setter->parameters[0]->datatype_specifier = member.variable->datatype_specifier; + member.variable->setter->parameters[0]->set_datatype(member.get_datatype()); + } - // Apply annotations. - for (GDScriptParser::AnnotationNode *&E : member.function->annotations) { - E->apply(parser, member.function); + resolve_function_body(member.variable->setter); + } + } } } @@ -902,17 +919,80 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) { resolve_class_body(member.m_class); } - // Check unused variables. + // Check unused variables and datatypes of property getters and setters. for (int i = 0; i < p_class->members.size(); i++) { GDScriptParser::ClassNode::Member member = p_class->members[i]; - if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) { - continue; - } + if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) { #ifdef DEBUG_ENABLED - if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) { - parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name); - } + if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) { + parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name); + } #endif + + if (member.variable->property == GDScriptParser::VariableNode::PROP_SETGET) { + GDScriptParser::FunctionNode *getter_function = nullptr; + GDScriptParser::FunctionNode *setter_function = nullptr; + + bool has_valid_getter = false; + bool has_valid_setter = false; + + if (member.variable->getter_pointer != nullptr) { + if (p_class->has_function(member.variable->getter_pointer->name)) { + getter_function = p_class->get_member(member.variable->getter_pointer->name).function; + } + + if (getter_function == nullptr) { + push_error(vformat(R"(Getter "%s" not found.)", member.variable->getter_pointer->name), member.variable); + + } else if (getter_function->parameters.size() != 0 || getter_function->datatype.has_no_type()) { + push_error(vformat(R"(Function "%s" cannot be used as getter because of its signature.)", getter_function->identifier->name), member.variable); + + } else if (!is_type_compatible(member.variable->datatype, getter_function->datatype, true)) { + push_error(vformat(R"(Function with return type "%s" cannot be used as getter for a property of type "%s".)", getter_function->datatype.to_string(), member.variable->datatype.to_string()), member.variable); + + } else { + has_valid_getter = true; + +#ifdef DEBUG_ENABLED + if (member.variable->datatype.builtin_type == Variant::INT && getter_function->datatype.builtin_type == Variant::FLOAT) { + parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION); + } +#endif + } + } + + if (member.variable->setter_pointer != nullptr) { + if (p_class->has_function(member.variable->setter_pointer->name)) { + setter_function = p_class->get_member(member.variable->setter_pointer->name).function; + } + + if (setter_function == nullptr) { + push_error(vformat(R"(Setter "%s" not found.)", member.variable->setter_pointer->name), member.variable); + + } else if (setter_function->parameters.size() != 1) { + push_error(vformat(R"(Function "%s" cannot be used as setter because of its signature.)", setter_function->identifier->name), member.variable); + + } else if (!is_type_compatible(member.variable->datatype, setter_function->parameters[0]->datatype, true)) { + push_error(vformat(R"(Function with argument type "%s" cannot be used as setter for a property of type "%s".)", setter_function->parameters[0]->datatype.to_string(), member.variable->datatype.to_string()), member.variable); + + } else { + has_valid_setter = true; + +#ifdef DEBUG_ENABLED + if (member.variable->datatype.builtin_type == Variant::INT && setter_function->return_type->datatype.builtin_type == Variant::FLOAT) { + parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION); + } +#endif + } + } + + if (member.variable->datatype.is_variant() && has_valid_getter && has_valid_setter) { + if (!is_type_compatible(getter_function->datatype, setter_function->parameters[0]->datatype, true)) { + push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable); + } + } + } + } } } @@ -1529,12 +1609,20 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { GDScriptParser::DataType result; + GDScriptParser::DataType expected_type; + bool has_expected_type = false; + + if (parser->current_function != nullptr) { + expected_type = parser->current_function->get_datatype(); + has_expected_type = true; + } + if (p_return->return_value != nullptr) { reduce_expression(p_return->return_value); if (p_return->return_value->type == GDScriptParser::Node::ARRAY) { // Check if assigned value is an array literal, so we can make it a typed array too if appropriate. - if (parser->current_function->get_datatype().has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) { - update_array_literal_element_type(parser->current_function->get_datatype(), static_cast<GDScriptParser::ArrayNode *>(p_return->return_value)); + if (has_expected_type && expected_type.has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) { + update_array_literal_element_type(expected_type, static_cast<GDScriptParser::ArrayNode *>(p_return->return_value)); } } result = p_return->return_value->get_datatype(); @@ -1546,23 +1634,24 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) { result.is_constant = true; } - GDScriptParser::DataType function_type = parser->current_function->get_datatype(); - function_type.is_meta_type = false; - if (function_type.is_hard_type()) { - if (!is_type_compatible(function_type, result)) { - // Try other way. Okay but not safe. - if (!is_type_compatible(result, function_type)) { - push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), function_type.to_string()), p_return); - } else { - // TODO: Add warning. - mark_node_unsafe(p_return); - } + if (has_expected_type) { + expected_type.is_meta_type = false; + if (expected_type.is_hard_type()) { + if (!is_type_compatible(expected_type, result)) { + // Try other way. Okay but not safe. + if (!is_type_compatible(result, expected_type)) { + push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), expected_type.to_string()), p_return); + } else { + // TODO: Add warning. + mark_node_unsafe(p_return); + } #ifdef DEBUG_ENABLED - } else if (function_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) { - parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION); - } else if (result.is_variant()) { - mark_node_unsafe(p_return); + } else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) { + parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION); + } else if (result.is_variant()) { + mark_node_unsafe(p_return); #endif + } } } diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index b8300cd872..6a7e4278d2 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -692,7 +692,8 @@ void GDScriptByteCodeGenerator::write_end_ternary() { void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) { if (HAS_BUILTIN_TYPE(p_target)) { - if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type)) { + if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type) && + IS_BUILTIN_TYPE(p_source, Variant::get_indexed_element_type(p_target.type.builtin_type))) { // Use indexed setter instead. Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type); append(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED, 3); @@ -746,7 +747,8 @@ void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address } void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) { - if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name)) { + if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name) && + IS_BUILTIN_TYPE(p_source, Variant::get_member_type(p_target.type.builtin_type, p_name))) { Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name); append(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED, 2); append(p_target); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 34b1e45cdf..1f9aad40af 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2089,77 +2089,18 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) { Error error = OK; - CodeGen codegen; - codegen.generator = memnew(GDScriptByteCodeGenerator); - - codegen.class_node = p_class; - codegen.script = p_script; - StringName func_name; + GDScriptParser::FunctionNode *function; if (p_is_setter) { - func_name = "@" + p_variable->identifier->name + "_setter"; + function = p_variable->setter; } else { - func_name = "@" + p_variable->identifier->name + "_getter"; + function = p_variable->getter; } - codegen.function_name = func_name; - - GDScriptDataType return_type; - if (p_is_setter) { - return_type.has_type = true; - return_type.kind = GDScriptDataType::BUILTIN; - return_type.builtin_type = Variant::NIL; - } else { - return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script); - } + _parse_function(error, p_script, p_class, function); - codegen.generator->write_start(p_script, func_name, false, Multiplayer::RPCConfig(), return_type); - - if (p_is_setter) { - uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype())); - codegen.parameters[p_variable->setter_parameter->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, _gdtype_from_datatype(p_variable->get_datatype())); - } - - error = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter); - if (error) { - memdelete(codegen.generator); - return error; - } - - GDScriptFunction *gd_function = codegen.generator->write_end(); - - p_script->member_functions[func_name] = gd_function; - -#ifdef DEBUG_ENABLED - if (EngineDebugger::is_active()) { - String signature; - //path - if (p_script->get_path() != String()) { - signature += p_script->get_path(); - } - //loc - signature += "::" + itos(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line); - - //function and class - - if (p_class->identifier) { - signature += "::" + String(p_class->identifier->name) + "." + String(func_name); - } else { - signature += "::" + String(func_name); - } - - codegen.generator->set_signature(signature); - } -#endif - codegen.generator->set_initial_line(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line); - -#ifdef TOOLS_ENABLED - p_script->member_lines[func_name] = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line; -#endif - memdelete(codegen.generator); - - return OK; + return error; } Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index e49bf518a2..71d2699c2e 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -1089,6 +1089,15 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool kwa++; } + 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()) { + ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_FUNCTION); + option.insert_text += "("; + r_result.insert(option.display, option); + } + OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list(); for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) { if (!E.value().is_singleton) { @@ -2325,7 +2334,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c GDScriptCompletionIdentifier connect_base; - if (GDScriptUtilityFunctions::function_exists(call->function_name)) { + if (Variant::has_utility_function(call->function_name)) { + MethodInfo info = Variant::get_utility_function_info(call->function_name); + r_arghint = _make_arguments_hint(info, p_argidx); + return; + } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) { MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name); r_arghint = _make_arguments_hint(info, p_argidx); return; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index d3b57fbe18..40be5cb324 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -947,7 +947,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var void GDScriptParser::parse_property_setter(VariableNode *p_variable) { switch (p_variable->property) { - case VariableNode::PROP_INLINE: + case VariableNode::PROP_INLINE: { consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)"); if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) { p_variable->setter_parameter = parse_identifier(); @@ -955,9 +955,30 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) { consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*"); consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*"); - p_variable->setter = parse_suite("setter definition"); - break; + IdentifierNode *identifier = alloc_node<IdentifierNode>(); + identifier->name = "@" + p_variable->identifier->name + "_setter"; + + FunctionNode *function = alloc_node<FunctionNode>(); + function->identifier = identifier; + + FunctionNode *previous_function = current_function; + current_function = function; + + ParameterNode *parameter = alloc_node<ParameterNode>(); + parameter->identifier = p_variable->setter_parameter; + + function->parameters_indices[parameter->identifier->name] = 0; + function->parameters.push_back(parameter); + + SuiteNode *body = alloc_node<SuiteNode>(); + body->add_local(parameter, function); + + function->body = parse_suite("setter declaration", body); + p_variable->setter = function; + current_function = previous_function; + break; + } case VariableNode::PROP_SETGET: consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "set")"); make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable); @@ -972,11 +993,25 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) { void GDScriptParser::parse_property_getter(VariableNode *p_variable) { switch (p_variable->property) { - case VariableNode::PROP_INLINE: + case VariableNode::PROP_INLINE: { consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)"); - p_variable->getter = parse_suite("getter definition"); + IdentifierNode *identifier = alloc_node<IdentifierNode>(); + identifier->name = "@" + p_variable->identifier->name + "_getter"; + + FunctionNode *function = alloc_node<FunctionNode>(); + function->identifier = identifier; + + FunctionNode *previous_function = current_function; + current_function = function; + + SuiteNode *body = alloc_node<SuiteNode>(); + function->body = parse_suite("getter declaration", body); + + p_variable->getter = function; + current_function = previous_function; break; + } case VariableNode::PROP_SETGET: consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "get")"); make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable); @@ -3423,7 +3458,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node String enum_hint_string; for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) { - enum_hint_string += E->key().operator String().camelcase_to_underscore(true).capitalize().xml_escape(); + enum_hint_string += E->key().operator String().capitalize().xml_escape(); enum_hint_string += ":"; enum_hint_string += String::num_int64(E->get()).xml_escape(); @@ -4437,7 +4472,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) { if (p_variable->property == VariableNode::PROP_INLINE) { push_line(":"); increase_indent(); - print_suite(p_variable->getter); + print_suite(p_variable->getter->body); decrease_indent(); } else { push_line(" ="); @@ -4457,7 +4492,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) { } push_line("):"); increase_indent(); - print_suite(p_variable->setter); + print_suite(p_variable->setter->body); decrease_indent(); } else { push_line(" ="); diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 593fb0cc5e..af9b973ada 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -1109,12 +1109,12 @@ public: PropertyStyle property = PROP_NONE; union { - SuiteNode *setter = nullptr; + FunctionNode *setter = nullptr; IdentifierNode *setter_pointer; }; IdentifierNode *setter_parameter = nullptr; union { - SuiteNode *getter = nullptr; + FunctionNode *getter = nullptr; IdentifierNode *getter_pointer; }; diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp index 730e554476..f4c0c4d9bb 100644 --- a/modules/gdscript/language_server/gdscript_extend_parser.cpp +++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp @@ -165,7 +165,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p case ClassNode::Member::VARIABLE: { lsp::DocumentSymbol symbol; symbol.name = m.variable->identifier->name; - symbol.kind = m.variable->property == VariableNode::PropertyStyle::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property; + symbol.kind = m.variable->property == VariableNode::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property; symbol.deprecated = false; symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line); symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column); diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd new file mode 100644 index 0000000000..f1be6aaa0c --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd @@ -0,0 +1,11 @@ +var _prop : int + +# Getter function has wrong return type. +var prop : String: + get = get_prop + +func get_prop(): + return _prop + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out new file mode 100644 index 0000000000..29eec51ef2 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Function with return type "int" cannot be used as getter for a property of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd new file mode 100644 index 0000000000..dd190157a1 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd @@ -0,0 +1,11 @@ +var _prop : int + +# Setter function has wrong argument type. +var prop : String: + set = set_prop + +func set_prop(value : int): + _prop = value + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out new file mode 100644 index 0000000000..7a25280d55 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Function with argument type "int" cannot be used as setter for a property of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd new file mode 100644 index 0000000000..7f2b29222a --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd @@ -0,0 +1,9 @@ +var _prop : int + +# Inline getter returns int instead of String. +var prop : String: + get: + return _prop + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out new file mode 100644 index 0000000000..e0adef1bf8 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot return value of type "int" because the function return type is "String". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd new file mode 100644 index 0000000000..0ce239dbbd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd @@ -0,0 +1,9 @@ +var _prop : int + +# Inline setter assigns String to int. +var prop : String: + set(value): + _prop = value + +func test(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out new file mode 100644 index 0000000000..bbadf1ce27 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Cannot assign a value of type "String" to a target of type "int". diff --git a/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd new file mode 100644 index 0000000000..3bbee5f5f7 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd @@ -0,0 +1,8 @@ +var with_setter := 0: + set(val): + var x: String = val + with_setter = val + +func test(): + with_setter = 1 + print(with_setter) diff --git a/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out new file mode 100644 index 0000000000..9eb2a42ccd --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out @@ -0,0 +1,2 @@ +GDTEST_ANALYZER_ERROR +Value of type "int" cannot be assigned to a variable of type "String". diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd b/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd new file mode 100644 index 0000000000..1706087f82 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd @@ -0,0 +1,16 @@ +var _prop = 1 +var prop: + get = get_prop, set = set_prop + +func get_prop(): + return _prop + +func set_prop(value): + _prop = value + +func test(): + print(prop) + + prop = 2 + + print(prop) diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_functions.out b/modules/gdscript/tests/scripts/analyzer/features/property_functions.out new file mode 100644 index 0000000000..f1253ca57e --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/property_functions.out @@ -0,0 +1,3 @@ +GDTEST_OK +1 +2 diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd b/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd new file mode 100644 index 0000000000..23eb011b23 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd @@ -0,0 +1,46 @@ +# Untyped inline property +var prop1: + get: + return prop1 + set(value): + prop1 = value + +# Typed inline property +var prop2 : int: + get: + return prop2 + set(value): + prop2 = value + +# Typed inline property with default value +var prop3 : int = 1: + get: + return prop3 + set(value): + prop3 = value + +# Typed inline property with backing variable +var _prop4 : int = 2 +var prop4: int: + get: + return _prop4 + set(value): + _prop4 = value + +func test(): + print(prop1) + print(prop2) + print(prop3) + print(prop4) + + print() + + prop1 = 1 + prop2 = 2 + prop3 = 3 + prop4 = 4 + + print(prop1) + print(prop2) + print(prop3) + print(prop4) diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_inline.out b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out new file mode 100644 index 0000000000..5482592e90 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out @@ -0,0 +1,10 @@ +GDTEST_OK +null +0 +1 +2 + +1 +2 +3 +4 diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd new file mode 100644 index 0000000000..9502f6e196 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd @@ -0,0 +1,10 @@ +class Inner: + var prop = "Inner" + + +var array: Array[Inner] = [Inner.new()] + + +func test(): + var element: Inner = array[0] + print(element.prop) diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out new file mode 100644 index 0000000000..8f250d2632 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out @@ -0,0 +1,2 @@ +GDTEST_OK +Inner diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp index 9d6a399eff..32a31aa764 100644 --- a/modules/hdr/image_loader_hdr.cpp +++ b/modules/hdr/image_loader_hdr.cpp @@ -65,7 +65,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force Vector<uint8_t> imgdata; - imgdata.resize(height * width * sizeof(uint32_t)); + imgdata.resize(height * width * (int)sizeof(uint32_t)); { uint8_t *w = imgdata.ptrw(); @@ -75,7 +75,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force if (width < 8 || width >= 32768) { // Read flat data - f->get_buffer(ptr, width * height * 4); + f->get_buffer(ptr, (uint64_t)width * height * 4); } else { // Read RLE-encoded data diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp index 7b52ef178a..17ce051b67 100644 --- a/modules/minimp3/audio_stream_mp3.cpp +++ b/modules/minimp3/audio_stream_mp3.cpp @@ -112,7 +112,7 @@ void AudioStreamPlaybackMP3::seek(float p_time) { } frames_mixed = uint32_t(mp3_stream->sample_rate * p_time); - mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels); + mp3dec_ex_seek(mp3d, (uint64_t)frames_mixed * mp3_stream->channels); } AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() { diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index f5d159040f..6c3e53b708 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -46,13 +46,13 @@ #endif /*************************************************************************/ -/* hb_bmp_font_t HarfBuzz Bitmap font interface */ +/* bmp_font_t HarfBuzz Bitmap font interface */ /*************************************************************************/ hb_font_funcs_t *TextServerAdvanced::funcs = nullptr; -TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { - hb_bmp_font_t *bm_font = memnew(hb_bmp_font_t); +TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { + bmp_font_t *bm_font = memnew(bmp_font_t); if (!bm_font) { return nullptr; @@ -64,13 +64,13 @@ TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextS return bm_font; } -void TextServerAdvanced::_hb_bmp_font_destroy(void *p_data) { - hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(p_data); +void TextServerAdvanced::_bmp_font_destroy(void *p_data) { + bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data); memdelete(bm_font); } -hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -89,8 +89,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void * return true; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -103,8 +103,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, return bm_font->face->glyph_map[p_glyph].advance.x * 64; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -117,8 +117,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, return -bm_font->face->glyph_map[p_glyph].advance.y * 64; } -hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return 0; @@ -131,8 +131,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64; } -hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -148,8 +148,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void return true; } -hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -167,8 +167,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void * return true; } -hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) { - const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data); +hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) { + const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data); if (!bm_font->face) { return false; @@ -181,40 +181,40 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void return true; } -void TextServerAdvanced::hb_bmp_create_font_funcs() { +void TextServerAdvanced::_bmp_create_font_funcs() { if (funcs == nullptr) { funcs = hb_font_funcs_create(); - hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr); - hb_font_funcs_set_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr); - hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr); - hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr); - hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr); - hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr); - hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr); + hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr); + hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr); + hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr); + hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr); + hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr); + hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr); hb_font_funcs_make_immutable(funcs); } } -void TextServerAdvanced::hb_bmp_free_font_funcs() { +void TextServerAdvanced::_bmp_free_font_funcs() { if (funcs != nullptr) { hb_font_funcs_destroy(funcs); funcs = nullptr; } } -void TextServerAdvanced::_hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { - hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_unref), _hb_bmp_font_destroy); +void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) { + hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy); } -hb_font_t *TextServerAdvanced::hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) { +hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) { hb_font_t *font; hb_face_t *face = hb_face_create(nullptr, 0); font = hb_font_create(face); hb_face_destroy(face); - _hb_bmp_font_set_funcs(font, p_face, false); + _bmp_font_set_funcs(font, p_face, false); return font; } @@ -442,9 +442,7 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const { } } -static Map<StringName, int32_t> feature_sets; - -static void _insert_feature_sets() { +void TextServerAdvanced::_insert_feature_sets() { // Registered OpenType feature tags. feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't')); feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f')); @@ -956,7 +954,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( edgeColoringSimple(shape, 3.0); // Max. angle. msdfgen::Bitmap<float, 4> image(w, h); // Texture size. - //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation. DistancePixelConversion distancePixelConversion(p_pixel_range); msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b)); @@ -986,10 +983,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf( wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f)); wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f)); wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f)); - //wr[ofs + 0] = 100; - //wr[ofs + 1] = 100; - //wr[ofs + 2] = 100; - //wr[ofs + 3] = 100; } } } @@ -1054,13 +1047,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma case FT_PIXEL_MODE_MONO: { int byte = i * bitmap.pitch + (j >> 3); int bit = 1 << (7 - (j % 8)); - wr[ofs + 0] = 255; //grayscale as 1 + wr[ofs + 0] = 255; // grayscale as 1 wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0; } break; case FT_PIXEL_MODE_GRAY: - wr[ofs + 0] = 255; //grayscale as 1 + wr[ofs + 0] = 255; // grayscale as 1 wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j]; - //wr[ofs + 1] = 100; break; case FT_PIXEL_MODE_BGRA: { int ofs_color = i * bitmap.pitch + (j << 2); @@ -1594,7 +1586,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced #endif } else { // Init bitmap font. - fd->hb_handle = hb_bmp_font_create(fd, nullptr); + fd->hb_handle = _bmp_font_create(fd, nullptr); } p_font_data->cache[p_size] = fd; return true; @@ -3161,7 +3153,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, E.value.rect.position.y -= E.value.rect.size.y / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.y); @@ -3189,7 +3181,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, E.value.rect.position.x -= E.value.rect.size.x / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.x); @@ -3351,7 +3343,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng E.value.rect.position.y -= E.value.rect.size.y / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.y); @@ -3379,7 +3371,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng E.value.rect.position.x -= E.value.rect.size.x / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.x); @@ -4485,7 +4477,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { E.value.rect.position.y -= E.value.rect.size.y / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.y); @@ -4513,7 +4505,7 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) { E.value.rect.position.x -= E.value.rect.size.x / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.x); @@ -4679,76 +4671,186 @@ float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) cons return sd->uthk; } -struct num_system_data { - Set<String> lang; - String digits; - String percent_sign; - String exp; -}; +void TextServerAdvanced::_insert_num_systems_lang() { + // Eastern Arabic numerals. + { + NumSystemData ar; + ar.lang.insert(StringName("ar")); // Arabic + ar.lang.insert(StringName("ar_AE")); + ar.lang.insert(StringName("ar_BH")); + ar.lang.insert(StringName("ar_DJ")); + ar.lang.insert(StringName("ar_EG")); + ar.lang.insert(StringName("ar_ER")); + ar.lang.insert(StringName("ar_IL")); + ar.lang.insert(StringName("ar_IQ")); + ar.lang.insert(StringName("ar_JO")); + ar.lang.insert(StringName("ar_KM")); + ar.lang.insert(StringName("ar_KW")); + ar.lang.insert(StringName("ar_LB")); + ar.lang.insert(StringName("ar_MR")); + ar.lang.insert(StringName("ar_OM")); + ar.lang.insert(StringName("ar_PS")); + ar.lang.insert(StringName("ar_QA")); + ar.lang.insert(StringName("ar_SA")); + ar.lang.insert(StringName("ar_SD")); + ar.lang.insert(StringName("ar_SO")); + ar.lang.insert(StringName("ar_SS")); + ar.lang.insert(StringName("ar_SY")); + ar.lang.insert(StringName("ar_TD")); + ar.lang.insert(StringName("ar_YE")); + ar.lang.insert(StringName("ckb")); // Central Kurdish + ar.lang.insert(StringName("ckb_IQ")); + ar.lang.insert(StringName("ckb_IR")); + ar.lang.insert(StringName("sd")); // Sindhi + ar.lang.insert(StringName("sd_PK")); + ar.lang.insert(StringName("sd_Arab")); + ar.lang.insert(StringName("sd_Arab_PK")); + ar.digits = U"٠١٢٣٤٥٦٧٨٩٫"; + ar.percent_sign = U"٪"; + ar.exp = U"اس"; + num_systems.push_back(ar); + } + + // Persian and Urdu numerals. + { + NumSystemData pr; + pr.lang.insert(StringName("fa")); // Persian + pr.lang.insert(StringName("fa_AF")); + pr.lang.insert(StringName("fa_IR")); + pr.lang.insert(StringName("ks")); // Kashmiri + pr.lang.insert(StringName("ks_IN")); + pr.lang.insert(StringName("ks_Arab")); + pr.lang.insert(StringName("ks_Arab_IN")); + pr.lang.insert(StringName("lrc")); // Northern Luri + pr.lang.insert(StringName("lrc_IQ")); + pr.lang.insert(StringName("lrc_IR")); + pr.lang.insert(StringName("mzn")); // Mazanderani + pr.lang.insert(StringName("mzn_IR")); + pr.lang.insert(StringName("pa_PK")); // Panjabi + pr.lang.insert(StringName("pa_Arab")); + pr.lang.insert(StringName("pa_Arab_PK")); + pr.lang.insert(StringName("ps")); // Pushto + pr.lang.insert(StringName("ps_AF")); + pr.lang.insert(StringName("ps_PK")); + pr.lang.insert(StringName("ur_IN")); // Urdu + pr.lang.insert(StringName("uz_AF")); // Uzbek + pr.lang.insert(StringName("uz_Arab")); + pr.lang.insert(StringName("uz_Arab_AF")); + pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫"; + pr.percent_sign = U"٪"; + pr.exp = U"اس"; + num_systems.push_back(pr); + } + + // Bengali numerals. + { + NumSystemData bn; + bn.lang.insert(StringName("as")); // Assamese + bn.lang.insert(StringName("as_IN")); + bn.lang.insert(StringName("bn")); // Bengali + bn.lang.insert(StringName("bn_BD")); + bn.lang.insert(StringName("bn_IN")); + bn.lang.insert(StringName("mni")); // Manipuri + bn.lang.insert(StringName("mni_IN")); + bn.lang.insert(StringName("mni_Beng")); + bn.lang.insert(StringName("mni_Beng_IN")); + bn.digits = U"০১২৩৪৫৬৭৮৯."; + bn.percent_sign = U"%"; + bn.exp = U"e"; + num_systems.push_back(bn); + } + + // Devanagari numerals. + { + NumSystemData mr; + mr.lang.insert(StringName("mr")); // Marathi + mr.lang.insert(StringName("mr_IN")); + mr.lang.insert(StringName("ne")); // Nepali + mr.lang.insert(StringName("ne_IN")); + mr.lang.insert(StringName("ne_NP")); + mr.lang.insert(StringName("sa")); // Sanskrit + mr.lang.insert(StringName("sa_IN")); + mr.digits = U"०१२३४५६७८९."; + mr.percent_sign = U"%"; + mr.exp = U"e"; + num_systems.push_back(mr); + } + + // Dzongkha numerals. + { + NumSystemData dz; + dz.lang.insert(StringName("dz")); // Dzongkha + dz.lang.insert(StringName("dz_BT")); + dz.digits = U"༠༡༢༣༤༥༦༧༨༩."; + dz.percent_sign = U"%"; + dz.exp = U"e"; + num_systems.push_back(dz); + } -static num_system_data num_systems[]{ - { Set<String>(), U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" }, - { Set<String>(), U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" }, - { Set<String>(), U"০১২৩৪৫৬৭৮৯.", U"%", U"e" }, - { Set<String>(), U"०१२३४५६७८९.", U"%", U"e" }, - { Set<String>(), U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" }, - { Set<String>(), U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" }, - { Set<String>(), U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" }, - { Set<String>(), String(), String(), String() }, -}; + // Santali numerals. + { + NumSystemData sat; + sat.lang.insert(StringName("sat")); // Santali + sat.lang.insert(StringName("sat_IN")); + sat.lang.insert(StringName("sat_Olck")); + sat.lang.insert(StringName("sat_Olck_IN")); + sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙."; + sat.percent_sign = U"%"; + sat.exp = U"e"; + num_systems.push_back(sat); + } + + // Burmese numerals. + { + NumSystemData my; + my.lang.insert(StringName("my")); // Burmese + my.lang.insert(StringName("my_MM")); + my.digits = U"၀၁၂၃၄၅၆၇၈၉."; + my.percent_sign = U"%"; + my.exp = U"e"; + num_systems.push_back(my); + } + + // Chakma numerals. + { + NumSystemData ccp; + ccp.lang.insert(StringName("ccp")); // Chakma + ccp.lang.insert(StringName("ccp_BD")); + ccp.lang.insert(StringName("ccp_IN")); + ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿."; + ccp.percent_sign = U"%"; + ccp.exp = U"e"; + num_systems.push_back(ccp); + } -static void _insert_num_systems_lang() { - num_systems[0].lang.insert(StringName("ar")); - num_systems[0].lang.insert(StringName("ar_AR")); - num_systems[0].lang.insert(StringName("ar_BH")); - num_systems[0].lang.insert(StringName("ar_DJ")); - num_systems[0].lang.insert(StringName("ar_EG")); - num_systems[0].lang.insert(StringName("ar_ER")); - num_systems[0].lang.insert(StringName("ar_IL")); - num_systems[0].lang.insert(StringName("ar_IQ")); - num_systems[0].lang.insert(StringName("ar_JO")); - num_systems[0].lang.insert(StringName("ar_KM")); - num_systems[0].lang.insert(StringName("ar_KW")); - num_systems[0].lang.insert(StringName("ar_LB")); - num_systems[0].lang.insert(StringName("ar_MR")); - num_systems[0].lang.insert(StringName("ar_OM")); - num_systems[0].lang.insert(StringName("ar_PS")); - num_systems[0].lang.insert(StringName("ar_QA")); - num_systems[0].lang.insert(StringName("ar_SA")); - num_systems[0].lang.insert(StringName("ar_SD")); - num_systems[0].lang.insert(StringName("ar_SO")); - num_systems[0].lang.insert(StringName("ar_SS")); - num_systems[0].lang.insert(StringName("ar_SY")); - num_systems[0].lang.insert(StringName("ar_TD")); - num_systems[0].lang.insert(StringName("ar_YE")); - - num_systems[1].lang.insert(StringName("fa")); - num_systems[1].lang.insert(StringName("ks")); - num_systems[1].lang.insert(StringName("pa_Arab")); - num_systems[1].lang.insert(StringName("ug")); - num_systems[1].lang.insert(StringName("ur_IN")); - num_systems[1].lang.insert(StringName("ur")); - num_systems[1].lang.insert(StringName("uz_Arab")); - - num_systems[2].lang.insert(StringName("as")); - num_systems[2].lang.insert(StringName("bn")); - num_systems[2].lang.insert(StringName("mni")); - - num_systems[3].lang.insert(StringName("mr")); - num_systems[3].lang.insert(StringName("ne")); - - num_systems[4].lang.insert(StringName("dz")); - - num_systems[5].lang.insert(StringName("sat")); - - num_systems[6].lang.insert(StringName("my")); + // Adlam numerals. + { + NumSystemData ff; + ff.lang.insert(StringName("ff")); // Fulah + ff.lang.insert(StringName("ff_Adlm_BF")); + ff.lang.insert(StringName("ff_Adlm_CM")); + ff.lang.insert(StringName("ff_Adlm_GH")); + ff.lang.insert(StringName("ff_Adlm_GM")); + ff.lang.insert(StringName("ff_Adlm_GN")); + ff.lang.insert(StringName("ff_Adlm_GW")); + ff.lang.insert(StringName("ff_Adlm_LR")); + ff.lang.insert(StringName("ff_Adlm_MR")); + ff.lang.insert(StringName("ff_Adlm_NE")); + ff.lang.insert(StringName("ff_Adlm_NG")); + ff.lang.insert(StringName("ff_Adlm_SL")); + ff.lang.insert(StringName("ff_Adlm_SN")); + ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙."; + ff.percent_sign = U"%"; + ff.exp = U"e"; + num_systems.push_back(ff); + } } String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const { const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; - for (int i = 0; num_systems[i].lang.size() != 0; i++) { + for (int i = 0; i < num_systems.size(); i++) { if (num_systems[i].lang.has(lang)) { if (num_systems[i].digits == String()) { return p_string; @@ -4773,7 +4875,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_ const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language; String res = p_string; - for (int i = 0; num_systems[i].lang.size() != 0; i++) { + for (int i = 0; i < num_systems.size(); i++) { if (num_systems[i].lang.has(lang)) { if (num_systems[i].digits == String()) { return p_string; @@ -4800,7 +4902,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_ String TextServerAdvanced::percent_sign(const String &p_language) const { const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language; - for (int i = 0; num_systems[i].lang.size() != 0; i++) { + for (int i = 0; i < num_systems.size(); i++) { if (num_systems[i].lang.has(lang)) { if (num_systems[i].percent_sign == String()) { return "%"; @@ -4814,11 +4916,11 @@ String TextServerAdvanced::percent_sign(const String &p_language) const { TextServerAdvanced::TextServerAdvanced() { _insert_num_systems_lang(); _insert_feature_sets(); - hb_bmp_create_font_funcs(); + _bmp_create_font_funcs(); } TextServerAdvanced::~TextServerAdvanced() { - hb_bmp_free_font_funcs(); + _bmp_free_font_funcs(); if (library != nullptr) { FT_Done_FreeType(library); } diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h index 1feeada76d..333b68e074 100644 --- a/modules/text_server_adv/text_server_adv.h +++ b/modules/text_server_adv/text_server_adv.h @@ -79,6 +79,19 @@ class TextServerAdvanced : public TextServer { static String interface_name; static uint32_t interface_features; + struct NumSystemData { + Set<StringName> lang; + String digits; + String percent_sign; + String exp; + }; + + Vector<NumSystemData> num_systems; + Map<StringName, int32_t> feature_sets; + + void _insert_num_systems_lang(); + void _insert_feature_sets(); + // ICU support data. uint8_t *icu_data = nullptr; @@ -258,24 +271,24 @@ class TextServerAdvanced : public TextServer { static hb_font_funcs_t *funcs; - struct hb_bmp_font_t { + struct bmp_font_t { TextServerAdvanced::FontDataForSizeAdvanced *face = nullptr; bool unref = false; /* Whether to destroy bm_face when done. */ }; - static hb_bmp_font_t *_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); - static void _hb_bmp_font_destroy(void *p_data); - static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); - static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data); - static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data); - static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data); - static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data); - static void hb_bmp_create_font_funcs(); - static void hb_bmp_free_font_funcs(); - static void _hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); - static hb_font_t *hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy); + static bmp_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); + static void _bmp_font_destroy(void *p_data); + static hb_bool_t _bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data); + static hb_position_t _bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); + static hb_position_t _bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data); + static hb_position_t _bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data); + static hb_bool_t _bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data); + static hb_bool_t _bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data); + static hb_bool_t _bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data); + static void _bmp_create_font_funcs(); + static void _bmp_free_font_funcs(); + static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref); + static hb_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy); protected: static void _bind_methods(){}; diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 3d868d7be3..02acd4727c 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -111,22 +111,14 @@ bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const { return false; // No RTL support. } -#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF))) - -struct FeatureInfo { - int32_t tag; - String name; -}; - -static FeatureInfo feature_set[] = { - // Registered OpenType variation tags. - { OT_TAG('i', 't', 'a', 'l'), "italic" }, - { OT_TAG('o', 'p', 's', 'z'), "optical_size" }, - { OT_TAG('s', 'l', 'n', 't'), "slant" }, - { OT_TAG('w', 'd', 't', 'h'), "width" }, - { OT_TAG('w', 'g', 'h', 't'), "weight" }, - { 0, String() }, -}; +void TextServerFallback::_insert_feature_sets() { + // Registered OpenType variation tag. + feature_sets.insert("italic", OT_TAG('i', 't', 'a', 'l')); + feature_sets.insert("optical_size", OT_TAG('o', 'p', 's', 'z')); + feature_sets.insert("slant", OT_TAG('s', 'l', 'n', 't')); + feature_sets.insert("width", OT_TAG('w', 'd', 't', 'h')); + feature_sets.insert("weight", OT_TAG('w', 'g', 'h', 't')); +} _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) { char tag[4]; @@ -150,10 +142,8 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) { } int32_t TextServerFallback::name_to_tag(const String &p_name) const { - for (int i = 0; feature_set[i].tag != 0; i++) { - if (feature_set[i].name == p_name) { - return feature_set[i].tag; - } + if (feature_sets.has(p_name)) { + return feature_sets[p_name]; } // No readable name, use tag string. @@ -168,9 +158,9 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) { } String TextServerFallback::tag_to_name(int32_t p_tag) const { - for (int i = 0; feature_set[i].tag != 0; i++) { - if (feature_set[i].tag == p_tag) { - return feature_set[i].name; + for (const KeyValue<StringName, int32_t> &E : feature_sets) { + if (E.value == p_tag) { + return E.key; } } @@ -421,7 +411,6 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf( edgeColoringSimple(shape, 3.0); // Max. angle. msdfgen::Bitmap<float, 4> image(w, h); // Texture size. - //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation. DistancePixelConversion distancePixelConversion(p_pixel_range); msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b)); @@ -515,11 +504,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma case FT_PIXEL_MODE_MONO: { int byte = i * bitmap.pitch + (j >> 3); int bit = 1 << (7 - (j % 8)); - wr[ofs + 0] = 255; //grayscale as 1 + wr[ofs + 0] = 255; // grayscale as 1 wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0; } break; case FT_PIXEL_MODE_GRAY: - wr[ofs + 0] = 255; //grayscale as 1 + wr[ofs + 0] = 255; // grayscale as 1 wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j]; break; case FT_PIXEL_MODE_BGRA: { @@ -2269,7 +2258,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, E.value.rect.position.y -= E.value.rect.size.y / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.y); @@ -2297,7 +2286,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, E.value.rect.position.x -= E.value.rect.size.x / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.x); @@ -2420,7 +2409,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng E.value.rect.position.y -= E.value.rect.size.y / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.y); @@ -2448,7 +2437,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng E.value.rect.position.x -= E.value.rect.size.x / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.x); @@ -2960,7 +2949,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { E.value.rect.position.y -= E.value.rect.size.y / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.y); @@ -2988,7 +2977,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) { E.value.rect.position.x -= E.value.rect.size.x / 2; } break; case INLINE_ALIGN_TOP_TO: { - //NOP + // NOP } break; } full_ascent = MAX(full_ascent, -E.value.rect.position.x); @@ -3148,7 +3137,9 @@ float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) cons return sd->uthk; } -TextServerFallback::TextServerFallback(){}; +TextServerFallback::TextServerFallback() { + _insert_feature_sets(); +}; TextServerFallback::~TextServerFallback() { if (library != nullptr) { diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h index 992ce5018f..fb7de8f443 100644 --- a/modules/text_server_fb/text_server_fb.h +++ b/modules/text_server_fb/text_server_fb.h @@ -54,6 +54,8 @@ #include FT_BBOX_H #endif +#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF))) + class TextServerFallback : public TextServer { GDCLASS(TextServerFallback, TextServer); _THREAD_SAFE_CLASS_ @@ -61,6 +63,10 @@ class TextServerFallback : public TextServer { static String interface_name; static uint32_t interface_features; + Map<StringName, int32_t> feature_sets; + + void _insert_feature_sets(); + // Font cache data. #ifdef MODULE_FREETYPE_ENABLED diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 8cb701ea20..d73b8d3ca0 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -4262,8 +4262,6 @@ void VisualScriptEditor::_bind_methods() { ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members); ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search); - - ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &VisualScriptEditor::add_syntax_highlighter); } VisualScriptEditor::VisualScriptEditor() { diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp index 8913ef1b65..58a6216b1e 100644 --- a/modules/xatlas_unwrap/register_types.cpp +++ b/modules/xatlas_unwrap/register_types.cpp @@ -114,7 +114,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver input_mesh.vertexPositionStride = sizeof(float) * 3; input_mesh.vertexNormalData = p_normals; input_mesh.vertexNormalStride = sizeof(uint32_t) * 3; - input_mesh.vertexUvData = NULL; + input_mesh.vertexUvData = nullptr; input_mesh.vertexUvStride = 0; xatlas::ChartOptions chart_options; diff --git a/platform/android/detect.py b/platform/android/detect.py index 61ccad9ac3..406f10de89 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -27,8 +27,7 @@ def get_opts(): ("ANDROID_NDK_ROOT", "Path to the Android NDK", get_android_ndk_root()), ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_android_sdk_root()), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), - EnumVariable("android_arch", "Target architecture", "armv7", ("armv7", "arm64v8", "x86", "x86_64")), - BoolVariable("android_neon", "Enable NEON support (armv7 only)", True), + EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")), ] @@ -143,10 +142,7 @@ def configure(env): if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]: env["android_arch"] = "armv7" - neon_text = "" - if env["android_arch"] == "armv7" and env["android_neon"]: - neon_text = " (with NEON)" - print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")" + neon_text) + print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")") can_vectorize = True if env["android_arch"] == "x86": @@ -174,10 +170,7 @@ def configure(env): target_subpath = "arm-linux-androideabi-4.9" abi_subpath = "arm-linux-androideabi" arch_subpath = "armeabi-v7a" - if env["android_neon"]: - env.extra_suffix = ".armv7.neon" + env.extra_suffix - else: - env.extra_suffix = ".armv7" + env.extra_suffix + env.extra_suffix = ".armv7" + env.extra_suffix elif env["android_arch"] == "arm64v8": if get_platform(env["ndk_platform"]) < 21: print( @@ -288,7 +281,6 @@ def configure(env): if get_platform(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) - env["neon_enabled"] = False if env["android_arch"] == "x86": target_opts = ["-target", "i686-none-linux-android"] # The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least @@ -301,12 +293,9 @@ def configure(env): target_opts = ["-target", "armv7-none-linux-androideabi"] env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split()) env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"]) - if env["android_neon"]: - env["neon_enabled"] = True - env.Append(CCFLAGS=["-mfpu=neon"]) - env.Append(CPPDEFINES=["__ARM_NEON__"]) - else: - env.Append(CCFLAGS=["-mfpu=vfpv3-d16"]) + # Enable ARM NEON instructions to compile more optimized code. + env.Append(CCFLAGS=["-mfpu=neon"]) + env.Append(CPPDEFINES=["__ARM_NEON__"]) elif env["android_arch"] == "arm64v8": target_opts = ["-target", "aarch64-none-linux-android"] diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 60ba1c558a..6ef17faf06 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -429,9 +429,8 @@ String EditorExportPlatformAndroid::get_package_name(const String &p_package) co return pname; } -String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset) const { - int export_format = int(p_preset->get("custom_template/export_format")); - return export_format == EXPORT_FORMAT_AAB ? AAB_ASSETS_DIRECTORY : APK_ASSETS_DIRECTORY; +String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const { + return p_export_format == EXPORT_FORMAT_AAB ? AAB_ASSETS_DIRECTORY : APK_ASSETS_DIRECTORY; } bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const { @@ -1645,10 +1644,12 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio } plugins_changed.clear(); - Vector<String> abis = get_abis(); + const Vector<String> abis = get_abis(); for (int i = 0; i < abis.size(); ++i) { - String abi = abis[i]; - bool is_default = (abi == "armeabi-v7a" || abi == "arm64-v8a"); + const String abi = abis[i]; + // All Android devices supporting Vulkan run 64-bit Android, + // so there is usually no point in exporting for 32-bit Android. + const bool is_default = abi == "arm64-v8a"; r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default)); } @@ -2477,7 +2478,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return ERR_UNCONFIGURED; } } - const String assets_directory = get_assets_directory(p_preset); + const String assets_directory = get_assets_directory(p_preset, export_format); String sdk_path = EDITOR_GET("export/android/android_sdk_path"); ERR_FAIL_COND_V_MSG(sdk_path.is_empty(), ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'."); print_verbose("Android sdk path: " + sdk_path); diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h index d33f616f11..e0ffaa718b 100644 --- a/platform/android/export/export_plugin.h +++ b/platform/android/export/export_plugin.h @@ -104,7 +104,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform { String get_package_name(const String &p_package) const; - String get_assets_directory(const Ref<EditorExportPreset> &p_preset) const; + String get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const; bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const; diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp index cfe6c69072..626aef3c60 100644 --- a/platform/javascript/audio_driver_javascript.cpp +++ b/platform/javascript/audio_driver_javascript.cpp @@ -117,14 +117,15 @@ Error AudioDriverJavaScript::init() { if (output_rb) { memdelete_arr(output_rb); } - output_rb = memnew_arr(float, buffer_length *channel_count); + const size_t array_size = buffer_length * (size_t)channel_count; + output_rb = memnew_arr(float, array_size); if (!output_rb) { return ERR_OUT_OF_MEMORY; } if (input_rb) { memdelete_arr(input_rb); } - input_rb = memnew_arr(float, buffer_length *channel_count); + input_rb = memnew_arr(float, array_size); if (!input_rb) { return ERR_OUT_OF_MEMORY; } diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index da6c45793a..3fe055a511 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -3014,7 +3014,7 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape ERR_FAIL_COND(!image.is_valid()); NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:NULL + initWithBitmapDataPlanes:nullptr pixelsWide:int(texture_size.width) pixelsHigh:int(texture_size.height) bitsPerSample:8 @@ -3418,7 +3418,7 @@ void DisplayServerOSX::set_icon(const Ref<Image> &p_icon) { img = img->duplicate(); img->convert(Image::FORMAT_RGBA8); NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes:NULL + initWithBitmapDataPlanes:nullptr pixelsWide:img->get_width() pixelsHigh:img->get_height() bitsPerSample:8 diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index bddc342c1a..18a50ae098 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -68,7 +68,7 @@ void AudioStreamPlayer2D::_notification(int p_what) { active.set(); Ref<AudioStreamPlayback> new_playback = stream->instance_playback(); ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); - AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get()); + AudioServer::get_singleton()->start_playback_stream(new_playback, _get_actual_bus(), volume_vector, setplay.get(), pitch_scale); stream_playbacks.push_back(new_playback); setplay.set(-1); } diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 67e35cc7a3..797e2e59cb 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -123,12 +123,12 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_s Point2 new_ofs = (screen_offset + (p_offset - screen_offset) * motion_scale) + motion_offset * p_scale + orig_offset * p_scale; if (mirroring.x) { - double den = mirroring.x * p_scale; + real_t den = mirroring.x * p_scale; new_ofs.x -= den * ceil(new_ofs.x / den); } if (mirroring.y) { - double den = mirroring.y * p_scale; + real_t den = mirroring.y * p_scale; new_ofs.y -= den * ceil(new_ofs.y / den); } diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index a54b10ba70..c422070480 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -282,7 +282,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { ERR_FAIL_COND_MSG(new_playback.is_null(), "Failed to instantiate playback."); Map<StringName, Vector<AudioFrame>> bus_map; bus_map[_get_actual_bus()] = volume_vector; - AudioServer::get_singleton()->start_playback_stream(new_playback, bus_map, setplay.get(), linear_attenuation, attenuation_filter_cutoff_hz, actual_pitch_scale); + AudioServer::get_singleton()->start_playback_stream(new_playback, bus_map, setplay.get(), actual_pitch_scale, linear_attenuation, attenuation_filter_cutoff_hz); stream_playbacks.push_back(new_playback); setplay.set(-1); } diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 18b7bcc789..588d2b5018 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -656,6 +656,7 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const { } RID Camera3D::get_pyramid_shape_rid() { + ERR_FAIL_COND_V_MSG(!is_inside_tree(), RID(), "Camera is not inside scene."); if (pyramid_shape == RID()) { pyramid_shape_points = get_near_plane_points(); pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create(); diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 4fa34615bf..9127168c58 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -475,7 +475,7 @@ Ref<Image> GPUParticlesCollisionSDF::bake() { _create_bvh(bvh, face_pos.ptr(), face_pos.size(), faces.ptr(), th); Vector<uint8_t> data; - data.resize(sdf_size.z * sdf_size.y * sdf_size.x * sizeof(float)); + data.resize(sdf_size.z * sdf_size.y * sdf_size.x * (int)sizeof(float)); if (bake_step_function) { bake_step_function(0, "Baking SDF"); diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 0334ba667b..d2fd65d3d9 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -135,7 +135,7 @@ void AudioStreamPlayer::play(float p_from_pos) { Ref<AudioStreamPlayback> stream_playback = stream->instance_playback(); ERR_FAIL_COND_MSG(stream_playback.is_null(), "Failed to instantiate playback."); - AudioServer::get_singleton()->start_playback_stream(stream_playback, bus, _get_volume_vector(), p_from_pos); + AudioServer::get_singleton()->start_playback_stream(stream_playback, bus, _get_volume_vector(), p_from_pos, pitch_scale); stream_playbacks.push_back(stream_playback); active.set(); set_process_internal(true); diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 653885aa08..54e7d8f960 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -241,7 +241,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) { _reset_caret_blink_timer(); if (b->is_pressed()) { - accept_event(); //don't pass event further when clicked on text field + accept_event(); // don't pass event further when clicked on text field if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; @@ -1931,7 +1931,7 @@ void LineEdit::_shape() { TS->shaped_text_clear(text_rid); String t; - if (text.length() == 0) { + if (text.length() == 0 && ime_text.length() == 0) { t = placeholder_translated; } else if (pass) { t = secret_character.repeat(text.length() + ime_text.length()); diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 2982e33fcf..0e62e6e30a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2881,9 +2881,8 @@ bool Viewport::gui_is_dragging() const { void Viewport::set_input_as_handled() { _drop_physics_mouseover(); - if (handle_input_locally) { - local_input_handled = true; - } else { + + if (!handle_input_locally) { ERR_FAIL_COND(!is_inside_tree()); Viewport *vp = this; while (true) { @@ -2895,16 +2894,19 @@ void Viewport::set_input_as_handled() { } vp = vp->get_parent()->get_viewport(); } - vp->set_input_as_handled(); + if (vp != this) { + vp->set_input_as_handled(); + return; + } } + + local_input_handled = true; } bool Viewport::is_input_handled() const { - if (handle_input_locally) { - return local_input_handled; - } else { - const Viewport *vp = this; + if (!handle_input_locally) { ERR_FAIL_COND_V(!is_inside_tree(), false); + const Viewport *vp = this; while (true) { if (Object::cast_to<Window>(vp)) { break; @@ -2914,8 +2916,11 @@ bool Viewport::is_input_handled() const { } vp = vp->get_parent()->get_viewport(); } - return vp->is_input_handled(); + if (vp != this) { + return vp->is_input_handled(); + } } + return local_input_handled; } void Viewport::set_handle_input_locally(bool p_enable) { diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index 18e6a51118..7ffe0b03e1 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -1577,7 +1577,7 @@ void ArrayMesh::regen_normal_maps() { } //dirty hack -bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL; +bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = nullptr; struct ArrayMeshLightmapSurface { Ref<Material> material; diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index e19ca38b82..f5e52b70e6 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -171,6 +171,8 @@ void TileSet::set_source_id(int p_source_id, int p_new_source_id) { source_ids.append(p_new_source_id); source_ids.sort(); + _compute_next_source_id(); + emit_changed(); } diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index a28dcb1015..47799dce96 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -46,7 +46,7 @@ Error AudioDriverDummy::init() { int latency = GLOBAL_GET("audio/driver/output_latency"); buffer_frames = closest_power_of_2(latency * mix_rate / 1000); - samples_in = memnew_arr(int32_t, buffer_frames * channels); + samples_in = memnew_arr(int32_t, (size_t)buffer_frames * channels); thread.start(AudioDriverDummy::thread_func, this); diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 3c8a1469cd..d9c442facf 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -176,8 +176,9 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m rb_bits = desired_rb_bits; rb_len = (1 << rb_bits); rb_mask = rb_len - 1; - rb = memnew_arr(float, rb_len *p_channels); - read_buf = memnew_arr(float, rb_len *p_channels); + const size_t array_size = rb_len * (size_t)p_channels; + rb = memnew_arr(float, array_size); + read_buf = memnew_arr(float, array_size); } src_mix_rate = p_src_mix_rate; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index ac1569c15d..a420134626 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -1112,16 +1112,16 @@ float AudioServer::get_playback_speed_scale() const { return playback_speed_scale; } -void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time) { +void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time, float p_pitch_scale) { ERR_FAIL_COND(p_playback.is_null()); Map<StringName, Vector<AudioFrame>> map; map[p_bus] = p_volume_db_vector; - start_playback_stream(p_playback, map, p_start_time); + start_playback_stream(p_playback, map, p_start_time, p_pitch_scale); } -void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_highshelf_gain, float p_attenuation_cutoff_hz, float p_pitch_scale) { +void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_pitch_scale, float p_highshelf_gain, float p_attenuation_cutoff_hz) { ERR_FAIL_COND(p_playback.is_null()); AudioStreamPlaybackListNode *playback_node = new AudioStreamPlaybackListNode(); diff --git a/servers/audio_server.h b/servers/audio_server.h index a60d4ae4c4..46873845dc 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -368,9 +368,9 @@ public: float get_playback_speed_scale() const; // Convenience method. - void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0); + void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0, float p_pitch_scale = 1); // Expose all parameters. - void start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0, float p_pitch_scale = 1); + void start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0); void stop_playback_stream(Ref<AudioStreamPlayback> p_playback); void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes); diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index 45d3b3f09f..a7bfea455d 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -3959,7 +3959,7 @@ void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { memcpy(w, r, buffer.size()); } } else { - memset(w, 0, multimesh->instances * multimesh->stride_cache * sizeof(float)); + memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float)); } } uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -4372,13 +4372,13 @@ void RendererStorageRD::_update_dirty_multimeshes() { if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) { //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much - RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data); } else { //not that many regions? update them all for (uint32_t i = 0; i < visible_region_count; i++) { if (multimesh->data_cache_dirty_regions[i]) { - uint64_t offset = i * region_size; - uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float); + uint32_t offset = i * region_size; + uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float); RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size]); } } @@ -9970,6 +9970,6 @@ RendererStorageRD::~RendererStorageRD() { if (effects) { memdelete(effects); - effects = NULL; + effects = nullptr; } } diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index d56afcc448..d6129bb57b 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -1284,7 +1284,7 @@ private: void _update_global_variables(); /* EFFECTS */ - EffectsRD *effects = NULL; + EffectsRD *effects = nullptr; public: virtual bool can_create_resources_async() const; 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 f3db4abe3b..4d466342f8 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -97,6 +97,11 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #endif inout vec3 diffuse_light, inout vec3 specular_light) { + vec4 orms_unpacked = unpackUnorm4x8(orms); + + float roughness = orms_unpacked.y; + float metallic = orms_unpacked.z; + #if defined(LIGHT_CODE_USED) // light is written by the light shader @@ -125,9 +130,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif - float metallic = unpackUnorm4x8(orms).z; if (metallic < 1.0) { - float roughness = unpackUnorm4x8(orms).y; float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance #if defined(DIFFUSE_LAMBERT_WRAP) @@ -199,7 +202,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #endif //LIGHT_TRANSMITTANCE_USED } - float roughness = unpackUnorm4x8(orms).y; if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely // D @@ -211,7 +213,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float blinn = pow(cNdotH, shininess); blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)); - specular_light += light_color * attenuation * specular_amount * blinn * f0 * unpackUnorm4x8(orms).w; + specular_light += light_color * attenuation * specular_amount * blinn * f0 * orms_unpacked.w; #elif defined(SPECULAR_PHONG) @@ -221,7 +223,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float phong = pow(cRdotV, shininess); phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI)); - specular_light += light_color * attenuation * specular_amount * phong * f0 * unpackUnorm4x8(orms).w; + specular_light += light_color * attenuation * specular_amount * phong * f0 * orms_unpacked.w; #elif defined(SPECULAR_TOON) diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index ebebb849d0..81a9e00d7c 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -1599,7 +1599,8 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { - //constructors + // Constructors. + { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1672,7 +1673,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mat3", TYPE_MAT3, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "mat4", TYPE_MAT4, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //conversion scalars + // Conversion scalars. { "int", TYPE_INT, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1694,7 +1695,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "bool", TYPE_BOOL, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true }, { "bool", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //conversion vectors + // Conversion vectors. { "ivec2", TYPE_IVEC2, { TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "ivec2", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1756,7 +1757,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true }, { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //conversion between matrixes + // Conversion between matrixes. { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1765,43 +1766,58 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //builtins - trigonometry + // Built-ins - trigonometric functions. + // radians { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, { "radians", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, { "radians", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, { "radians", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, + // degrees + { "degrees", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, { "degrees", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, { "degrees", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, { "degrees", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, + // sin + { "sin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "sin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "sin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "sin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, + // cos + { "cos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "cos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "cos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "cos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, + // tan + { "tan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "tan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "tan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "tan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, + // asin + { "asin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // acos + { "acos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // atan + { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false }, { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false }, { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false }, @@ -1811,66 +1827,101 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false }, { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false }, + // sinh + { "sinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // cosh + { "cosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "cosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "cosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "cosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // tanh + { "tanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "tanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "tanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "tanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // asinh + { "asinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // acosh + { "acosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // atanh + { "atanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "atanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "atanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "atanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, - //builtins - exponential + // Builtins - exponential functions. + // pow + { "pow", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "pow", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "pow", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "pow", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, + + // exp + { "exp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // log + { "log", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // exp2 + { "exp2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // log2 + { "log2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // sqrt + { "sqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // inversesqrt + { "inversesqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "inversesqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "inversesqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "inversesqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, - //builtins - common + + // Built-ins - common functions. + // abs + { "abs", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "abs", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "abs", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, @@ -1881,6 +1932,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "abs", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "abs", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // sign + { "sign", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sign", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sign", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, @@ -1891,31 +1944,50 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "sign", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sign", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // floor + { "floor", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "floor", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "floor", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "floor", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // trunc + { "trunc", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "trunc", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "trunc", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "trunc", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // round + { "round", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "round", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "round", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "round", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // roundEven + { "roundEven", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "roundEven", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "roundEven", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "roundEven", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // ceil + { "ceil", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "ceil", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "ceil", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "ceil", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // fract + { "fract", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "fract", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "fract", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "fract", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // mod + { "mod", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, @@ -1924,11 +1996,15 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, + // modf + { "modf", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, { "modf", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, { "modf", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, { "modf", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, + // min + { "min", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -1953,6 +2029,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // max + { "max", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -1977,6 +2055,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // clamp + { "clamp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false }, { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false }, { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false }, @@ -2001,6 +2081,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true }, { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true }, + // mix + { "mix", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_BVEC2, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, @@ -2012,6 +2094,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, + // step + { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, @@ -2019,6 +2103,9 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "step", TYPE_VEC2, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, + + // smoothstep + { "smoothstep", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, { "smoothstep", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, { "smoothstep", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, @@ -2027,77 +2114,127 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "smoothstep", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, { "smoothstep", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, + // isnan + { "isnan", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isnan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isnan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isnan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // isinf + { "isinf", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isinf", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isinf", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isinf", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // floatBitsToInt + { "floatBitsToInt", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToInt", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToInt", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToInt", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, + // floatBitsToUint + { "floatBitsToUint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToUint", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToUint", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToUint", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, + // intBitsToFloat + { "intBitsToFloat", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "intBitsToFloat", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "intBitsToFloat", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "intBitsToFloat", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, + // uintBitsToFloat + { "uintBitsToFloat", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "uintBitsToFloat", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "uintBitsToFloat", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "uintBitsToFloat", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, - //builtins - geometric + // Built-ins - geometric functions. + // length + + { "length", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "length", TYPE_FLOAT, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "length", TYPE_FLOAT, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "length", TYPE_FLOAT, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // distance + + { "distance", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "distance", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "distance", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "distance", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + + // dot + + { "dot", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "dot", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "dot", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "dot", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + + // cross + { "cross", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + + // normalize + + { "normalize", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, { "normalize", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, { "normalize", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, { "normalize", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, + + // reflect + { "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "I", "N" }, TAG_GLOBAL, false }, + + // refract + { "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "I", "N", "eta" }, TAG_GLOBAL, false }, + // faceforward + { "faceforward", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false }, { "faceforward", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false }, { "faceforward", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false }, + // matrixCompMult + { "matrixCompMult", TYPE_MAT2, { TYPE_MAT2, TYPE_MAT2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "matrixCompMult", TYPE_MAT3, { TYPE_MAT3, TYPE_MAT3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "matrixCompMult", TYPE_MAT4, { TYPE_MAT4, TYPE_MAT4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + // outerProduct + { "outerProduct", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false }, { "outerProduct", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false }, { "outerProduct", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false }, + // transpose + { "transpose", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "transpose", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "transpose", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, + // determinant + { "determinant", TYPE_FLOAT, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "determinant", TYPE_FLOAT, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "determinant", TYPE_FLOAT, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, + // inverse + { "inverse", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "inverse", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "inverse", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, + // lessThan + { "lessThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2110,6 +2247,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "lessThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "lessThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // greaterThan + { "greaterThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2122,6 +2261,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "greaterThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "greaterThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // lessThanEqual + { "lessThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2134,6 +2275,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "lessThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "lessThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // greaterThanEqual + { "greaterThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2146,6 +2289,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "greaterThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "greaterThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // equal + { "equal", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "equal", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "equal", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2162,6 +2307,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "equal", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "equal", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + // notEqual + { "notEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "notEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "notEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2178,19 +2325,27 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "notEqual", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "notEqual", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + // any + { "any", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "any", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "any", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // all + { "all", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "all", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "all", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // not + { "not", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "not", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "not", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, - //builtins - texture + // Built-ins: texture functions. + // textureSize + { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, @@ -2203,6 +2358,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, + // texture + { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, @@ -2226,6 +2383,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, + // textureProj + { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true }, @@ -2245,6 +2404,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true }, + // textureLod + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, @@ -2257,6 +2418,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false }, { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false }, + // texelFetch + { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, @@ -2267,6 +2430,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, + // textureProjLod + { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, @@ -2277,6 +2442,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, + // textureGrad + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, @@ -2289,39 +2456,148 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, + // dFdx + { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, + // dFdy + { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdy", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, + // fwidth + { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "fwidth", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, - //sub-functions + // Sub-functions. + // array - //array { "length", TYPE_INT, { TYPE_VOID }, { "" }, TAG_ARRAY, true }, - // modern functions + // Modern functions. + // fma { "fma", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, { "fma", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, { "fma", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, { "fma", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, + // Packing/Unpacking functions. + + { "packHalf2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packUnorm2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packSnorm2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packUnorm4x8", TYPE_UINT, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packSnorm4x8", TYPE_UINT, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + + { "unpackHalf2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackUnorm2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackSnorm2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackUnorm4x8", TYPE_VEC4, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackSnorm4x8", TYPE_VEC4, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + + // bitfieldExtract + + { "bitfieldExtract", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + + { "bitfieldExtract", TYPE_UINT, { TYPE_UINT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_UVEC2, { TYPE_UVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_UVEC3, { TYPE_UVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_UVEC4, { TYPE_UVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + + // bitfieldInsert + + { "bitfieldInsert", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + + { "bitfieldInsert", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + + // bitfieldReverse + + { "bitfieldReverse", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "bitfieldReverse", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // bitCount + + { "bitCount", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "bitCount", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // findLSB + + { "findLSB", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "findLSB", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // findMSB + + { "findMSB", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "findMSB", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // uaddCarry + + { "uaddCarry", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + { "uaddCarry", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + { "uaddCarry", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + { "uaddCarry", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + + // usubBorrow + + { "usubBorrow", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { "usubBorrow", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { "usubBorrow", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { "usubBorrow", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { nullptr, TYPE_VOID, { TYPE_VOID }, { "" }, TAG_GLOBAL, false } }; const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { //constructors { "modf", 1 }, + { "uaddCarry", 2 }, + { "usubBorrow", 2 }, { nullptr, 0 } }; |