Browse Source

Merge pull request #45663 from akien-mga/3.2-cherrypicks

Cherry-picks for the 3.2 branch (future 3.2.4) - 19th batch
Rémi Verschelde 4 years ago
parent
commit
3115ac4b60

+ 4 - 1
.gitignore

@@ -265,9 +265,12 @@ __pycache__/
 # KDE
 .directory
 
-#Kdevelop project files
+# Kdevelop project files
 *.kdev4
 
+# Kate swap files
+*.kate-swp
+
 # Xcode
 xcuserdata/
 *.xcscmblueprint

+ 1 - 0
.mailmap

@@ -116,6 +116,7 @@ Theo Hallenius <[email protected]>
 Thomas Herzog <[email protected]>
 Thomas Herzog <[email protected]> <[email protected]>
 Thomas Herzog <[email protected]> <[email protected]>
+Tomasz Chabora <[email protected]>
 Twarit <[email protected]>
 V.VamsiKrishna <[email protected]> <[email protected]>
 Wilhem Barbier <[email protected]> <[email protected]>

+ 3 - 0
AUTHORS.md

@@ -57,7 +57,9 @@ name is available.
     Daniel J. Ramirez (djrm)
     Daniel Rakos (aqnuep)
     dankan1890
+    Danil Alexeev (dalexeev)
     David Sichma (DavidSichma)
+    David Snopek (dsnopek)
     Dharkael (lupoDharkael)
     Dmitry Koteroff (Krakean)
     Dominik Jasiński (dreamsComeTrue)
@@ -99,6 +101,7 @@ name is available.
     Jérôme Gully (Nutriz)
     Jia Jun Chai (SkyLucilfer)
     Joan Fons Sanchez (JFonS)
+    Johannes Witt (HaSa1002)
     Johan Manuel (29jm)
     Joshua Grams (JoshuaGrams)
     Juan Linietsky (reduz)

+ 77 - 51
DONORS.md

@@ -48,7 +48,6 @@ generous deed immortalized in the next stable release of Godot Engine.
     Digital Grows
     Dov Zimring
     Edward Flick
-    Franz Silva
     Gamechuck
     GameDev.net
     Hein-Pieter van Braam
@@ -81,6 +80,7 @@ generous deed immortalized in the next stable release of Godot Engine.
 
     Acheron
     albinaask
+    Alvaro A Baena R
     Asher Glick
     Bernhard Werner
     Carlo Cabanilla
@@ -89,6 +89,7 @@ generous deed immortalized in the next stable release of Godot Engine.
     Daniel James
     David Gehrig
     David Snopek
+    Don B
     Ed Morley
     Ellen Poe
     Florian Neumann
@@ -103,7 +104,6 @@ generous deed immortalized in the next stable release of Godot Engine.
     Joan Fons
     Johnny IV Young
     Jon Woodward
-    Kai Klyden
     Karl Werf
     Klavdij Voncina
     Lex Steers
@@ -136,6 +136,7 @@ generous deed immortalized in the next stable release of Godot Engine.
     Tom Langwaldt
     Tricky Fat Cat
     tukon
+    Vitaliy Sapronenko
     William Wold
     xagonist
     Xeno Coliseum
@@ -144,17 +145,24 @@ generous deed immortalized in the next stable release of Godot Engine.
     Aaron Winter
     Adam Nakonieczny
     Adrian Adamiak
+    Aleksey Korotkevich
     Alexander J Maynard
     Alex de la Mare
+    Alexey Dyadchenko
     Alex Khayrullin
     alice gambrell
     Andreas Funke
     André Frélicot
+    Andrew Cunningham
+    Anm
+    Antanas Paskauskas
     Antoni Batchelli
     Arisaka Mayuki
+    Arthur S. Muszynski
     Aubin Detrez
     Barugon
     Ben Botwin
+    Caleb Sizemore
     Can Eris
     Charlie Whitfield
     Chase Taranto
@@ -166,16 +174,19 @@ generous deed immortalized in the next stable release of Godot Engine.
     Conrad Curry
     Craig Ostrin
     Craig Smith
+    Cristopher
     D
+    dan didenko
     Darrian Little
+    Dennis Belfrage
     Dev To be curious
     Digital Denizen
+    Dimitri Nüscheler
     Donn Eddy
     Easypete
     Edgar Sun
     Eugenio Hugo Salgüero Jáñez
     flesk
-    Francisco Arámburo
     F S
     Gabrielius Vaiškūnas
     Gary Hulst
@@ -189,11 +200,14 @@ generous deed immortalized in the next stable release of Godot Engine.
     Horváth Péter
     Hu Hund
     Idilio Alfaro
+    Jake Burga
     James Couzens
     Jared
     Jared White
+    Jesús Chicharro
     Joel Fivat
     Joel Höglund
+    Johnathan Kupferer
     Jose Malheiro
     Joseph Crane
     Joshie Sparks
@@ -208,10 +222,12 @@ generous deed immortalized in the next stable release of Godot Engine.
     Kelteseth
     kickmaniac
     kinfox
-    kuku
+    Kos
     Lachie
     Lain Ballard
+    Laszlo Kiss
     Leo Fidel R Liban
+    Liam Smyth
     Luc-Frédéric Langis
     luka duren
     MadScientistCarl
@@ -220,17 +236,23 @@ generous deed immortalized in the next stable release of Godot Engine.
     Marcus Richter
     Marisa Clardy
     Mark Barrett
+    Mark Diaz
     Markus Fehr
     Martin Eigel
     Martin Kotz
     Martin Soucek
     Matt Eunson
     Matt Greene
+    Matthias Toepp
+    medecau
     Michael
     Michael Dürwald
+    Michael Noll
+    Michael Policastro
     MikadoSC
     MuffinManKen
     Nick Abousselam
+    Nick Barovic
     Oliver Dick
     Oscar Campos
     Patrick Brock
@@ -245,32 +267,37 @@ generous deed immortalized in the next stable release of Godot Engine.
     Raymond Harris
     Raz A
     Ricardo Alcantara
+    Robert Larnach
     Robert Willes
     Rob McInroy
     Rocknight Studios
     Rodrigo Favarete
     Ronnie Ashlock
     Ronny Mühle
-    Ryan Wilson
+    Ryan Scott
+    Ryszard Sommefeldt
     Samuel Judd
     Scott Pilet
     Sean Morgan
+    Sebastian Hutter
     Sébastien
     Serban Serafimescu
     Sergey Minakov
     Shishir Tandale
     SKison
