summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DONORS.md76
-rw-r--r--core/io/file_access_encrypted.cpp4
-rw-r--r--core/io/file_access_network.cpp6
-rw-r--r--core/io/http_client.cpp6
-rw-r--r--core/list.h3
-rw-r--r--doc/classes/@GDScript.xml10
-rw-r--r--doc/classes/InputEventKey.xml2
-rw-r--r--doc/classes/MultiMeshInstance2D.xml27
-rw-r--r--doc/classes/Navigation.xml2
-rw-r--r--doc/classes/OS.xml9
-rw-r--r--doc/classes/Particles.xml3
-rw-r--r--doc/classes/ProjectSettings.xml2
-rwxr-xr-xdoc/tools/makerst.py47
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp2
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp19
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp8
-rw-r--r--drivers/gles2/shaders/canvas.glsl5
-rw-r--r--drivers/gles3/shaders/canvas.glsl5
-rw-r--r--drivers/windows/file_access_windows.cpp4
-rw-r--r--editor/dependency_editor.cpp2
-rw-r--r--editor/editor_data.cpp1
-rw-r--r--editor/editor_file_dialog.cpp9
-rw-r--r--editor/editor_file_dialog.h1
-rw-r--r--editor/editor_help.cpp3
-rw-r--r--editor/editor_inspector.cpp5
-rw-r--r--editor/editor_node.cpp42
-rw-r--r--editor/editor_node.h11
-rw-r--r--editor/filesystem_dock.cpp31
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/icons/icon_multi_mesh_instance_2d.svg4
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp4
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp71
-rw-r--r--editor/script_editor_debugger.cpp7
-rw-r--r--modules/gdscript/gdscript_parser.cpp4
-rw-r--r--modules/mono/SCsub5
-rw-r--r--modules/mono/build_scripts/godotsharptools_build.py35
-rw-r--r--modules/mono/build_scripts/mono_configure.py133
-rw-r--r--modules/mono/build_scripts/patches/fix-mono-android-tkill.diff70
-rw-r--r--modules/mono/config.py10
-rw-r--r--modules/mono/csharp_script.h1
-rw-r--r--modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs3
-rw-r--r--modules/mono/editor/godotsharp_export.cpp22
-rw-r--r--modules/mono/glue/base_object_glue.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp13
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp14
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_method.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_property.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp26
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.h18
-rw-r--r--modules/mono/signal_awaiter_utils.cpp2
-rw-r--r--platform/osx/os_osx.h1
-rw-r--r--platform/osx/os_osx.mm128
-rw-r--r--platform/uwp/export/export.cpp4
-rw-r--r--platform/x11/os_x11.cpp27
-rw-r--r--scene/2d/animated_sprite.cpp1
-rw-r--r--scene/2d/cpu_particles_2d.h2
-rw-r--r--scene/2d/line_2d.cpp1
-rw-r--r--scene/2d/multimesh_instance_2d.cpp111
-rw-r--r--scene/2d/multimesh_instance_2d.h65
-rw-r--r--scene/2d/tile_map.cpp7
-rw-r--r--scene/gui/graph_node.cpp4
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/text_edit.cpp2
-rw-r--r--scene/gui/tree.cpp6
-rw-r--r--scene/register_scene_types.cpp12
-rw-r--r--scene/resources/default_theme/default_theme.cpp12
-rw-r--r--scene/resources/resource_format_text.cpp6
69 files changed, 855 insertions, 336 deletions
diff --git a/DONORS.md b/DONORS.md
index 95c46c139b..30eb5c220f 100644
--- a/DONORS.md
+++ b/DONORS.md
@@ -17,25 +17,24 @@ generous deed immortalized in the next stable release of Godot Engine.
## Gold sponsors
Gamblify <https://www.gamblify.com>
- Image Campus <https://www.imagecampus.edu.ar>
## Mini sponsors
Alan Beauchamp
+ Aleksandar Kordic
Anandarup Mallik
Andrew Dunai
Brandon Lamb
+ Christian Chipont
Christian Uldall Pedersen
Christoph Woinke
- Connor Hill
Denis Malyavin
Edward Flick
GameDev.net
GameDev.tv
Hein-Pieter van Braam
Jacob McKenney
- Javary Games
- Jay Sistar
+ Javary Co.
Justin Arnold
Kyle Szklenski
Leonard Meagher
@@ -44,15 +43,13 @@ generous deed immortalized in the next stable release of Godot Engine.
Mike King
Neal Gompa (Conan Kudo)
Patrick Aarstad
- "Rainway "
Slobodan Milnovic
- StarFlare Software
Stephan Lanfermann
Stephen Telford
Steve
- TigerJ
VilliHaukka
Xananax
+ Y8.com
Zashi
## Gold donors
@@ -77,12 +74,14 @@ generous deed immortalized in the next stable release of Godot Engine.
Andreas Schüle
Asher Glick
Austen McRae
+ Brian van der Stel
+ Carlo Cabanilla
Daniel James
David Giardi
- David Graham
Edward E
Florian Breisch
Gero
+ Javier Roman
Jay Horton
Jon Smith
Jon Woodward
@@ -107,12 +106,12 @@ generous deed immortalized in the next stable release of Godot Engine.
William Wold
Wyatt Goodin
+ Alex Khayrullin
Chris Goddard
Chris Serino
Christian Padilla
Conrad Curry
Craig Smith
- Daniel Egger
Dean Harmon
Ian Richard Kunert
Ivan Trombley
@@ -135,17 +134,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Wojciech Chojnacki
Xavier PATRICELLI
+ Adam Neumann
Alessandra Pereyra
+ Alexander J Maynard
Alexey Dyadchenko
Andrew Bowen
Asdf
- Benjamin W Flint
+ Ben Botwin
Carlos de Sousa Marques
Chris Petrich
Christian Leth Jeppesen
Christoph Schröder
Cody Parker
- ComicSads
D
Daniel
Daniel Eichler
@@ -163,6 +163,8 @@ generous deed immortalized in the next stable release of Godot Engine.
Guilherme Felipe de C. G. da Silva
Heath Hayes
Hysteria
+ Idzard Kwadijk
+ Jared White
Jose Malheiro
Joshua Flores
Juan T Chen
@@ -173,7 +175,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Leandro Voltolino
Maarten Elings
Malcolm Peralty
- Marius Kamm
Markus Fehr
Markus Wiesner
Martin Eigel
@@ -184,6 +185,7 @@ generous deed immortalized in the next stable release of Godot Engine.
M H
Nick Nikitin
Oliver Dick
+ Paolo Munoz
Paul Hocker
Paul Von Zimmerman
Pete Goodwin
@@ -197,7 +199,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Urho
WytRabbit
Xavier Fumado Beltran
- yuanzhe zhou
## Silver donors
@@ -208,6 +209,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Adam Nakonieczny
Adam Smeltzer
Adisibio
+ Agustinus Arya
Aidan O'Flannagain
Alder Stefano
Alessandro Senese
@@ -231,21 +233,23 @@ generous deed immortalized in the next stable release of Godot Engine.
Benedikt
Ben Phelan
Ben Vercammen
+ Ben Woodley
+ Berbank
Bernd Jänichen
Black Block
Blair Allen
Bobby CC Wong
Boyquotes
- Branwen Zak
+ Branwyn Tylwyth
Bryan Stevenson
- Carl Winder
Carwyn Edwards
Chris Brown
Chris Chapin
+ Chris Gonzales
Christian Baune
Christian Winter
Christoffer Sundbom
- Christopher Fisher
+ Christopher Schmitt
Chris Wilson
Clay Heaton
Cobaltum
@@ -262,7 +266,6 @@ generous deed immortalized in the next stable release of Godot Engine.
Dominik Wetzel
Duobix
Edward Herbert
- E.G.
Egon Elbre
Ellen Marie Dash
Elmeri '- Duy Kevin Nguyen
@@ -271,30 +274,33 @@ generous deed immortalized in the next stable release of Godot Engine.
Eric Martini
Eric McCarthy
Eric Williams
- Fabian Lökes
+ Evan Rose
Felix Kollmann
fengjiongmax
- Foomf
+ Flaredown
G3Dev sàrl
Gary Hulst
Gerrit Großkopf
gmmath
Grant Clarke
Greg Olson
- Greg Pennefather
+ Greg P
Guldoman
Heribert Hirth
Hiroshi Naruo
HMan
Hunter Jones
+ Hylpher
ialex32x
Igor Buzatovic
Iiari
+ IndustrialRobot
Isaac Morton
Jaime Ruiz-Borau Vizárraga
Jako Danar
James A F Manley
Jax
+ Jed
Jeff Hungerford
Jeff Nyte
Jeremy Kahn
@@ -302,6 +308,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Joe Alden
Joel Fivat
Joel Setterberg
+ Johannes Eichler
Johannes Wuensch
Jonas Rudlang
Jonas Yamazaki
@@ -316,6 +323,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Juan Negrier
Judd
Julian Murgia
+ Kasier Bald0
KC Chan
kickmaniac
Kiyohiro Kawamura (kyorohiro)
@@ -324,22 +332,24 @@ generous deed immortalized in the next stable release of Godot Engine.
KsyTek Games
Kuan Cheang
kycho
+ Lavik1988
Levi Lindsey
Linus Lind Lundgren
Lionel Gaillard
Luis Moraes
+ LunaticInAHat
+ Lurkars
Macil
- magodev
Major Haul
Malcolm
Malik Ahmed
+ Malik Nejer
+ Marcus Richter
Markus Michael Egger
Martin Holas
Matthew Little
Maxwell
medecau
- Menno Finlay-Smits
- Mertcan Mermerkaya
mhilbrunner
Michael Dürwald
Michael Gringauz
@@ -347,9 +357,9 @@ generous deed immortalized in the next stable release of Godot Engine.
Mikael Olsson
Mikayla Hutchinson
Mike Cunningham
+ mlevin cantu
MoM
Moritz Laass
- Moritz Weissenberger
MuffinManKen
Natrim
nee
@@ -360,6 +370,7 @@ generous deed immortalized in the next stable release of Godot Engine.
Nicolas SAN AGUSTIN
Nithin Jino
NZ
+ Omar Delarosa
Oscar Norlander
Pan Ip
Patrick Forringer
@@ -370,30 +381,30 @@ generous deed immortalized in the next stable release of Godot Engine.
Philip O. Staiger
Pierre-Igor Berthet
Pietro Vertechi
- Piotr Kaczmarski
Pitsanu Tongprasin
Poryg
+ Rafa Laguna
+ Rafal Wyszomirski
Raphael Leroux
- Red Hara
Rémi Verschelde
Ricardo Alcantara
- Rob Crowle
Robert Farr (Larington)
Robert Hernandez
Rodrigo Loli
- Roger Burgess
Roger Smith
Roland Rząsa
Roman Tinkov
Ryan Groom
Ryan Hentz
Saad Khoudmi
- Samdze
+ Samuele Zolfanelli
+ Sanka.X
Sasori Olkof
Scott D. Yelich
Sebastian Michailidis
Shane Sicienski
Shane Spoor
+ Simon Ledam
Simon Wenner
SK
Sootstone
@@ -408,13 +419,18 @@ generous deed immortalized in the next stable release of Godot Engine.
Tim Drumheller
Tim Gudex
Timo Schmidt
+ Timothy B. MacDonald
+ Tobbun
Tom Larrow
Torsten Crass
Travis O'Brien
+ Trent Skinner
Tryggve Sollid
- Tyler Strafos
+ Turgut Temucin
+ Tyler Stafos
UltyX
Vaiktorg
+ Valeria Viana Gusmao
Veodok
Victor
Vigilant Watch
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 3ff9fa569c..7dea749a43 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -308,8 +308,8 @@ uint32_t FileAccessEncrypted::_get_unix_permissions(const String &p_file) {
}
Error FileAccessEncrypted::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
-
- return FAILED;
+ ERR_PRINT("Setting UNIX permissions on encrypted files is not implemented yet");
+ return ERR_UNAVAILABLE;
}
FileAccessEncrypted::FileAccessEncrypted() {
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 2572602e16..5dd167c581 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -501,13 +501,13 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
}
uint32_t FileAccessNetwork::_get_unix_permissions(const String &p_file) {
- //could be implemented, not sure if worth it
+ ERR_PRINT("Getting UNIX permissions from network drives is not implemented yet");
return 0;
}
Error FileAccessNetwork::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
-
- return FAILED;
+ ERR_PRINT("Setting UNIX permissions on network drives is not implemented yet");
+ return ERR_UNAVAILABLE;
}
void FileAccessNetwork::configure() {
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index ce2054db36..891fb7b0ca 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -346,6 +346,12 @@ Error HTTPClient::poll() {
} else {
// We are already handshaking, which means we can use your already active SSL connection
ssl = static_cast<Ref<StreamPeerSSL> >(connection);
+ if (ssl.is_null()) {
+ close();
+ status = STATUS_SSL_HANDSHAKE_ERROR;
+ return ERR_CANT_CONNECT;
+ }
+
ssl->poll(); // Try to finish the handshake
}
diff --git a/core/list.h b/core/list.h
index 103a82a31d..d1b528562d 100644
--- a/core/list.h
+++ b/core/list.h
@@ -602,9 +602,6 @@ public:
Element *next = current->next_ptr;
- //disconnect
- current->next_ptr = NULL;
-
if (from != current) {
current->prev_ptr = NULL;
diff --git a/doc/classes/@GDScript.xml b/doc/classes/@GDScript.xml
index 553fd4d629..b6de5dbf62 100644
--- a/doc/classes/@GDScript.xml
+++ b/doc/classes/@GDScript.xml
@@ -92,13 +92,13 @@
<argument index="0" name="condition" type="bool">
</argument>
<description>
- Assert that the [code]condition[/code] is [code]true[/code] . If the [code]condition[/code] is [code]false[/code] a fatal error is generated and the program is halted. Useful for debugging to make sure a value is always [code]true[/code].
+ Asserts that the [code]condition[/code] is [code]true[/code] . If the [code]condition[/code] is [code]false[/code], an error is generated and the program is halted until you resume it. Only executes in debug builds, or when running the game from the editor. Use it for debugging purposes, to make sure a statement is [code]true[/code] during development.
[codeblock]
- # Speed should always be between 0 and 20
+ # Imagine we always want speed to be between 0 and 20
speed = -10
- assert(speed &lt; 20) # Is true and program continues
- assert(speed &gt;= 0) # Is false and program stops
- assert(speed &gt;= 0 &amp;&amp; speed &lt; 20) # Or combined
+ assert(speed &lt; 20) # True, the program will continue
+ assert(speed &gt;= 0) # False, the program will stop
+ assert(speed &gt;= 0 &amp;&amp; speed &lt; 20) # You can also combine the two conditional statements in one check
[/codeblock]
</description>
</method>
diff --git a/doc/classes/InputEventKey.xml b/doc/classes/InputEventKey.xml
index 86a1362230..53b1f74bd4 100644
--- a/doc/classes/InputEventKey.xml
+++ b/doc/classes/InputEventKey.xml
@@ -29,7 +29,7 @@
Key scancode, one of the [enum KeyList] constants.
</member>
<member name="unicode" type="int" setter="set_unicode" getter="get_unicode">
- Key unicode identifier when relevant.
+ Key unicode identifier when relevant. Unicode identifiers for the composite characters and complex scripts may not be available unless IME input mode is active. See [method OS.set_ime_active] for more information.
</member>
</members>
<constants>
diff --git a/doc/classes/MultiMeshInstance2D.xml b/doc/classes/MultiMeshInstance2D.xml
new file mode 100644
index 0000000000..0bf243ee24
--- /dev/null
+++ b/doc/classes/MultiMeshInstance2D.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="MultiMeshInstance2D" inherits="Node2D" category="Core" version="3.2">
+ <brief_description>
+ Node that instances a [MultiMesh] in 2D.
+ </brief_description>
+ <description>
+ [MultiMeshInstance2D] is a specialized node to instance a [MultiMesh] resource in 2D.
+ Usage is the same as [MultiMeshInstance].
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ </methods>
+ <members>
+ <member name="multimesh" type="MultiMesh" setter="set_multimesh" getter="get_multimesh">
+ The [MultiMesh] that will be drawn by the [MultiMeshInstance2D].
+ </member>
+ <member name="normal_map" type="Texture" setter="set_normal_map" getter="get_normal_map">
+ The normal map that will be used if using the default [CanvasItemMaterial].
+ </member>
+ <member name="texture" type="Texture" setter="set_texture" getter="get_texture">
+ The [Texture] that will be used if using the default [CanvasItemMaterial]. Can be accessed as [code]TEXTURE[/code] in CanvasItem shader.
+ </member>
+ </members>
+ <constants>
+ </constants>
+</class>
diff --git a/doc/classes/Navigation.xml b/doc/classes/Navigation.xml
index 3690c1d682..f0ae3fef99 100644
--- a/doc/classes/Navigation.xml
+++ b/doc/classes/Navigation.xml
@@ -59,7 +59,7 @@
<argument index="2" name="optimize" type="bool" default="true">
</argument>
<description>
- Returns the path between two given points. Points are in local coordinate space. If [code]optimize[/code] is [code]true[/code] (the default), the agent properties associated with each [NavigationMesh] (raidus, height, etc.) are considered in the path calculation, otherwise they are ignored.
+ Returns the path between two given points. Points are in local coordinate space. If [code]optimize[/code] is [code]true[/code] (the default), the agent properties associated with each [NavigationMesh] (radius, height, etc.) are considered in the path calculation, otherwise they are ignored.
</description>
</method>
<method name="navmesh_add">
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index dd0fcd63e7..f7cd6c3e83 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -221,14 +221,16 @@
<return type="Vector2">
</return>
<description>
- Returns IME selection range.
+ Returns IME cursor position (currently edited portion of the string) relative to the characters in the composition string.
+ [code]NOTIFICATION_OS_IME_UPDATE[/code] is sent to the application to notify it of changes to the IME cursor position.
</description>
</method>
<method name="get_ime_text" qualifiers="const">
<return type="String">
</return>
<description>
- Returns IME intermediate text.
+ Returns IME intermediate composition string.
+ [code]NOTIFICATION_OS_IME_UPDATE[/code] is sent to the application to notify it of changes to the IME composition string.
</description>
</method>
<method name="get_latin_keyboard_variant" qualifiers="const">
@@ -710,6 +712,9 @@
</argument>
<description>
Sets whether IME input mode should be enabled.
+ If active IME handles key events before the application and creates an composition string and suggestion list.
+ Application can retrieve the composition status by using [method get_ime_selection] and [method get_ime_text] functions.
+ Completed composition string is committed when input is finished.
</description>
</method>
<method name="set_ime_position">
diff --git a/doc/classes/Particles.xml b/doc/classes/Particles.xml
index 0023fce97d..7820c63ad7 100644
--- a/doc/classes/Particles.xml
+++ b/doc/classes/Particles.xml
@@ -15,13 +15,14 @@
<return type="AABB">
</return>
<description>
+ Returns the bounding box that contains all the particles that are active in the current frame.
</description>
</method>
<method name="restart">
<return type="void">
</return>
<description>
- Restarts the particle emmission, clearing existing particles.
+ Restarts the particle emission, clearing existing particles.
</description>
</method>
</methods>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 5bcd39a8d6..460db5e792 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -723,7 +723,7 @@
Shaders have a time variable that constantly increases. At some point, it needs to be rolled back to zero to avoid precision errors on shader animations. This setting specifies when (in seconds).
</member>
<member name="rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround" type="bool" setter="" getter="">
- Some NVIDIA GPU drivers have a bug which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to [url=https://github.com/godotengine/godot/issues/9913][/url] for details.
+ Some NVIDIA GPU drivers have a bug which produces flickering issues for the [code]draw_rect[/code] method, especially as used in [TileMap]. Refer to [url=https://github.com/godotengine/godot/issues/9913]GitHub issue 9913[/url] for details.
If [code]true[/code], this option enables a "safe" code path for such NVIDIA GPUs at the cost of performance. This option only impacts the GLES2 rendering backend (so the bug stays if you use GLES3), and only desktop platforms.
</member>
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="">
diff --git a/doc/tools/makerst.py b/doc/tools/makerst.py
index c3e15b2f9a..454c71d3c7 100755
--- a/doc/tools/makerst.py
+++ b/doc/tools/makerst.py
@@ -478,24 +478,7 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
f.write(make_heading('Tutorials', '-'))
for t in class_def.tutorials:
link = t.strip()
- match = GODOT_DOCS_PATTERN.search(link)
- if match:
- groups = match.groups()
- if match.lastindex == 2:
- # Doc reference with fragment identifier: emit direct link to section with reference to page, for example:
- # `#calling-javascript-from-script in Exporting For Web`
- f.write("- `" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`\n\n")
- # Commented out alternative: Instead just emit:
- # `Subsection in Exporting For Web`
- # f.write("- `Subsection <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`\n\n")
- elif match.lastindex == 1:
- # Doc reference, for example:
- # `Math`
- f.write("- :doc:`../" + groups[0] + "`\n\n")
- else:
- # External link, for example:
- # `http://enet.bespin.org/usergroup0.html`
- f.write("- `" + link + " <" + link + ">`_\n\n")
+ f.write("- " + make_url(link) + "\n\n")
# Property descriptions
if len(class_def.properties) > 0:
@@ -802,15 +785,16 @@ def rstize_text(text, state): # type: (str, State) -> str
tag_text = "" # '![](' + cmd[6:] + ')'
elif cmd.find('url=') == 0:
url_link = cmd[4:]
- tag_text = ':ref:`'
+ tag_text = '`'
tag_depth += 1
- url_has_name = False
inside_url = True
+ url_has_name = False
elif cmd == '/url':
- tag_text = ('' if url_has_name else url_link) + '<' + url_link + ">`"
+ tag_text = ('' if url_has_name else url_link) + " <" + url_link + ">`_"
tag_depth -= 1
escape_post = True
inside_url = False
+ url_has_name = False
elif cmd == 'center':
tag_depth += 1
tag_text = ''
@@ -996,5 +980,26 @@ def make_heading(title, underline): # type: (str, str) -> str
return title + '\n' + (underline * len(title)) + "\n\n"
+def make_url(link): # type: (str) -> str
+ match = GODOT_DOCS_PATTERN.search(link)
+ if match:
+ groups = match.groups()
+ if match.lastindex == 2:
+ # Doc reference with fragment identifier: emit direct link to section with reference to page, for example:
+ # `#calling-javascript-from-script in Exporting For Web`
+ return "`" + groups[1] + " <../" + groups[0] + ".html" + groups[1] + ">`_ in :doc:`../" + groups[0] + "`"
+ # Commented out alternative: Instead just emit:
+ # `Subsection in Exporting For Web`
+ # return "`Subsection <../" + groups[0] + ".html" + groups[1] + ">`__ in :doc:`../" + groups[0] + "`"
+ elif match.lastindex == 1:
+ # Doc reference, for example:
+ # `Math`
+ return ":doc:`../" + groups[0] + "`"
+ else:
+ # External link, for example:
+ # `http://enet.bespin.org/usergroup0.html`
+ return "`" + link + " <" + link + ">`_"
+
+
if __name__ == '__main__':
main()
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index ee722e9d6c..b82186162d 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -1081,6 +1081,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
} else {
glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs);
}
+ } else {
+ glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0);
}
if (multi_mesh->custom_data_floats) {
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 50cb39b13f..35694f000c 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2931,14 +2931,16 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
#elif IPHONE_ENABLED
+
glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
glResolveMultisampleFramebufferAPPLE();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-#else
- // In GLES2 Blit is not available, so just copy color texture manually
+#elif ANDROID_ENABLED
+
+ // In GLES2 AndroidBlit is not available, so just copy color texture manually
_copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
#endif
}
@@ -2972,8 +2974,17 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-#else
- // In GLES2 Blit is not available, so just copy color texture manually
+#elif IPHONE_ENABLED
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glResolveMultisampleFramebufferAPPLE();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+#elif ANDROID_ENABLED
+
+ // In GLES2 Android Blit is not available, so just copy color texture manually
_copy_texture_to_front_buffer(storage->frame.current_rt->multisample_color);
#endif
}
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index c610f31bc1..7b5f193b2b 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -91,7 +91,7 @@ GLuint RasterizerStorageGLES2::system_fbo = 0;
//void *glRenderbufferStorageMultisampleAPPLE;
//void *glResolveMultisampleFramebufferAPPLE;
#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE
-#else
+#elif ANDROID_ENABLED
#include <GLES2/gl2ext.h>
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT;
@@ -4719,7 +4719,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color);
-#else
+#elif ANDROID_ENABLED
// Render to a texture in android
glGenTextures(1, &rt->multisample_color);
glBindTexture(GL_TEXTURE_2D, rt->multisample_color);
@@ -5602,11 +5602,11 @@ void RasterizerStorageGLES2::initialize() {
//Manually load extensions for android and ios
#ifdef IPHONE_ENABLED
-
+ // appears that IPhone doesn't need to dlopen TODO: test this rigorously before removing
//void *gles2_lib = dlopen(NULL, RTLD_LAZY);
//glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE");
//glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE");
-#else
+#elif ANDROID_ENABLED
void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY);
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT");
diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index 7dce784f52..0818942b0a 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -112,7 +112,12 @@ void main() {
#ifdef USE_INSTANCING
mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
color *= instance_color;
+
+#ifdef USE_INSTANCE_CUSTOM
vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
#else
mat4 extra_matrix_instance = extra_matrix;
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 0d1e7ee4a1..a46b31c92e 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -117,7 +117,12 @@ void main() {
#ifdef USE_INSTANCING
mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
color *= instance_color;
+
+#ifdef USE_INSTANCE_CUSTOM
vec4 instance_custom = instance_custom_data;
+#else
+ vec4 instance_custom = vec4(0.0);
+#endif
#else
mat4 extra_matrix_instance = extra_matrix;
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index c13300d09f..31360d319f 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -340,13 +340,11 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
}
uint32_t FileAccessWindows::_get_unix_permissions(const String &p_file) {
- ERR_PRINT("Windows does not support unix permissions");
return 0;
}
Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_permissions) {
- ERR_PRINT("Windows does not support unix permissions");
- return FAILED;
+ return ERR_UNAVAILABLE;
}
FileAccessWindows::FileAccessWindows() :
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index bde73e9268..cc9e2c12e8 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -725,7 +725,7 @@ bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd, HashMa
int ds = efsd->get_file_deps(i).size();
ti->set_text(1, itos(ds));
if (ds) {
- ti->add_button(1, get_icon("GuiVisibilityVisible", "EditorIcons"));
+ ti->add_button(1, get_icon("GuiVisibilityVisible", "EditorIcons"), -1, false, TTR("Show Dependencies"));
}
ti->set_metadata(0, path);
has_children = true;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index f61a831015..38f30df169 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -560,6 +560,7 @@ void EditorData::move_edited_scene_index(int p_idx, int p_to_idx) {
ERR_FAIL_INDEX(p_to_idx, edited_scene.size());
SWAP(edited_scene.write[p_idx], edited_scene.write[p_to_idx]);
}
+
void EditorData::remove_scene(int p_idx) {
ERR_FAIL_INDEX(p_idx, edited_scene.size());
if (edited_scene[p_idx].root) {
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 3d198dec67..1a293adb4b 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1253,6 +1253,12 @@ void EditorFileDialog::_favorite_toggled(bool p_toggle) {
_update_favorites();
}
+void EditorFileDialog::_favorite_pressed() {
+
+ favorite->set_pressed(!favorite->is_pressed());
+ _favorite_toggled(favorite->is_pressed());
+}
+
void EditorFileDialog::_recent_selected(int p_idx) {
Vector<String> recentd = EditorSettings::get_singleton()->get_recent_dirs();
@@ -1376,6 +1382,7 @@ void EditorFileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_go_up"), &EditorFileDialog::_go_up);
ClassDB::bind_method(D_METHOD("_favorite_toggled"), &EditorFileDialog::_favorite_toggled);
+ ClassDB::bind_method(D_METHOD("_favorite_pressed"), &EditorFileDialog::_favorite_pressed);
ClassDB::bind_method(D_METHOD("_favorite_selected"), &EditorFileDialog::_favorite_selected);
ClassDB::bind_method(D_METHOD("_favorite_move_up"), &EditorFileDialog::_favorite_move_up);
ClassDB::bind_method(D_METHOD("_favorite_move_down"), &EditorFileDialog::_favorite_move_down);
@@ -1519,7 +1526,7 @@ EditorFileDialog::EditorFileDialog() {
favorite->set_flat(true);
favorite->set_toggle_mode(true);
favorite->set_tooltip(TTR("(Un)favorite current folder."));
- favorite->connect("toggled", this, "_favorite_toggled");
+ favorite->connect("pressed", this, "_favorite_pressed");
pathhb->add_child(favorite);
Ref<ButtonGroup> view_mode_group;
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index edaccac51d..529aaa71de 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -151,6 +151,7 @@ private:
void _update_favorites();
void _favorite_toggled(bool p_toggle);
+ void _favorite_pressed();
void _favorite_selected(int p_idx);
void _favorite_move_up();
void _favorite_move_down();
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 5917869988..df25b08b4c 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -203,8 +203,9 @@ String EditorHelp::_fix_constant(const String &p_constant) const {
if (p_constant.strip_edges() == "2147483647") {
return "0x7FFFFFFF";
}
+
if (p_constant.strip_edges() == "1048575") {
- return "0xfffff";
+ return "0xFFFFF";
}
return p_constant;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index ecb9ea5f35..e4ddf44bc4 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -66,7 +66,7 @@ Size2 EditorProperty::get_minimum_size() const {
if (checkable) {
Ref<Texture> check = get_icon("checked", "CheckBox");
- ms.width += check->get_width() + get_constant("hseparator", "Tree");
+ ms.width += check->get_width() + get_constant("hseparation", "CheckBox") + get_constant("hseparator", "Tree");
}
if (bottom_editor != NULL && bottom_editor->is_visible()) {
@@ -228,8 +228,7 @@ void EditorProperty::_notification(int p_what) {
}
check_rect = Rect2(ofs, ((size.height - checkbox->get_height()) / 2), checkbox->get_width(), checkbox->get_height());
draw_texture(checkbox, check_rect.position, color2);
- ofs += get_constant("hseparator", "Tree");
- ofs += checkbox->get_width();
+ ofs += get_constant("hseparator", "Tree") + checkbox->get_width() + get_constant("hseparation", "CheckBox");
text_limit -= ofs;
} else {
check_rect = Rect2();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 43c8ef60aa..969e1affd7 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -523,6 +523,7 @@ void EditorNode::_fs_changed() {
void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
List<String> scenes; //will load later
+ int current_tab = scene_tabs->get_current_tab();
for (int i = 0; i < p_resources.size(); i++) {
String file_type = ResourceLoader::get_resource_type(p_resources[i]);
@@ -545,6 +546,8 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
for (List<String>::Element *E = scenes.front(); E; E = E->next()) {
reload_scene(E->get());
}
+
+ scene_tabs->set_current_tab(current_tab);
}
void EditorNode::_sources_changed(bool p_exist) {
@@ -1214,6 +1217,17 @@ void EditorNode::save_all_scenes() {
_save_all_scenes();
}
+void EditorNode::save_scene_list(Vector<String> p_scene_filenames) {
+
+ for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
+ Node *scene = editor_data.get_edited_scene_root(i);
+
+ if (scene && (p_scene_filenames.find(scene->get_filename()) >= 0)) {
+ _save_scene(scene->get_filename(), i);
+ }
+ }
+}
+
void EditorNode::restart_editor() {
exiting = true;
@@ -2859,7 +2873,7 @@ bool EditorNode::is_addon_plugin_enabled(const String &p_addon) const {
return plugin_addons.has(p_addon);
}
-void EditorNode::_remove_edited_scene() {
+void EditorNode::_remove_edited_scene(bool p_change_tab) {
int new_index = editor_data.get_edited_scene();
int old_index = new_index;
@@ -2875,18 +2889,19 @@ void EditorNode::_remove_edited_scene() {
if (editor_data.get_scene_path(old_index) != String()) {
ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(editor_data.get_scene_path(old_index));
}
- _scene_tab_changed(new_index);
+
+ if (p_change_tab) _scene_tab_changed(new_index);
editor_data.remove_scene(old_index);
editor_data.get_undo_redo().clear_history(false);
_update_title();
_update_scene_tabs();
}
-void EditorNode::_remove_scene(int index) {
+void EditorNode::_remove_scene(int index, bool p_change_tab) {
if (editor_data.get_edited_scene() == index) {
//Scene to remove is current scene
- _remove_edited_scene();
+ _remove_edited_scene(p_change_tab);
} else {
//Scene to remove is not active scene
editor_data.remove_scene(index);
@@ -4182,6 +4197,14 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
return true;
}
+int EditorNode::get_current_tab() {
+ return scene_tabs->get_current_tab();
+}
+
+void EditorNode::set_current_tab(int p_tab) {
+ scene_tabs->set_current_tab(p_tab);
+}
+
void EditorNode::_update_layouts_menu() {
editor_layouts->clear();
@@ -4809,8 +4832,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) {
if (get_edited_scene()) {
- //scene is not open, so at it might be instanced, just refresh, set tab to itself and it will reload
- set_current_scene(current_tab);
+ //scene is not open, so at it might be instanced. We'll refresh the whole scene later.
editor_data.get_undo_redo().clear_history();
}
return;
@@ -4820,17 +4842,19 @@ void EditorNode::reload_scene(const String &p_path) {
editor_data.apply_changes_in_editors();
_set_scene_metadata(p_path);
}
+
//remove scene
- _remove_scene(scene_idx);
- //reload scene
+ _remove_scene(scene_idx, false);
+ //reload scene
load_scene(p_path, true, false, true, true);
+
//adjust index so tab is back a the previous position
editor_data.move_edited_scene_to_index(scene_idx);
get_undo_redo()->clear_history();
+
//recover the tab
scene_tabs->set_current_tab(current_tab);
- _scene_tab_changed(current_tab);
}
int EditorNode::plugin_init_callback_count = 0;
diff --git a/editor/editor_node.h b/editor/editor_node.h
index ea988cb134..f3bc95c409 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -525,8 +525,8 @@ private:
static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
void _cleanup_scene();
- void _remove_edited_scene();
- void _remove_scene(int index);
+ void _remove_edited_scene(bool p_change_tab = true);
+ void _remove_scene(int index, bool p_change_tab = true);
bool _find_and_save_resource(RES p_res, Map<RES, bool> &processed, int32_t flags);
bool _find_and_save_edited_subresources(Object *obj, Map<RES, bool> &processed, int32_t flags);
void _save_edited_subresources(Node *scene, Map<RES, bool> &processed, int32_t flags);
@@ -644,6 +644,12 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+protected:
+ friend class FileSystemDock;
+
+ int get_current_tab();
+ void set_current_tab(int p_tab);
+
public:
bool call_build();
@@ -815,6 +821,7 @@ public:
void remove_tool_menu_item(const String &p_name);
void save_all_scenes();
+ void save_scene_list(Vector<String> p_scene_filenames);
void restart_editor();
void dim_editor(bool p_dimming);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 6a4d9fea0c..ee88b558c8 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1203,6 +1203,21 @@ void FileSystemDock::_update_favorites_list_after_move(const Map<String, String>
EditorSettings::get_singleton()->set_favorites(new_favorites);
}
+void FileSystemDock::_save_scenes_after_move(const Map<String, String> &p_renames) const {
+ Vector<String> remaps;
+ _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), p_renames, remaps);
+ Vector<String> new_filenames;
+
+ for (int i = 0; i < remaps.size(); ++i) {
+ String file = p_renames.has(remaps[i]) ? p_renames[remaps[i]] : remaps[i];
+ if (ResourceLoader::get_resource_type(file) == "PackedScene") {
+ new_filenames.push_back(file);
+ }
+ }
+
+ editor->save_scene_list(new_filenames);
+}
+
void FileSystemDock::_make_dir_confirm() {
String dir_name = make_dir_dialog_text->get_text().strip_edges();
@@ -1281,14 +1296,21 @@ void FileSystemDock::_rename_operation_confirm() {
Map<String, String> file_renames;
Map<String, String> folder_renames;
_try_move_item(to_rename, new_path, file_renames, folder_renames);
+
+ int current_tab = editor->get_current_tab();
+
_update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames);
_update_project_settings_after_move(file_renames);
_update_favorites_list_after_move(file_renames, folder_renames);
- //Rescan everything
+ editor->set_current_tab(current_tab);
+
print_verbose("FileSystem: calling rescan.");
_rescan();
+
+ print_verbose("FileSystem: saving moved scenes.");
+ _save_scenes_after_move(file_renames);
}
void FileSystemDock::_duplicate_operation_confirm() {
@@ -1384,13 +1406,20 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool overw
}
if (is_moved) {
+ int current_tab = editor->get_current_tab();
+
_update_dependencies_after_move(file_renames);
_update_resource_paths_after_move(file_renames);
_update_project_settings_after_move(file_renames);
_update_favorites_list_after_move(file_renames, folder_renames);
+ editor->set_current_tab(current_tab);
+
print_verbose("FileSystem: calling rescan.");
_rescan();
+
+ print_verbose("FileSystem: saving moved scenes.");
+ _save_scenes_after_move(file_renames);
}
}
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 978235b328..46eaf71a8a 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -202,6 +202,7 @@ private:
void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
void _update_dependencies_after_move(const Map<String, String> &p_renames) const;
void _update_resource_paths_after_move(const Map<String, String> &p_renames) const;
+ void _save_scenes_after_move(const Map<String, String> &p_renames) const;
void _update_favorites_list_after_move(const Map<String, String> &p_files_renames, const Map<String, String> &p_folders_renames) const;
void _update_project_settings_after_move(const Map<String, String> &p_folders_renames) const;
diff --git a/editor/icons/icon_multi_mesh_instance_2d.svg b/editor/icons/icon_multi_mesh_instance_2d.svg
new file mode 100644
index 0000000000..07202ac659
--- /dev/null
+++ b/editor/icons/icon_multi_mesh_instance_2d.svg
@@ -0,0 +1,4 @@
+<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg">
+<rect x="-1" y="-1" width="582" height="402" fill="none"/>
+<path d="m3 1c-1.1046 0-2 0.89543-2 2 5.6e-4 0.71397 0.38169 1.3735 1 1.7305v6.541c-0.61771 0.35664-0.99874 1.0152-1 1.7285 0 1.1046 0.89543 2 2 2 0.71397-5.6e-4 1.3735-0.38169 1.7305-1h1.2695v-2h-1.2715c-0.17478-0.30301-0.42598-0.55488-0.72852-0.73047v-5.8555l3.5859 3.5859h1.4141v-1.4141l-3.5859-3.5859h5.8574c0.17532 0.30158 0.42647 0.55205 0.72852 0.72656v1.2734h2v-1.2695c0.61831-0.35698 0.99944-1.0165 1-1.7305 0-1.1046-0.89543-2-2-2-0.71397 5.6e-4 -1.3735 0.38169-1.7305 1h-6.541c-0.35664-0.61771-1.0152-0.99874-1.7285-1zm8 7v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2z" fill="#a5b7f3" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/>
+</svg>
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 0dfb53b34a..a0774ac696 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -733,6 +733,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt
image_data = cached_data;
file->close();
+ memdelete(file);
}
}
@@ -807,6 +808,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
if (file) {
file->store_line(new_etag);
file->close();
+ memdelete(file);
}
int len = p_data.size();
@@ -816,6 +818,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons
file->store_32(len);
file->store_buffer(r.ptr(), len);
file->close();
+ memdelete(file);
}
break;
@@ -855,6 +858,7 @@ void EditorAssetLibrary::_update_image_queue() {
if (file) {
headers.push_back("If-None-Match: " + file->get_line());
file->close();
+ memdelete(file);
}
}
diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 4ef2d17128..5e1d818ce9 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -299,9 +299,13 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
Vector2 position;
int current = manual_palette->get_current();
if (current != -1) {
- position = manual_palette->get_item_metadata(current);
+ if (tool != TOOL_PASTING) {
+ position = manual_palette->get_item_metadata(current);
+ } else {
+ position = p_autotile_coord;
+ }
} else {
- // if there is no manual tile selected, that either means that
+ // If there is no manual tile selected, that either means that
// autotiling is enabled, or the given tile is not autotiling. Either
// way, the coordinate of the tile does not matter, so assigning it to
// the coordinate of the existing tile works fine.
@@ -309,7 +313,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
}
if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose && prev_position == position)
- return; //check that it's actually different
+ return; // Check that it's actually different.
for (int y = p_pos.y - 1; y <= p_pos.y + 1; y++) {
for (int x = p_pos.x - 1; x <= p_pos.x + 1; x++) {
@@ -322,21 +326,19 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, Vector<int> p_values, bool p
node->_set_celld(p_pos, _create_cell_dictionary(p_value, p_flip_h, p_flip_v, p_transpose, p_autotile_coord));
+ if (tool == TOOL_PASTING)
+ return;
+
if (manual_autotile || (p_value != -1 && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE)) {
if (current != -1) {
node->set_cell_autotile_coord(p_pos.x, p_pos.y, position);
-
- } else if (tool != TOOL_PASTING && node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE && priority_atlastile) {
-
- // BIND_CENTER is used to indicate that bitmask should not update for this tile cell
+ } else if (node->get_tileset()->tile_get_tile_mode(p_value) == TileSet::ATLAS_TILE && priority_atlastile) {
+ // BIND_CENTER is used to indicate that bitmask should not update for this tile cell.
node->get_tileset()->autotile_set_bitmask(p_value, Vector2(p_pos.x, p_pos.y), TileSet::BIND_CENTER);
node->update_cell_bitmask(p_pos.x, p_pos.y);
}
} else {
- // manually placing tiles should not update bitmasks
- if (tool != TOOL_PASTING) {
- node->update_bitmask_area(Point2(p_pos));
- }
+ node->update_bitmask_area(Point2(p_pos));
}
}
@@ -396,6 +398,8 @@ void TileMapEditor::_update_palette() {
// Update the palette
Vector<int> selected = get_selected_tiles();
+ int selected_single = palette->get_current();
+ int selected_manual = manual_palette->get_current();
palette->clear();
manual_palette->clear();
manual_palette->hide();
@@ -503,7 +507,7 @@ void TileMapEditor::_update_palette() {
if (selected.get(0) != TileMap::INVALID_CELL) {
set_selected_tiles(selected);
sel_tile = selected.get(Math::rand() % selected.size());
- } else {
+ } else if (palette->get_item_count() > 0) {
palette->select(0);
}
@@ -545,9 +549,10 @@ void TileMapEditor::_update_palette() {
if (manual_palette->get_item_count() > 0) {
// Only show the manual palette if at least tile exists in it
- int selected2 = manual_palette->get_current();
- if (selected2 == -1) selected2 = 0;
- manual_palette->set_current(selected2);
+ if (selected_manual == -1 || selected_single != palette->get_current())
+ selected_manual = 0;
+ if (selected_manual < manual_palette->get_item_count())
+ manual_palette->set_current(selected_manual);
manual_palette->show();
}
@@ -759,15 +764,15 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p
Rect2 r = node->get_tileset()->tile_get_region(p_cell);
if (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::AUTO_TILE || node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE) {
Vector2 offset;
- int selected = manual_palette->get_current();
- if ((manual_autotile || (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE && !priority_atlastile)) && selected != -1) {
- offset = manual_palette->get_item_metadata(selected);
- } else {
- if (tool != TOOL_PASTING) {
- offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell);
+ if (tool != TOOL_PASTING) {
+ int selected = manual_palette->get_current();
+ if ((manual_autotile || (node->get_tileset()->tile_get_tile_mode(p_cell) == TileSet::ATLAS_TILE && !priority_atlastile)) && selected != -1) {
+ offset = manual_palette->get_item_metadata(selected);
} else {
- offset = p_autotile_coord;
+ offset = node->get_tileset()->autotile_get_icon_coordinate(p_cell);
}
+ } else {
+ offset = p_autotile_coord;
}
int spacing = node->get_tileset()->autotile_get_spacing(p_cell);
@@ -775,7 +780,8 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p
r.position += (r.size + Vector2(spacing, spacing)) * offset;
}
Size2 sc = p_xform.get_scale();
- Size2 cell_size = node->get_cell_size();
+ /* For a future CheckBox to Center Texture:
+ Size2 cell_size = node->get_cell_size(); */
Rect2 rect = Rect2();
rect.position = node->map_to_world(p_point) + node->get_cell_draw_offset();
@@ -787,10 +793,11 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p
if (p_transpose) {
SWAP(tile_ofs.x, tile_ofs.y);
+ /* For a future CheckBox to Center Texture:
rect.position.x += cell_size.x / 2 - rect.size.y / 2;
rect.position.y += cell_size.y / 2 - rect.size.x / 2;
} else {
- rect.position += cell_size / 2 - rect.size / 2;
+ rect.position += cell_size / 2 - rect.size / 2; */
}
if (p_flip_h) {
@@ -810,10 +817,11 @@ void TileMapEditor::_draw_cell(Control *p_viewport, int p_cell, const Point2i &p
Color modulate = node->get_tileset()->tile_get_modulate(p_cell);
modulate.a = 0.5;
- if (r.has_no_area())
+ if (r.has_no_area()) {
p_viewport->draw_texture_rect(t, rect, false, modulate, p_transpose);
- else
+ } else {
p_viewport->draw_texture_rect_region(t, rect, r, modulate, p_transpose);
+ }
}
void TileMapEditor::_draw_fill_preview(Control *p_viewport, int p_cell, const Point2i &p_point, bool p_flip_h, bool p_flip_v, bool p_transpose, const Point2i p_autotile_coord, const Transform2D &p_xform) {
@@ -848,7 +856,6 @@ void TileMapEditor::_update_copydata() {
TileData tcd;
tcd.cell = node->get_cell(j, i);
-
if (tcd.cell != TileMap::INVALID_CELL) {
tcd.pos = Point2i(j, i);
tcd.flip_h = node->is_cell_x_flipped(j, i);
@@ -1980,31 +1987,31 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) {
p->connect("id_pressed", this, "_menu_option");
rotate_left_button = memnew(ToolButton);
- rotate_left_button->set_tooltip(TTR("Rotate left"));
+ rotate_left_button->set_tooltip(TTR("Rotate Left"));
rotate_left_button->set_focus_mode(FOCUS_NONE);
rotate_left_button->connect("pressed", this, "_rotate", varray(-1));
tool_hb->add_child(rotate_left_button);
rotate_right_button = memnew(ToolButton);
- rotate_right_button->set_tooltip(TTR("Rotate right"));
+ rotate_right_button->set_tooltip(TTR("Rotate Right"));
rotate_right_button->set_focus_mode(FOCUS_NONE);
rotate_right_button->connect("pressed", this, "_rotate", varray(1));
tool_hb->add_child(rotate_right_button);
flip_horizontal_button = memnew(ToolButton);
- flip_horizontal_button->set_tooltip(TTR("Flip horizontally"));
+ flip_horizontal_button->set_tooltip(TTR("Flip Horizontally"));
flip_horizontal_button->set_focus_mode(FOCUS_NONE);
flip_horizontal_button->connect("pressed", this, "_flip_horizontal");
tool_hb->add_child(flip_horizontal_button);
flip_vertical_button = memnew(ToolButton);
- flip_vertical_button->set_tooltip(TTR("Flip vertically"));
+ flip_vertical_button->set_tooltip(TTR("Flip Vertically"));
flip_vertical_button->set_focus_mode(FOCUS_NONE);
flip_vertical_button->connect("pressed", this, "_flip_vertical");
tool_hb->add_child(flip_vertical_button);
clear_transform_button = memnew(ToolButton);
- clear_transform_button->set_tooltip(TTR("Clear transform"));
+ clear_transform_button->set_tooltip(TTR("Clear Transform"));
clear_transform_button->set_focus_mode(FOCUS_NONE);
clear_transform_button->connect("pressed", this, "_clear_transform");
tool_hb->add_child(clear_transform_button);
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 621ab039f4..c3b62810f1 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -1025,7 +1025,9 @@ void ScriptEditorDebugger::_performance_draw() {
int pi = which[i];
Color c = get_color("accent_color", "Editor");
float h = (float)which[i] / (float)(perf_items.size());
- c.set_hsv(Math::fmod(h + 0.4, 0.9), c.get_s() * 0.9, c.get_v() * 1.4);
+ // Use a darker color on light backgrounds for better visibility
+ float value_multiplier = EditorSettings::get_singleton()->is_dark_theme() ? 1.4 : 0.55;
+ c.set_hsv(Math::fmod(h + 0.4, 0.9), c.get_s() * 0.9, c.get_v() * value_multiplier);
c.a = 0.6;
perf_draw->draw_string(graph_font, r.position + Point2(0, graph_font->get_ascent()), perf_items[pi]->get_text(0), c, r.size.x);
@@ -1045,9 +1047,8 @@ void ScriptEditorDebugger::_performance_draw() {
float h2 = E->get()[pi] / m;
h2 = (1.0 - h2) * r.size.y;
- c.a = 0.7;
if (E != perf_history.front())
- perf_draw->draw_line(r.position + Point2(from, h2), r.position + Point2(from + spacing, prev), c, 2.0);
+ perf_draw->draw_line(r.position + Point2(from, h2), r.position + Point2(from + spacing, prev), c, Math::round(EDSCALE), true);
prev = h2;
E = E->next();
from -= spacing;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 922ee395dd..44a91303e9 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -6021,7 +6021,11 @@ bool GDScriptParser::_is_type_compatible(const DataType &p_container, const Data
}
GDScriptParser::DataType GDScriptParser::_reduce_node_type(Node *p_node) {
+#ifdef DEBUG_ENABLED
+ if (p_node->get_datatype().has_type && p_node->type != Node::TYPE_ARRAY && p_node->type != Node::TYPE_DICTIONARY) {
+#else
if (p_node->get_datatype().has_type) {
+#endif
return p_node->get_datatype();
}
diff --git a/modules/mono/SCsub b/modules/mono/SCsub
index 341d57f3e4..6c3ecee272 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -20,11 +20,6 @@ if env['tools']:
'glue/cs_glue_version.gen.h'
)
-vars = Variables()
-vars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
-vars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
-vars.Update(env_mono)
-
# Glue sources
if env_mono['mono_glue']:
env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
diff --git a/modules/mono/build_scripts/godotsharptools_build.py b/modules/mono/build_scripts/godotsharptools_build.py
index af3a5cb5c6..17f9a990af 100644
--- a/modules/mono/build_scripts/godotsharptools_build.py
+++ b/modules/mono/build_scripts/godotsharptools_build.py
@@ -1,6 +1,5 @@
# Build GodotSharpTools solution
-
import os
from SCons.Script import Builder, Dir
@@ -53,21 +52,9 @@ def find_nuget_windows(env):
if os.path.isfile(hint_path) and os.access(hint_path, os.X_OK):
return hint_path
- from . import mono_reg_utils as monoreg
-
- mono_root = ''
- bits = env['bits']
+ from . mono_reg_utils import find_mono_root_dir
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
+ mono_root = env['mono_prefix'] or find_mono_root_dir(env['bits'])
if mono_root:
mono_bin_dir = os.path.join(mono_root, 'bin')
@@ -114,21 +101,9 @@ def find_msbuild_unix(filename):
def find_msbuild_windows(env):
- from . import mono_reg_utils as monoreg
+ from . mono_reg_utils import find_mono_root_dir, find_msbuild_tools_path_reg
- mono_root = ''
- bits = env['bits']
-
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
- else:
- mono_root = monoreg.find_mono_root_dir(bits)
+ mono_root = env['mono_prefix'] or find_mono_root_dir(env['bits'])
if not mono_root:
raise RuntimeError('Cannot find mono root directory')
@@ -148,7 +123,7 @@ def find_msbuild_windows(env):
}
return (msbuild_mono, framework_path, mono_msbuild_env)
- msbuild_tools_path = monoreg.find_msbuild_tools_path_reg()
+ msbuild_tools_path = find_msbuild_tools_path_reg()
if msbuild_tools_path:
return (os.path.join(msbuild_tools_path, 'MSBuild.exe'), framework_path, {})
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index 4cfa2a5b93..c549640d61 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -1,15 +1,30 @@
import imp
import os
+import os.path
import sys
import subprocess
from distutils.version import LooseVersion
-from SCons.Script import BoolVariable, Dir, Environment, Variables
+from SCons.Script import Dir, Environment
if os.name == 'nt':
from . import mono_reg_utils as monoreg
+android_arch_dirs = {
+ 'armv7': 'armeabi-v7a',
+ 'arm64v8': 'arm64-v8a',
+ 'x86': 'x86',
+ 'x86_64': 'x86_64'
+}
+
+
+def get_android_out_dir(env):
+ return os.path.join(Dir('#platform/android/java/libs').abspath,
+ 'release' if env['target'] == 'release' else 'debug',
+ android_arch_dirs[env['android_arch']])
+
+
def find_file_in_dir(directory, files, prefix='', extension=''):
if not extension.startswith('.'):
extension = '.' + extension
@@ -20,47 +35,47 @@ def find_file_in_dir(directory, files, prefix='', extension=''):
def copy_file(src_dir, dst_dir, name):
- from shutil import copyfile
+ from shutil import copy
- src_path = os.path.join(src_dir, name)
- dst_path = os.path.join(dst_dir, name)
+ src_path = os.path.join(Dir(src_dir).abspath, name)
+ dst_dir = Dir(dst_dir).abspath
if not os.path.isdir(dst_dir):
os.mkdir(dst_dir)
- copyfile(src_path, dst_path)
+ copy(src_path, dst_dir)
def configure(env, env_mono):
- envvars = Variables()
- envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
- envvars.Add(BoolVariable('copy_mono_root', 'Make a copy of the mono installation directory to bundle with the editor', False))
- envvars.Update(env)
-
bits = env['bits']
+ is_android = env['platform'] == 'android'
tools_enabled = env['tools']
mono_static = env['mono_static']
copy_mono_root = env['copy_mono_root']
+ mono_prefix = env['mono_prefix']
+
mono_lib_names = ['mono-2.0-sgen', 'monosgen-2.0']
+ if is_android and not env['android_arch'] in android_arch_dirs:
+ raise RuntimeError('This module does not support for the specified \'android_arch\': ' + env['android_arch'])
+
+ if is_android and tools_enabled:
+ # TODO: Implement this. We have to add the data directory to the apk, concretely the Api and Tools folders.
+ raise RuntimeError('This module does not currently support building for android with tools enabled')
+
+ if (os.getenv('MONO32_PREFIX') or os.getenv('MONO64_PREFIX')) and not mono_prefix:
+ print("WARNING: The environment variables 'MONO32_PREFIX' and 'MONO64_PREFIX' are deprecated; use the 'mono_prefix' SCons parameter instead")
+
if env['platform'] == 'windows':
- mono_root = ''
+ mono_root = mono_prefix
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- elif os.name == 'nt':
- mono_root = monoreg.find_mono_root_dir(bits)
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
- elif os.name == 'nt':
- mono_root = monoreg.find_mono_root_dir(bits)
+ if not mono_root and os.name == 'nt':
+ mono_root = monoreg.find_mono_root_dir(bits)
if not mono_root:
- raise RuntimeError('Mono installation directory not found')
+ raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter")
print('Found Mono root directory: ' + mono_root)
@@ -113,21 +128,18 @@ def configure(env, env_mono):
if not mono_dll_name:
raise RuntimeError('Could not find mono shared library in: ' + mono_bin_path)
- copy_file(mono_bin_path, 'bin', mono_dll_name + '.dll')
+ copy_file(mono_bin_path, '#bin', mono_dll_name + '.dll')
else:
is_apple = (sys.platform == 'darwin' or "osxcross" in env)
sharedlib_ext = '.dylib' if is_apple else '.so'
- mono_root = ''
+ mono_root = mono_prefix
mono_lib_path = ''
+ mono_so_name = ''
- if bits == '32':
- if os.getenv('MONO32_PREFIX'):
- mono_root = os.getenv('MONO32_PREFIX')
- else:
- if os.getenv('MONO64_PREFIX'):
- mono_root = os.getenv('MONO64_PREFIX')
+ if not mono_root and is_android:
+ raise RuntimeError("Mono installation directory not found; specify one manually with the 'mono_prefix' SCons parameter")
if not mono_root and is_apple:
# Try with some known directories under OSX
@@ -142,7 +154,8 @@ def configure(env, env_mono):
if not mono_root and mono_static:
mono_root = pkgconfig_try_find_mono_root(mono_lib_names, sharedlib_ext)
if not mono_root:
- raise RuntimeError('Building with mono_static=yes, but failed to find the mono prefix with pkg-config. Specify one manually')
+ raise RuntimeError("Building with mono_static=yes, but failed to find the mono prefix with pkg-config; " + \
+ "specify one manually with the 'mono_prefix' SCons parameter")
if mono_root:
print('Found Mono root directory: ' + mono_root)
@@ -174,6 +187,8 @@ def configure(env, env_mono):
if is_apple:
env.Append(LIBS=['iconv', 'pthread'])
+ elif is_android:
+ env.Append(LIBS=['m', 'dl'])
else:
env.Append(LIBS=['m', 'rt', 'dl', 'pthread'])
@@ -183,7 +198,7 @@ def configure(env, env_mono):
if not mono_so_name:
raise RuntimeError('Could not find mono shared library in: ' + mono_lib_path)
- copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+ copy_file(mono_lib_path, '#bin', 'lib' + mono_so_name + sharedlib_ext)
else:
assert not mono_static
@@ -196,9 +211,6 @@ def configure(env, env_mono):
env.ParseConfig('pkg-config monosgen-2 --libs')
env_mono.ParseConfig('pkg-config monosgen-2 --cflags')
- mono_lib_path = ''
- mono_so_name = ''
-
tmpenv = Environment()
tmpenv.AppendENVPath('PKG_CONFIG_PATH', os.getenv('PKG_CONFIG_PATH'))
tmpenv.ParseConfig('pkg-config monosgen-2 --libs-only-L')
@@ -213,11 +225,13 @@ def configure(env, env_mono):
if not mono_so_name:
raise RuntimeError('Could not find mono shared library in: ' + str(tmpenv['LIBPATH']))
- copy_file(mono_lib_path, 'bin', 'lib' + mono_so_name + sharedlib_ext)
+ if not mono_static:
+ libs_output_dir = get_android_out_dir(env) if is_android else '#bin'
+ copy_file(mono_lib_path, libs_output_dir, 'lib' + mono_so_name + sharedlib_ext)
env.Append(LINKFLAGS='-rdynamic')
- if not tools_enabled:
+ if not tools_enabled and not is_android:
if not mono_root:
mono_root = subprocess.check_output(['pkg-config', 'mono-2', '--variable=prefix']).decode('utf8').strip()
@@ -241,7 +255,7 @@ def make_template_dir(env, mono_root):
template_dir_name = ''
- if platform in ['windows', 'osx', 'x11']:
+ if platform in ['windows', 'osx', 'x11', 'android']:
template_dir_name = 'data.mono.%s.%s.%s' % (platform, env['bits'], target)
else:
assert False
@@ -256,12 +270,13 @@ def make_template_dir(env, mono_root):
# Copy etc/mono/
- template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
- copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform'])
+ if platform != 'android':
+ template_mono_config_dir = os.path.join(template_mono_root_dir, 'etc', 'mono')
+ copy_mono_etc_dir(mono_root, template_mono_config_dir, env['platform'])
# Copy the required shared libraries
- copy_mono_shared_libs(mono_root, template_mono_root_dir, env['platform'])
+ copy_mono_shared_libs(env, mono_root, template_mono_root_dir)
def copy_mono_root_files(env, mono_root):
@@ -285,7 +300,7 @@ def copy_mono_root_files(env, mono_root):
# Copy the required shared libraries
- copy_mono_shared_libs(mono_root, editor_mono_root_dir, env['platform'])
+ copy_mono_shared_libs(env, mono_root, editor_mono_root_dir)
# Copy framework assemblies
@@ -332,39 +347,55 @@ def copy_mono_etc_dir(mono_root, target_mono_config_dir, platform):
copy_tree(os.path.join(mono_etc_dir, '2.0'), os.path.join(target_mono_config_dir, '2.0'))
copy_tree(os.path.join(mono_etc_dir, '4.0'), os.path.join(target_mono_config_dir, '4.0'))
copy_tree(os.path.join(mono_etc_dir, '4.5'), os.path.join(target_mono_config_dir, '4.5'))
- copy_tree(os.path.join(mono_etc_dir, 'mconfig'), os.path.join(target_mono_config_dir, 'mconfig'))
+ if os.path.isdir(os.path.join(mono_etc_dir, 'mconfig')):
+ copy_tree(os.path.join(mono_etc_dir, 'mconfig'), os.path.join(target_mono_config_dir, 'mconfig'))
for file in glob(os.path.join(mono_etc_dir, '*')):
if os.path.isfile(file):
copy(file, target_mono_config_dir)
-def copy_mono_shared_libs(mono_root, target_mono_root_dir, platform):
+def copy_mono_shared_libs(env, mono_root, target_mono_root_dir):
from shutil import copy
+ def copy_if_exists(src, dst):
+ if os.path.isfile(src):
+ copy(src, dst)
+
+ platform = env['platform']
+
if platform == 'windows':
target_mono_bin_dir = os.path.join(target_mono_root_dir, 'bin')
if not os.path.isdir(target_mono_bin_dir):
os.makedirs(target_mono_bin_dir)
- copy(os.path.join(mono_root, 'bin', 'MonoPosixHelper.dll'), os.path.join(target_mono_bin_dir, 'MonoPosixHelper.dll'))
+ copy(os.path.join(mono_root, 'bin', 'MonoPosixHelper.dll'), target_mono_bin_dir)
else:
- target_mono_lib_dir = os.path.join(target_mono_root_dir, 'lib')
+ target_mono_lib_dir = get_android_out_dir(env) if platform == 'android' else os.path.join(target_mono_root_dir, 'lib')
if not os.path.isdir(target_mono_lib_dir):
os.makedirs(target_mono_lib_dir)
if platform == 'osx':
- copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), os.path.join(target_mono_lib_dir, 'libMonoPosixHelper.dylib'))
- elif platform == 'x11':
- copy(os.path.join(mono_root, 'lib', 'libmono-btls-shared.so'), os.path.join(target_mono_lib_dir, 'libmono-btls-shared.so'))
- copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.so'), os.path.join(target_mono_lib_dir, 'libMonoPosixHelper.so'))
+ # TODO: Make sure nothing is missing
+ copy(os.path.join(mono_root, 'lib', 'libMonoPosixHelper.dylib'), target_mono_lib_dir)
+ elif platform == 'x11' or platform == 'android':
+ lib_file_names = [lib_name + '.so' for lib_name in [
+ 'libmono-btls-shared', 'libmono-ee-interp', 'libmono-native', 'libMonoPosixHelper',
+ 'libmono-profiler-aot', 'libmono-profiler-coverage', 'libmono-profiler-log', 'libMonoSupportW'
+ ]]
+
+ for lib_file_name in lib_file_names:
+ copy_if_exists(os.path.join(mono_root, 'lib', lib_file_name), target_mono_lib_dir)
def configure_for_mono_version(env, mono_version):
if mono_version is None:
- raise RuntimeError('Mono JIT compiler version not found')
+ if os.getenv('MONO_VERSION'):
+ mono_version = os.getenv('MONO_VERSION')
+ else:
+ raise RuntimeError("Mono JIT compiler version not found; specify one manually with the 'MONO_VERSION' environment variable")
print('Found Mono JIT compiler version: ' + str(mono_version))
if mono_version >= LooseVersion('5.12.0'):
env.Append(CPPFLAGS=['-DHAS_PENDING_EXCEPTIONS'])
diff --git a/modules/mono/build_scripts/patches/fix-mono-android-tkill.diff b/modules/mono/build_scripts/patches/fix-mono-android-tkill.diff
new file mode 100644
index 0000000000..05f8dcadcc
--- /dev/null
+++ b/modules/mono/build_scripts/patches/fix-mono-android-tkill.diff
@@ -0,0 +1,70 @@
+diff --git a/libgc/include/private/gcconfig.h b/libgc/include/private/gcconfig.h
+index e2bdf13ac3e..f962200ba4e 100644
+--- a/libgc/include/private/gcconfig.h
++++ b/libgc/include/private/gcconfig.h
+@@ -2255,6 +2255,14 @@
+ # define GETPAGESIZE() getpagesize()
+ # endif
+
++#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
++ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
++ || defined(ARM32) || defined(I386) /* but not x32 */)
++ /* tkill() exists only on arm32/mips(32)/x86. */
++ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
++# define USE_TKILL_ON_ANDROID
++#endif
++
+ # if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
+ /* OS has SVR4 generic features. Probably others also qualify. */
+ # define SVR4
+diff --git a/libgc/pthread_stop_world.c b/libgc/pthread_stop_world.c
+index f93ce26b562..4a49a6d578c 100644
+--- a/libgc/pthread_stop_world.c
++++ b/libgc/pthread_stop_world.c
+@@ -336,7 +336,7 @@ void GC_push_all_stacks()
+ pthread_t GC_stopping_thread;
+ int GC_stopping_pid;
+
+-#ifdef HOST_ANDROID
++#ifdef USE_TKILL_ON_ANDROID
+ static
+ int android_thread_kill(pid_t tid, int sig)
+ {
+diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c
+index ad9b8823f8f..3542b32b540 100644
+--- a/mono/metadata/threads.c
++++ b/mono/metadata/threads.c
+@@ -77,8 +77,12 @@ mono_native_thread_join_handle (HANDLE thread_handle, gboolean close_handle);
+ #include <zircon/syscalls.h>
+ #endif
+
+-#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
+-#define USE_TKILL_ON_ANDROID 1
++#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
++ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
++ || defined(ARM32) || defined(I386) /* but not x32 */)
++ /* tkill() exists only on arm32/mips(32)/x86. */
++ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
++# define USE_TKILL_ON_ANDROID
+ #endif
+
+ #ifdef HOST_ANDROID
+diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c
+index 3e4bf93de5f..79c9f731fe7 100644
+--- a/mono/utils/mono-threads-posix.c
++++ b/mono/utils/mono-threads-posix.c
+@@ -31,8 +31,12 @@
+
+ #include <errno.h>
+
+-#if defined(HOST_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
+-#define USE_TKILL_ON_ANDROID 1
++#if defined(HOST_ANDROID) && !(__ANDROID_API__ >= 23) \
++ && ((defined(MIPS) && (CPP_WORDSZ == 32)) \
++ || defined(ARM32) || defined(I386) /* but not x32 */)
++ /* tkill() exists only on arm32/mips(32)/x86. */
++ /* NDK r11+ deprecates tkill() but keeps it for Mono clients. */
++# define USE_TKILL_ON_ANDROID
+ #endif
+
+ #ifdef USE_TKILL_ON_ANDROID
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 3b2e96765e..9adf4ee6e5 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -8,6 +8,16 @@ def configure(env):
env.use_ptrcall = True
env.add_module_version_string('mono')
+ from SCons.Script import BoolVariable, PathVariable, Variables
+
+ envvars = Variables()
+ envvars.Add(PathVariable('mono_prefix', 'Path to the mono installation directory for the target platform and architecture', '', PathVariable.PathAccept))
+ envvars.Add(BoolVariable('mono_static', 'Statically link mono', False))
+ envvars.Add(BoolVariable('mono_glue', 'Build with the mono glue sources', True))
+ envvars.Add(BoolVariable('copy_mono_root', 'Make a copy of the mono installation directory to bundle with the editor', False))
+ envvars.Add(BoolVariable('xbuild_fallback', 'If MSBuild is not found, fallback to xbuild', False))
+ envvars.Update(env)
+
def get_doc_classes():
return [
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 5525c0a121..4a1fb8e5ed 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -380,7 +380,6 @@ public:
virtual bool supports_builtin_mode() const;
/* TODO? */ virtual int find_function(const String &p_function, const String &p_code) const { return -1; }
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
- /* TODO? */ Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<String> *r_options, String &r_call_hint) { return ERR_UNAVAILABLE; }
virtual String _get_indentation() const;
/* TODO? */ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {}
/* TODO */ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) {}
diff --git a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
index e45dd2025b..44a43f0ddd 100644
--- a/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
+++ b/modules/mono/editor/GodotSharpTools/Editor/GodotSharpExport.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Runtime.CompilerServices;
namespace GodotSharpTools.Editor
@@ -62,7 +63,7 @@ namespace GodotSharpTools.Editor
{
// OSX export templates are contained in a zip, so we place
// our custom template inside it and let Godot do the rest.
- return !featureSet.Contains("OSX");
+ return !featureSet.Any(f => new[] {"OSX", "Android"}.Contains(f));
}
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/modules/mono/editor/godotsharp_export.cpp b/modules/mono/editor/godotsharp_export.cpp
index ae5b939b26..126178125f 100644
--- a/modules/mono/editor/godotsharp_export.cpp
+++ b/modules/mono/editor/godotsharp_export.cpp
@@ -125,11 +125,21 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
bool load_success = GDMono::get_singleton()->load_assembly_from(project_dll_name,
project_dll_src_path, &scripts_assembly, /* refonly: */ true);
- ERR_EXPLAIN("Cannot load refonly assembly: " + project_dll_name);
+ ERR_EXPLAIN("Cannot load assembly (refonly): " + project_dll_name);
ERR_FAIL_COND(!load_success);
Vector<String> search_dirs;
- GDMonoAssembly::fill_search_dirs(search_dirs, build_config);
+ String templates_dir = EditorSettings::get_singleton()->get_templates_dir().plus_file(VERSION_FULL_CONFIG);
+ String android_bcl_dir = templates_dir.plus_file("android-bcl");
+
+ String custom_lib_dir;
+
+ if (p_features.find("Android") && DirAccess::exists(android_bcl_dir)) {
+ custom_lib_dir = android_bcl_dir;
+ }
+
+ GDMonoAssembly::fill_search_dirs(search_dirs, build_config, custom_lib_dir);
+
Error depend_error = _get_assembly_dependencies(scripts_assembly, search_dirs, dependencies);
ERR_FAIL_COND(depend_error != OK);
}
@@ -152,7 +162,7 @@ void GodotSharpExport::_export_begin(const Set<String> &p_features, bool p_debug
int i = 0;
for (const Set<String>::Element *E = p_features.front(); E; E = E->next()) {
MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get());
- mono_array_set(features, MonoString *, i, boxed);
+ mono_array_setref(features, i, boxed);
i++;
}
@@ -234,8 +244,10 @@ Error GodotSharpExport::_get_assembly_dependencies(GDMonoAssembly *p_assembly, c
r_dependencies.insert(ref_name, ref_assembly->get_path());
Error err = _get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
- if (err != OK)
- return err;
+ if (err != OK) {
+ ERR_EXPLAIN("Cannot load one of the dependencies for the assembly: " + ref_name);
+ ERR_FAIL_V(err);
+ }
}
return OK;
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index 7385014a53..75b2dfce9a 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -166,7 +166,7 @@ MonoArray *godot_icall_DynamicGodotObject_SetMemberList(Object *p_ptr) {
int i = 0;
for (List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
MonoString *boxed = GDMonoMarshal::mono_string_from_godot(E->get().name);
- mono_array_set(result, MonoString *, i, boxed);
+ mono_array_setref(result, i, boxed);
i++;
}
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 19e49d29f9..7699e0d0cd 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -251,17 +251,19 @@ void GDMono::initialize() {
String bundled_config_dir = GodotSharpDirs::get_data_mono_etc_dir();
#ifdef TOOLS_ENABLED
- if (DirAccess::exists(bundled_assembly_rootdir) && DirAccess::exists(bundled_config_dir)) {
+ if (DirAccess::exists(bundled_assembly_rootdir)) {
assembly_rootdir = bundled_assembly_rootdir;
+ }
+
+ if (DirAccess::exists(bundled_config_dir)) {
config_dir = bundled_config_dir;
}
#ifdef WINDOWS_ENABLED
if (assembly_rootdir.empty() || config_dir.empty()) {
+ ERR_PRINT("Cannot find Mono in the registry");
// Assertion: if they are not set, then they weren't found in the registry
CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
-
- ERR_PRINT("Cannot find Mono in the registry");
}
#endif // WINDOWS_ENABLED
@@ -807,6 +809,8 @@ Error GDMono::_unload_scripts_domain() {
mono_gc_collect(mono_gc_max_generation());
+ GDMonoUtils::clear_godot_api_cache();
+
_domain_assemblies_cleanup(mono_domain_get_id(scripts_domain));
core_api_assembly = NULL;
@@ -926,6 +930,7 @@ Error GDMono::reload_scripts_domain() {
Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
CRASH_COND(p_domain == NULL);
+ CRASH_COND(p_domain == SCRIPTS_DOMAIN); // Should use _unload_scripts_domain() instead
String domain_name = mono_domain_get_friendly_name(p_domain);
@@ -1078,8 +1083,6 @@ GDMono::~GDMono() {
}
assemblies.clear();
- GDMonoUtils::clear_cache();
-
print_verbose("Mono: Runtime cleanup...");
mono_jit_cleanup(root_domain);
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 8fec28b186..f1f0015ac9 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -46,11 +46,17 @@ bool GDMonoAssembly::in_preload = false;
Vector<String> GDMonoAssembly::search_dirs;
-void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config) {
+void GDMonoAssembly::fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config, const String &p_custom_bcl_dir) {
- const char *rootdir = mono_assembly_getrootdir();
- if (rootdir) {
- String framework_dir = String::utf8(rootdir).plus_file("mono").plus_file("4.5");
+ String framework_dir;
+
+ if (!p_custom_bcl_dir.empty()) {
+ framework_dir = p_custom_bcl_dir;
+ } else if (mono_assembly_getrootdir()) {
+ framework_dir = String::utf8(mono_assembly_getrootdir()).plus_file("mono").plus_file("4.5");
+ }
+
+ if (!framework_dir.empty()) {
r_search_dirs.push_back(framework_dir);
r_search_dirs.push_back(framework_dir.plus_file("Facades"));
}
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index 32432af37d..39749dfc1d 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -122,7 +122,7 @@ public:
GDMonoClass *get_object_derived_class(const StringName &p_class);
- static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String());
+ static void fill_search_dirs(Vector<String> &r_search_dirs, const String &p_custom_config = String(), const String &p_custom_bcl_dir = String());
static GDMonoAssembly *load_from(const String &p_name, const String &p_path, bool p_refonly);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index c462b8f71d..87157ed233 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -1019,7 +1019,7 @@ MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) {
for (int i = 0; i < p_array.size(); i++) {
MonoString *boxed = mono_string_from_godot(r[i]);
- mono_array_set(ret, MonoString *, i, boxed);
+ mono_array_setref(ret, i, boxed);
}
return ret;
diff --git a/modules/mono/mono_gd/gd_mono_method.cpp b/modules/mono/mono_gd/gd_mono_method.cpp
index f290c6c8ac..968b316a3e 100644
--- a/modules/mono/mono_gd/gd_mono_method.cpp
+++ b/modules/mono/mono_gd/gd_mono_method.cpp
@@ -109,7 +109,7 @@ MonoObject *GDMonoMethod::invoke(MonoObject *p_object, const Variant **p_params,
for (int i = 0; i < params_count; i++) {
MonoObject *boxed_param = GDMonoMarshal::variant_to_mono_object(p_params[i], param_types[i]);
- mono_array_set(params, MonoObject *, i, boxed_param);
+ mono_array_setref(params, i, boxed_param);
}
MonoException *exc = NULL;
diff --git a/modules/mono/mono_gd/gd_mono_property.cpp b/modules/mono/mono_gd/gd_mono_property.cpp
index 5842e26241..f1da00638f 100644
--- a/modules/mono/mono_gd/gd_mono_property.cpp
+++ b/modules/mono/mono_gd/gd_mono_property.cpp
@@ -142,7 +142,7 @@ bool GDMonoProperty::has_setter() {
void GDMonoProperty::set_value(MonoObject *p_object, MonoObject *p_value, MonoException **r_exc) {
MonoMethod *prop_method = mono_property_get_set_method(mono_property);
MonoArray *params = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(MonoObject), 1);
- mono_array_set(params, MonoObject *, 0, p_value);
+ mono_array_setref(params, 0, p_value);
MonoException *exc = NULL;
GDMonoUtils::runtime_invoke_array(prop_method, p_object, params, &exc);
if (exc) {
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index 413c8cba85..1b32f1126e 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -50,6 +50,7 @@ MonoCache mono_cache;
#define CACHE_AND_CHECK(m_var, m_val) \
{ \
+ CRASH_COND(m_var != NULL); \
m_var = m_val; \
if (!m_var) { \
ERR_EXPLAIN("Mono Cache: Member " #m_var " is null"); \
@@ -65,7 +66,9 @@ MonoCache mono_cache;
#define CACHE_METHOD_THUNK_AND_CHECK(m_class, m_method, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.methodthunk_##m_class##_##m_method, m_val)
#define CACHE_PROPERTY_AND_CHECK(m_class, m_property, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.property_##m_class##_##m_property, m_val)
-void MonoCache::clear_members() {
+void MonoCache::clear_corlib_cache() {
+
+ corlib_cache_updated = false;
class_MonoObject = NULL;
class_bool = NULL;
@@ -93,6 +96,11 @@ void MonoCache::clear_members() {
#endif
class_KeyNotFoundException = NULL;
+}
+
+void MonoCache::clear_godot_api_cache() {
+
+ godot_api_cache_updated = false;
rawclass_Dictionary = NULL;
@@ -176,12 +184,6 @@ void MonoCache::clear_members() {
task_scheduler_handle = Ref<MonoGCHandle>();
}
-void MonoCache::cleanup() {
-
- corlib_cache_updated = false;
- godot_api_cache_updated = false;
-}
-
#define GODOT_API_CLASS(m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(BINDINGS_NAMESPACE, #m_class))
#define GODOT_API_NS_CLAS(m_ns, m_class) (GDMono::get_singleton()->get_core_api_assembly()->get_class(m_ns, #m_class))
@@ -281,13 +283,10 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, (ArrayGetElementType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("ArrayGetElementType", 2));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, (DictionaryGetKeyValueTypes)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("DictionaryGetKeyValueTypes", 3));
-
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType, (GenericIEnumerableIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType, (GenericIDictionaryIsAssignableFromType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIEnumerableIsAssignableFromType", 2));
- CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIEnumerableIsAssignableFromType_with_info, (GenericIEnumerableIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3));
+ CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GenericIDictionaryIsAssignableFromType_with_info, (GenericIDictionaryIsAssignableFromType_with_info)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("GenericIDictionaryIsAssignableFromType", 3));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericArrayType, (MakeGenericArrayType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericArrayType", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, MakeGenericDictionaryType, (MakeGenericDictionaryType)GODOT_API_CLASS(MarshalUtils)->get_method_thunk("MakeGenericDictionaryType", 2));
@@ -310,11 +309,6 @@ void update_godot_api_cache() {
mono_cache.godot_api_cache_updated = true;
}
-void clear_cache() {
- mono_cache.cleanup();
- mono_cache.clear_members();
-}
-
MonoObject *unmanaged_get_managed(Object *unmanaged) {
if (!unmanaged)
diff --git a/modules/mono/mono_gd/gd_mono_utils.h b/modules/mono/mono_gd/gd_mono_utils.h
index ee239be959..00e1ffdd31 100644
--- a/modules/mono/mono_gd/gd_mono_utils.h
+++ b/modules/mono/mono_gd/gd_mono_utils.h
@@ -218,14 +218,12 @@ struct MonoCache {
bool corlib_cache_updated;
bool godot_api_cache_updated;
- void clear_members();
- void cleanup();
+ void clear_corlib_cache();
+ void clear_godot_api_cache();
MonoCache() {
- corlib_cache_updated = false;
- godot_api_cache_updated = false;
-
- clear_members();
+ clear_corlib_cache();
+ clear_godot_api_cache();
}
};
@@ -233,7 +231,13 @@ extern MonoCache mono_cache;
void update_corlib_cache();
void update_godot_api_cache();
-void clear_cache();
+
+inline void clear_corlib_cache() {
+ mono_cache.clear_corlib_cache();
+}
+inline void clear_godot_api_cache() {
+ mono_cache.clear_godot_api_cache();
+}
_FORCE_INLINE_ void hash_combine(uint32_t &p_hash, const uint32_t &p_with_hash) {
p_hash ^= p_with_hash + 0x9e3779b9 + (p_hash << 6) + (p_hash >> 2);
diff --git a/modules/mono/signal_awaiter_utils.cpp b/modules/mono/signal_awaiter_utils.cpp
index 5d37e8212f..0e1739b754 100644
--- a/modules/mono/signal_awaiter_utils.cpp
+++ b/modules/mono/signal_awaiter_utils.cpp
@@ -95,7 +95,7 @@ Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argc
for (int i = 0; i < signal_argc; i++) {
MonoObject *boxed = GDMonoMarshal::variant_to_mono_object(*p_args[i]);
- mono_array_set(signal_args, MonoObject *, i, boxed);
+ mono_array_setref(signal_args, i, boxed);
}
MonoException *exc = NULL;
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 212966af11..eed230ba89 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -60,6 +60,7 @@ public:
unsigned int osx_state;
bool pressed;
bool echo;
+ bool raw;
uint32_t scancode;
uint32_t unicode;
};
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 113c6636f0..567d24de3e 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -392,7 +392,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
@interface GodotContentView : NSView <NSTextInputClient> {
NSTrackingArea *trackingArea;
NSMutableAttributedString *markedText;
- bool imeMode;
+ bool imeInputEventInProgress;
}
- (void)cancelComposition;
- (BOOL)wantsUpdateLayer;
@@ -418,7 +418,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
- (id)init {
self = [super init];
trackingArea = nil;
- imeMode = false;
+ imeInputEventInProgress = false;
[self updateTrackingAreas];
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
markedText = [[NSMutableAttributedString alloc] init];
@@ -452,7 +452,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
[markedText initWithString:aString];
}
if (OS_OSX::singleton->im_active) {
- imeMode = true;
+ imeInputEventInProgress = true;
OS_OSX::singleton->im_text.parse_utf8([[markedText mutableString] UTF8String]);
OS_OSX::singleton->im_selection = Point2(selectedRange.location, selectedRange.length);
@@ -467,7 +467,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
}
- (void)unmarkText {
- imeMode = false;
+ imeInputEventInProgress = false;
[[markedText mutableString] setString:@""];
if (OS_OSX::singleton->im_active) {
OS_OSX::singleton->im_text = String();
@@ -540,6 +540,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
ke.osx_state = [event modifierFlags];
ke.pressed = true;
ke.echo = false;
+ ke.raw = false; // IME input event
ke.scancode = 0;
ke.unicode = codepoint;
@@ -1045,29 +1046,52 @@ static int remapKey(unsigned int key) {
- (void)keyDown:(NSEvent *)event {
- //disable raw input in IME mode
- if (!imeMode) {
- OS_OSX::KeyEvent ke;
+ // Ignore all input if IME input is in progress
+ if (!imeInputEventInProgress) {
+ NSString *characters = [event characters];
+ NSUInteger length = [characters length];
- ke.osx_state = [event modifierFlags];
- ke.pressed = true;
- ke.echo = [event isARepeat];
- ke.scancode = remapKey([event keyCode]);
- ke.unicode = 0;
+ if (!OS_OSX::singleton->im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode]))) {
+ // Fallback unicode character handler used if IME is not active
+ for (NSUInteger i = 0; i < length; i++) {
+ OS_OSX::KeyEvent ke;
- push_to_key_event_buffer(ke);
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.scancode = remapKey([event keyCode]);
+ ke.raw = true;
+ ke.unicode = [characters characterAtIndex:i];
+
+ push_to_key_event_buffer(ke);
+ }
+ } else {
+ OS_OSX::KeyEvent ke;
+
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.scancode = remapKey([event keyCode]);
+ ke.raw = false;
+ ke.unicode = 0;
+
+ push_to_key_event_buffer(ke);
+ }
}
- if (OS_OSX::singleton->im_active == true)
+ // Pass events to IME handler
+ if (OS_OSX::singleton->im_active)
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
}
- (void)flagsChanged:(NSEvent *)event {
- if (!imeMode) {
+ // Ignore all input if IME input is in progress
+ if (!imeInputEventInProgress) {
OS_OSX::KeyEvent ke;
ke.echo = false;
+ ke.raw = true;
int key = [event keyCode];
int mod = [event modifierFlags];
@@ -1114,17 +1138,37 @@ static int remapKey(unsigned int key) {
- (void)keyUp:(NSEvent *)event {
- if (!imeMode) {
+ // Ignore all input if IME input is in progress
+ if (!imeInputEventInProgress) {
+ NSString *characters = [event characters];
+ NSUInteger length = [characters length];
- OS_OSX::KeyEvent ke;
+ // Fallback unicode character handler used if IME is not active
+ if (!OS_OSX::singleton->im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode]))) {
+ for (NSUInteger i = 0; i < length; i++) {
+ OS_OSX::KeyEvent ke;
- ke.osx_state = [event modifierFlags];
- ke.pressed = false;
- ke.echo = false;
- ke.scancode = remapKey([event keyCode]);
- ke.unicode = 0;
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = false;
+ ke.echo = [event isARepeat];
+ ke.scancode = remapKey([event keyCode]);
+ ke.raw = true;
+ ke.unicode = [characters characterAtIndex:i];
- push_to_key_event_buffer(ke);
+ push_to_key_event_buffer(ke);
+ }
+ } else {
+ OS_OSX::KeyEvent ke;
+
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = false;
+ ke.echo = [event isARepeat];
+ ke.scancode = remapKey([event keyCode]);
+ ke.raw = true;
+ ke.unicode = 0;
+
+ push_to_key_event_buffer(ke);
+ }
}
}
@@ -2612,30 +2656,44 @@ void OS_OSX::process_key_events() {
const KeyEvent &ke = key_event_buffer[i];
- if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) {
+ if (ke.raw) {
+ // Non IME input - no composite characters, pass events as is
k.instance();
get_key_modifier_state(ke.osx_state, k);
k->set_pressed(ke.pressed);
k->set_echo(ke.echo);
- k->set_scancode(0);
+ k->set_scancode(ke.scancode);
k->set_unicode(ke.unicode);
push_input(k);
- }
- if (ke.scancode != 0) {
- k.instance();
+ } else {
+ // IME input
+ if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) {
+ k.instance();
- get_key_modifier_state(ke.osx_state, k);
- k->set_pressed(ke.pressed);
- k->set_echo(ke.echo);
- k->set_scancode(ke.scancode);
+ get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_scancode(0);
+ k->set_unicode(ke.unicode);
- if (i + 1 < key_event_pos && key_event_buffer[i + 1].scancode == 0) {
- k->set_unicode(key_event_buffer[i + 1].unicode);
+ push_input(k);
}
+ if (ke.scancode != 0) {
+ k.instance();
- push_input(k);
+ get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_scancode(ke.scancode);
+
+ if (i + 1 < key_event_pos && key_event_buffer[i + 1].scancode == 0) {
+ k->set_unicode(key_event_buffer[i + 1].unicode);
+ }
+
+ push_input(k);
+ }
}
}
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index cdcad33f6d..ec43a4c26f 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -241,7 +241,6 @@ void AppxPackager::make_block_map() {
tmp_file->close();
memdelete(tmp_file);
- tmp_file = NULL;
}
String AppxPackager::content_type(String p_extension) {
@@ -291,7 +290,6 @@ void AppxPackager::make_content_types() {
tmp_file->close();
memdelete(tmp_file);
- tmp_file = NULL;
}
Vector<uint8_t> AppxPackager::make_file_header(FileMeta p_file_meta) {
@@ -606,7 +604,6 @@ void AppxPackager::finish() {
blockmap_file->close();
memdelete(blockmap_file);
- blockmap_file = NULL;
// Add content types
EditorNode::progress_task_step("export", "Setting content types...", 5);
@@ -622,7 +619,6 @@ void AppxPackager::finish() {
types_file->close();
memdelete(types_file);
- types_file = NULL;
// Pre-process central directory before signing
for (int i = 0; i < file_metadata.size(); i++) {
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 311b42be22..494ae41220 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -1017,12 +1017,12 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) {
XFree(xsh);
}
- if (!p_enabled && !get_borderless_window()) {
- // put decorations back if the window wasn't suppoesed to be borderless
+ if (!p_enabled) {
+ // put back or remove decorations according to the last set borderless state
Hints hints;
Atom property;
hints.flags = 2;
- hints.decorations = 1;
+ hints.decorations = current_videomode.borderless_window ? 0 : 1;
property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5);
}
@@ -1531,7 +1531,7 @@ bool OS_X11::is_window_always_on_top() const {
void OS_X11::set_borderless_window(bool p_borderless) {
- if (current_videomode.borderless_window == p_borderless)
+ if (get_borderless_window() == p_borderless)
return;
if (!p_borderless && layered_window)
@@ -1551,7 +1551,24 @@ void OS_X11::set_borderless_window(bool p_borderless) {
}
bool OS_X11::get_borderless_window() {
- return current_videomode.borderless_window;
+
+ bool borderless = current_videomode.borderless_window;
+ Atom prop = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True);
+ if (prop != None) {
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+ if (XGetWindowProperty(x11_display, x11_window, prop, 0, sizeof(Hints), False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ if (data && (format == 32) && (len >= 5)) {
+ borderless = !((Hints *)data)->decorations;
+ }
+ XFree(data);
+ }
+ }
+ return borderless;
}
void OS_X11::request_attention() {
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index 25ad6bd5c9..075b0e6252 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -646,6 +646,7 @@ void AnimatedSprite::_reset_timeout() {
void AnimatedSprite::set_animation(const StringName &p_animation) {
ERR_EXPLAIN(vformat("There is no animation with name '%s'.", p_animation));
+ ERR_FAIL_COND(frames == NULL)
ERR_FAIL_COND(frames->get_animation_names().find(p_animation) == -1);
if (animation == p_animation)
diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h
index 23d2586331..81343a4604 100644
--- a/scene/2d/cpu_particles_2d.h
+++ b/scene/2d/cpu_particles_2d.h
@@ -116,7 +116,7 @@ private:
const Particle *particles;
bool operator()(int p_a, int p_b) const {
- return particles[p_a].time < particles[p_b].time;
+ return particles[p_a].time > particles[p_b].time;
}
};
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index ba06b3ebff..e116d404d6 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -105,6 +105,7 @@ void Line2D::set_point_position(int i, Vector2 pos) {
}
Vector2 Line2D::get_point_position(int i) const {
+ ERR_FAIL_INDEX_V(i, _points.size(), Vector2())
return _points.get(i);
}
diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp
new file mode 100644
index 0000000000..ca75302163
--- /dev/null
+++ b/scene/2d/multimesh_instance_2d.cpp
@@ -0,0 +1,111 @@
+/*************************************************************************/
+/* multimesh_instance_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "multimesh_instance_2d.h"
+
+void MultiMeshInstance2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_DRAW) {
+ if (multimesh.is_valid()) {
+ draw_multimesh(multimesh, texture, normal_map);
+ }
+ }
+}
+
+void MultiMeshInstance2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_multimesh", "multimesh"), &MultiMeshInstance2D::set_multimesh);
+ ClassDB::bind_method(D_METHOD("get_multimesh"), &MultiMeshInstance2D::get_multimesh);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &MultiMeshInstance2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &MultiMeshInstance2D::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MultiMeshInstance2D::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map"), &MultiMeshInstance2D::get_normal_map);
+
+ ADD_SIGNAL(MethodInfo("texture_changed"));
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multimesh", PROPERTY_HINT_RESOURCE_TYPE, "MultiMesh"), "set_multimesh", "get_multimesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+}
+
+void MultiMeshInstance2D::set_multimesh(const Ref<MultiMesh> &p_multimesh) {
+
+ multimesh = p_multimesh;
+ update();
+}
+
+Ref<MultiMesh> MultiMeshInstance2D::get_multimesh() const {
+
+ return multimesh;
+}
+
+void MultiMeshInstance2D::set_texture(const Ref<Texture> &p_texture) {
+
+ if (p_texture == texture)
+ return;
+ texture = p_texture;
+ update();
+ emit_signal("texture_changed");
+ _change_notify("texture");
+}
+
+Ref<Texture> MultiMeshInstance2D::get_texture() const {
+
+ return texture;
+}
+
+void MultiMeshInstance2D::set_normal_map(const Ref<Texture> &p_texture) {
+
+ normal_map = p_texture;
+ update();
+}
+
+Ref<Texture> MultiMeshInstance2D::get_normal_map() const {
+
+ return normal_map;
+}
+
+Rect2 MultiMeshInstance2D::_edit_get_rect() const {
+
+ if (multimesh.is_valid()) {
+ AABB aabb = multimesh->get_aabb();
+ return Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
+ }
+
+ return Node2D::_edit_get_rect();
+}
+
+MultiMeshInstance2D::MultiMeshInstance2D() {
+}
+
+MultiMeshInstance2D::~MultiMeshInstance2D() {
+}
diff --git a/scene/2d/multimesh_instance_2d.h b/scene/2d/multimesh_instance_2d.h
new file mode 100644
index 0000000000..3795497183
--- /dev/null
+++ b/scene/2d/multimesh_instance_2d.h
@@ -0,0 +1,65 @@
+/*************************************************************************/
+/* multimesh_instance_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef MULTIMESH_INSTANCE_2D_H
+#define MULTIMESH_INSTANCE_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/resources/multimesh.h"
+
+class MultiMeshInstance2D : public Node2D {
+ GDCLASS(MultiMeshInstance2D, Node2D);
+
+ Ref<MultiMesh> multimesh;
+
+ Ref<Texture> texture;
+ Ref<Texture> normal_map;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_multimesh(const Ref<MultiMesh> &p_multimesh);
+ Ref<MultiMesh> get_multimesh() const;
+
+ void set_texture(const Ref<Texture> &p_texture);
+ Ref<Texture> get_texture() const;
+
+ void set_normal_map(const Ref<Texture> &p_texture);
+ Ref<Texture> get_normal_map() const;
+
+ virtual Rect2 _edit_get_rect() const;
+
+ MultiMeshInstance2D();
+ ~MultiMeshInstance2D();
+};
+
+#endif // MULTIMESH_INSTANCE_2D_H
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 2b43861eea..b3b6f3175d 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -220,8 +220,8 @@ void TileMap::_fix_cell_transform(Transform2D &xform, const Cell &p_cell, const
xform.elements[1].y = -xform.elements[1].y;
offset.y = s.y - offset.y;
}
-
- offset += cell_size / 2 - s / 2;
+ /* For a future CheckBox to Center Texture:
+ offset += cell_size / 2 - s / 2; */
xform.elements[2] += offset;
}
@@ -372,10 +372,11 @@ void TileMap::update_dirty_quadrants() {
if (c.transpose) {
SWAP(tile_ofs.x, tile_ofs.y);
+ /* For a future CheckBox to Center Texture:
rect.position.x += cell_size.x / 2 - rect.size.y / 2;
rect.position.y += cell_size.y / 2 - rect.size.x / 2;
} else {
- rect.position += cell_size / 2 - rect.size / 2;
+ rect.position += cell_size / 2 - rect.size / 2; */
}
if (c.flip_h) {
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index e8692d56d2..6463ee5ad5 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -159,9 +159,7 @@ void GraphNode::_resort() {
fit_child_in_rect(c, r);
cache_y.push_back(vofs + size.y * 0.5);
- if (vofs > 0)
- vofs += sep;
- vofs += size.y;
+ vofs += size.y + sep;
}
update();
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index cc966efee9..da6bff8ab8 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -44,7 +44,7 @@
static bool _is_text_char(CharType c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+ return !is_symbol(c);
}
void LineEdit::_gui_input(Ref<InputEvent> p_event) {
@@ -539,7 +539,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (handled) {
accept_event();
- } else if (!k->get_alt() && !k->get_command()) {
+ } else if (!k->get_command()) {
if (k->get_unicode() >= 32 && k->get_scancode() != KEY_DELETE) {
if (editable) {
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 3117d8c59f..6203b15992 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -50,7 +50,7 @@ inline bool _is_symbol(CharType c) {
static bool _is_text_char(CharType c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+ return !is_symbol(c);
}
static bool _is_whitespace(CharType c) {
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 474eb51860..2007ae2669 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -3532,14 +3532,14 @@ TreeItem *Tree::_search_item_text(TreeItem *p_at, const String &p_find, int *r_c
TreeItem *Tree::search_item_text(const String &p_find, int *r_col, bool p_selectable) {
- TreeItem *from = get_selected()->get_next_visible();
+ TreeItem *from = get_selected();
- if (!root)
+ if (!from)
from = root;
if (!from)
return NULL;
- return _search_item_text(from, p_find, r_col, p_selectable);
+ return _search_item_text(from->get_next_visible(true), p_find, r_col, p_selectable);
}
void Tree::_do_incr_search(const String &p_add) {
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 8e6e8e2a53..5e4cf9c2ee 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -48,6 +48,7 @@
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/line_2d.h"
#include "scene/2d/mesh_instance_2d.h"
+#include "scene/2d/multimesh_instance_2d.h"
#include "scene/2d/navigation_2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
@@ -543,6 +544,7 @@ void register_scene_types() {
ClassDB::register_class<Position2D>();
ClassDB::register_class<Line2D>();
ClassDB::register_class<MeshInstance2D>();
+ ClassDB::register_class<MultiMeshInstance2D>();
ClassDB::register_virtual_class<CollisionObject2D>();
ClassDB::register_virtual_class<PhysicsBody2D>();
ClassDB::register_class<StaticBody2D>();
@@ -587,9 +589,13 @@ void register_scene_types() {
SceneTree::add_idle_callback(ParticlesMaterial::flush_changes);
ParticlesMaterial::init_shaders();
-#ifndef _3D_DISABLED
ClassDB::register_virtual_class<Mesh>();
ClassDB::register_class<ArrayMesh>();
+ ClassDB::register_class<MultiMesh>();
+ ClassDB::register_class<SurfaceTool>();
+ ClassDB::register_class<MeshDataTool>();
+
+#ifndef _3D_DISABLED
ClassDB::register_virtual_class<PrimitiveMesh>();
ClassDB::register_class<CapsuleMesh>();
ClassDB::register_class<CubeMesh>();
@@ -603,7 +609,6 @@ void register_scene_types() {
SceneTree::add_idle_callback(SpatialMaterial::flush_changes);
SpatialMaterial::init_shaders();
- ClassDB::register_class<MultiMesh>();
ClassDB::register_class<MeshLibrary>();
OS::get_singleton()->yield(); //may take time to init
@@ -619,9 +624,6 @@ void register_scene_types() {
ClassDB::register_class<ConvexPolygonShape>();
ClassDB::register_class<ConcavePolygonShape>();
- ClassDB::register_class<SurfaceTool>();
- ClassDB::register_class<MeshDataTool>();
-
OS::get_singleton()->yield(); //may take time to init
ClassDB::register_class<SpatialVelocityTracker>();
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index bdb6c78782..e8359e3dfe 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -582,14 +582,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// GraphNode
- Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 5);
+ Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graphsbcomment = make_stylebox(graph_node_comment_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graphsbcommentselected = make_stylebox(graph_node_comment_focus_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png, 6, 24, 6, 5, 16, 24, 16, 6);
Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png, 4, 4, 4, 4, 6, 4, 4, 4);
Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png, 4, 4, 4, 4, 6, 4, 4, 4);
- Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 5);
- Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 5);
+ Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 6);
+ Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 6);
//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 6e7bb27e74..0921c0dae9 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -1712,15 +1712,15 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
Vector<StringName> groups = state->get_node_groups(i);
String header = "[node";
- header += " name=\"" + String(name) + "\"";
+ header += " name=\"" + String(name).c_escape() + "\"";
if (type != StringName()) {
header += " type=\"" + String(type) + "\"";
}
if (path != NodePath()) {
- header += " parent=\"" + String(path.simplified()) + "\"";
+ header += " parent=\"" + String(path.simplified()).c_escape() + "\"";
}
if (owner != NodePath() && owner != NodePath(".")) {
- header += " owner=\"" + String(owner.simplified()) + "\"";
+ header += " owner=\"" + String(owner.simplified()).c_escape() + "\"";
}
if (index >= 0) {
header += " index=\"" + itos(index) + "\"";