summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/project_settings.cpp85
-rw-r--r--doc/classes/Input.xml2
-rw-r--r--doc/classes/NavigationPolygon.xml33
-rw-r--r--doc/classes/PathFollow2D.xml1
-rw-r--r--doc/classes/PhysicsServer.xml2
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--doc/classes/StreamPeerTCP.xml3
-rw-r--r--doc/classes/Vector2.xml4
-rw-r--r--doc/classes/Vector3.xml6
-rw-r--r--doc/classes/YSort.xml1
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp5
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp11
-rw-r--r--drivers/gles2/shaders/copy.glsl22
-rw-r--r--drivers/gles2/shaders/scene.glsl2
-rw-r--r--drivers/gles3/shaders/scene.glsl2
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp18
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h1
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp5
-rw-r--r--editor/editor_file_dialog.cpp25
-rw-r--r--editor/editor_inspector.cpp6
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/filesystem_dock.cpp12
-rw-r--r--editor/filesystem_dock.h2
-rw-r--r--editor/plugin_config_dialog.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp10
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp87
-rw-r--r--editor/plugins/spatial_editor_plugin.h3
-rw-r--r--editor/scene_tree_dock.cpp7
-rw-r--r--editor/script_editor_debugger.cpp2
-rw-r--r--main/input_default.cpp35
-rw-r--r--main/input_default.h1
-rw-r--r--modules/csg/csg_shape.cpp5
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp3
-rw-r--r--modules/gdscript/gdscript.cpp1
-rw-r--r--modules/gdscript/gdscript_compiler.cpp20
-rw-r--r--modules/gdscript/gdscript_compiler.h10
-rw-r--r--modules/gdscript/gdscript_editor.cpp3
-rw-r--r--modules/gdscript/gdscript_function.cpp49
-rw-r--r--modules/gdscript/gdscript_function.h10
-rw-r--r--modules/gdscript/gdscript_parser.cpp8
-rw-r--r--modules/jpg/image_loader_jpegd.cpp22
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp1
-rw-r--r--modules/websocket/emws_server.cpp3
-rw-r--r--modules/websocket/lws_client.cpp28
-rw-r--r--platform/android/os_android.cpp2
-rw-r--r--platform/javascript/engine.js3
-rw-r--r--platform/javascript/pre.js3
-rw-r--r--platform/osx/os_osx.mm27
-rw-r--r--platform/x11/os_x11.cpp2
-rw-r--r--scene/3d/arvr_nodes.cpp4
-rw-r--r--scene/3d/arvr_nodes.h4
-rw-r--r--scene/3d/light.cpp9
-rw-r--r--scene/3d/mesh_instance.cpp6
-rw-r--r--scene/3d/mesh_instance.h1
-rw-r--r--scene/3d/path.cpp39
-rw-r--r--scene/3d/path.h4
-rw-r--r--scene/3d/voxel_light_baker.cpp2
-rw-r--r--scene/gui/gradient_edit.cpp4
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/gui/tabs.cpp81
-rw-r--r--scene/gui/tabs.h2
-rw-r--r--scene/main/node.cpp2
-rw-r--r--scene/resources/packed_scene.cpp2
-rw-r--r--servers/audio/audio_stream.cpp16
-rw-r--r--servers/audio/audio_stream.h2
-rw-r--r--servers/audio_server.cpp8
-rw-r--r--servers/audio_server.h1
-rw-r--r--servers/physics/collision_solver_sat.cpp1
68 files changed, 533 insertions, 262 deletions
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 99a23bbee1..5dedff3a71 100644
--- a/core/project_settings.cpp
+++ b/core/project_settings.cpp
@@ -288,9 +288,28 @@ void ProjectSettings::_convert_to_last_version() {
}
}
+/*
+ * This method is responsible for loading a project.godot file and/or data file
+ * using the following merit order:
+ * - If using NetworkClient, try to lookup project file or fail.
+ * - If --main-pack was passed by the user (`p_main_pack`), load it or fail.
+ * - Search for .pck file matching binary name. There are two possibilities:
+ * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck')
+ * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck')
+ * For each tentative, if the file exists, load it or fail.
+ * - On relevant platforms (Android/iOS), lookup project file in OS resource path.
+ * If found, load it or fail.
+ * - Lookup project file in passed `p_path` (--path passed by the user), i.e. we
+ * are running from source code.
+ * If not found and `p_upwards` is true (--upwards passed by the user), look for
+ * project files in parent folders up to the system root (used to run a game
+ * from command line while in a subfolder).
+ * If a project file is found, load it or fail.
+ * If nothing was found, error out.
+ */
Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) {
- //If looking for files in network, just use network!
+ // If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
@@ -302,9 +321,7 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- String exec_path = OS::get_singleton()->get_executable_path();
-
- //Attempt with a passed main pack first
+ // Attempt with a user-defined main pack first
if (p_main_pack != "") {
@@ -320,25 +337,39 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- //Attempt with execname.pck
+ // Attempt with exec_name.pck
+ // (This is the usual case when distributing a Godot game.)
+
+ // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle)
+ // or the exec path's basename + '.pck' (Windows).
+ // We need to test both possibilities as extensions for Linux binaries are optional
+ // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck').
+
+ String exec_path = OS::get_singleton()->get_executable_path();
+
if (exec_path != "") {
bool found = false;
- // get our filename without our path (note, using exec_path.get_file before get_basename anymore because not all file systems have dots in their file names!)
- String filebase_name = exec_path.get_file().get_basename();
+ String exec_dir = exec_path.get_base_dir();
+ String exec_filename = exec_path.get_file();
+ String exec_basename = exec_filename.get_basename();
+
+ // Try to load data pack at the location of the executable
+ // As mentioned above, we have two potential names to attempt
- // try to open at the location of executable
- String datapack_name = exec_path.get_base_dir().plus_file(filebase_name) + ".pck";
- if (_load_resource_pack(datapack_name)) {
+ if (_load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) ||
+ _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck"))) {
found = true;
} else {
- datapack_name = filebase_name + ".pck";
- if (_load_resource_pack(datapack_name)) {
+ // If we couldn't find them next to the executable, we attempt
+ // the current working directory. Same story, two tests.
+ if (_load_resource_pack(exec_basename + ".pck") ||
+ _load_resource_pack(exec_filename + ".pck")) {
found = true;
}
}
- // if we opened our package, try and load our project...
+ // If we opened our package, try and load our project
if (found) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
@@ -350,17 +381,15 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
}
}
- //Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
- if (OS::get_singleton()->get_resource_dir() != "") {
- //OS will call Globals->get_resource_path which will be empty if not overridden!
- //if the OS would rather use somewhere else, then it will not be empty.
+ // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this)
+ if (OS::get_singleton()->get_resource_dir() != "") {
+ // OS will call ProjectSettings->get_resource_path which will be empty if not overridden!
+ // If the OS would rather use a specific location, then it will not be empty.
resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/");
- if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
+ if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') {
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
-
- // data.pck and data.zip are deprecated and no longer supported, apologies.
- // make sure this is loaded from the resource path
+ }
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
if (err == OK) {
@@ -371,21 +400,19 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
return err;
}
- //Nothing was found, try to find a project.godot somewhere!
+ // Nothing was found, try to find a project file in provided path (`p_path`)
+ // or, if requested (`p_upwards`) in parent directories.
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
ERR_FAIL_COND_V(!d, ERR_CANT_CREATE);
-
d->change_dir(p_path);
- String candidate = d->get_current_dir();
String current_dir = d->get_current_dir();
-
+ String candidate = current_dir;
bool found = false;
Error err;
while (true) {
-
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
if (err == OK) {
// Optional, we don't mind if it fails
@@ -396,10 +423,10 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
}
if (p_upwards) {
- // Try to load settings ascending through dirs shape!
+ // Try to load settings ascending through parent directories
d->change_dir("..");
if (d->get_current_dir() == current_dir)
- break; //not doing anything useful
+ break; // not doing anything useful
current_dir = d->get_current_dir();
} else {
break;
@@ -416,6 +443,8 @@ Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bo
if (resource_path.length() && resource_path[resource_path.length() - 1] == '/')
resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end
+ // If we're loading a project.godot from source code, we can operate some
+ // ProjectSettings conversions if need be.
_convert_to_last_version();
return OK;
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 10ec15b99d..0e6e54c8fd 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -123,7 +123,7 @@
<argument index="0" name="button_index" type="int">
</argument>
<description>
- Receives a [code]JOY_BUTTON_*[/code] Enum and returns it's equivalent name as a string.
+ Receives a [code]JOY_BUTTON_*[/code] Enum and returns its equivalent name as a string.
</description>
</method>
<method name="get_joy_guid" qualifiers="const">
diff --git a/doc/classes/NavigationPolygon.xml b/doc/classes/NavigationPolygon.xml
index b29e19e5d8..4ede80b98c 100644
--- a/doc/classes/NavigationPolygon.xml
+++ b/doc/classes/NavigationPolygon.xml
@@ -1,8 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="NavigationPolygon" inherits="Resource" category="Core" version="3.1">
<brief_description>
+ A node that has methods to draw outlines or use indices of vertices to create navigation polygons.
</brief_description>
<description>
+ There are two ways to create polygons. Either by using the [method add_outline] method or using the [method add_polygon] method.
+ Using [method add_outline]:
+ [code]
+ var polygon = NavigationPolygon.new()
+ var outline = PoolVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
+ polygon.add_outline(outline)
+ polygon.make_polygons_from_outlines()
+ $NavigationPolygonInstance.navpoly = polygon
+ [/code]
+ Using [method add_polygon] and indices of the vertices array.
+ [code]
+ var polygon = NavigationPolygon.new()
+ var vertices = PoolVector2Array([Vector2(0, 0), Vector2(0, 50), Vector2(50, 50), Vector2(50, 0)])
+ polygon.set_vertices(vertices)
+ var indices = PoolIntArray(0, 3, 1)
+ polygon.add_polygon(indices)
+ $NavigationPolygonInstance.navpoly = polygon
+ [/code]
</description>
<tutorials>
</tutorials>
@@ -15,6 +34,7 @@
<argument index="0" name="outline" type="PoolVector2Array">
</argument>
<description>
+ Appends a [PoolVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
</description>
</method>
<method name="add_outline_at_index">
@@ -25,6 +45,7 @@
<argument index="1" name="index" type="int">
</argument>
<description>
+ Adds a [PoolVector2Array] that contains the vertices of an outline to the internal array that contains all the outlines at a fixed position. You have to call [method make_polygons_from_outlines] in order for this array to be converted to polygons that the engine will use.
</description>
</method>
<method name="add_polygon">
@@ -33,18 +54,21 @@
<argument index="0" name="polygon" type="PoolIntArray">
</argument>
<description>
+ Adds a polygon using the indices of the vertices you get when calling [method get_vertices].
</description>
</method>
<method name="clear_outlines">
<return type="void">
</return>
<description>
+ Clears the array of the outlines, but it doesn't clear the vertices and the polygons that were created by them.
</description>
</method>
<method name="clear_polygons">
<return type="void">
</return>
<description>
+ Clears the array of polygons, but it doesn't clear the array of outlines and vertices.
</description>
</method>
<method name="get_outline" qualifiers="const">
@@ -53,12 +77,14 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns a [PoolVector2Array] containing the vertices of an outline that was created in the editor or by script.
</description>
</method>
<method name="get_outline_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of outlines that were created in the editor or by script.
</description>
</method>
<method name="get_polygon">
@@ -67,24 +93,28 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns a [PoolIntArray] containing the indices of the vertices of a created polygon.
</description>
</method>
<method name="get_polygon_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the count of all polygons.
</description>
</method>
<method name="get_vertices" qualifiers="const">
<return type="PoolVector2Array">
</return>
<description>
+ Returns a [PoolVector2Array] containing all the vertices being used to create the polygons.
</description>
</method>
<method name="make_polygons_from_outlines">
<return type="void">
</return>
<description>
+ Creates polygons from the outlines added in the editor or by script.
</description>
</method>
<method name="remove_outline">
@@ -93,6 +123,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Removes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_outline">
@@ -103,6 +134,7 @@
<argument index="1" name="outline" type="PoolVector2Array">
</argument>
<description>
+ Changes an outline created in the editor or by script. You have to call [method make_polygons_from_outlines] for the polygons to update.
</description>
</method>
<method name="set_vertices">
@@ -111,6 +143,7 @@
<argument index="0" name="vertices" type="PoolVector2Array">
</argument>
<description>
+ Sets the vertices that can be then indexed to create polygons with the [method add_polygon] method.
</description>
</method>
</methods>
diff --git a/doc/classes/PathFollow2D.xml b/doc/classes/PathFollow2D.xml
index f9940dab2f..515c921d0d 100644
--- a/doc/classes/PathFollow2D.xml
+++ b/doc/classes/PathFollow2D.xml
@@ -23,6 +23,7 @@
The node's offset along the curve.
</member>
<member name="lookahead" type="float" setter="set_lookahead" getter="get_lookahead">
+ How far to look ahead of the curve to calculate the tangent if the node is rotating. E.g. shorter lookaheads will lead to faster rotations. Default value: [code]4[/code].
</member>
<member name="loop" type="bool" setter="set_loop" getter="has_loop">
If [code]true[/code], any offset outside the path's length will wrap around, instead of stopping at the ends. Use it for cyclic paths.
diff --git a/doc/classes/PhysicsServer.xml b/doc/classes/PhysicsServer.xml
index f79baea0be..c836414dd2 100644
--- a/doc/classes/PhysicsServer.xml
+++ b/doc/classes/PhysicsServer.xml
@@ -1260,7 +1260,7 @@
The higher, the stronger.
</constant>
<constant name="PIN_JOINT_IMPULSE_CLAMP" value="2" enum="PinJointParam">
- If above 0, this value is the maximum value for an impulse that this Joint puts on it's ends.
+ If above 0, this value is the maximum value for an impulse that this Joint puts on its ends.
</constant>
<constant name="HINGE_JOINT_BIAS" value="0" enum="HingeJointParam">
The speed with which the two bodies get pulled together when they move in different directions.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4516fc522a..dfecff9050 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -182,7 +182,7 @@
Name of the project. It is used from both project manager and by the exporters. Overriding this as name.locale allows setting it in multiple languages.
</member>
<member name="application/config/use_custom_user_dir" type="bool" setter="" getter="">
- Allow the project to save to it's own custom user dir (in AppData on windows or ~/.config on unixes). This setting only works for desktop exporters. A name must be set in the "custom_user_dir_name" setting for this to take effect.
+ Allow the project to save to its own custom user dir (in AppData on windows or ~/.config on unixes). This setting only works for desktop exporters. A name must be set in the "custom_user_dir_name" setting for this to take effect.
</member>
<member name="application/run/disable_stderr" type="bool" setter="" getter="">
Disable printing to stderr on exported build.
@@ -691,7 +691,7 @@
<member name="rendering/quality/reflections/high_quality_ggx.mobile" type="bool" setter="" getter="">
</member>
<member name="rendering/quality/reflections/texture_array_reflections" type="bool" setter="" getter="">
- For reflection probes and panorama backgrounds (sky), use a texure array instead of mipmaps. This reduces jitter noise on reflections, but costs more performance and memory.
+ For reflection probes and panorama backgrounds (sky), use a texture array instead of mipmaps. This reduces jitter noise on reflections, but costs more performance and memory.
</member>
<member name="rendering/quality/reflections/texture_array_reflections.mobile" type="bool" setter="" getter="">
</member>
@@ -704,7 +704,7 @@
<member name="rendering/quality/shading/force_lambert_over_burley.mobile" type="bool" setter="" getter="">
</member>
<member name="rendering/quality/shading/force_vertex_shading" type="bool" setter="" getter="">
- Force vertex shading for all rendering. This can increase performance a lot, but also reduces quality inmensely. Can work to optimize on very low end mobile.
+ Force vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can work to optimize on very low end mobile.
</member>
<member name="rendering/quality/shading/force_vertex_shading.mobile" type="bool" setter="" getter="">
</member>
diff --git a/doc/classes/StreamPeerTCP.xml b/doc/classes/StreamPeerTCP.xml
index 664ffc60c3..9a0fceddab 100644
--- a/doc/classes/StreamPeerTCP.xml
+++ b/doc/classes/StreamPeerTCP.xml
@@ -4,7 +4,7 @@
TCP Stream peer.
</brief_description>
<description>
- TCP Stream peer. This object can be used to connect to TCP servers, or also is returned by a tcp server.
+ TCP Stream peer. This object can be used to connect to TCP servers, or also is returned by a TCP server.
</description>
<tutorials>
</tutorials>
@@ -54,6 +54,7 @@
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if this peer is currently connected to a host, [code]false[code] otherwise.
</description>
</method>
<method name="set_no_delay">
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index c323cf6992..1f8eb47044 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -259,10 +259,10 @@
</methods>
<members>
<member name="x" type="float" setter="" getter="">
- The vector's x component.
+ The vector's x component. Also accessible by using the index position [code][0][/code].
</member>
<member name="y" type="float" setter="" getter="">
- The vector's y component.
+ The vector's y component. Also accessible by using the index position [code][1][/code].
</member>
</members>
<constants>
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index 8c4e08778d..2499ba75ff 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -260,13 +260,13 @@
</methods>
<members>
<member name="x" type="float" setter="" getter="">
- The vector's x component.
+ The vector's x component. Also accessible by using the index position [code][0][/code].
</member>
<member name="y" type="float" setter="" getter="">
- The vector's y component.
+ The vector's y component. Also accessible by using the index position [code][1][/code].
</member>
<member name="z" type="float" setter="" getter="">
- The vector's z component.
+ The vector's z component. Also accessible by using the index position [code][2][/code].
</member>
</members>
<constants>
diff --git a/doc/classes/YSort.xml b/doc/classes/YSort.xml
index 12b9cb623f..45ae8645b1 100644
--- a/doc/classes/YSort.xml
+++ b/doc/classes/YSort.xml
@@ -14,6 +14,7 @@
</methods>
<members>
<member name="sort_enabled" type="bool" setter="set_sort_enabled" getter="is_sort_enabled">
+ If [code]true[/code] child nodes are sorted, otherwise sorting is disabled. Default: [code]true[/code].
</member>
</members>
<constants>
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index aaec63d7ff..850b90d59b 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -145,9 +145,6 @@ Error AudioDriverCoreAudio::init() {
unsigned int buffer_size = buffer_frames * channels;
samples_in.resize(buffer_size);
input_buf.resize(buffer_size);
- input_buffer.resize(buffer_size * 8);
- input_position = 0;
- input_size = 0;
print_verbose("CoreAudio: detected " + itos(channels) + " channels");
print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
@@ -487,6 +484,8 @@ void AudioDriverCoreAudio::capture_finish() {
Error AudioDriverCoreAudio::capture_start() {
+ input_buffer_init(buffer_frames);
+
OSStatus result = AudioOutputUnitStart(input_unit);
if (result != noErr) {
ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result));
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index fbcbebc88c..7e6d969ccb 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -2455,13 +2455,20 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
glEnableVertexAttribArray(VS::ARRAY_VERTEX);
glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, asymmetrical);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, !asymmetrical);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, true);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
- storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, true);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false);
storage->shaders.copy.bind();
storage->shaders.copy.set_uniform(CopyShaderGLES2::MULTIPLIER, p_energy);
+ if (asymmetrical) {
+ // pack the bits we need from our projection matrix
+ storage->shaders.copy.set_uniform(CopyShaderGLES2::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]);
+ ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here.
+ storage->shaders.copy.set_uniform(CopyShaderGLES2::PANO_TRANSFORM, p_transform);
+ }
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -2469,6 +2476,8 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false);
storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
}
diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl
index 16bbde196d..0b8da4f875 100644
--- a/drivers/gles2/shaders/copy.glsl
+++ b/drivers/gles2/shaders/copy.glsl
@@ -35,6 +35,8 @@ void main() {
#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
cube_interp = cube_in;
+#elif defined(USE_ASYM_PANO)
+ uv_interp = vertex_attrib.xy;
#else
uv_interp = uv_in;
#endif
@@ -68,6 +70,11 @@ varying vec2 uv_interp;
#endif
/* clang-format on */
+#ifdef USE_ASYM_PANO
+uniform highp mat4 pano_transform;
+uniform highp vec4 asym_proj;
+#endif
+
#ifdef USE_CUBEMAP
uniform samplerCube source_cube; // texunit:0
#else
@@ -108,6 +115,21 @@ void main() {
vec4 color = texturePanorama(source, normalize(cube_interp));
+#elif defined(USE_ASYM_PANO)
+
+ // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result.
+ // Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1.
+ // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image.
+
+ vec3 cube_normal;
+ cube_normal.z = -1000000.0;
+ cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y;
+ cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a;
+ cube_normal = mat3(pano_transform) * cube_normal;
+ cube_normal.z = -cube_normal.z;
+
+ vec4 color = texturePanorama(source, normalize(cube_normal.xyz));
+
#elif defined(USE_CUBEMAP)
vec4 color = textureCube(source_cube, normalize(cube_interp));
#else
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 7b57f5d497..a1f0c2680c 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -359,7 +359,7 @@ void main() {
normal = normalize((world_matrix * vec4(normal, 0.0)).xyz);
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- tangent = normalize((world_matrix * vec4(tangent, 0.0)), xyz);
+ tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz);
binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz);
#endif
#endif
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 8388b15edb..91ab34f775 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -2053,7 +2053,7 @@ FRAGMENT_SHADER_CODE
emission = emission * rev_amount + fog_color * fog_amount;
ambient_light *= rev_amount;
- specular_light *rev_amount;
+ specular_light *= rev_amount;
diffuse_light *= rev_amount;
}
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 9c02549e39..d78316945f 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -613,20 +613,18 @@ Error AudioDriverPulseAudio::capture_init_device() {
break;
}
- print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels");
-
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16LE;
spec.channels = pa_rec_map.channels;
spec.rate = mix_rate;
- int latency = 30;
- input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
- int buffer_size = input_buffer_frames * spec.channels;
+ int input_latency = 30;
+ int input_buffer_frames = closest_power_of_2(input_latency * mix_rate / 1000);
+ int input_buffer_size = input_buffer_frames * spec.channels;
pa_buffer_attr attr;
- attr.fragsize = buffer_size * sizeof(int16_t);
+ attr.fragsize = input_buffer_size * sizeof(int16_t);
pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
if (pa_rec_str == NULL) {
@@ -642,9 +640,10 @@ Error AudioDriverPulseAudio::capture_init_device() {
ERR_FAIL_V(ERR_CANT_OPEN);
}
- input_buffer.resize(input_buffer_frames * 8);
- input_position = 0;
- input_size = 0;
+ input_buffer_init(input_buffer_frames);
+
+ print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels");
+ print_verbose("PulseAudio: input buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms");
return OK;
}
@@ -760,7 +759,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() {
mix_rate = 0;
buffer_frames = 0;
- input_buffer_frames = 0;
pa_buffer_size = 0;
channels = 0;
pa_ready = 0;
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index f8358a452b..d8bab841ff 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -64,7 +64,6 @@ class AudioDriverPulseAudio : public AudioDriver {
unsigned int mix_rate;
unsigned int buffer_frames;
- unsigned int input_buffer_frames;
unsigned int pa_buffer_size;
int channels;
int pa_ready;
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index a91e41b008..8665f701b1 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -336,10 +336,7 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) {
HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- // Set the buffer size
- input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS);
- input_position = 0;
- input_size = 0;
+ input_buffer_init(max_frames);
return OK;
}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index f425d0a995..438d7ea306 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1135,14 +1135,10 @@ void EditorFileDialog::_update_drives() {
}
void EditorFileDialog::_favorite_selected(int p_idx) {
-
- Vector<String> favorited = EditorSettings::get_singleton()->get_favorites();
- ERR_FAIL_INDEX(p_idx, favorited.size());
-
- dir_access->change_dir(favorited[p_idx]);
+ dir_access->change_dir(favorites->get_item_metadata(p_idx));
file->set_text("");
- invalidate();
update_dir();
+ invalidate();
_push_history();
}
@@ -1192,7 +1188,7 @@ void EditorFileDialog::_update_favorites() {
bool res = access == ACCESS_RESOURCES;
String current = get_current_dir();
- Ref<Texture> star = get_icon("Favorites", "EditorIcons");
+ Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons");
favorites->clear();
favorite->set_pressed(false);
@@ -1203,16 +1199,23 @@ void EditorFileDialog::_update_favorites() {
if (cres != res)
continue;
String name = favorited[i];
-
- bool setthis = name == current;
+ bool setthis = false;
if (res && name == "res://") {
+ if (name == current)
+ setthis = true;
name = "/";
+ } else if (name.ends_with("/")) {
+ if (name == current)
+ setthis = true;
+ name = name.substr(0, name.length() - 1);
+ name = name.get_file();
+
+ favorites->add_item(name, folder_icon);
} else {
- name = name.get_file() + "/";
+ continue; // We don't handle favorite files here
}
- favorites->add_item(name, star);
favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]);
if (setthis) {
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index a90f15004a..3ecaa2b136 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -738,9 +738,9 @@ Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
tooltip_text = p_text;
EditorHelpBit *help_bit = memnew(EditorHelpBit);
help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
- help_bit->get_rich_text()->set_fixed_size_to_width(300);
+ help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
- String text = TTR("Property: ") + "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
+ String text = TTR("Property:") + " [u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
text += p_text.get_slice("::", 1).strip_edges();
help_bit->set_text(text);
help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene
@@ -960,7 +960,7 @@ Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) cons
tooltip_text = p_text;
EditorHelpBit *help_bit = memnew(EditorHelpBit);
help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
- help_bit->get_rich_text()->set_fixed_size_to_width(300);
+ help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
String text = "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
text += p_text.get_slice("::", 1).strip_edges();
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 18dd85617b..d01543198a 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3892,7 +3892,9 @@ void EditorNode::_scene_tab_hover(int p_tab) {
tab_preview_panel->hide();
} else {
String path = editor_data.get_scene_path(p_tab);
- EditorResourcePreview::get_singleton()->queue_resource_preview(path, this, "_thumbnail_done", p_tab);
+ if (path != String()) {
+ EditorResourcePreview::get_singleton()->queue_resource_preview(path, this, "_thumbnail_done", p_tab);
+ }
}
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 26bc43c540..701f10ca00 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -225,7 +225,7 @@ void FileSystemDock::_update_tree(const Vector<String> p_uncollapsed_paths, bool
updating_tree = false;
}
-void FileSystemDock::_update_display_mode() {
+void FileSystemDock::_update_display_mode(bool p_force) {
// Compute the new display mode
DisplayMode new_display_mode;
if (display_mode_setting == DISPLAY_MODE_SETTING_TREE_ONLY) {
@@ -234,7 +234,7 @@ void FileSystemDock::_update_display_mode() {
new_display_mode = DISPLAY_MODE_SPLIT;
}
- if (new_display_mode != display_mode || old_display_mode_setting != display_mode_setting) {
+ if (p_force || new_display_mode != display_mode || old_display_mode_setting != display_mode_setting) {
display_mode = new_display_mode;
old_display_mode_setting = display_mode_setting;
button_toggle_display_mode->set_pressed(display_mode_setting == DISPLAY_MODE_SETTING_SPLIT ? true : false);
@@ -352,6 +352,9 @@ void FileSystemDock::_notification(int p_what) {
tree->set_drop_mode_flags(0);
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ _update_display_mode(true);
+ } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
// Update icons
String ei = "EditorIcons";
@@ -360,6 +363,11 @@ void FileSystemDock::_notification(int p_what) {
button_tree->set_icon(get_icon("Filesystem", ei));
button_hist_next->set_icon(get_icon("Forward", ei));
button_hist_prev->set_icon(get_icon("Back", ei));
+ if (button_file_list_display_mode->is_pressed()) {
+ button_file_list_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons"));
+ } else {
+ button_file_list_display_mode->set_icon(get_icon("FileList", "EditorIcons"));
+ }
tree_search_box->set_right_icon(get_icon("Search", ei));
tree_search_box->set_clear_button_enabled(true);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index d964515572..2aa79b1ddd 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -268,7 +268,7 @@ private:
void _file_list_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
void _tree_thumbnail_done(const String &p_path, const Ref<Texture> &p_preview, const Ref<Texture> &p_small_preview, const Variant &p_udata);
- void _update_display_mode();
+ void _update_display_mode(bool p_force = false);
Vector<String> _tree_get_selected(bool remove_self_inclusion = true);
diff --git a/editor/plugin_config_dialog.cpp b/editor/plugin_config_dialog.cpp
index a334f79f5a..8e626e7111 100644
--- a/editor/plugin_config_dialog.cpp
+++ b/editor/plugin_config_dialog.cpp
@@ -180,7 +180,7 @@ PluginConfigDialog::PluginConfigDialog() {
grid->add_child(desc_lb);
desc_edit = memnew(TextEdit);
- desc_edit->set_custom_minimum_size(Size2(400.0f, 50.0f));
+ desc_edit->set_custom_minimum_size(Size2(400, 80) * EDSCALE);
grid->add_child(desc_edit);
Label *author_lb = memnew(Label);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 7e11c4a253..07a7e7952a 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -490,7 +490,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
edit(text_file, true);
return;
}
- // if it's a path then its most likely a deleted file not help
+ // if it's a path then it's most likely a deleted file not help
} else if (path.find("::") != -1) {
// built-in script
Ref<Script> script = ResourceLoader::load(path);
@@ -2912,7 +2912,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
script_list = memnew(ItemList);
list_split->add_child(script_list);
- script_list->set_custom_minimum_size(Size2(150 * EDSCALE, 90)); //need to give a bit of limit to avoid it from disappearing
+ script_list->set_custom_minimum_size(Size2(150, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
script_list->set_v_size_flags(SIZE_EXPAND_FILL);
script_split->set_split_offset(140);
_sort_list_on_update = true;
@@ -2951,7 +2951,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
overview_vbox->add_child(members_overview);
members_overview->set_allow_reselect(true);
- members_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing
+ members_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
members_overview->set_v_size_flags(SIZE_EXPAND_FILL);
members_overview->set_allow_rmb_select(true);
members_overview->set_drag_forwarding(this);
@@ -2959,12 +2959,12 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
help_overview = memnew(ItemList);
overview_vbox->add_child(help_overview);
help_overview->set_allow_reselect(true);
- help_overview->set_custom_minimum_size(Size2(0, 90)); //need to give a bit of limit to avoid it from disappearing
+ help_overview->set_custom_minimum_size(Size2(0, 90) * EDSCALE); //need to give a bit of limit to avoid it from disappearing
help_overview->set_v_size_flags(SIZE_EXPAND_FILL);
tab_container = memnew(TabContainer);
tab_container->set_tabs_visible(false);
- tab_container->set_custom_minimum_size(Size2(200 * EDSCALE, 0));
+ tab_container->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
script_split->add_child(tab_container);
tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 45c632af1f..ab89d170da 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -2259,6 +2259,11 @@ void SpatialEditorViewport::_notification(int p_what) {
float cinema_half_width = cinema_label->get_size().width / 2.0f;
cinema_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -cinema_half_width);
}
+
+ if (lock_rotation) {
+ float locked_half_width = locked_label->get_size().width / 2.0f;
+ locked_label->set_anchor_and_margin(MARGIN_LEFT, 0.5f, -locked_half_width);
+ }
}
if (p_what == NOTIFICATION_ENTER_TREE) {
@@ -2269,27 +2274,36 @@ void SpatialEditorViewport::_notification(int p_what) {
surface->connect("mouse_exited", this, "_surface_mouse_exit");
surface->connect("focus_entered", this, "_surface_focus_enter");
surface->connect("focus_exited", this, "_surface_focus_exit");
- view_menu->set_flat(false);
- view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
+
_init_gizmo_instance(index);
}
+
if (p_what == NOTIFICATION_EXIT_TREE) {
_finish_gizmo_instances();
}
- if (p_what == NOTIFICATION_MOUSE_ENTER) {
- }
+ if (p_what == NOTIFICATION_THEME_CHANGED) {
+
+ view_menu->set_icon(get_icon("GuiMiniTabMenu", "EditorIcons"));
+ preview_camera->set_icon(get_icon("Camera", "EditorIcons"));
+
+ view_menu->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ view_menu->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
- if (p_what == NOTIFICATION_DRAW) {
+ preview_camera->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("hover", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("pressed", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("focus", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ preview_camera->add_style_override("disabled", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+
+ info_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ fps_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ cinema_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
+ locked_label->add_style_override("normal", editor->get_gui_base()->get_stylebox("Information3dViewport", "EditorStyles"));
}
}
@@ -2530,8 +2544,14 @@ void SpatialEditorViewport::_menu_option(int p_option) {
if (!se)
continue;
- Transform xform = camera_transform;
- xform.scale_basis(sp->get_scale());
+ Transform xform;
+ if (orthogonal) {
+ xform = sp->get_global_transform();
+ xform.basis.set_euler(camera_transform.basis.get_euler());
+ } else {
+ xform = camera_transform;
+ xform.scale_basis(sp->get_scale());
+ }
undo_redo->add_do_method(sp, "set_global_transform", xform);
undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_gizmo_transform());
@@ -2579,9 +2599,9 @@ void SpatialEditorViewport::_menu_option(int p_option) {
lock_rotation = !current;
view_menu->get_popup()->set_item_checked(idx, !current);
if (lock_rotation) {
- view_menu->set_icon(get_icon("Lock", "EditorIcons"));
+ locked_label->show();
} else {
- view_menu->set_icon(Ref<Texture>());
+ locked_label->hide();
}
} break;
@@ -2651,11 +2671,6 @@ void SpatialEditorViewport::_menu_option(int p_option) {
bool current = view_menu->get_popup()->is_item_checked(idx);
view_menu->get_popup()->set_item_checked(idx, !current);
- if (current)
- preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- else
- preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 15 * EDSCALE + fps_label->get_size().height);
-
} break;
case VIEW_DISPLAY_NORMAL: {
@@ -2769,7 +2784,7 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), camera->get_camera()); //restore
if (!preview)
preview_camera->hide();
- view_menu->show();
+ view_menu->set_disabled(false);
surface->update();
} else {
@@ -2777,7 +2792,7 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
previewing = preview;
previewing->connect("tree_exiting", this, "_preview_exited_scene");
VS::get_singleton()->viewport_attach_camera(viewport->get_viewport_rid(), preview->get_camera()); //replace
- view_menu->hide();
+ view_menu->set_disabled(true);
surface->update();
}
}
@@ -3434,8 +3449,10 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
surface->set_focus_mode(FOCUS_ALL);
view_menu = memnew(MenuButton);
+ view_menu->set_flat(false);
surface->add_child(view_menu);
- view_menu->set_position(Point2(4, 4) * EDSCALE);
+ view_menu->set_position(Point2(10, 10) * EDSCALE);
+
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/top_view"), VIEW_TOP);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/bottom_view"), VIEW_BOTTOM);
view_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("spatial_editor/left_view"), VIEW_LEFT);
@@ -3486,12 +3503,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_Q);
ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT);
- preview_camera = memnew(Button);
- preview_camera->set_toggle_mode(true);
- preview_camera->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
- preview_camera->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
- preview_camera->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, -10 * EDSCALE);
- preview_camera->set_h_grow_direction(GROW_DIRECTION_BEGIN);
+ preview_camera = memnew(CheckBox);
+ preview_camera->set_position(Point2(10, 38) * EDSCALE); // Below the 'view_menu' MenuButton.
preview_camera->set_text(TTR("Preview"));
surface->add_child(preview_camera);
preview_camera->hide();
@@ -3511,7 +3524,6 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
surface->add_child(info_label);
info_label->hide();
- // FPS Counter.
fps_label = memnew(Label);
fps_label->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -90 * EDSCALE);
fps_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 10 * EDSCALE);
@@ -3529,6 +3541,16 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
cinema_label->hide();
previewing_cinema = false;
+ locked_label = memnew(Label);
+ locked_label->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -20 * EDSCALE);
+ locked_label->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -10 * EDSCALE);
+ locked_label->set_h_grow_direction(GROW_DIRECTION_END);
+ locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN);
+ locked_label->set_align(Label::ALIGN_CENTER);
+ surface->add_child(locked_label);
+ locked_label->set_text(TTR("View Rotation Locked"));
+ locked_label->hide();
+
accept = NULL;
freelook_active = false;
@@ -5452,7 +5474,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
view_menu = memnew(MenuButton);
view_menu->set_text(TTR("View"));
- view_menu->set_position(Point2(212, 0));
hbc_menu->add_child(view_menu);
p = view_menu->get_popup();
diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h
index c552f21e39..3cce76cc17 100644
--- a/editor/plugins/spatial_editor_plugin.h
+++ b/editor/plugins/spatial_editor_plugin.h
@@ -192,7 +192,7 @@ private:
EditorSelection *editor_selection;
UndoRedo *undo_redo;
- Button *preview_camera;
+ CheckBox *preview_camera;
ViewportContainer *viewport_container;
MenuButton *view_menu;
@@ -211,6 +211,7 @@ private:
Label *info_label;
Label *fps_label;
Label *cinema_label;
+ Label *locked_label;
struct _RayResult {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 45c20121da..a8f4c38695 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -1307,6 +1307,13 @@ bool SceneTreeDock::_validate_no_foreign() {
return false;
}
+ // When edited_scene inherits from another one the root Node will be the parent Scene,
+ // we don't want to consider that Node a foreign one otherwise we would not be able to
+ // delete it
+ if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene == E->get()) {
+ continue;
+ }
+
if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get())) >= 0) {
accept->set_text(TTR("Can't operate on nodes the current scene inherits from!"));
diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp
index 6fbac0d4b5..a36a844710 100644
--- a/editor/script_editor_debugger.cpp
+++ b/editor/script_editor_debugger.cpp
@@ -355,7 +355,7 @@ void ScriptEditorDebugger::_video_mem_request() {
Size2 ScriptEditorDebugger::get_minimum_size() const {
Size2 ms = Control::get_minimum_size();
- ms.y = MAX(ms.y, 250);
+ ms.y = MAX(ms.y, 250 * EDSCALE);
return ms;
}
void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) {
diff --git a/main/input_default.cpp b/main/input_default.cpp
index 913c143025..33c422190d 100644
--- a/main/input_default.cpp
+++ b/main/input_default.cpp
@@ -261,6 +261,13 @@ void InputDefault::parse_input_event(const Ref<InputEvent> &p_event) {
void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) {
+ // Notes on mouse-touch emulation:
+ // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects
+ // as true mouse events. The only difference is the situation is flagged as emulated so they are not
+ // emulated back to touch events in an endless loop.
+ // - Emulated touch events are handed right to the main loop (i.e., the SceneTree) because they don't
+ // require additional handling by this class.
+
_THREAD_SAFE_METHOD_
Ref<InputEventKey> k = p_event;
@@ -316,11 +323,21 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
}
}
- if (emulate_mouse_from_touch) {
+ Ref<InputEventScreenTouch> st = p_event;
+
+ if (st.is_valid()) {
+
+ if (st->is_pressed()) {
+ SpeedTrack &track = touch_speed_track[st->get_index()];
+ track.reset();
+ } else {
+ // Since a pointer index may not occur again (OSs may or may not reuse them),
+ // imperatively remove it from the map to keep no fossil entries in it
+ touch_speed_track.erase(st->get_index());
+ }
- Ref<InputEventScreenTouch> st = p_event;
+ if (emulate_mouse_from_touch) {
- if (st.is_valid()) {
bool translate = false;
if (st->is_pressed()) {
if (mouse_from_touch_index == -1) {
@@ -351,10 +368,18 @@ void InputDefault::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool
_parse_input_event_impl(button_event, true);
}
}
+ }
+
+ Ref<InputEventScreenDrag> sd = p_event;
+
+ if (sd.is_valid()) {
+
+ SpeedTrack &track = touch_speed_track[sd->get_index()];
+ track.update(sd->get_relative());
+ sd->set_speed(track.speed);
- Ref<InputEventScreenDrag> sd = p_event;
+ if (emulate_mouse_from_touch && sd->get_index() == mouse_from_touch_index) {
- if (sd.is_valid() && sd->get_index() == mouse_from_touch_index) {
Ref<InputEventMouseMotion> motion_event;
motion_event.instance();
diff --git a/main/input_default.h b/main/input_default.h
index b420ec124b..4964b9a83c 100644
--- a/main/input_default.h
+++ b/main/input_default.h
@@ -117,6 +117,7 @@ class InputDefault : public Input {
};
SpeedTrack mouse_speed_track;
+ Map<int, SpeedTrack> touch_speed_track;
Map<int, Joypad> joy_names;
int fallback_mapping;
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index d1ef08dc83..44044d2750 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -521,6 +521,11 @@ CSGBrush *CSGMesh::_build_brush() {
Array arrays = mesh->surface_get_arrays(i);
+ if (arrays.size() == 0) {
+ _make_dirty();
+ ERR_FAIL_COND_V(arrays.size() == 0, NULL);
+ }
+
PoolVector<Vector3> avertices = arrays[Mesh::ARRAY_VERTEX];
if (avertices.size() == 0)
continue;
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 37e72bf9f8..3e56275396 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -1711,8 +1711,7 @@ void NativeReloadNode::_notification(int p_what) {
}
RES ResourceFormatLoaderNativeScript::load(const String &p_path, const String &p_original_path, Error *r_error) {
- ResourceFormatLoaderText rsflt;
- return rsflt.load(p_path, p_original_path, r_error);
+ return ResourceFormatLoaderText::singleton->load(p_path, p_original_path, r_error);
}
void ResourceFormatLoaderNativeScript::get_recognized_extensions(List<String> *p_extensions) const {
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 48c1760662..4909ac8d92 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2081,6 +2081,7 @@ GDScriptLanguage::GDScriptLanguage() {
#ifdef DEBUG_ENABLED
GLOBAL_DEF("debug/gdscript/warnings/enable", true);
GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
+ GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
GLOBAL_DEF("debug/gdscript/warnings/" + warning, !warning.begins_with("unsafe_"));
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 310c4e21f2..45319c59e7 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1603,13 +1603,13 @@ Error GDScriptCompiler::_parse_block(CodeGen &codegen, const GDScriptParser::Blo
return OK;
}
-Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
+Error GDScriptCompiler::_parse_function(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready) {
Vector<int> bytecode;
CodeGen codegen;
codegen.class_node = p_class;
- codegen.script = p_script;
+ codegen.script = p_script.ptr();
codegen.function_node = p_func;
codegen.stack_max = 0;
codegen.current_line = 0;
@@ -1853,7 +1853,7 @@ Error GDScriptCompiler::_parse_function(GDScript *p_script, const GDScriptParser
return OK;
}
-Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+Error GDScriptCompiler::_parse_class_level(Ref<GDScript> p_script, Ref<GDScript> p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
if (p_class->owner && p_class->owner->owner) {
// Owner is not root
@@ -1887,7 +1887,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
p_script->initializer = NULL;
p_script->subclasses.clear();
- p_script->_owner = p_owner;
+ p_script->_owner = p_owner.ptr();
p_script->tool = p_class->tool;
p_script->name = p_class->name;
@@ -1994,7 +1994,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
StringName name = p_class->_signals[i].name;
- GDScript *c = p_script;
+ GDScript *c = p_script.ptr();
while (c) {
@@ -2054,7 +2054,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
return OK;
}
-Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+Error GDScriptCompiler::_parse_class_blocks(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
//parse methods
bool has_initializer = false;
@@ -2159,7 +2159,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
return OK;
}
-void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+void GDScriptCompiler::_make_scripts(const Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
Map<StringName, Ref<GDScript> > old_subclasses;
@@ -2178,20 +2178,20 @@ void GDScriptCompiler::_make_scripts(const GDScript *p_script, const GDScriptPar
subclass.instance();
}
- subclass->_owner = const_cast<GDScript *>(p_script);
+ subclass->_owner = const_cast<GDScript *>(p_script.ptr());
class_map.insert(name, subclass);
_make_scripts(subclass.ptr(), p_class->subclasses[i], p_keep_state);
}
}
-Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state) {
+Error GDScriptCompiler::compile(const GDScriptParser *p_parser, Ref<GDScript> p_script, bool p_keep_state) {
err_line = -1;
err_column = -1;
error = "";
parser = p_parser;
- main_script = p_script;
+ main_script = p_script.ptr();
const GDScriptParser::Node *root = parser->get_parse_tree();
ERR_FAIL_COND_V(root->type != GDScriptParser::Node::TYPE_CLASS, ERR_INVALID_DATA);
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 55f5e2b48e..23c6450aa7 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -148,17 +148,17 @@ class GDScriptCompiler {
int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level);
int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false);
Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1);
- Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
- Error _parse_class_level(GDScript *p_script, GDScript *p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
- Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
- void _make_scripts(const GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ Error _parse_function(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
+ Error _parse_class_level(Ref<GDScript> p_script, Ref<GDScript> p_owner, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ Error _parse_class_blocks(Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ void _make_scripts(const Ref<GDScript> p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
int err_line;
int err_column;
StringName source;
String error;
public:
- Error compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state = false);
+ Error compile(const GDScriptParser *p_parser, Ref<GDScript> p_script, bool p_keep_state = false);
String get_error() const;
int get_error_line() const;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index ddd9e6b01c..2ce92f340d 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1999,7 +1999,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionContext &p_context
if (!_static) {
List<MethodInfo> methods;
- ClassDB::get_method_list(type, &methods, false, true);
+ bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize();
+ ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters);
for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
if (E->get().name.begins_with("_")) {
continue;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index f09ff224e8..31115a4bd9 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -275,7 +275,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#endif
uint32_t alloca_size = 0;
- GDScript *_class;
+ GDScript *script;
int ip = 0;
int line = _initial_line;
@@ -286,7 +286,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
line = p_state->line;
ip = p_state->ip;
alloca_size = p_state->stack.size();
- _class = p_state->_class;
+ script = p_state->script.ptr();
p_instance = p_state->instance;
defarg = p_state->defarg;
self = p_state->self;
@@ -368,9 +368,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else {
self = p_instance->owner;
}
- _class = p_instance->script.ptr();
+ script = p_instance->script.ptr();
} else {
- _class = _script;
+ script = this->_script.ptr();
}
}
@@ -395,7 +395,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text); \
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, stack, err_text); \
if (unlikely(!m_v)) \
OPCODE_BREAK;
@@ -404,7 +404,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define CHECK_SPACE(m_space)
#define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
- m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, _class, self, stack, err_text);
+ m_v = _get_variant(_code_ptr[ip + m_code_ofs], p_instance, script, self, stack, err_text);
#endif
@@ -1185,7 +1185,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GET_VARIANT_PTR(dst, argc + 3);
- const GDScript *gds = _script;
+ const GDScript *gds = _script.ptr();
const Map<StringName, GDScriptFunction *>::Element *E = NULL;
while (gds->base.ptr()) {
@@ -1256,11 +1256,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->state.stack_size = _stack_size;
gdfs->state.self = self;
gdfs->state.alloca_size = alloca_size;
- gdfs->state._class = _class;
+ gdfs->state.script = _script;
gdfs->state.ip = ip + ipofs;
gdfs->state.line = line;
gdfs->state.instance_id = (p_instance && p_instance->get_owner()) ? p_instance->get_owner()->get_instance_id() : 0;
- gdfs->state.script_id = _class->get_instance_id();
//gdfs->state.result_pos=ip+ipofs-1;
gdfs->state.defarg = defarg;
gdfs->state.instance = p_instance;
@@ -1549,8 +1548,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
String err_file;
if (p_instance)
err_file = p_instance->script->path;
- else if (_class)
- err_file = _class->path;
+ else if (script)
+ err_file = script->path;
if (err_file == "")
err_file = "<built-in>";
String err_func = name;
@@ -1765,15 +1764,20 @@ GDScriptFunction::~GDScriptFunction() {
Variant GDScriptFunctionState::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
#ifdef DEBUG_ENABLED
- if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
- ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ // Checking this first since it's faster
+ if (!state.script.is_valid()) {
+ ERR_EXPLAIN("Resumed after yield, but script is gone");
ERR_FAIL_V(Variant());
}
- if (state.script_id && !ObjectDB::get_instance(state.script_id)) {
- ERR_EXPLAIN("Resumed after yield, but script is gone");
+ if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
+ ERR_EXPLAIN("Resumed after yield, but class instance is gone");
ERR_FAIL_V(Variant());
}
+#else
+ if (!is_valid()) {
+ return Variant();
+ }
#endif
Variant arg;
@@ -1841,12 +1845,12 @@ bool GDScriptFunctionState::is_valid(bool p_extended_check) const {
return false;
if (p_extended_check) {
+ //script gone? (checking this first since it's faster)
+ if (!state.script.is_valid())
+ return false;
//class instance gone?
if (state.instance_id && !ObjectDB::get_instance(state.instance_id))
return false;
- //script gone?
- if (state.script_id && !ObjectDB::get_instance(state.script_id))
- return false;
}
return true;
@@ -1856,13 +1860,14 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
ERR_FAIL_COND_V(!function, Variant());
#ifdef DEBUG_ENABLED
- if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
- ERR_EXPLAIN("Resumed after yield, but class instance is gone");
+ // Checking this first since it's faster
+ if (!state.script.is_valid()) {
+ ERR_EXPLAIN("Resumed after yield, but script is gone");
ERR_FAIL_V(Variant());
}
- if (state.script_id && !ObjectDB::get_instance(state.script_id)) {
- ERR_EXPLAIN("Resumed after yield, but script is gone");
+ if (state.instance_id && !ObjectDB::get_instance(state.instance_id)) {
+ ERR_EXPLAIN("Resumed after yield, but class instance is gone");
ERR_FAIL_V(Variant());
}
#endif
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index bfb6d673f1..a47070de4f 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -225,7 +225,7 @@ private:
bool _static;
MultiplayerAPI::RPCMode rpc_mode;
- GDScript *_script;
+ Ref<GDScript> _script;
StringName name;
Vector<Variant> constants;
@@ -272,15 +272,13 @@ private:
public:
struct CallState {
- ObjectID instance_id; //by debug only
- ObjectID script_id;
-
+ ObjectID instance_id;
GDScriptInstance *instance;
Vector<uint8_t> stack;
int stack_size;
Variant self;
uint32_t alloca_size;
- GDScript *_class;
+ Ref<GDScript> script;
int ip;
int line;
int defarg;
@@ -299,7 +297,7 @@ public:
int get_default_argument_addr(int p_idx) const;
GDScriptDataType get_return_type() const;
GDScriptDataType get_argument_type(int p_idx) const;
- GDScript *get_script() const { return _script; }
+ GDScript *get_script() const { return const_cast<GDScript *>(_script.ptr()); }
StringName get_source() const { return source; }
void debug_get_stack_member_state(int p_line, List<Pair<StringName, int> > *r_stackvars) const;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 5f2655eb92..97ac6f7de6 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -6709,9 +6709,15 @@ GDScriptParser::DataType GDScriptParser::_reduce_function_call_type(const Operat
}
}
+ bool rets = false;
return_type.has_type = true;
return_type.kind = DataType::BUILTIN;
- return_type.builtin_type = Variant::get_method_return_type(base_type.builtin_type, callee_name);
+ return_type.builtin_type = Variant::get_method_return_type(base_type.builtin_type, callee_name, &rets);
+ // If the method returns, but it might return any type, (Variant::NIL), pretend we don't know the type.
+ // At least make sure we know that it returns
+ if (rets && return_type.builtin_type == Variant::NIL) {
+ return_type.has_type = false;
+ }
break;
}
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index a49137ae73..24d40111cf 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -48,9 +48,9 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
const int image_width = decoder.get_width();
const int image_height = decoder.get_height();
- int comps = decoder.get_num_components();
- if (comps == 3)
- comps = 4; //weird
+ const int comps = decoder.get_num_components();
+ if (comps != 1 && comps != 3)
+ return ERR_FILE_CORRUPT;
if (decoder.begin_decoding() != jpgd::JPGD_SUCCESS)
return ERR_FILE_CORRUPT;
@@ -73,7 +73,19 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
}
jpgd::uint8 *pDst = pImage_data + y * dst_bpl;
- memcpy(pDst, pScan_line, dst_bpl);
+
+ if (comps == 1) {
+ memcpy(pDst, pScan_line, dst_bpl);
+ } else {
+ // For images with more than 1 channel pScan_line will always point to a buffer
+ // containing 32-bit RGBA pixels. Alpha is always 255 and we ignore it.
+ for (int x = 0; x < image_width; x++) {
+ pDst[0] = pScan_line[x * 4 + 0];
+ pDst[1] = pScan_line[x * 4 + 1];
+ pDst[2] = pScan_line[x * 4 + 2];
+ pDst += 3;
+ }
+ }
}
//all good
@@ -82,7 +94,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
if (comps == 1)
fmt = Image::FORMAT_L8;
else
- fmt = Image::FORMAT_RGBA8;
+ fmt = Image::FORMAT_RGB8;
dw = PoolVector<uint8_t>::Write();
p_image->create(image_width, image_height, 0, fmt, data);
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 0c4433112d..4d88cca6f1 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -191,7 +191,6 @@ void GDMono::initialize() {
String hint_config_dir = path_join(locations[i], "etc");
if (FileAccess::exists(hint_mscorlib_path) && DirAccess::exists(hint_config_dir)) {
- need_set_mono_dirs = false;
assembly_rootdir = hint_assembly_rootdir;
config_dir = hint_config_dir;
break;
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index ad4a758c0f..db02162699 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -71,6 +71,9 @@ int EMWSServer::get_peer_port(int p_peer_id) const {
void EMWSServer::disconnect_peer(int p_peer_id, int p_code, String p_reason) {
}
+void EMWSServer::poll() {
+}
+
EMWSServer::EMWSServer() {
}
diff --git a/modules/websocket/lws_client.cpp b/modules/websocket/lws_client.cpp
index add3931b50..d71d091720 100644
--- a/modules/websocket/lws_client.cpp
+++ b/modules/websocket/lws_client.cpp
@@ -34,10 +34,6 @@
#include "core/io/stream_peer_ssl.h"
#include "tls/mbedtls/wrapper/include/openssl/ssl.h"
-#if defined(MINGW_ENABLED) || defined(_MSC_VER)
-#define strncpy strncpy_s
-#endif
-
Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, PoolVector<String> p_protocols) {
ERR_FAIL_COND_V(context != NULL, FAILED);
@@ -80,26 +76,11 @@ Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
ERR_FAIL_V(FAILED);
}
- char abuf[1024];
- char hbuf[1024];
- char pbuf[2048];
- String addr_str = (String)addr;
- strncpy(abuf, addr_str.ascii().get_data(), 1023);
- abuf[1023] = '\0';
- strncpy(hbuf, p_host.utf8().get_data(), 1023);
- hbuf[1023] = '\0';
- strncpy(pbuf, p_path.utf8().get_data(), 2047);
- pbuf[2047] = '\0';
-
i.context = context;
if (p_protocols.size() > 0)
i.protocol = _lws_ref->lws_names;
else
i.protocol = NULL;
- i.address = abuf;
- i.host = hbuf;
- i.path = pbuf;
- i.port = p_port;
if (p_ssl) {
i.ssl_connection = LCCSCF_USE_SSL;
@@ -109,7 +90,16 @@ Error LWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
i.ssl_connection = 0;
}
+ // This String needs to survive till we call lws_client_connect_via_info
+ String addr_str = (String)addr;
+
+ i.address = addr_str.ascii().get_data();
+ i.host = p_host.utf8().get_data();
+ i.path = p_path.utf8().get_data();
+ i.port = p_port;
+
lws_client_connect_via_info(&i);
+
return OK;
};
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 30bc413459..8e050c1d27 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -586,7 +586,7 @@ Error OS_Android::shell_open(String p_uri) {
String OS_Android::get_resource_dir() const {
- return "/"; //android has it's own filesystem for resources inside the APK
+ return "/"; //android has its own filesystem for resources inside the APK
}
String OS_Android::get_locale() const {
diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js
index c3ef5bbbb5..91458eb4c3 100644
--- a/platform/javascript/engine.js
+++ b/platform/javascript/engine.js
@@ -1,3 +1,6 @@
+ // The following is concatenated with generated code, and acts as the end
+ // of a wrapper for said code. See pre.js for the other part of the
+ // wrapper.
exposedLibs['PATH'] = PATH;
exposedLibs['FS'] = FS;
return Module;
diff --git a/platform/javascript/pre.js b/platform/javascript/pre.js
index 02194bc75e..a870e676ea 100644
--- a/platform/javascript/pre.js
+++ b/platform/javascript/pre.js
@@ -1,2 +1,5 @@
var Engine = {
RuntimeEnvironment: function(Module, exposedLibs) {
+ // The above is concatenated with generated code, and acts as the start of
+ // a wrapper for said code. See engine.js for the other part of the
+ // wrapper.
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 6ab433203f..70b49805d2 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -100,12 +100,13 @@ static int prev_mouse_y = 0;
static int button_mask = 0;
static bool mouse_down_control = false;
-static Vector2 get_mouse_pos(NSEvent *event) {
+static Vector2 get_mouse_pos(NSPoint locationInWindow, CGFloat backingScaleFactor) {
const NSRect contentRect = [OS_OSX::singleton->window_view frame];
- const NSPoint p = [event locationInWindow];
- mouse_x = p.x * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
- mouse_y = (contentRect.size.height - p.y) * OS_OSX::singleton->_mouse_scale([[event window] backingScaleFactor]);
+ const NSPoint p = locationInWindow;
+ const float s = OS_OSX::singleton->_mouse_scale(backingScaleFactor);
+ mouse_x = p.x * s;
+ mouse_y = (contentRect.size.height - p.y) * s;
return Vector2(mouse_x, mouse_y);
}
@@ -325,6 +326,13 @@ static Vector2 get_mouse_pos(NSEvent *event) {
- (void)windowDidBecomeKey:(NSNotification *)notification {
//_GodotInputWindowFocus(window, GL_TRUE);
//_GodotPlatformSetCursorMode(window, window->cursorMode);
+ [OS_OSX::singleton->context update];
+
+ get_mouse_pos(
+ [OS_OSX::singleton->window_object mouseLocationOutsideOfEventStream],
+ [OS_OSX::singleton->window_view backingScaleFactor]);
+ OS_OSX::singleton->input->set_mouse_position(Point2(mouse_x, mouse_y));
+
if (OS_OSX::singleton->get_main_loop())
OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
}
@@ -593,12 +601,13 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
mm->set_button_mask(button_mask);
prev_mouse_x = mouse_x;
prev_mouse_y = mouse_y;
- const Vector2 pos = get_mouse_pos(event);
+ const CGFloat backingScaleFactor = [[event window] backingScaleFactor];
+ const Vector2 pos = get_mouse_pos([event locationInWindow], backingScaleFactor);
mm->set_position(pos);
mm->set_global_position(pos);
Vector2 relativeMotion = Vector2();
- relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]);
- relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale([[event window] backingScaleFactor]);
+ relativeMotion.x = [event deltaX] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor);
+ relativeMotion.y = [event deltaY] * OS_OSX::singleton -> _mouse_scale(backingScaleFactor);
mm->set_relative(relativeMotion);
get_key_modifier_state([event modifierFlags], mm);
@@ -681,7 +690,7 @@ static void _mouseDownEvent(NSEvent *event, int index, int mask, bool pressed) {
Ref<InputEventMagnifyGesture> ev;
ev.instance();
get_key_modifier_state([event modifierFlags], ev);
- ev->set_position(get_mouse_pos(event));
+ ev->set_position(get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]));
ev->set_factor([event magnification] + 1.0);
OS_OSX::singleton->push_input(ev);
}
@@ -1073,6 +1082,8 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) {
- (void)scrollWheel:(NSEvent *)event {
double deltaX, deltaY;
+ get_mouse_pos([event locationInWindow], [[event window] backingScaleFactor]);
+
deltaX = [event scrollingDeltaX];
deltaY = [event scrollingDeltaY];
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 7c4c8f0eff..88c2c8aec6 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -2095,7 +2095,7 @@ void OS_X11::process_xevents() {
last_timestamp = event.xkey.time;
// key event is a little complex, so
- // it will be handled in it's own function.
+ // it will be handled in its own function.
handle_key_event((XKeyEvent *)&event);
} break;
case SelectionRequest: {
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index 4bff26a200..2dc500f7ab 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -38,14 +38,14 @@
void ARVRCamera::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
- // need to find our ARVROrigin parent and let it know we're it's camera!
+ // need to find our ARVROrigin parent and let it know we're its camera!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin != NULL) {
origin->set_tracked_camera(this);
}
}; break;
case NOTIFICATION_EXIT_TREE: {
- // need to find our ARVROrigin parent and let it know we're no longer it's camera!
+ // need to find our ARVROrigin parent and let it know we're no longer its camera!
ARVROrigin *origin = Object::cast_to<ARVROrigin>(get_parent());
if (origin != NULL) {
origin->clear_tracked_camera_if(this);
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 67fb658562..d6690676cc 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -62,7 +62,7 @@ public:
};
/*
- ARVRController is a helper node that automatically updates it's position based on tracker data.
+ ARVRController is a helper node that automatically updates its position based on tracker data.
It must be a child node of our ARVROrigin node
*/
@@ -102,7 +102,7 @@ public:
};
/*
- ARVRAnchor is a helper node that automatically updates it's position based on anchor data, it represents a real world location.
+ ARVRAnchor is a helper node that automatically updates its position based on anchor data, it represents a real world location.
It must be a child node of our ARVROrigin node
*/
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 7e1d60ab8e..11d61315ba 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -163,11 +163,6 @@ void Light::_update_visibility() {
if (!is_inside_tree())
return;
- // FIXME: Since the call to VS::instance_light_set_enabled was disabled below,
- // the whole logic became pointless so editor_ok triggers unused variable warnings.
- // Commenting out for now but this should be fixed/reimplemented so that editor_only
- // works as expected (GH-17989).
- /*
bool editor_ok = true;
#ifdef TOOLS_ENABLED
@@ -184,8 +179,8 @@ void Light::_update_visibility() {
}
#endif
- //VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible_in_tree() && editor_ok);
- */
+ VS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree() && editor_ok);
+
_change_notify("geometry/visible");
}
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 4cbf6f2de3..cf0317cd58 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -253,6 +253,11 @@ void MeshInstance::_notification(int p_what) {
}
}
+int MeshInstance::get_surface_material_count() const {
+
+ return materials.size();
+}
+
void MeshInstance::set_surface_material(int p_surface, const Ref<Material> &p_material) {
ERR_FAIL_INDEX(p_surface, materials.size());
@@ -359,6 +364,7 @@ void MeshInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path);
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path);
+ ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count);
ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material);
ClassDB::bind_method(D_METHOD("get_surface_material", "surface"), &MeshInstance::get_surface_material);
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 0dfec538f9..0b5b4b9e7b 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -76,6 +76,7 @@ public:
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
+ int get_surface_material_count() const;
void set_surface_material(int p_surface, const Ref<Material> &p_material);
Ref<Material> get_surface_material(int p_surface) const;
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index e37efa0e8a..339a434a6e 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -43,6 +43,16 @@ void Path::_curve_changed() {
if (is_inside_tree()) {
emit_signal("curve_changed");
}
+
+ // update the configuration warnings of all children of type OrientedPathFollows
+ if (is_inside_tree()) {
+ for (int i = 0; i < get_child_count(); i++) {
+ OrientedPathFollow *child = Object::cast_to<OrientedPathFollow>(get_child(i));
+ if (child) {
+ child->update_configuration_warning();
+ }
+ }
+ }
}
void Path::set_curve(const Ref<Curve3D> &p_curve) {
@@ -207,6 +217,18 @@ void PathFollow::_validate_property(PropertyInfo &property) const {
}
}
+String PathFollow::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!Object::cast_to<Path>(get_parent())) {
+ return TTR("PathFollow only works when set as a child of a Path node.");
+ }
+
+ return String();
+}
+
void PathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &PathFollow::set_offset);
@@ -444,6 +466,23 @@ void OrientedPathFollow::_validate_property(PropertyInfo &property) const {
}
}
+String OrientedPathFollow::get_configuration_warning() const {
+
+ if (!is_visible_in_tree() || !is_inside_tree())
+ return String();
+
+ if (!Object::cast_to<Path>(get_parent())) {
+ return TTR("OrientedPathFollow only works when set as a child of a Path node.");
+ } else {
+ Path *path = Object::cast_to<Path>(get_parent());
+ if (path->get_curve().is_valid() && !path->get_curve()->is_up_vector_enabled()) {
+ return TTR("OrientedPathFollow requires up vectors enabled in its parent Path.");
+ }
+ }
+
+ return String();
+}
+
void OrientedPathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &OrientedPathFollow::set_offset);
diff --git a/scene/3d/path.h b/scene/3d/path.h
index f73bf17dfe..beb37d9714 100644
--- a/scene/3d/path.h
+++ b/scene/3d/path.h
@@ -106,6 +106,8 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
+ String get_configuration_warning() const;
+
PathFollow();
};
@@ -151,6 +153,8 @@ public:
void set_cubic_interpolation(bool p_enable);
bool get_cubic_interpolation() const;
+ String get_configuration_warning() const;
+
OrientedPathFollow();
};
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 541f6047d9..0eccbbc8f9 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -261,7 +261,7 @@ static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3
void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
if (p_level == cell_subdiv - 1) {
- //plot the face by guessing it's albedo and emission value
+ //plot the face by guessing its albedo and emission value
//find best axis to map to, for scanning values
int closest_axis = 0;
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 934b84ec0c..c13964d196 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -236,8 +236,8 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
//Snap to nearest point if holding shift
if (mm->get_shift()) {
- float snap_treshhold = 0.03;
- float smallest_ofs = snap_treshhold;
+ float snap_threshold = 0.03;
+ float smallest_ofs = snap_threshold;
bool found = false;
int nearest_point = 0;
for (int i = 0; i < points.size(); ++i) {
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 6f344f1028..c4373876b1 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -1608,6 +1608,8 @@ LineEdit::LineEdit() {
text_changed_dirty = false;
placeholder_alpha = 0.6;
clear_button_enabled = false;
+ clear_button_status.press_attempt = false;
+ clear_button_status.pressing_inside = false;
deselect();
set_focus_mode(FOCUS_ALL);
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index c56b7d0f26..b7f8c74046 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -106,41 +106,8 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
}
}
- // test hovering to display right or close button
- int hover_now = -1;
- int hover_buttons = -1;
- for (int i = 0; i < tabs.size(); i++) {
-
- if (i < offset)
- continue;
-
- Rect2 rect = get_tab_rect(i);
- if (rect.has_point(pos)) {
- hover_now = i;
- }
- if (tabs[i].rb_rect.has_point(pos)) {
- rb_hover = i;
- cb_hover = -1;
- hover_buttons = i;
- break;
- } else if (!tabs[i].disabled && tabs[i].cb_rect.has_point(pos)) {
- cb_hover = i;
- rb_hover = -1;
- hover_buttons = i;
- break;
- }
- }
- if (hover != hover_now) {
- hover = hover_now;
- emit_signal("tab_hover", hover);
- }
-
- if (hover_buttons == -1) { // no hover
- rb_hover = hover_buttons;
- cb_hover = hover_buttons;
- }
+ _update_hover();
update();
-
return;
}
@@ -522,6 +489,48 @@ Ref<Texture> Tabs::get_tab_right_button(int p_tab) const {
return tabs[p_tab].right_button;
}
+void Tabs::_update_hover() {
+
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ const Point2 &pos = get_local_mouse_position();
+ // test hovering to display right or close button
+ int hover_now = -1;
+ int hover_buttons = -1;
+ for (int i = 0; i < tabs.size(); i++) {
+
+ if (i < offset)
+ continue;
+
+ Rect2 rect = get_tab_rect(i);
+ if (rect.has_point(pos)) {
+ hover_now = i;
+ }
+ if (tabs[i].rb_rect.has_point(pos)) {
+ rb_hover = i;
+ cb_hover = -1;
+ hover_buttons = i;
+ break;
+ } else if (!tabs[i].disabled && tabs[i].cb_rect.has_point(pos)) {
+ cb_hover = i;
+ rb_hover = -1;
+ hover_buttons = i;
+ break;
+ }
+ }
+ if (hover != hover_now) {
+ hover = hover_now;
+ emit_signal("tab_hover", hover);
+ }
+
+ if (hover_buttons == -1) { // no hover
+ rb_hover = hover_buttons;
+ cb_hover = hover_buttons;
+ }
+}
+
void Tabs::_update_cache() {
Ref<StyleBox> tab_disabled = get_stylebox("tab_disabled");
Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
@@ -597,6 +606,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) {
tabs.push_back(t);
_update_cache();
+ call_deferred("_update_hover");
update();
minimum_size_changed();
}
@@ -604,6 +614,7 @@ void Tabs::add_tab(const String &p_str, const Ref<Texture> &p_icon) {
void Tabs::clear_tabs() {
tabs.clear();
current = 0;
+ call_deferred("_update_hover");
update();
}
@@ -614,6 +625,7 @@ void Tabs::remove_tab(int p_idx) {
if (current >= p_idx)
current--;
_update_cache();
+ call_deferred("_update_hover");
update();
minimum_size_changed();
@@ -931,6 +943,7 @@ bool Tabs::get_select_with_rmb() const {
void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input);
+ ClassDB::bind_method(D_METHOD("_update_hover"), &Tabs::_update_hover);
ClassDB::bind_method(D_METHOD("get_tab_count"), &Tabs::get_tab_count);
ClassDB::bind_method(D_METHOD("set_current_tab", "tab_idx"), &Tabs::set_current_tab);
ClassDB::bind_method(D_METHOD("get_current_tab"), &Tabs::get_current_tab);
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index e204f4364b..a98744b804 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -97,6 +97,8 @@ private:
int get_tab_width(int p_idx) const;
void _ensure_no_over_offset();
+
+ void _update_hover();
void _update_cache();
protected:
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 8fd7dc1d7b..50e94e6db5 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -2192,7 +2192,7 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const {
if (p_copy->has_node(ptarget))
copytarget = p_copy->get_node(ptarget);
- if (copy && copytarget) {
+ if (copy && copytarget && !copy->is_connected(E->get().signal, copytarget, E->get().method)) {
copy->connect(E->get().signal, copytarget, E->get().method, E->get().binds, E->get().flags);
}
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 086fb83af9..42ce9d10cd 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -264,7 +264,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
}
if (n.instance >= 0 || n.type != TYPE_INSTANCED || i == 0) {
- //if node was not part of instance, must set it's name, parenthood and ownership
+ //if node was not part of instance, must set its name, parenthood and ownership
if (i > 0) {
if (parent) {
parent->_add_child_nocheck(node, snames[n.name]);
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp
index 7de0695e8c..02a0bed964 100644
--- a/servers/audio/audio_stream.cpp
+++ b/servers/audio/audio_stream.cpp
@@ -136,16 +136,20 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer();
unsigned int input_size = AudioDriver::get_singleton()->get_input_size();
+ int mix_rate = AudioDriver::get_singleton()->get_mix_rate();
+ int playback_delay = MIN(((50 * mix_rate) / 1000) * 2, buf.size() >> 1);
+#ifdef DEBUG_ENABLED
+ unsigned int input_position = AudioDriver::get_singleton()->get_input_position();
+#endif
- // p_frames is multiplied by two since an AudioFrame is stereo
- if ((p_frames + MICROPHONE_PLAYBACK_DELAY * 2) > input_size) {
+ if (playback_delay > input_size) {
for (int i = 0; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0.0f, 0.0f);
}
input_ofs = 0;
} else {
for (int i = 0; i < p_frames; i++) {
- if (input_size >= input_ofs) {
+ if (input_size > input_ofs) {
float l = (buf[input_ofs++] >> 16) / 32768.f;
if (input_ofs >= buf.size()) {
input_ofs = 0;
@@ -162,6 +166,12 @@ void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_fr
}
}
+#ifdef DEBUG_ENABLED
+ if (input_ofs > input_position && (input_ofs - input_position) < (p_frames * 2)) {
+ print_verbose(String(get_class_name()) + " buffer underrun: input_position=" + itos(input_position) + " input_ofs=" + itos(input_ofs) + " input_size=" + itos(input_size));
+ }
+#endif
+
AudioDriver::get_singleton()->unlock();
}
diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h
index 2740f86d55..f6ed45cc9c 100644
--- a/servers/audio/audio_stream.h
+++ b/servers/audio/audio_stream.h
@@ -122,8 +122,6 @@ class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled {
GDCLASS(AudioStreamPlaybackMicrophone, AudioStreamPlayback)
friend class AudioStreamMicrophone;
- static const int MICROPHONE_PLAYBACK_DELAY = 256;
-
bool active;
unsigned int input_ofs;
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index d36057b465..37454d9253 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -80,6 +80,14 @@ double AudioDriver::get_mix_time() const {
return total;
}
+void AudioDriver::input_buffer_init(int driver_buffer_frames) {
+
+ const int input_buffer_channels = 2;
+ input_buffer.resize(driver_buffer_frames * input_buffer_channels * 4);
+ input_position = 0;
+ input_size = 0;
+}
+
void AudioDriver::input_buffer_write(int32_t sample) {
input_buffer.write[input_position++] = sample;
diff --git a/servers/audio_server.h b/servers/audio_server.h
index ba6569eb38..b12ca6e589 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -59,6 +59,7 @@ protected:
void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true);
void update_mix_time(int p_frames);
+ void input_buffer_init(int driver_buffer_frames);
void input_buffer_write(int32_t sample);
#ifdef DEBUG_ENABLED
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index 087ae570fb..f17f6f7014 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -98,7 +98,6 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 c = rel_A.cross(rel_B).cross(rel_B);
- //if ( Math::abs(rel_A.dot(c) )<_EDGE_IS_VALID_SUPPORT_TRESHOLD ) {
if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) {
// should handle somehow..