+    Song Junwoo
     spilldata
     Stephan Hennion
     Steven Landow
     Stoned Xander
-    TheLevelOfDetail .
+    TheLevelOfDetail
     Thomas Bjarnelöf
     Thomas Kurz
     Tim Howard
+    tinyBigGAMES LLC
     Tobias Bocanegra
-    Trent Fehl
     Turntsnaco
+    tweaklab
     Valryia
     Vincent Cloutier
     Vlad Ceru Opran
@@ -287,7 +314,6 @@ generous deed immortalized in the next stable release of Godot Engine.
 ## Silver donors
 
     1D_Inc
-    Aaron Passchier
     Abraham Haskins
     Adam
     Adam Brunnmeier
@@ -305,24 +331,24 @@ generous deed immortalized in the next stable release of Godot Engine.
     AJ Austinson
     Aki Mimoto
     Alan Beauchamp
+    Alberto Vilches
     Albin Jonasson Svärdsby
     Alder Stefano
     AleMax
     Alessandro Senese
     Alexander Erlemann
+    Alexander Ryndin
+    Alexander Walter (SilvanuZ)
     Alexandre Beaudoin
     alex clavelle
-    Ali Al-Khalifa
     Allan Davis
     Allen Schade
     Ancient Phoenix
     Anders Marstein Kruke
     Andreas Krampitz
-    André Simões
     Andre Stackhouse
     andrew james morris
     Andrew Mansuetti
-    Andrew Rosenwinkel
     Andrew Thomas
     Ano Nim
     Anthony Avina
@@ -330,16 +356,14 @@ generous deed immortalized in the next stable release of Godot Engine.
     AP Condomines
     Arch Toasty
     Arda Erol
+    Aria
     Armin Preiml
     Arseniy M
-    Arthur S. Muszynski
     Ashley Claymore
     Astier Mickael
     Aubrey Falconer
     AzulCrescent
-    B A
     Balázs Batári
-    Balázs Kondákor
     Bartosz Bielecki
     Bekhoucha Danyl
     Benedikt
@@ -347,6 +371,7 @@ generous deed immortalized in the next stable release of Godot Engine.
     Bernd Jänichen
     Bjarne Voigtländer
     Black Block
+    blackjacksike
     Blair Allen
     Bobby CC Wong
     Borkzilla
@@ -356,6 +381,7 @@ generous deed immortalized in the next stable release of Godot Engine.
     Brian Klein
     Brodie Fairhall
     Bronson Zgeb
+    Bùi Việt Thành
     Burney Waring
     Caleb Gartner
     Cameron Meyer
@@ -364,7 +390,9 @@ generous deed immortalized in the next stable release of Godot Engine.
     Carwyn Edwards
     Cas Brugman
     Cassidy James
+    Cédric Givord
     Chad Steadman
+    Charles Alston
     Chris Chapin
     Chris Jagusch
     Chris Langford
@@ -377,8 +405,9 @@ generous deed immortalized in the next stable release of Godot Engine.
     Christoph Woinke
     Chris Truebe
     Clay Heaton
+    Cody Parker
     Conall O
-    Cyrelouyea
+    Craig Post
     CzechBlueBear
     Daniel Cheney
     Daniel Johnson
@@ -398,10 +427,10 @@ generous deed immortalized in the next stable release of Godot Engine.
     Dr.Raccoon
     Duobix
     Duodecimal
+    DurrDiss
     Eduardo Teixeira
     Edward Herbert
     Edward Swartz
-    Eelco F Hillenius
     Egon Elbre
     Elgenzay
     Elias Nykrem
@@ -409,7 +438,6 @@ generous deed immortalized in the next stable release of Godot Engine.
     Eric Ellingson
     Eric Williams
     Erkki Seppälä
-    ET Garcia
     Evan Rose
     Fain
     Faisal Alkubaisi
@@ -423,6 +451,7 @@ generous deed immortalized in the next stable release of Godot Engine.
     FuDiggity
     Gadzhi Kharkharov
     gamedev by Celio
+    Game Endeavor
     Gary Thomas
     George Marques
     Gerard Ruiz Torruella
@@ -438,19 +467,16 @@ generous deed immortalized in the next stable release of Godot Engine.
     Hal A
     helija
     Heribert Hirth
-    Hoai Nam Tran
+    Hieu Thanh
     Hunter Jones
-    Hylpher
     Ian Williams
     Iiari
-    iKlem
     IndustrialRobot
+    Ivan Nikolaev
     iveks
-    Ivica Šimić
     Jackson Harmer
     Jacob
     Jaguar
-    Jaiden Gerig
     Jaime Ruiz-Borau Vizárraga
     Jake D
     Jake Huxell
@@ -461,12 +487,13 @@ generous deed immortalized in the next stable release of Godot Engine.
     Jamiee H
     Jamie Massey
     JARKKO PARVIAINEN
+    Jasiek Vetulani
     Jason Uechi
     Jean-Baptiste LEPESME
     Jeff Hungerford
     Jennifer Graves
     Jesse Dubay
-    Joe Alden
+    Jhon Adams
     Joe Klemmer
     John Gabriel
     Jonas
@@ -483,42 +510,41 @@ generous deed immortalized in the next stable release of Godot Engine.
     Jorge Javier Araya Navarro
     Jose C. Rubio
     Joseph Catrambone
-    Josh Mitchell
     Josh Taylor
-    Joshua Southerland
+    Josue David
     Juanfran
     Jueast
     Julian Murgia
     June Little
-    JungleRobba
+    Justin Hamilton
     Justin Oaksford
     Justin Spedding
     KaDokta
     Kalin
-    Karel Němec
     Kauzig
     Keedong Park
     Keinan Powers
     Keith Bradner
     Kenji Kawabata
+    Ken Minardo
     Kenneth Lee
     Kent Jofur
+    Ketafuki
     Kevin McPhillips
     Kiri Jolly
-    Kiyohiro Kawamura (kyorohiro)
     Kjetil Haugland
+    Konstantin Goncharov
+    Kridsada Thanabulpong
     Kristian Nygaard Jensen
     KsyTek Games
-    Kuan Cheang
     kycho
     Kyle Jacobs
     Kyle Szklenski
     Kyuppin
     Laurent CHEA
     Laurent Tréguier
-    Lee Meichin
+    Laxman Pradhan
     LEMMiNO
