summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS.md2
-rw-r--r--DONORS.md92
-rw-r--r--core/bind/core_bind.cpp14
-rw-r--r--core/bind/core_bind.h15
-rw-r--r--core/math/expression.cpp8
-rw-r--r--core/math/expression.h1
-rw-r--r--core/math/math_funcs.h11
-rw-r--r--doc/classes/@GDScript.xml18
-rw-r--r--editor/editor_themes.cpp2
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp50
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h4
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_set_editor_plugin.cpp114
-rw-r--r--editor/plugins/tile_set_editor_plugin.h2
-rw-r--r--modules/assimp/editor_scene_importer_assimp.cpp2
-rw-r--r--modules/gdscript/gdscript_functions.cpp14
-rw-r--r--modules/gdscript/gdscript_functions.h1
-rw-r--r--modules/mono/glue/Managed/Files/Mathf.cs10
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml9
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp19
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h1
-rw-r--r--scene/resources/style_box.cpp13
-rw-r--r--scene/resources/tile_set.cpp29
-rw-r--r--scene/resources/tile_set.h20
24 files changed, 359 insertions, 96 deletions
diff --git a/AUTHORS.md b/AUTHORS.md
index b7eca2d9b1..99482fb4df 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -45,6 +45,7 @@ name is available.
Błażej Szczygieł (zaps166)
Bojidar Marinov (bojidar-bg)
bruvzg
+ Camille Mohr-Daurat (pouleyKetchoupp)
Carl Olsson (not-surt)
Carter Anderson (cart)
Chris Bradfield (cbscribe)
@@ -115,6 +116,7 @@ name is available.
Pieter-Jan Briers (PJB3005)
Poommetee Ketson (Noshyaar)
Przemysław Gołąb (n-pigeon)
+ Rafał Mikrut (qarmin)
Ralf Hölzemer (rollenrolm)
Ramesh Ravone (RameshRavone)
Ray Koopa (RayKoopa)
diff --git a/DONORS.md b/DONORS.md
index 05d7f3b7c1..fc332d4beb 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -18,22 +18,21 @@ generous deed immortalized in the next stable release of Godot Engine.
Gamblify <https://www.gamblify.com>
Image Campus <https://www.imagecampus.edu.ar>
- Yakaz.com <https://yakaz.com>
## Mini sponsors
Alan Beauchamp
Anandarup Mallik
Andrew Dunai
- Arda Erol
Brandon Lamb
Christian Uldall Pedersen
Christoph Woinke
+ Connor Hill
Edward Flick
GameDev.net
GameDev.tv
Hein-Pieter van Braam
- Jamal Alyafei
+ Jacob McKenney
Javary Games
Jay Sistar
Justin Arnold
@@ -43,22 +42,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Matthieu Huvé
Maxim Karsten
Mike King
- Nathan Warden
Neal Gompa (Conan Kudo)
Patrick Aarstad
"Rainway "
- Ruslan Mustakov
Slobodan Milnovic
StarFlare Software
Stephan Lanfermann
- Stoney Meyerhoeffer
- thechris
+ TigerJ
VilliHaukka
Zashi
## Gold donors
- Asdf
Brandon Waite
cheese65536
David Gehrig
@@ -69,8 +64,10 @@ generous deed immortalized in the next stable release of Godot Engine.
Nathanael Beisiegel
Officine Pixel S.n.c.
Retro Village
+ Sofox
Zaven Muradyan
+ Alexander Trey Saunders
Allen Schade
Andreas Schüle
Asher Glick
@@ -80,7 +77,6 @@ generous deed immortalized in the next stable release of Godot Engine.
David Giardi
Edward E
Florian Breisch
- Gary Oberbrunner
Gero
Jay Horton
Jon Smith
@@ -88,6 +84,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Jorge Bernal
Joshua Lesperance
Justo Delgado Baudí
+ Karl Werf
+ Kommentgames
Krzysztof Dluzniewski
Moonwards
Mored1984
@@ -95,6 +93,7 @@ generous deed immortalized in the next stable release of Godot Engine.
paul gruenbacher
Paul LaMotte
Rob Messick
+ Ross Esmond
Scott Wadden
Sergey
Svenne Krap
@@ -103,19 +102,20 @@ generous deed immortalized in the next stable release of Godot Engine.
Wyatt Goodin
Xananax
- BanjoNode2D
- Beliar
+ Abel Oroz Vicente
Chris Serino
Christian Padilla
Conrad Curry
Craig Smith
Daniel Egger
Dean Harmon
+ Ian Richard Kunert
Ivan Trombley
Joan Fons
Krzysztof Jankowski
Lord Bloodhound
Lucas Ferreira Franca
+ Michele Zilli
Nathan Lundquist
Pascal Grüter
Petr Malac
@@ -125,27 +125,34 @@ generous deed immortalized in the next stable release of Godot Engine.
Ronnie Ashlock
ScottMakesGames
Thomas Bjarnelöf
+ Vincent Henderson
Wojciech Chojnacki
Xavier PATRICELLI
Alessandra Pereyra
Alexey Dyadchenko
Andrew Bowen
+ Asdf
Benjamin W Flint
Chau Siu Hung
Chris Goddard
Chris Petrich
Christian Leth Jeppesen
+ Christoph Schröder
Cody Parker
ComicSads
D
+ Daniel
+ Daniel Eichler
Deadly Lampshade
+ Eagle 3d
E.G.
Eric
Eric Monson
Ethan Bennis
Eugenio Hugo Salgüero Jáñez
flesk
+ Francisco Javier Moreno Carracedo
gavlig
GGGames.org
Giles Montgomery
@@ -153,21 +160,24 @@ generous deed immortalized in the next stable release of Godot Engine.
Guilherme Felipe de C. G. da Silva
Heath Hayes
Hysteria
- Jalal Chaabane
- Jeppe Zapp
Jose Malheiro
+ Joshua Flores
Juan T Chen
Juraj Móza
Kasper Jeppesen
Klavdij Voncina
Leandro Voltolino
- Lukáš Rendvanský
+ Maarten Elings
+ Malcolm Peralty
Marius Kamm
+ Markus Fehr
Markus Wiesner
Martin Eigel
Marvin
Matt Eunson
+ Matthew Hillier
Max R.R. Collada
+ MegaC
Nick Nikitin
Oliver Dick
oziatek
@@ -175,39 +185,45 @@ generous deed immortalized in the next stable release of Godot Engine.
Paul Von Zimmerman
Pete Goodwin
Ranoller
- ray-tracer
- Ruben Soares Luis
Samuel Judd
- Sofox
+ Scott Pilet
spilldata
Stoned Xander
+ Thomas Krampl
Tobias Bocanegra
+ Urho
WytRabbit
Xavier Fumado Beltran
+ yuanzhe zhou
## Silver donors
1D_Inc
+ Abraham Haskins
Adam Brunnmeier
Adam Carr
Adam Nakonieczny
Adam Smeltzer
Adisibio
+ Aidan O'Flannagain
Alder Stefano
Alessandro Senese
Alexander Gillberg
Alexander Koppe
+ Alex Davies-Moore
Alice Robinson
+ Andreas Evers
Andreas Krampitz
Anthony Bongiovanni
- Arbor Interactive
+ Arda Erol
Arthur S. Muszynski
Aubrey Falconer
Avencherus
- Bailey
Balázs Batári
Bastian Böhm
+ Beliar
Benedikt
+ Ben Phelan
Ben Vercammen
Bernd Jänichen
Blair Allen
@@ -221,14 +237,17 @@ generous deed immortalized in the next stable release of Godot Engine.
Christian Baune
Christian Winter
Christoffer Sundbom
+ Christopher Fisher
Chris Wilson
+ Clay Heaton
Collin Shooltz
- Connor Hill
Daniel Johnson
DanielMaximiano
Daniel Reed
+ David Bullock
David Cravens
David May
+ Diliup Gabadamudalige
Dominik Wetzel
Duobix
Edward Herbert
@@ -238,20 +257,24 @@ generous deed immortalized in the next stable release of Godot Engine.
Eric Martini
Eric McCarthy
Eric Williams
- Fabian Becker
+ Fabian Lökes
fengjiongmax
Foomf
G3Dev sàrl
+ Gary Hulst
Gerrit Großkopf
Grant Clarke
Greg Olson
+ Greg Pennefather
Guldoman
- Haley Aycock
Heribert Hirth
Hiroshi Naruo
+ HMan
Hunter Jones
ialex32x
Igor Buzatovic
+ Iiari
+ Isaac Morton
Jaime Ruiz-Borau Vizárraga
Jako Danar
James A F Manley
@@ -259,6 +282,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Jeremy Kahn
Jesse Dubay
Joel Fivat
+ Joel Setterberg
Johannes Wuensch
Jonas Rudlang
Jonas Yamazaki
@@ -267,14 +291,16 @@ generous deed immortalized in the next stable release of Godot Engine.
Jonathon
Jon Bonazza
Jon Sully
+ Jose Aleman
Josh 'Cheeseness' Bush
Juanfran
Juan Negrier
Judd
Julian Murgia
+ Julius Hackel
Kajornthep Piyanun
KC Chan
- Kevin Boyer
+ kickmaniac
Kiyohiro Kawamura (kyorohiro)
Klagsam
KR McGinley
@@ -289,10 +315,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Major Haul
Malcolm
Markus Michael Egger
+ Martin Holas
+ Matthew Little
Matthias Grandis
Matt Welke
Maxwell
medecau
+ Menno Finlay-Smits
Mertcan Mermerkaya
mhilbrunner
Michael Dürwald
@@ -300,17 +329,19 @@ generous deed immortalized in the next stable release of Godot Engine.
Michael Labbe
Mikael Olsson
Mikayla Hutchinson
+ Mike Cunningham
MoM
Moritz Laass
Moritz Weissenberger
+ MuffinManKen
Natrim
nee
Neil Blakey-Milner
Nerdforge
- Nick Pavlica
Niclas Eriksen
Nicolás Montaña
Nicolas SAN AGUSTIN
+ Nithin Jino
Oscar Norlander
Pan Ip
Patrick Nafarrete
@@ -321,20 +352,29 @@ generous deed immortalized in the next stable release of Godot Engine.
Pierre-Igor Berthet
Pietro Vertechi
Piotr Kaczmarski
+ Pitsanu Tongprasin
+ Poryg
Prokhorenko Leonid
Psyagnostic
Rafael
+ Raphael Leroux
Rémi Verschelde
+ Reneator
Ricardo Alcantara
Richman Stewart
+ Rob Crowle
Robert Farr (Larington)
+ Robert Hernandez
+ Rodrigo Loli
Roger Burgess
Roger Smith
Roland Rząsa
Roman Tinkov
Ryan Cheung
+ Ryan Groom
Ryan Hentz
Sasori Olkof
+ Scott D. Yelich
Sebastian Michailidis
Shane Spoor
Simon Wenner
@@ -348,6 +388,7 @@ generous deed immortalized in the next stable release of Godot Engine.
tiansheng li
Tim
Tim Drumheller
+ Tim Gudex
Tom Larrow
Torsten Crass
Tryggve Sollid
@@ -355,10 +396,13 @@ generous deed immortalized in the next stable release of Godot Engine.
UltyX
Vaiktorg
Victor
+ Vigilant Watch
Viktor Ferenczi
waka nya
Wayne Haak
werner mendizabal
+ Wiley Thompson
+ Will
William Gervasio
William Hogben
Wout Standaert
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 67de156fc3..98d3e77f66 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -148,7 +148,7 @@ _ResourceLoader::_ResourceLoader() {
singleton = this;
}
-Error _ResourceSaver::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error _ResourceSaver::save(const String &p_path, const RES &p_resource, SaverFlags p_flags) {
ERR_FAIL_COND_V(p_resource.is_null(), ERR_INVALID_PARAMETER);
return ResourceSaver::save(p_path, p_resource, p_flags);
@@ -1579,7 +1579,7 @@ _Geometry::_Geometry() {
///////////////////////// FILE
-Error _File::open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key) {
+Error _File::open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key) {
Error err = open(p_path, p_mode_flags);
if (err)
@@ -1596,7 +1596,7 @@ Error _File::open_encrypted(const String &p_path, int p_mode_flags, const Vector
return OK;
}
-Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass) {
+Error _File::open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass) {
Error err = open(p_path, p_mode_flags);
if (err)
@@ -1614,7 +1614,7 @@ Error _File::open_encrypted_pass(const String &p_path, int p_mode_flags, const S
return OK;
}
-Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode) {
+Error _File::open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode) {
FileAccessCompressed *fac = memnew(FileAccessCompressed);
@@ -1631,7 +1631,7 @@ Error _File::open_compressed(const String &p_path, int p_mode_flags, int p_compr
return OK;
}
-Error _File::open(const String &p_path, int p_mode_flags) {
+Error _File::open(const String &p_path, ModeFlags p_mode_flags) {
close();
Error err;
@@ -2453,12 +2453,12 @@ void _Thread::_start_func(void *ud) {
}
}
-Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, int p_priority) {
+Error _Thread::start(Object *p_instance, const StringName &p_method, const Variant &p_userdata, Priority p_priority) {
ERR_FAIL_COND_V(active, ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_instance, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_method == StringName(), ERR_INVALID_PARAMETER);
- ERR_FAIL_INDEX_V(p_priority, 3, ERR_INVALID_PARAMETER);
+ ERR_FAIL_INDEX_V(p_priority, PRIORITY_MAX, ERR_INVALID_PARAMETER);
ret = Variant();
target_method = p_method;
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 1c26d9b144..2906de4a4a 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -85,7 +85,7 @@ public:
static _ResourceSaver *get_singleton() { return singleton; }
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags);
+ Error save(const String &p_path, const RES &p_resource, SaverFlags p_flags);
PoolVector<String> get_recognized_extensions(const RES &p_resource);
_ResourceSaver();
@@ -436,11 +436,11 @@ public:
COMPRESSION_GZIP = Compression::MODE_GZIP
};
- Error open_encrypted(const String &p_path, int p_mode_flags, const Vector<uint8_t> &p_key);
- Error open_encrypted_pass(const String &p_path, int p_mode_flags, const String &p_pass);
- Error open_compressed(const String &p_path, int p_mode_flags, int p_compress_mode = 0);
+ Error open_encrypted(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &p_key);
+ Error open_encrypted_pass(const String &p_path, ModeFlags p_mode_flags, const String &p_pass);
+ Error open_compressed(const String &p_path, ModeFlags p_mode_flags, CompressionMode p_compress_mode = COMPRESSION_FASTLZ);
- Error open(const String &p_path, int p_mode_flags); ///< open a file
+ Error open(const String &p_path, ModeFlags p_mode_flags); ///< open a file
void close(); ///< close a file
bool is_open() const; ///< true when file is open
@@ -632,10 +632,11 @@ public:
PRIORITY_LOW,
PRIORITY_NORMAL,
- PRIORITY_HIGH
+ PRIORITY_HIGH,
+ PRIORITY_MAX
};
- Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), int p_priority = PRIORITY_NORMAL);
+ Error start(Object *p_instance, const StringName &p_method, const Variant &p_userdata = Variant(), Priority p_priority = PRIORITY_NORMAL);
String get_id() const;
bool is_active() const;
Variant wait_to_finish();
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 708054e4ab..05b49f0815 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -68,6 +68,7 @@ const char *Expression::func_name[Expression::FUNC_MAX] = {
"lerp",
"inverse_lerp",
"range_lerp",
+ "smoothstep",
"dectime",
"randomize",
"randi",
@@ -185,6 +186,7 @@ int Expression::get_func_argument_count(BuiltinFunc p_func) {
return 2;
case MATH_LERP:
case MATH_INVERSE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_WRAP:
case MATH_WRAPF:
@@ -392,6 +394,12 @@ void Expression::exec_func(BuiltinFunc p_func, const Variant **p_inputs, Variant
VALIDATE_ARG_NUM(4);
*r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
} break;
+ case MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
diff --git a/core/math/expression.h b/core/math/expression.h
index fa0878c93c..f9075cb689 100644
--- a/core/math/expression.h
+++ b/core/math/expression.h
@@ -66,6 +66,7 @@ public:
MATH_LERP,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
+ MATH_SMOOTHSTEP,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 6ac6839827..0d209402dd 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -208,6 +208,17 @@ public:
static _ALWAYS_INLINE_ double range_lerp(double p_value, double p_istart, double p_istop, double p_ostart, double p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
static _ALWAYS_INLINE_ float range_lerp(float p_value, float p_istart, float p_istop, float p_ostart, float p_ostop) { return Math::lerp(p_ostart, p_ostop, Math::inverse_lerp(p_istart, p_istop, p_value)); }
+ static _ALWAYS_INLINE_ double smoothstep(double p_from, double p_to, double p_weight) {
+ if (is_equal_approx(p_from, p_to)) return p_from;
+ double x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0, 1.0);
+ return x * x * (3.0 - 2.0 * x);
+ }
+ static _ALWAYS_INLINE_ float smoothstep(float p_from, float p_to, float p_weight) {
+ if (is_equal_approx(p_from, p_to)) return p_from;
+ float x = CLAMP((p_weight - p_from) / (p_to - p_from), 0.0f, 1.0f);
+ return x * x * (3.0f - 2.0f * x);
+ }
+
static _ALWAYS_INLINE_ double linear2db(double p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
static _ALWAYS_INLINE_ float linear2db(float p_linear) { return Math::log(p_linear) * 8.6858896380650365530225783783321; }
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index df52f8503a..17ca11490a 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -975,6 +975,24 @@
[/codeblock]
</description>
</method>
+ <method name="smoothstep">
+ <return type="float">
+ </return>
+ <argument index="0" name="from" type="float">
+ </argument>
+ <argument index="1" name="to" type="float">
+ </argument>
+ <argument index="2" name="weight" type="float">
+ </argument>
+ <description>
+ Returns a number smoothly interpolated between the [code]from[/code] and [code]to[/code], based on the [code]weight[/code]. Similar to [method lerp], but interpolates faster at the beginning and slower at the end.
+ [codeblock]
+ smooth_step(0, 2, 0.5) # returns 0.15
+ smooth_step(0, 2, 1.0) # returns 0.5
+ smooth_step(0, 2, 2.0) # returns 1.0
+ [/codeblock]
+ </description>
+ </method>
<method name="sqrt">
<return type="float">
</return>
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 0df932cd62..335e3fcd29 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -832,7 +832,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
theme->set_color("font_color", "TextEdit", font_color);
- theme->set_color("caret_color", "TextEdit", highlight_color);
+ theme->set_color("caret_color", "TextEdit", font_color);
theme->set_color("selection_color", "TextEdit", font_color_selection);
// H/VSplitContainer
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index c5dfba6b06..f13c2170ea 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -80,6 +80,7 @@ void AnimationNodeBlendTreeEditor::_update_options_menu() {
}
add_node->get_popup()->add_separator();
add_node->get_popup()->add_item(TTR("Load..."), MENU_LOAD_FILE);
+ use_popup_menu_position = false;
}
Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const {
@@ -317,7 +318,15 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
EditorNode::get_singleton()->show_warning(TTR("Output node can't be added to the blend tree."));
return;
}
- Point2 instance_pos = graph->get_scroll_ofs() + graph->get_size() * 0.5;
+
+ Point2 instance_pos = graph->get_scroll_ofs();
+ if (use_popup_menu_position) {
+ instance_pos += popup_menu_position;
+ } else {
+ instance_pos += graph->get_size() * 0.5;
+ }
+
+ instance_pos /= graph->get_zoom();
int base = 1;
String name = base_name;
@@ -412,6 +421,40 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
undo_redo->commit_action();
}
+void AnimationNodeBlendTreeEditor::_delete_nodes_request() {
+
+ List<StringName> to_erase;
+
+ for (int i = 0; i < graph->get_child_count(); i++) {
+ GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
+ if (gn) {
+ if (gn->is_selected() && gn->is_close_button_visible()) {
+ to_erase.push_back(gn->get_name());
+ }
+ }
+ }
+
+ if (to_erase.empty())
+ return;
+
+ undo_redo->create_action(TTR("Delete Node(s)"));
+
+ for (List<StringName>::Element *F = to_erase.front(); F; F = F->next()) {
+ _delete_request(F->get());
+ }
+
+ undo_redo->commit_action();
+}
+
+void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+
+ _update_options_menu();
+ use_popup_menu_position = true;
+ popup_menu_position = graph->get_local_mouse_position();
+ add_node->get_popup()->set_position(p_position);
+ add_node->get_popup()->popup();
+}
+
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
@@ -730,6 +773,8 @@ void AnimationNodeBlendTreeEditor::_bind_methods() {
ClassDB::bind_method("_open_in_editor", &AnimationNodeBlendTreeEditor::_open_in_editor);
ClassDB::bind_method("_scroll_changed", &AnimationNodeBlendTreeEditor::_scroll_changed);
ClassDB::bind_method("_delete_request", &AnimationNodeBlendTreeEditor::_delete_request);
+ ClassDB::bind_method("_delete_nodes_request", &AnimationNodeBlendTreeEditor::_delete_nodes_request);
+ ClassDB::bind_method("_popup_request", &AnimationNodeBlendTreeEditor::_popup_request);
ClassDB::bind_method("_edit_filters", &AnimationNodeBlendTreeEditor::_edit_filters);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
ClassDB::bind_method("_filter_edited", &AnimationNodeBlendTreeEditor::_filter_edited);
@@ -850,6 +895,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
singleton = this;
updating = false;
+ use_popup_menu_position = false;
graph = memnew(GraphEdit);
add_child(graph);
@@ -860,6 +906,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->connect("disconnection_request", this, "_disconnection_request", varray(), CONNECT_DEFERRED);
graph->connect("node_selected", this, "_node_selected");
graph->connect("scroll_offset_changed", this, "_scroll_changed");
+ graph->connect("delete_nodes_request", this, "_delete_nodes_request");
+ graph->connect("popup_request", this, "_popup_request");
VSeparator *vs = memnew(VSeparator);
graph->get_zoom_hbox()->add_child(vs);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index f2a77cecb4..cb40159a40 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -51,6 +51,8 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
Ref<AnimationNodeBlendTree> blend_tree;
GraphEdit *graph;
MenuButton *add_node;
+ Vector2 popup_menu_position;
+ bool use_popup_menu_position;
PanelContainer *error_panel;
Label *error_label;
@@ -97,6 +99,8 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _open_in_editor(const String &p_which);
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
+ void _delete_nodes_request();
+ void _popup_request(const Vector2 &p_position);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 8a18af7ae8..33e4bb2336 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -481,10 +481,10 @@ void TileMapEditor::_update_palette() {
if (sel_tile != TileMap::INVALID_CELL) {
if ((manual_autotile && tileset->tile_get_tile_mode(sel_tile) == TileSet::AUTO_TILE) || tileset->tile_get_tile_mode(sel_tile) == TileSet::ATLAS_TILE) {
- const Map<Vector2, uint16_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
+ const Map<Vector2, uint32_t> &tiles2 = tileset->autotile_get_bitmask_map(sel_tile);
Vector<Vector2> entries2;
- for (const Map<Vector2, uint16_t>::Element *E = tiles2.front(); E; E = E->next()) {
+ for (const Map<Vector2, uint32_t>::Element *E = tiles2.front(); E; E = E->next()) {
entries2.push_back(E->key());
}
entries2.sort();
diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp
index 54e6e5b154..5bc1067718 100644
--- a/editor/plugins/tile_set_editor_plugin.cpp
+++ b/editor/plugins/tile_set_editor_plugin.cpp
@@ -734,7 +734,7 @@ void TileSetEditor::_on_edit_mode_changed(int p_edit_mode) {
tools[SHAPE_KEEP_INSIDE_TILE]->hide();
tools[TOOL_SELECT]->set_pressed(true);
- tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nClick on another Tile to edit it."));
+ tools[TOOL_SELECT]->set_tooltip(TTR("LMB: Set bit on.\nRMB: Set bit off.\nShift+LMB: Set wildcard bit.\nClick on another Tile to edit it."));
spin_priority->hide();
} break;
case EDITMODE_Z_INDEX:
@@ -818,52 +818,92 @@ void TileSetEditor::_on_workspace_draw() {
} break;
case EDITMODE_BITMASK: {
Color c(1, 0, 0, 0.5);
+ Color ci(0.3, 0.6, 1, 0.5);
for (float x = 0; x < region.size.x / (spacing + size.x); x++) {
for (float y = 0; y < region.size.y / (spacing + size.y); y++) {
Vector2 coord(x, y);
Point2 anchor(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
anchor += WORKSPACE_MARGIN;
anchor += region.position;
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
- if (mask & TileSet::BIND_TOPLEFT) {
+ if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
+ workspace->draw_rect(Rect2(anchor, size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + size / 4, size / 4), ci);
+ } else if (mask & TileSet::BIND_TOPLEFT) {
workspace->draw_rect(Rect2(anchor, size / 2), c);
}
- if (mask & TileSet::BIND_TOPRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 3 / 4, size.y / 4), size / 4), ci);
+ } else if (mask & TileSet::BIND_TOPRIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, 0), size / 2), c);
}
- if (mask & TileSet::BIND_BOTTOMLEFT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 4, size.y * 3 / 4), size / 4), ci);
+ } else if (mask & TileSet::BIND_BOTTOMLEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 2), size / 2), c);
}
- if (mask & TileSet::BIND_BOTTOMRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
+ workspace->draw_rect(Rect2(anchor + size / 2, size / 4), ci);
+ workspace->draw_rect(Rect2(anchor + size * 3 / 4, size / 4), ci);
+ } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c);
}
} else {
- if (mask & TileSet::BIND_TOPLEFT) {
+ if (mask & TileSet::BIND_IGNORE_TOPLEFT) {
+ workspace->draw_rect(Rect2(anchor, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size / 6, size / 6), ci);
+ } else if (mask & TileSet::BIND_TOPLEFT) {
workspace->draw_rect(Rect2(anchor, size / 3), c);
}
- if (mask & TileSet::BIND_TOP) {
+ if (mask & TileSet::BIND_IGNORE_TOP) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_TOP) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, 0), size / 3), c);
}
- if (mask & TileSet::BIND_TOPRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_TOPRIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, 0), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_TOPRIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, 0), size / 3), c);
}
- if (mask & TileSet::BIND_LEFT) {
+ if (mask & TileSet::BIND_IGNORE_LEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y / 2), size / 6), ci);
+ } else if (mask & TileSet::BIND_LEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_CENTER) {
+ if (mask & TileSet::BIND_IGNORE_CENTER) {
+ workspace->draw_rect(Rect2(anchor + size / 3, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size / 2, size / 6), ci);
+ } else if (mask & TileSet::BIND_CENTER) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_RIGHT) {
+ if (mask & TileSet::BIND_IGNORE_RIGHT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 4 / 6, size.y / 3), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x * 5 / 6, size.y / 2), size / 6), ci);
+ } else if (mask & TileSet::BIND_RIGHT) {
workspace->draw_rect(Rect2(anchor + Vector2((size.x / 3) * 2, size.y / 3), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOMLEFT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMLEFT) {
+ workspace->draw_rect(Rect2(anchor + Vector2(0, size.y * 4 / 6), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 6, size.y * 5 / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOMLEFT) {
workspace->draw_rect(Rect2(anchor + Vector2(0, (size.y / 3) * 2), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOM) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOM) {
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, size.y * 4 / 6), size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + Vector2(size.x / 2, size.y * 5 / 6), size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOM) {
workspace->draw_rect(Rect2(anchor + Vector2(size.x / 3, (size.y / 3) * 2), size / 3), c);
}
- if (mask & TileSet::BIND_BOTTOMRIGHT) {
+ if (mask & TileSet::BIND_IGNORE_BOTTOMRIGHT) {
+ workspace->draw_rect(Rect2(anchor + size * 4 / 6, size / 6), ci);
+ workspace->draw_rect(Rect2(anchor + size * 5 / 6, size / 6), ci);
+ } else if (mask & TileSet::BIND_BOTTOMRIGHT) {
workspace->draw_rect(Rect2(anchor + (size / 3) * 2, size / 3), c);
}
}
@@ -882,10 +922,10 @@ void TileSetEditor::_on_workspace_draw() {
} break;
case EDITMODE_PRIORITY: {
spin_priority->set_value(tileset->autotile_get_subtile_priority(get_current_tile(), edited_shape_coord));
- uint16_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
+ uint32_t mask = tileset->autotile_get_bitmask(get_current_tile(), edited_shape_coord);
Vector<Vector2> queue_others;
int total = 0;
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
if (E->value() == mask) {
total += tileset->autotile_get_subtile_priority(get_current_tile(), E->key());
if (E->key() != edited_shape_coord) {
@@ -1037,6 +1077,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
static bool dragging;
static bool erasing;
+ static bool alternative;
draw_edited_region = false;
Rect2 current_tile_region = Rect2();
@@ -1220,10 +1261,11 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((mb->get_button_index() == BUTTON_RIGHT || mb->get_button_index() == BUTTON_LEFT) && current_tile_region.has_point(mb->get_position())) {
dragging = true;
erasing = (mb->get_button_index() == BUTTON_RIGHT);
+ alternative = Input::get_singleton()->is_key_pressed(KEY_SHIFT);
Vector2 coord((int)((mb->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mb->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mb->get_position() - (pos + current_tile_region.position);
- uint16_t bit = 0;
+ uint32_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1266,13 +1308,19 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
- uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint16_t new_mask = old_mask;
- if (erasing) {
+ uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t new_mask = old_mask;
+ if (alternative) {
new_mask &= ~bit;
+ new_mask |= (bit << 16);
+ } else if (erasing) {
+ new_mask &= ~bit;
+ new_mask &= ~(bit << 16);
} else {
new_mask |= bit;
+ new_mask &= ~(bit << 16);
}
+
if (old_mask != new_mask) {
undo_redo->create_action(TTR("Edit Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), coord, new_mask);
@@ -1286,6 +1334,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
if ((erasing && mb->get_button_index() == BUTTON_RIGHT) || (!erasing && mb->get_button_index() == BUTTON_LEFT)) {
dragging = false;
erasing = false;
+ alternative = false;
}
}
}
@@ -1294,7 +1343,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
Vector2 coord((int)((mm->get_position().x - current_tile_region.position.x) / (spacing + size.x)), (int)((mm->get_position().y - current_tile_region.position.y) / (spacing + size.y)));
Vector2 pos(coord.x * (spacing + size.x), coord.y * (spacing + size.y));
pos = mm->get_position() - (pos + current_tile_region.position);
- uint16_t bit = 0;
+ uint32_t bit = 0;
if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_2X2) {
if (pos.x < size.x / 2) {
if (pos.y < size.y / 2) {
@@ -1337,12 +1386,17 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) {
}
}
- uint16_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
- uint16_t new_mask = old_mask;
- if (erasing) {
+ uint32_t old_mask = tileset->autotile_get_bitmask(get_current_tile(), coord);
+ uint32_t new_mask = old_mask;
+ if (alternative) {
+ new_mask &= ~bit;
+ new_mask |= (bit << 16);
+ } else if (erasing) {
new_mask &= ~bit;
+ new_mask &= ~(bit << 16);
} else {
new_mask |= bit;
+ new_mask &= ~(bit << 16);
}
if (old_mask != new_mask) {
undo_redo->create_action(TTR("Edit Tile Bitmask"));
@@ -1529,10 +1583,10 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
undo_redo->create_action(TTR("Paste Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
undo_redo->add_undo_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint16_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = bitmask_map_copy.front(); E; E = E->next()) {
undo_redo->add_do_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
undo_redo->add_do_method(workspace, "update");
@@ -1541,7 +1595,7 @@ void TileSetEditor::_on_tool_clicked(int p_tool) {
} else if (p_tool == BITMASK_CLEAR) {
undo_redo->create_action(TTR("Clear Tile Bitmask"));
undo_redo->add_do_method(tileset.ptr(), "autotile_clear_bitmask_map", get_current_tile());
- for (Map<Vector2, uint16_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tileset->autotile_get_bitmask_map(get_current_tile()).front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", get_current_tile(), E->key(), E->value());
}
undo_redo->add_do_method(workspace, "update");
@@ -2139,8 +2193,8 @@ void TileSetEditor::_undo_tile_removal(int p_id) {
for (Map<Vector2, Ref<NavigationPolygon> >::Element *E = navigation_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_navigation_polygon", p_id, E->value(), E->key());
}
- Map<Vector2, uint16_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
- for (Map<Vector2, uint16_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
+ Map<Vector2, uint32_t> bitmask_map = tileset->autotile_get_bitmask_map(p_id);
+ for (Map<Vector2, uint32_t>::Element *E = bitmask_map.front(); E; E = E->next()) {
undo_redo->add_undo_method(tileset.ptr(), "autotile_set_bitmask", p_id, E->key(), E->value());
}
Map<Vector2, int> priority_map = tileset->autotile_get_priority_map(p_id);
diff --git a/editor/plugins/tile_set_editor_plugin.h b/editor/plugins/tile_set_editor_plugin.h
index 2827964592..1176e1bb92 100644
--- a/editor/plugins/tile_set_editor_plugin.h
+++ b/editor/plugins/tile_set_editor_plugin.h
@@ -126,7 +126,7 @@ class TileSetEditor : public HSplitContainer {
Vector2 edited_shape_coord;
PoolVector2Array current_shape;
Map<Vector2i, SubtileData> current_tile_data;
- Map<Vector2, uint16_t> bitmask_map_copy;
+ Map<Vector2, uint32_t> bitmask_map_copy;
Vector2 snap_step;
Vector2 snap_offset;
diff --git a/modules/assimp/editor_scene_importer_assimp.cpp b/modules/assimp/editor_scene_importer_assimp.cpp
index 4662cf9d0a..ee66097ffd 100644
--- a/modules/assimp/editor_scene_importer_assimp.cpp
+++ b/modules/assimp/editor_scene_importer_assimp.cpp
@@ -1945,7 +1945,7 @@ void EditorSceneImporterAssimp::_add_mesh_to_mesh_instance(const aiNode *p_node,
morphs[j] = array_copy;
}
- r_name_morph_mesh_names.insert(_ai_raw_string_to_string(p_node->mName), morph_mesh_idx_names);
+ r_name_morph_mesh_names.insert(_ai_string_to_string(p_node->mName), morph_mesh_idx_names);
mesh->add_surface_from_arrays(primitive, array_mesh, morphs);
mesh->surface_set_material(i, mat);
mesh->surface_set_name(i, _ai_string_to_string(ai_mesh->mName));
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 46c9efd54f..4fd136d5cc 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -74,6 +74,7 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"lerp",
"inverse_lerp",
"range_lerp",
+ "smoothstep",
"dectime",
"randomize",
"randi",
@@ -369,6 +370,13 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(4);
r_ret = Math::range_lerp((double)*p_args[0], (double)*p_args[1], (double)*p_args[2], (double)*p_args[3], (double)*p_args[4]);
} break;
+ case MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_COUNT(3);
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ r_ret = Math::smoothstep((double)*p_args[0], (double)*p_args[1], (double)*p_args[2]);
+ } break;
case MATH_DECTIME: {
VALIDATE_ARG_COUNT(3);
VALIDATE_ARG_NUM(0);
@@ -1435,6 +1443,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
case MATH_LERP:
case MATH_INVERSE_LERP:
case MATH_RANGE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_DEG2RAD:
case MATH_RAD2DEG:
@@ -1618,6 +1627,11 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::REAL;
return mi;
} break;
+ case MATH_SMOOTHSTEP: {
+ MethodInfo mi("smoothstep", PropertyInfo(Variant::REAL, "from"), PropertyInfo(Variant::REAL, "to"), PropertyInfo(Variant::REAL, "weight"));
+ mi.return_val.type = Variant::REAL;
+ return mi;
+ } break;
case MATH_DECTIME: {
MethodInfo mi("dectime", PropertyInfo(Variant::REAL, "value"), PropertyInfo(Variant::REAL, "amount"), PropertyInfo(Variant::REAL, "step"));
mi.return_val.type = Variant::REAL;
diff --git a/modules/gdscript/gdscript_functions.h b/modules/gdscript/gdscript_functions.h
index fcb8f32e54..14bf3d7560 100644
--- a/modules/gdscript/gdscript_functions.h
+++ b/modules/gdscript/gdscript_functions.h
@@ -65,6 +65,7 @@ public:
MATH_LERP,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
+ MATH_SMOOTHSTEP,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
diff --git a/modules/mono/glue/Managed/Files/Mathf.cs b/modules/mono/glue/Managed/Files/Mathf.cs
index 5f5de12959..a064278237 100644
--- a/modules/mono/glue/Managed/Files/Mathf.cs
+++ b/modules/mono/glue/Managed/Files/Mathf.cs
@@ -261,6 +261,16 @@ namespace Godot
return (real_t)Math.Sinh(s);
}
+ public static real_t SmoothStep(real_t from, real_t to, real_t weight)
+ {
+ if (IsEqualApprox(from, to))
+ {
+ return from;
+ }
+ real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0);
+ return x * x * (3 - 2 * x);
+ }
+
public static real_t Sqrt(real_t s)
{
return (real_t)Math.Sqrt(s);
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index dd14d60327..104a90059e 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -204,7 +204,14 @@
<constant name="COLORN" value="62" enum="BuiltinFunc">
Return the [Color] with the given name and alpha ranging from 0 to 1. Note: names are defined in color_names.inc.
</constant>
- <constant name="FUNC_MAX" value="63" enum="BuiltinFunc">
+ <constant name="MATH_SMOOTHSTEP" value="63" enum="BuiltinFunc">
+ Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [code]MATH_LERP[/code], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula:
+ [codeblock]
+ var t = clamp((weight - from) / (to - from), 0.0, 1.0)
+ return t * t * (3.0 - 2.0 * t)
+ [/codeblock]
+ </constant>
+ <constant name="FUNC_MAX" value="64" enum="BuiltinFunc">
The maximum value the [member function] property can have.
</constant>
</constants>
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 0d379205e4..c2ce5f0bf5 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -102,6 +102,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"var2bytes",
"bytes2var",
"color_named",
+ "smoothstep",
};
VisualScriptBuiltinFunc::BuiltinFunc VisualScriptBuiltinFunc::find_function(const String &p_string) {
@@ -204,6 +205,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
return 2;
case MATH_LERP:
case MATH_INVERSE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME:
case MATH_WRAP:
case MATH_WRAPF:
@@ -337,6 +339,14 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
else
return PropertyInfo(Variant::REAL, "ostop");
} break;
+ case MATH_SMOOTHSTEP: {
+ if (p_idx == 0)
+ return PropertyInfo(Variant::REAL, "from");
+ else if (p_idx == 1)
+ return PropertyInfo(Variant::REAL, "to");
+ else
+ return PropertyInfo(Variant::REAL, "weight");
+ } break;
case MATH_DECTIME: {
if (p_idx == 0)
return PropertyInfo(Variant::REAL, "value");
@@ -569,6 +579,7 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
case MATH_LERP:
case MATH_INVERSE_LERP:
case MATH_RANGE_LERP:
+ case MATH_SMOOTHSTEP:
case MATH_DECTIME: {
t = Variant::REAL;
@@ -899,6 +910,12 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
VALIDATE_ARG_NUM(4);
*r_return = Math::range_lerp((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2], (double)*p_inputs[3], (double)*p_inputs[4]);
} break;
+ case VisualScriptBuiltinFunc::MATH_SMOOTHSTEP: {
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+ *r_return = Math::smoothstep((double)*p_inputs[0], (double)*p_inputs[1], (double)*p_inputs[2]);
+ } break;
case VisualScriptBuiltinFunc::MATH_DECTIME: {
VALIDATE_ARG_NUM(0);
@@ -1379,6 +1396,7 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(VAR_TO_BYTES);
BIND_ENUM_CONSTANT(BYTES_TO_VAR);
BIND_ENUM_CONSTANT(COLORN);
+ BIND_ENUM_CONSTANT(MATH_SMOOTHSTEP);
BIND_ENUM_CONSTANT(FUNC_MAX);
}
@@ -1433,6 +1451,7 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_LERP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/inverse_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_INVERSE_LERP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/range_lerp", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANGE_LERP>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/smoothstep", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_SMOOTHSTEP>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/dectime", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_DECTIME>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/randomize", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RANDOMIZE>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/rand", create_builtin_func_node<VisualScriptBuiltinFunc::MATH_RAND>);
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index 2d8454ddd4..50854c16b1 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -101,6 +101,7 @@ public:
VAR_TO_BYTES,
BYTES_TO_VAR,
COLORN,
+ MATH_SMOOTHSTEP,
FUNC_MAX
};
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index c313d9f9fd..5dd429fa75 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -669,11 +669,15 @@ inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, cons
void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
//PREPARATIONS
+ bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
+ bool draw_shadow = (shadow_size > 0);
+ if (!draw_border && !draw_center && !draw_shadow) {
+ return;
+ }
bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
bool aa_on = rounded_corners && anti_aliased;
- bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0);
bool blend_on = blend_border && draw_border;
@@ -710,11 +714,8 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Vector<int> indices;
Vector<Color> colors;
- //DRAWING
- VisualServer *vs = VisualServer::get_singleton();
-
//DRAW SHADOW
- if (shadow_size > 0) {
+ if (draw_shadow) {
int shadow_width[4] = { shadow_size, shadow_size, shadow_size, shadow_size };
Rect2 shadow_inner_rect = style_rect;
@@ -798,6 +799,8 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
}
+ //DRAWING
+ VisualServer *vs = VisualServer::get_singleton();
vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors);
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 4ddfc0331b..21b2893502 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -215,7 +215,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = autotile_get_spacing(id);
else if (what == "bitmask_flags") {
Array p;
- for (Map<Vector2, uint16_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) {
+ for (Map<Vector2, uint32_t>::Element *E = tile_map[id].autotile_data.flags.front(); E; E = E->next()) {
p.push_back(E->key());
p.push_back(E->value());
}
@@ -544,7 +544,7 @@ const Map<Vector2, int> &TileSet::autotile_get_z_index_map(int p_id) const {
return tile_map[p_id].autotile_data.z_index_map;
}
-void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag) {
+void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag) {
ERR_FAIL_COND(!tile_map.has(p_id));
if (p_flag == 0) {
@@ -555,7 +555,7 @@ void TileSet::autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag) {
}
}
-uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
+uint32_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
if (!tile_map[p_id].autotile_data.flags.has(p_coord)) {
@@ -564,13 +564,13 @@ uint16_t TileSet::autotile_get_bitmask(int p_id, Vector2 p_coord) {
return tile_map[p_id].autotile_data.flags[p_coord];
}
-const Map<Vector2, uint16_t> &TileSet::autotile_get_bitmask_map(int p_id) {
+const Map<Vector2, uint32_t> &TileSet::autotile_get_bitmask_map(int p_id) {
- static Map<Vector2, uint16_t> dummy;
- static Map<Vector2, uint16_t> dummy_atlas;
+ static Map<Vector2, uint32_t> dummy;
+ static Map<Vector2, uint32_t> dummy_atlas;
ERR_FAIL_COND_V(!tile_map.has(p_id), dummy);
if (tile_get_tile_mode(p_id) == ATLAS_TILE) {
- dummy_atlas = Map<Vector2, uint16_t>();
+ dummy_atlas = Map<Vector2, uint32_t>();
Rect2 region = tile_get_region(p_id);
Size2 size = autotile_get_size(p_id);
float spacing = autotile_get_spacing(p_id);
@@ -600,18 +600,25 @@ Vector2 TileSet::autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask,
}
List<Vector2> coords;
- uint16_t mask;
- for (Map<Vector2, uint16_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) {
+ uint32_t mask;
+ uint16_t mask_;
+ uint16_t mask_ignore;
+ for (Map<Vector2, uint32_t>::Element *E = tile_map[p_id].autotile_data.flags.front(); E; E = E->next()) {
mask = E->get();
if (tile_map[p_id].autotile_data.bitmask_mode == BITMASK_2X2) {
- mask &= (BIND_BOTTOMLEFT | BIND_BOTTOMRIGHT | BIND_TOPLEFT | BIND_TOPRIGHT);
+ mask |= (BIND_IGNORE_TOP | BIND_IGNORE_LEFT | BIND_IGNORE_CENTER | BIND_IGNORE_RIGHT | BIND_IGNORE_BOTTOM);
}
- if (mask == p_bitmask) {
+
+ mask_ = mask & 0xFFFF;
+ mask_ignore = mask >> 16;
+
+ if (((mask_ & (~mask_ignore)) == (p_bitmask & (~mask_ignore))) && (((~mask_) | mask_ignore) == ((~p_bitmask) | mask_ignore))) {
for (int i = 0; i < autotile_get_subtile_priority(p_id, E->key()); i++) {
coords.push_back(E->key());
}
}
}
+
if (coords.size() == 0) {
return autotile_get_icon_coordinate(p_id);
} else {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index fac48243d0..fb84cee218 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -72,7 +72,17 @@ public:
BIND_RIGHT = 32,
BIND_BOTTOMLEFT = 64,
BIND_BOTTOM = 128,
- BIND_BOTTOMRIGHT = 256
+ BIND_BOTTOMRIGHT = 256,
+
+ BIND_IGNORE_TOPLEFT = 1 << 16,
+ BIND_IGNORE_TOP = 1 << 17,
+ BIND_IGNORE_TOPRIGHT = 1 << 18,
+ BIND_IGNORE_LEFT = 1 << 19,
+ BIND_IGNORE_CENTER = 1 << 20,
+ BIND_IGNORE_RIGHT = 1 << 21,
+ BIND_IGNORE_BOTTOMLEFT = 1 << 22,
+ BIND_IGNORE_BOTTOM = 1 << 23,
+ BIND_IGNORE_BOTTOMRIGHT = 1 << 24
};
enum TileMode {
@@ -86,7 +96,7 @@ public:
Size2 size;
int spacing;
Vector2 icon_coord;
- Map<Vector2, uint16_t> flags;
+ Map<Vector2, uint32_t> flags;
Map<Vector2, Ref<OccluderPolygon2D> > occluder_map;
Map<Vector2, Ref<NavigationPolygon> > navpoly_map;
Map<Vector2, int> priority_map;
@@ -181,9 +191,9 @@ public:
int autotile_get_z_index(int p_id, const Vector2 &p_coord);
const Map<Vector2, int> &autotile_get_z_index_map(int p_id) const;
- void autotile_set_bitmask(int p_id, Vector2 p_coord, uint16_t p_flag);
- uint16_t autotile_get_bitmask(int p_id, Vector2 p_coord);
- const Map<Vector2, uint16_t> &autotile_get_bitmask_map(int p_id);
+ void autotile_set_bitmask(int p_id, Vector2 p_coord, uint32_t p_flag);
+ uint32_t autotile_get_bitmask(int p_id, Vector2 p_coord);
+ const Map<Vector2, uint32_t> &autotile_get_bitmask_map(int p_id);
Vector2 autotile_get_subtile_for_bitmask(int p_id, uint16_t p_bitmask, const Node *p_tilemap_node = NULL, const Vector2 &p_tile_location = Vector2());
void tile_set_shape(int p_id, int p_shape_id, const Ref<Shape2D> &p_shape);