-    Lenny
     Leonardo Dimano
     Lin Chear
     Linus Lind Lundgren
@@ -527,13 +553,13 @@ generous deed immortalized in the next stable release of Godot Engine.
     Luis Gaemperle
     Luis M
     LunaticInAHat
-    Lurkars
     Major Haul
     makoto asano
     Malcolm
     Marco Lardelli
     Mark Jad
     Mark Krenz
+    Mark Malone
     Markus Martin
     Markus Michael Egger
     Martin FIbik
@@ -550,8 +576,10 @@ generous deed immortalized in the next stable release of Godot Engine.
     Maxwell
     Megasploot
     Melissa Mears
+    Merlyn Morgan-Graham
     mewin
     Michael
+    Michael Bruce-Lockhart
     Michael Haney
     Michał Skwarek
     Mikayla
@@ -566,27 +594,27 @@ generous deed immortalized in the next stable release of Godot Engine.
     Nathaniel
     Natrim
     nee
+    neighty
     Neil Blakey-Milner
     Neil Wang
     Nerdforge
     Nerdyninja
     Nicholas
-    Nicholas Girga
     Nick Allen
     Nick Macholl
     Niclas Eriksen
     Nicolas Goll-Perrier
-    Nicolás Montaña
+    Nicolas Rosset
     Nicolas SAN AGUSTIN
     Nima Farid
     NZ
+    oceoh
     OKV
     Oleg Reva
     Oleksandr Kryvonos
     Olivier
     Omar Delarosa
     Oscar Domingo
-    Oscar Norlander
     Parinya Teerakasemsuk
     patricio lara briones
     Patrick Dully
@@ -595,24 +623,27 @@ generous deed immortalized in the next stable release of Godot Engine.
     Paul Mason
     Paweł Kowal
     Paweł Łyczkowski
-    Pedro Assuncao
+    Peter Höglund
     Petrus Prinsloo
     Philip Cohoe
+    Phillip Zolla
     Piotr Góral
+    Pipo
     Point08
     Preethi Vaidyanathan
-    Price Comstock
     pwab
+    pyacier
+    Rad Cat
     Rafa Laguna
     Raffaele Aramo
+    RAMupgrade
     Remi Rampin
     Rémi Verschelde
     Reneator
-    Richard Diss
+    Riccardo Marini
     Richard Ivánek
     Riley
     Robert Farr (Larington)
-    Robert Larnach
     Rob Ruana
     Roger Smith
     Roland Rząsa
@@ -623,19 +654,19 @@ generous deed immortalized in the next stable release of Godot Engine.
     Ryan Groom
     Sam Edson
     Samuele Zolfanelli
-    sayaks
+    scapegoat57
     Scott D. Yelich
     Scott Longley
-    ScottMakesGames
+    Sean Lynch
     Sebastian Michailidis
     Sebastian Vetter
     SeongWan Kim
     Sergiy Onenko
-    Shaher
     Shane
     Shane Sicienski
     Shane Spoor
     Siim Raidma
+    simdee
     Simon Jonas Larsen
     Simon Schoenenberger
     Simon Wenner
@@ -644,20 +675,20 @@ generous deed immortalized in the next stable release of Godot Engine.
     smo1704
     soft circles
     Squirrel
-    Stefano Caronia
     Steve Cloete
+    summerblind
     Sung soo Choi
     Svenne Krap
     tadashi endo
     tannhauser_gate
+    Tarch
     Terry
     Theodore Lindsey
-    TheTrainDoctor
     TheVoiceInMyHead
     thomas
     Thomas Bechtold
     Thomas Detoy
-    Thomas Kelly
+    Thomas Horwath
     Tim Drumheller
     Tim Erskine
     Tim Gleason
@@ -671,7 +702,6 @@ generous deed immortalized in the next stable release of Godot Engine.
     Travis O'Brien
     Trent Skinner
     tril zerobyte
-    Triptych
     Triumph263 .
     Troy Bonneau
     Tryggve Sollid
@@ -684,8 +714,6 @@ generous deed immortalized in the next stable release of Godot Engine.
     Victor
     Vigilant Watch
     Viktor Ismagilov
-    Vitaliy Sapronenko
-    Vitor Balbio
     Vladimir Savin
     Vladislav Smirnov
     Výrus Hemomancer
@@ -693,17 +721,15 @@ generous deed immortalized in the next stable release of Godot Engine.
     Wayne Haak
     werner mendizabal
     Wiley Thompson
-    Will
     William Edwards
     William F Siqueira
     William Hogben
     Wyatt Goodin
+    Xaver Fischer
     xenomat
     Yegor Smirnov
-    YiYin Gu
     Zack Yang
     Zak Stephens
-    ΒΑΣΙΛΗΣ ΓΕΩΡΓΑΚΟΠΟΥΛΟΣ
     蕭惟允
     郝晨煜
 

+ 1 - 1
SConstruct

@@ -304,7 +304,7 @@ if selected_platform in platform_list:
     else:
         env = env_base.Clone()
 
-    # Compilation DB requires SCons 3.1.1+.
+    # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later.
     from SCons import __version__ as scons_raw_version
 
     scons_ver = env._get_major_minor_revision(scons_raw_version)

+ 1 - 0
doc/classes/Control.xml

@@ -16,6 +16,7 @@
 	<tutorials>
 		<link title="GUI tutorial index">https://docs.godotengine.org/en/3.2/tutorials/gui/index.html</link>
 		<link title="Custom drawing in 2D">https://docs.godotengine.org/en/3.2/tutorials/2d/custom_drawing_in_2d.html</link>
+		<link title="Control node gallery">https://docs.godotengine.org/en/latest/tutorials/ui/control_node_gallery.html</link>
 		<link title="All GUI Demos">https://github.com/godotengine/godot-demo-projects/tree/master/gui</link>
 	</tutorials>
 	<methods>

+ 1 - 1
doc/classes/TileMap.xml

@@ -144,7 +144,7 @@
 			<argument index="1" name="ignore_half_ofs" type="bool" default="false">
 			</argument>
 			<description>
-				Returns the global position corresponding to the given tilemap (grid-based) coordinates.
+				Returns the local position corresponding to the given tilemap (grid-based) coordinates.
 				Optionally, the tilemap's half offset can be ignored.
 			</description>
 		</method>

+ 11 - 1
doc/classes/TreeItem.xml

@@ -190,6 +190,7 @@
 			<argument index="0" name="column" type="int">
 			</argument>
 			<description>
+				Returns the metadata value that was set for the given column using [method set_metadata].
 			</description>
 		</method>
 		<method name="get_next">
@@ -239,6 +240,7 @@
 			<argument index="0" name="column" type="int">
 			</argument>
 			<description>
+				Returns the value of a [constant CELL_MODE_RANGE] column.
 			</description>
 		</method>
 		<method name="get_range_config">
@@ -247,6 +249,7 @@
 			<argument index="0" name="column" type="int">
 			</argument>
 			<description>
+				Returns a dictionary containing the range parameters for a given column. The keys are "min", "max", "step", and "expr".
 			</description>
 		</method>
 		<method name="get_suffix" qualifiers="const">
@@ -255,6 +258,7 @@
 			<argument index="0" name="column" type="int">
 			</argument>
 			<description>
+				Gets the suffix string shown after the column value.
 			</description>
 		</method>
 		<method name="get_text" qualifiers="const">
@@ -541,6 +545,7 @@
 			<argument index="1" name="meta" type="Variant">
 			</argument>
 			<description>
+				Sets the metadata value for the given column, which can be retrieved later using [method get_metadata]. This can be used, for example, to store a reference to the original data.
 			</description>
 		</method>
 		<method name="set_range">
@@ -551,6 +556,7 @@
 			<argument index="1" name="value" type="float">
 			</argument>
 			<description>
+				Sets the value of a [constant CELL_MODE_RANGE] column.
 			</description>
 		</method>
 		<method name="set_range_config">
@@ -567,6 +573,8 @@
 			<argument index="4" name="expr" type="bool" default="false">
 			</argument>
 			<description>
+				Sets the range of accepted values for a column. The column must be in the [constant CELL_MODE_RANGE] mode.
+				If [code]expr[/code] is [code]true[/code], the edit mode slider will use an exponential scale as with [member Range.exp_edit].
 			</description>
 		</method>
 		<method name="set_selectable">
@@ -588,6 +596,7 @@
 			<argument index="1" name="text" type="String">
 			</argument>
 			<description>
+				Sets a string to be shown after a column's value (for example, a unit abbreviation).
 			</description>
 		</method>
 		<method name="set_text">
@@ -598,6 +607,7 @@
 			<argument index="1" name="text" type="String">
 			</argument>
 			<description>
+				Sets the given column's text value.
 			</description>
 		</method>
 		<method name="set_text_align">
@@ -639,7 +649,7 @@
 			Cell contains a string.
 		</constant>
 		<constant name="CELL_MODE_CHECK" value="1" enum="TreeCellMode">
-			Cell can be checked.
+			Cell contains a checkbox.
 		</constant>
 		<constant name="CELL_MODE_RANGE" value="2" enum="TreeCellMode">
 			Cell contains a range.

+ 4 - 0
editor/editor_export.cpp

@@ -942,6 +942,10 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c
 
 	EditorProgress ep("savepack", TTR("Packing"), 102, true);
 
+	// Create the temporary export directory if it doesn't exist.
+	DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+	da->make_dir_recursive(EditorSettings::get_singleton()->get_cache_dir());
+
 	String tmppath = EditorSettings::get_singleton()->get_cache_dir().plus_file("packtmp");
 	FileAccess *ftmp = FileAccess::open(tmppath, FileAccess::WRITE);
 	ERR_FAIL_COND_V_MSG(!ftmp, ERR_CANT_CREATE, "Cannot create file '" + tmppath + "'.");

+ 1 - 0
editor/editor_node.cpp

@@ -1815,6 +1815,7 @@ void EditorNode::push_item(Object *p_object, const String &p_property, bool p_in
 		node_dock->set_node(NULL);
 		scene_tree_dock->set_selected(NULL);
 		inspector_dock->update(NULL);
+		_display_top_editors(false);
 		return;
 	}
 

+ 137 - 63
editor/plugins/spatial_editor_plugin.cpp

@@ -2502,6 +2502,13 @@ void SpatialEditorViewport::_notification(int p_what) {
 			text += "Z: " + rtos(current_camera->get_translation().z).pad_decimals(1) + "\n";
 			text += TTR("Pitch") + ": " + itos(Math::round(current_camera->get_rotation_degrees().x)) + "\n";
 			text += TTR("Yaw") + ": " + itos(Math::round(current_camera->get_rotation_degrees().y)) + "\n\n";
+
+			text += TTR("Size") +
+					vformat(
+							": %dx%d (%.1fMP)\n",
+							viewport->get_size().x,
+							viewport->get_size().y,
+							viewport->get_size().x * viewport->get_size().y * 0.000'001);
 			text += TTR("Objects Drawn") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_OBJECTS_IN_FRAME)) + "\n";
 			text += TTR("Material Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_MATERIAL_CHANGES_IN_FRAME)) + "\n";
 			text += TTR("Shader Changes") + ": " + itos(viewport->get_render_info(Viewport::RENDER_INFO_SHADER_CHANGES_IN_FRAME)) + "\n";
@@ -5164,6 +5171,42 @@ void SpatialEditor::_init_indicators() {
 			origin_points.push_back(axis * -1048576);
 		}
 
+		Ref<Shader> grid_shader = memnew(Shader);
+		grid_shader->set_code(
+				"\n"
+				"shader_type spatial; \n"
+				"render_mode unshaded; \n"
+				"uniform bool orthogonal; \n"
+				"uniform float grid_size; \n"
+				"\n"
+				"void vertex() { \n"
+				"	// From FLAG_SRGB_VERTEX_COLOR \n"
+				"	if (!OUTPUT_IS_SRGB) { \n"
+				"		COLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045))); \n"
+				"	} \n"
+				"} \n"
+				"\n"
+				"void fragment() { \n"
+				"	ALBEDO = COLOR.rgb; \n"
+				"	vec3 dir = orthogonal ? -vec3(0, 0, 1) : VIEW; \n"
+				"	float angle_fade = abs(dot(dir, NORMAL)); \n"
+				"	angle_fade = smoothstep(0.05, 0.2, angle_fade); \n"
+				"	\n"
+				"	vec3 world_pos = (CAMERA_MATRIX * vec4(VERTEX, 1.0)).xyz; \n"
+				"	vec3 world_normal = (CAMERA_MATRIX * vec4(NORMAL, 0.0)).xyz; \n"
+				"	vec3 camera_world_pos = CAMERA_MATRIX[3].xyz; \n"
+				"	vec3 camera_world_pos_on_plane = camera_world_pos * (1.0 - world_normal); \n"
+				"	float dist_fade = 1.0 - (distance(world_pos, camera_world_pos_on_plane) / grid_size); \n"
+				"	dist_fade = smoothstep(0.02, 0.3, dist_fade); \n"
+				"	\n"
+				"	ALPHA = COLOR.a * dist_fade * angle_fade; \n"
+				"}");
+
+		for (int i = 0; i < 3; i++) {
+			grid_mat[i].instance();
+			grid_mat[i]->set_shader(grid_shader);
+		}
+
 		grid_enable[0] = EditorSettings::get_singleton()->get("editors/3d/grid_xy_plane");
 		grid_enable[1] = EditorSettings::get_singleton()->get("editors/3d/grid_yz_plane");
 		grid_enable[2] = EditorSettings::get_singleton()->get("editors/3d/grid_xz_plane");
@@ -5368,32 +5411,34 @@ void SpatialEditor::_init_indicators() {
 				}
 
 				Ref<Shader> rotate_shader = memnew(Shader);
-				rotate_shader->set_code("\n"
-										"shader_type spatial; \n"
-										"render_mode unshaded, depth_test_disable; \n"
-										"uniform vec4 albedo; \n"
-										"\n"
-										"mat3 orthonormalize(mat3 m) { \n"
-										"	vec3 x = normalize(m[0]); \n"
-										"	vec3 y = normalize(m[1] - x * dot(x, m[1])); \n"
-										"	vec3 z = m[2] - x * dot(x, m[2]); \n"
-										"	z = normalize(z - y * (dot(y,m[2]))); \n"
-										"	return mat3(x,y,z); \n"
-										"} \n"
-										"\n"
-										"void vertex() { \n"
-										"	mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n"
-										"	vec3 n = mv * VERTEX; \n"
-										"	float orientation = dot(vec3(0,0,-1),n); \n"
-										"	if (orientation <= 0.005) { \n"
-										"		VERTEX += NORMAL*0.02; \n"
-										"	} \n"
-										"} \n"
-										"\n"
-										"void fragment() { \n"
-										"	ALBEDO = albedo.rgb; \n"
-										"	ALPHA = albedo.a; \n"
-										"}");
+
+				rotate_shader->set_code(
+						"\n"
+						"shader_type spatial; \n"
+						"render_mode unshaded, depth_test_disable; \n"
+						"uniform vec4 albedo; \n"
+						"\n"
+						"mat3 orthonormalize(mat3 m) { \n"
+						"	vec3 x = normalize(m[0]); \n"
+						"	vec3 y = normalize(m[1] - x * dot(x, m[1])); \n"
+						"	vec3 z = m[2] - x * dot(x, m[2]); \n"
+						"	z = normalize(z - y * (dot(y,m[2]))); \n"
+						"	return mat3(x,y,z); \n"
+						"} \n"
+						"\n"
+						"void vertex() { \n"
+						"	mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n"
+						"	vec3 n = mv * VERTEX; \n"
+						"	float orientation = dot(vec3(0,0,-1),n); \n"
+						"	if (orientation <= 0.005) { \n"
+						"		VERTEX += NORMAL*0.02; \n"
+						"	} \n"
+						"} \n"
+						"\n"
+						"void fragment() { \n"
+						"	ALBEDO = albedo.rgb; \n"
+						"	ALPHA = albedo.a; \n"
+						"}");
 
 				Ref<ShaderMaterial> rotate_mat = memnew(ShaderMaterial);
 				rotate_mat->set_render_priority(Material::RENDER_PRIORITY_MAX);
@@ -5413,33 +5458,34 @@ void SpatialEditor::_init_indicators() {
 					Ref<ShaderMaterial> border_mat = rotate_mat->duplicate();
 
 					Ref<Shader> border_shader = memnew(Shader);
-					border_shader->set_code("\n"
-											"shader_type spatial; \n"
-											"render_mode unshaded, depth_test_disable; \n"
-											"uniform vec4 albedo; \n"
-											"\n"
-											"mat3 orthonormalize(mat3 m) { \n"
-											"	vec3 x = normalize(m[0]); \n"
-											"	vec3 y = normalize(m[1] - x * dot(x, m[1])); \n"
-											"	vec3 z = m[2] - x * dot(x, m[2]); \n"
-											"	z = normalize(z - y * (dot(y,m[2]))); \n"
-											"	return mat3(x,y,z); \n"
-											"} \n"
-											"\n"
-											"void vertex() { \n"
-											"	mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n"
-											"	mv = inverse(mv); \n"
-											"	VERTEX += NORMAL*0.008; \n"
-											"	vec3 camera_dir_local = mv * vec3(0,0,1); \n"
-											"	vec3 camera_up_local = mv * vec3(0,1,0); \n"
-											"	mat3 rotation_matrix = mat3(cross(camera_dir_local, camera_up_local), camera_up_local, camera_dir_local); \n"
-											"	VERTEX = rotation_matrix * VERTEX; \n"
-											"} \n"
-											"\n"
-											"void fragment() { \n"
-											"	ALBEDO = albedo.rgb; \n"
-											"	ALPHA = albedo.a; \n"
-											"}");
+					border_shader->set_code(
+							"\n"
+							"shader_type spatial; \n"
+							"render_mode unshaded, depth_test_disable; \n"
+							"uniform vec4 albedo; \n"
+							"\n"
+							"mat3 orthonormalize(mat3 m) { \n"
+							"	vec3 x = normalize(m[0]); \n"
+							"	vec3 y = normalize(m[1] - x * dot(x, m[1])); \n"
+							"	vec3 z = m[2] - x * dot(x, m[2]); \n"
+							"	z = normalize(z - y * (dot(y,m[2]))); \n"
+							"	return mat3(x,y,z); \n"
+							"} \n"
+							"\n"
+							"void vertex() { \n"
+							"	mat3 mv = orthonormalize(mat3(MODELVIEW_MATRIX)); \n"
+							"	mv = inverse(mv); \n"
+							"	VERTEX += NORMAL*0.008; \n"
+							"	vec3 camera_dir_local = mv * vec3(0,0,1); \n"
+							"	vec3 camera_up_local = mv * vec3(0,1,0); \n"
+							"	mat3 rotation_matrix = mat3(cross(camera_dir_local, camera_up_local), camera_up_local, camera_dir_local); \n"
+							"	VERTEX = rotation_matrix * VERTEX; \n"
+							"} \n"
+							"\n"
+							"void fragment() { \n"
+							"	ALBEDO = albedo.rgb; \n"
+							"	ALPHA = albedo.a; \n"
+							"}");
 
 					border_mat->set_shader(border_shader);
 					border_mat->set_shader_param("albedo", Color(0.75, 0.75, 0.75, col.a / 3.0));
@@ -5601,8 +5647,11 @@ void SpatialEditor::_init_grid() {
 		return; // Camera is invalid, don't draw the grid.
 	}
 
+	bool orthogonal = camera->get_projection() == Camera::PROJECTION_ORTHOGONAL;
+
 	PoolVector<Color> grid_colors[3];
 	PoolVector<Vector3> grid_points[3];
+	PoolVector<Vector3> grid_normals[3];
 
 	Color primary_grid_color = EditorSettings::get_singleton()->get("editors/3d/primary_grid_color");
 	Color secondary_grid_color = EditorSettings::get_singleton()->get("editors/3d/secondary_grid_color");
@@ -5638,10 +5687,26 @@ void SpatialEditor::_init_grid() {
 		int b = (a + 1) % 3;
 		int c = (a + 2) % 3;
 
-		real_t division_level = Math::log(Math::abs(camera_position[c])) / Math::log((double)primary_grid_steps) + division_level_bias;
-		division_level = CLAMP(division_level, division_level_min, division_level_max);
-		real_t division_level_floored = Math::floor(division_level);
-		real_t division_level_decimals = division_level - division_level_floored;
+		Vector3 normal;
+		normal[c] = 1.0;
+
+		real_t camera_distance = Math::abs(camera_position[c]);
+
+		if (orthogonal) {
+			camera_distance = camera->get_size() / 2.0;
+			Vector3 camera_direction = -camera->get_global_transform().get_basis().get_axis(2);
+			Plane grid_plane = Plane(Vector3(), normal);
+			Vector3 intersection;
+			if (grid_plane.intersects_ray(camera_position, camera_direction, &intersection)) {
+				camera_position = intersection;
+			}
+		}
+
+		real_t division_level = Math::log(Math::abs(camera_distance)) / Math::log((double)primary_grid_steps) + division_level_bias;
+
+		real_t clamped_division_level = CLAMP(division_level, division_level_min, division_level_max);
+		real_t division_level_floored = Math::floor(clamped_division_level);
+		real_t division_level_decimals = clamped_division_level - division_level_floored;
 
 		real_t small_step_size = Math::pow(primary_grid_steps, division_level_floored);
 		real_t large_step_size = small_step_size * primary_grid_steps;
@@ -5653,6 +5718,15 @@ void SpatialEditor::_init_grid() {
 		real_t bgn_b = center_b - grid_size * small_step_size;
 		real_t end_b = center_b + grid_size * small_step_size;
 
+		real_t fade_size = Math::pow(primary_grid_steps, division_level - 1.0);
+		real_t min_fade_size = Math::pow(primary_grid_steps, float(division_level_min));
+		real_t max_fade_size = Math::pow(primary_grid_steps, float(division_level_max));
+		fade_size = CLAMP(fade_size, min_fade_size, max_fade_size);
+
+		real_t grid_fade_size = (grid_size - primary_grid_steps) * fade_size;
+		grid_mat[c]->set_shader_param("grid_size", grid_fade_size);
+		grid_mat[c]->set_shader_param("orthogonal", orthogonal);
+
 		// In each iteration of this loop, draw one line in each direction (so two lines per loop, in each if statement).
 		for (int i = -grid_size; i <= grid_size; i++) {
 			Color line_color;
@@ -5663,11 +5737,6 @@ void SpatialEditor::_init_grid() {
 				line_color = secondary_grid_color;
 				line_color.a = line_color.a * (1 - division_level_decimals);
 			}
-			// Makes lines farther from the center fade out.
-			// Due to limitations of lines, any that come near the camera have full opacity always.
-			// This should eventually be replaced by some kind of "distance fade" system, outside of this function.
-			// But the effect is still somewhat convincing...
-			line_color.a *= 1 - (1 - division_level_decimals * 0.9) * (Math::abs(i / (float)grid_size));
 
 			real_t position_a = center_a + i * small_step_size;
 			real_t position_b = center_b + i * small_step_size;
@@ -5684,6 +5753,8 @@ void SpatialEditor::_init_grid() {
 				grid_points[c].push_back(line_end);
 				grid_colors[c].push_back(line_color);
 				grid_colors[c].push_back(line_color);
+				grid_normals[c].push_back(normal);
+				grid_normals[c].push_back(normal);
 			}
 
 			if (!(origin_enabled && Math::is_zero_approx(position_b))) {
@@ -5697,6 +5768,8 @@ void SpatialEditor::_init_grid() {
 				grid_points[c].push_back(line_end);
 				grid_colors[c].push_back(line_color);
 				grid_colors[c].push_back(line_color);
+				grid_normals[c].push_back(normal);
+				grid_normals[c].push_back(normal);
 			}
 		}
 
@@ -5706,8 +5779,9 @@ void SpatialEditor::_init_grid() {
 		d.resize(VS::ARRAY_MAX);
 		d[VisualServer::ARRAY_VERTEX] = grid_points[c];
 		d[VisualServer::ARRAY_COLOR] = grid_colors[c];
+		d[VisualServer::ARRAY_NORMAL] = grid_normals[c];
 		VisualServer::get_singleton()->mesh_add_surface_from_arrays(grid[c], VisualServer::PRIMITIVE_LINES, d);
-		VisualServer::get_singleton()->mesh_surface_set_material(grid[c], 0, indicator_mat->get_rid());
+		VisualServer::get_singleton()->mesh_surface_set_material(grid[c], 0, grid_mat[c]->get_rid());
 		grid_instance[c] = VisualServer::get_singleton()->instance_create2(grid[c], get_tree()->get_root()->get_world()->get_scenario());
 
 		// Yes, the end of this line is supposed to be a.

+ 1 - 1
editor/plugins/spatial_editor_plugin.h

@@ -574,7 +574,6 @@ private:
 	/////
 
 	ToolMode tool_mode;
-	bool orthogonal;
 
 	VisualServer::ScenarioDebugMode scenario_debug;
 
@@ -607,6 +606,7 @@ private:
 	RID cursor_mesh;
 	RID cursor_instance;
 	Ref<SpatialMaterial> indicator_mat;
+	Ref<ShaderMaterial> grid_mat[3];
 	Ref<SpatialMaterial> cursor_material;
 
 	// Scene drag and drop support

+ 1 - 0
editor/plugins/visual_shader_editor_plugin.cpp

@@ -2645,6 +2645,7 @@ VisualShaderEditor::VisualShaderEditor() {
 	add_options.push_back(AddOption("FragCoord", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord"), "fragcoord", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
 	add_options.push_back(AddOption("Light", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light"), "light", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
 	add_options.push_back(AddOption("LightColor", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "light_color"), "light_color", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
+	add_options.push_back(AddOption("Metallic", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "metallic"), "metallic", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
 	add_options.push_back(AddOption("Roughness", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "roughness"), "roughness", VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
 	add_options.push_back(AddOption("Specular", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "specular"), "specular", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
 	add_options.push_back(AddOption("Transmission", "Input", "Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "transmission"), "transmission", VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));

+ 25 - 8
editor/project_manager.cpp

@@ -1378,11 +1378,10 @@ void ProjectList::create_project_item_control(int p_index) {
 	vb->add_child(path_hb);
 
 	Button *show = memnew(Button);
-	// Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't
+	// Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't.
 	show->set_icon(get_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons"));
-	show->set_flat(true);
 	if (!item.grayed) {
-		// Don't make the icon less prominent if the parent is already grayed out
+		// Don't make the icon less prominent if the parent is already grayed out.
 		show->set_modulate(Color(1, 1, 1, 0.5));
 	}
 	path_hb->add_child(show);
@@ -2190,8 +2189,9 @@ void ProjectManager::_run_project() {
 }
 
 void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) {
-	DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
-	da->change_dir(path);
+	DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+	Error error = da->change_dir(path);
+	ERR_FAIL_COND_MSG(error != OK, "Could not scan directory at: " + path);
 	da->list_dir_begin();
 	String n = da->get_next();
 	while (n != String()) {
@@ -2203,7 +2203,6 @@ void ProjectManager::_scan_dir(const String &path, List<String> *r_projects) {
 		n = da->get_next();
 	}
 	da->list_dir_end();
-	memdelete(da);
 }
 
 void ProjectManager::_scan_begin(const String &p_base) {
@@ -2736,8 +2735,26 @@ ProjectManager::ProjectManager() {
 
 	_load_recent_projects();
 
-	if (EditorSettings::get_singleton()->get("filesystem/directories/autoscan_project_path")) {
-		_scan_begin(EditorSettings::get_singleton()->get("filesystem/directories/autoscan_project_path"));
+	DirAccessRef dir_access = DirAccess::create(DirAccess::AccessType::ACCESS_FILESYSTEM);
+
+	String default_project_path = EditorSettings::get_singleton()->get("filesystem/directories/default_project_path");
+	if (!dir_access->dir_exists(default_project_path)) {
+		Error error = dir_access->make_dir_recursive(default_project_path);
+		if (error != OK) {
+			ERR_PRINT("Could not create default project directory at: " + default_project_path);
+		}
+	}
+
+	String autoscan_path = EditorSettings::get_singleton()->get("filesystem/directories/autoscan_project_path");
+	if (autoscan_path != "") {
+		if (dir_access->dir_exists(autoscan_path)) {
+			_scan_begin(autoscan_path);
+		} else {
+			Error error = dir_access->make_dir_recursive(autoscan_path);
+			if (error != OK) {
+				ERR_PRINT("Could not create project autoscan directory at: " + autoscan_path);
+			}
+		}
 	}
 
 	SceneTree::get_singleton()->connect("files_dropped", this, "_files_dropped");

+ 1 - 1
modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs

@@ -104,7 +104,7 @@ namespace GodotTools.Ides.Rider
             if (line >= 0)
             {
                 args.Add("--line");
-                args.Add(line.ToString());
+                args.Add((line + 1).ToString()); // https://github.com/JetBrains/godot-support/issues/61
             }
             args.Add(scriptPath);
             try

+ 8 - 8
modules/mono/glue/GodotSharp/GodotSharp/Core/StringExtensions.cs

@@ -470,18 +470,18 @@ namespace Godot
         }
 
         // <summary>
-        // Hash the string and return a 32 bits integer.
+        // Hash the string and return a 32 bits unsigned integer.
         // </summary>
-        public static int Hash(this string instance)
+        public static uint Hash(this string instance)
         {
-            int index = 0;
-            int hashv = 5381;
-            int c;
+            uint hash = 5381;
 
-            while ((c = instance[index++]) != 0)
-                hashv = (hashv << 5) + hashv + c; // hash * 33 + c
+            foreach(uint c in instance)
+            {
+                hash = (hash << 5) + hash + c; // hash * 33 + c
+            }
 
-            return hashv;
+            return hash;
         }
 
         /// <summary>

+ 4 - 2
modules/webxr/doc_classes/WebXRInterface.xml

@@ -16,9 +16,9 @@
 		var vr_supported = false
 
 		func _ready():
-		    # We assume this node has a canvas layer with a button on it as a child.
+		    # We assume this node has a button as a child.
 		    # This button is for the user to consent to entering immersive VR mode.
-		    $CanvasLayer/Button.connect("pressed", self, "_on_Button_pressed")
+		    $Button.connect("pressed", self, "_on_Button_pressed")
 
 		    webxr_interface = ARVRServer.find_interface("WebXR")
 		    if webxr_interface:
@@ -67,6 +67,7 @@
 		        return
 
 		func _webxr_session_started():
+		    $Button.visible = false
 		    # This tells Godot to start rendering to the headset.
 		    get_viewport().arvr = true
 		    # This will be the reference space type you ultimately got, out of the
@@ -75,6 +76,7 @@
 		    print ("Reference space type: " + webxr_interface.reference_space_type)
 
 		func _webxr_session_ended():
+		    $Button.visible = true
 		    # If the user exits immersive mode, then we tell Godot to render to the web
 		    # page again.
 		    get_viewport().arvr = false

+ 1 - 1
platform/android/java/lib/build.gradle

@@ -68,7 +68,7 @@ android {
         File sconsExecutableFile = null
         def sconsName = "scons"
         def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows()
-            ? [".bat", ".exe"]
+            ? [".bat", ".cmd", ".ps1", ".exe"]
             : [""])
         logger.lifecycle("Looking for $sconsName executable path")
         for (ext in sconsExts) {

+ 6 - 3
platform/x11/detect.py

@@ -65,13 +65,13 @@ def get_opts():
         BoolVariable("use_llvm", "Use the LLVM compiler", False),
         BoolVariable("use_lld", "Use the LLD linker", False),
         BoolVariable("use_thinlto", "Use ThinLTO", False),
-        BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", False),
+        BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True),
         BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False),
         BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False),
         BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False),
         BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False),
         BoolVariable("pulseaudio", "Detect and use PulseAudio", True),
-        BoolVariable("udev", "Use udev for gamepad connection callbacks", False),
+        BoolVariable("udev", "Use udev for gamepad connection callbacks", True),
         EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
         BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False),
         BoolVariable("touch", "Enable touch events", True),
@@ -380,4 +380,7 @@ def configure(env):
 
     # Link those statically for portability
     if env["use_static_cpp"]:
-        env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
+        # Workaround for GH-31743, Ubuntu 18.04 i386 crashes when it's used.
+        # That doesn't make any sense but it's likely a Ubuntu bug?
+        if is64 or env["bits"] == "64":
+            env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])

+ 16 - 4
platform/x11/joypad_linux.cpp

@@ -32,6 +32,7 @@
 
 #include "joypad_linux.h"
 
+#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/input.h>
@@ -205,13 +206,24 @@ void JoypadLinux::monitor_joypads() {
 
 	while (!exit_udev) {
 		joy_mutex->lock();
-		for (int i = 0; i < 32; i++) {
+
+		DIR *input_directory;
+		input_directory = opendir("/dev/input");
+		if (input_directory) {
+			struct dirent *current;
 			char fname[64];
-			sprintf(fname, "/dev/input/event%d", i);
-			if (attached_devices.find(fname) == -1) {
-				open_joypad(fname);
+
+			while ((current = readdir(input_directory)) != NULL) {
+				if (strncmp(current->d_name, "event", 5) != 0) {
+					continue;
+				}
+				sprintf(fname, "/dev/input/%.*s", 16, current->d_name);
+				if (attached_devices.find(fname) == -1) {
+					open_joypad(fname);
+				}
 			}
 		}
+		closedir(input_directory);
 		joy_mutex->unlock();
 		usleep(1000000); // 1s
 	}

+ 6 - 3
scene/3d/visibility_notifier.cpp

@@ -85,15 +85,18 @@ void VisibilityNotifier::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_WORLD: {
 
-			get_world()->_register_notifier(this, get_global_transform().xform(aabb));
+			world = get_world();
+			ERR_FAIL_COND(!world.is_valid());
+			world->_register_notifier(this, get_global_transform().xform(aabb));
 		} break;
 		case NOTIFICATION_TRANSFORM_CHANGED: {
 
-			get_world()->_update_notifier(this, get_global_transform().xform(aabb));
+			world->_update_notifier(this, get_global_transform().xform(aabb));
 		} break;
 		case NOTIFICATION_EXIT_WORLD: {
 
-			get_world()->_remove_notifier(this);
+			ERR_FAIL_COND(!world.is_valid());
+			world->_remove_notifier(this);
 		} break;
 	}
 }

+ 2 - 0
scene/3d/visibility_notifier.h

@@ -33,11 +33,13 @@
 
 #include "scene/3d/spatial.h"
 
+class World;
 class Camera;
 class VisibilityNotifier : public Spatial {
 
 	GDCLASS(VisibilityNotifier, Spatial);
 
+	Ref<World> world;
 	Set<Camera *> cameras;
 
 	AABB aabb;

+ 0 - 1
scene/gui/spin_box.cpp

@@ -300,7 +300,6 @@ SpinBox::SpinBox() {
 	line_edit->connect("text_entered", this, "_text_entered", Vector<Variant>(), CONNECT_DEFERRED);
 	line_edit->connect("focus_exited", this, "_line_edit_focus_exit", Vector<Variant>(), CONNECT_DEFERRED);
 	line_edit->connect("gui_input", this, "_line_edit_input");
-	drag.enabled = false;
 
 	range_click_timer = memnew(Timer);
 	range_click_timer->connect("timeout", this, "_range_click_timeout");

+ 4 - 4
scene/gui/spin_box.h

@@ -53,11 +53,11 @@ class SpinBox : public Range {
 	void _line_edit_input(const Ref<InputEvent> &p_event);
 
 	struct Drag {
-		float base_val;
-		bool allowed;
-		bool enabled;
+		float base_val = 0;
+		bool allowed = false;
+		bool enabled = false;
 		Vector2 capture_pos;
-		float diff_y;
+		float diff_y = 0;
 	} drag;
 
 	void _line_edit_focus_exit();

+ 1 - 1
scene/resources/material.cpp

@@ -610,7 +610,7 @@ void SpatialMaterial::_update_shader() {
 	if (flags[FLAG_SRGB_VERTEX_COLOR]) {
 
 		code += "\tif (!OUTPUT_IS_SRGB) {\n";
-		code += "\t\tCOLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );\n";
+		code += "\t\tCOLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));\n";
 		code += "\t}\n";
 	}
 	if (flags[FLAG_USE_POINT_SIZE]) {

+ 1 - 0
scene/resources/visual_shader.cpp

@@ -1588,6 +1588,7 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
 	{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "diffuse", "DIFFUSE_LIGHT" },
 	{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR, "specular", "SPECULAR_LIGHT" },
 	{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
+	{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
 
 	{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "world", "WORLD_MATRIX" },
 	{ Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_TRANSFORM, "inv_camera", "INV_CAMERA_MATRIX" },

+ 1 - 0
servers/visual/shader_types.cpp

@@ -145,6 +145,7 @@ ShaderTypes::ShaderTypes() {
 	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ATTENUATION"] = constt(ShaderLanguage::TYPE_VEC3);
 	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ALBEDO"] = constt(ShaderLanguage::TYPE_VEC3);
 	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["TRANSMISSION"] = constt(ShaderLanguage::TYPE_VEC3);
+	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["METALLIC"] = constt(ShaderLanguage::TYPE_FLOAT);
 	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["ROUGHNESS"] = constt(ShaderLanguage::TYPE_FLOAT);
 	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["DIFFUSE_LIGHT"] = ShaderLanguage::TYPE_VEC3;
 	shader_modes[VS::SHADER_SPATIAL].functions["light"].built_ins["SPECULAR_LIGHT"] = ShaderLanguage::TYPE_VEC3;