summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/bind/core_bind.cpp1
-rw-r--r--core/bind/core_bind.h1
-rw-r--r--core/hash_map.h4
-rw-r--r--core/io/file_access_network.cpp4
-rw-r--r--core/io/file_access_network.h1
-rw-r--r--core/io/logger.cpp4
-rw-r--r--core/io/resource_format_binary.cpp2
-rw-r--r--core/message_queue.cpp1
-rw-r--r--core/project_settings.cpp86
-rw-r--r--core/register_core_types.cpp1
-rw-r--r--core/script_debugger_remote.cpp2
-rw-r--r--core/ustring.cpp17
-rw-r--r--doc/classes/AudioServer.xml2
-rw-r--r--doc/classes/GridContainer.xml10
-rw-r--r--doc/classes/Input.xml2
-rw-r--r--doc/classes/KinematicBody2D.xml2
-rw-r--r--doc/classes/MeshInstance.xml6
-rw-r--r--doc/classes/NavigationPolygon.xml33
-rw-r--r--doc/classes/NetworkedMultiplayerPeer.xml2
-rw-r--r--doc/classes/Node.xml18
-rw-r--r--doc/classes/PackedScene.xml17
-rw-r--r--doc/classes/PathFollow2D.xml1
-rw-r--r--doc/classes/PhysicsServer.xml2
-rw-r--r--doc/classes/ProjectSettings.xml17
-rw-r--r--doc/classes/ResourceSaver.xml2
-rw-r--r--doc/classes/StreamPeerTCP.xml3
-rw-r--r--doc/classes/SurfaceTool.xml4
-rw-r--r--doc/classes/TabContainer.xml6
-rw-r--r--doc/classes/Tabs.xml20
-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.cpp207
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.h4
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp2
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp5
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp12
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h1
-rw-r--r--drivers/gles2/shaders/copy.glsl22
-rw-r--r--drivers/gles2/shaders/scene.glsl9
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp5
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp17
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp2
-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/rtaudio/audio_driver_rtaudio.cpp11
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp5
-rw-r--r--drivers/windows/file_access_windows.cpp4
-rw-r--r--editor/animation_track_editor.cpp2
-rw-r--r--editor/code_editor.cpp2
-rw-r--r--editor/editor_autoload_settings.cpp2
-rw-r--r--editor/editor_file_dialog.cpp25
-rw-r--r--editor/editor_inspector.cpp6
-rw-r--r--editor/editor_node.cpp12
-rw-r--r--editor/editor_properties.cpp38
-rw-r--r--editor/filesystem_dock.cpp36
-rw-r--r--editor/filesystem_dock.h2
-rw-r--r--editor/icons/icon_GUI_viewport_hdiagsplitter.svg67
-rw-r--r--editor/icons/icon_GUI_viewport_vdiagsplitter.svg73
-rw-r--r--editor/icons/icon_GUI_viewport_vhsplitter.svg66
-rw-r--r--editor/icons/icon_script_extend.svg8
-rw-r--r--editor/plugin_config_dialog.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp24
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp3
-rw-r--r--editor/plugins/camera_editor_plugin.cpp12
-rw-r--r--editor/plugins/camera_editor_plugin.h1
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp31
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h2
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp53
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp30
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp38
-rw-r--r--editor/plugins/script_editor_plugin.cpp10
-rw-r--r--editor/plugins/script_text_editor.cpp32
-rw-r--r--editor/plugins/spatial_editor_plugin.cpp166
-rw-r--r--editor/plugins/spatial_editor_plugin.h3
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp66
-rw-r--r--editor/property_editor.cpp14
-rw-r--r--editor/scene_tree_dock.cpp49
-rw-r--r--editor/scene_tree_dock.h4
-rw-r--r--editor/scene_tree_editor.cpp2
-rw-r--r--editor/script_editor_debugger.cpp2
-rw-r--r--editor/spatial_editor_gizmos.cpp3
-rw-r--r--main/input_default.cpp35
-rw-r--r--main/input_default.h1
-rw-r--r--main/main.cpp14
-rw-r--r--main/tests/test_string.cpp173
-rw-r--r--modules/csg/csg_shape.cpp5
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp3
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp18
-rw-r--r--modules/gdscript/gdscript.cpp5
-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/gdscript/gdscript_tokenizer.cpp2
-rw-r--r--modules/jpg/image_loader_jpegd.cpp22
-rw-r--r--modules/mono/SCsub3
-rw-r--r--modules/mono/editor/bindings_generator.cpp229
-rw-r--r--modules/mono/editor/bindings_generator.h29
-rw-r--r--modules/mono/editor/godotsharp_builds.cpp44
-rw-r--r--modules/mono/editor/godotsharp_editor.cpp33
-rw-r--r--modules/mono/editor/godotsharp_editor.h2
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp1
-rw-r--r--modules/mono/mono_gd/gd_mono_field.cpp316
-rw-r--r--modules/mono/mono_gd/gd_mono_header.h10
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.cpp317
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h285
-rw-r--r--modules/mono/utils/macros.h9
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml6
-rw-r--r--modules/visual_script/visual_script.cpp24
-rw-r--r--modules/visual_script/visual_script.h1
-rw-r--r--modules/visual_script/visual_script_nodes.cpp14
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp56
-rw-r--r--modules/websocket/emws_server.cpp3
-rw-r--r--modules/websocket/lws_client.cpp24
-rw-r--r--modules/websocket/websocket_multiplayer.cpp2
-rw-r--r--platform/android/java_glue.cpp2
-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/windows/context_gl_win.cpp24
-rw-r--r--platform/windows/joypad.cpp4
-rw-r--r--platform/windows/os_windows.cpp46
-rw-r--r--platform/x11/os_x11.cpp2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp2
-rw-r--r--scene/2d/node_2d.cpp6
-rw-r--r--scene/2d/node_2d.h2
-rw-r--r--scene/2d/tile_map.cpp2
-rw-r--r--scene/3d/arvr_nodes.cpp4
-rw-r--r--scene/3d/arvr_nodes.h4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp4
-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.cpp8
-rw-r--r--scene/gui/gradient_edit.cpp4
-rw-r--r--scene/gui/graph_edit.cpp12
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/gui/item_list.cpp1
-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/gui/text_edit.cpp5
-rw-r--r--scene/main/node.cpp2
-rw-r--r--scene/main/scene_tree.cpp3
-rw-r--r--scene/main/viewport.cpp5
-rw-r--r--scene/resources/convex_polygon_shape.cpp3
-rw-r--r--scene/resources/dynamic_font.cpp4
-rw-r--r--scene/resources/packed_scene.cpp2
-rw-r--r--scene/resources/style_box.cpp28
-rw-r--r--servers/audio/audio_stream.cpp16
-rw-r--r--servers/audio/audio_stream.h2
-rw-r--r--servers/audio/effects/reverb.cpp24
-rw-r--r--servers/audio_server.cpp9
-rw-r--r--servers/audio_server.h1
-rw-r--r--servers/physics/collision_solver_sat.cpp1
-rw-r--r--servers/physics/collision_solver_sw.cpp1
-rw-r--r--servers/physics/space_sw.cpp1
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp4
-rw-r--r--servers/physics_2d/space_2d_sw.cpp1
-rw-r--r--servers/visual/shader_language.cpp1
-rw-r--r--servers/visual/visual_server_canvas.cpp2
-rw-r--r--servers/visual_server.cpp1
170 files changed, 2325 insertions, 1382 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 02b8c71465..a3ff4bf13e 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -180,6 +180,7 @@ void _ResourceSaver::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_OMIT_EDITOR_PROPERTIES);
BIND_ENUM_CONSTANT(FLAG_SAVE_BIG_ENDIAN);
BIND_ENUM_CONSTANT(FLAG_COMPRESS);
+ BIND_ENUM_CONSTANT(FLAG_REPLACE_SUBRESOURCE_PATHS);
}
_ResourceSaver::_ResourceSaver() {
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 3a913e01ed..79403879ac 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -80,6 +80,7 @@ public:
FLAG_OMIT_EDITOR_PROPERTIES = 8,
FLAG_SAVE_BIG_ENDIAN = 16,
FLAG_COMPRESS = 32,
+ FLAG_REPLACE_SUBRESOURCE_PATHS = 64,
};
static _ResourceSaver *get_singleton() { return singleton; }
diff --git a/core/hash_map.h b/core/hash_map.h
index 8620edba73..3869cd3c36 100644
--- a/core/hash_map.h
+++ b/core/hash_map.h
@@ -150,7 +150,7 @@ private:
if (new_hash_table_power == -1)
return;
- Element **new_hash_table = memnew_arr(Element *, (1 << new_hash_table_power));
+ Element **new_hash_table = memnew_arr(Element *, ((uint64_t)1 << new_hash_table_power));
if (!new_hash_table) {
ERR_PRINT("Out of Memory");
@@ -230,7 +230,7 @@ private:
if (!p_t.hash_table || p_t.hash_table_power == 0)
return; /* not copying from empty table */
- hash_table = memnew_arr(Element *, 1 << p_t.hash_table_power);
+ hash_table = memnew_arr(Element *, (uint64_t)1 << p_t.hash_table_power);
hash_table_power = p_t.hash_table_power;
elements = p_t.elements;
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 6b6856dcc8..b9544ac166 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -500,8 +500,9 @@ uint64_t FileAccessNetwork::_get_modified_time(const String &p_file) {
void FileAccessNetwork::configure() {
GLOBAL_DEF("network/remote_fs/page_size", 65536);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/remote_fs/page_size", PropertyInfo(Variant::INT, "network/remote_fs/page_size", PROPERTY_HINT_RANGE, "1,65536,1,or_greater")); //is used as denominator and can't be zero
GLOBAL_DEF("network/remote_fs/page_read_ahead", 4);
- GLOBAL_DEF("network/remote_fs/max_pages", 20);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/remote_fs/page_read_ahead", PropertyInfo(Variant::INT, "network/remote_fs/page_read_ahead", PROPERTY_HINT_RANGE, "0,8,1,or_greater"));
}
FileAccessNetwork::FileAccessNetwork() {
@@ -519,7 +520,6 @@ FileAccessNetwork::FileAccessNetwork() {
nc->unlock_mutex();
page_size = GLOBAL_GET("network/remote_fs/page_size");
read_ahead = GLOBAL_GET("network/remote_fs/page_read_ahead");
- max_pages = GLOBAL_GET("network/remote_fs/max_pages");
last_activity_val = 0;
waiting_on_page = -1;
last_page = -1;
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index e32dcea990..c929e8446d 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -98,7 +98,6 @@ class FileAccessNetwork : public FileAccess {
int page_size;
int read_ahead;
- int max_pages;
mutable int waiting_on_page;
mutable int last_activity_val;
diff --git a/core/io/logger.cpp b/core/io/logger.cpp
index 051c02ab32..01755c8ee9 100644
--- a/core/io/logger.cpp
+++ b/core/io/logger.cpp
@@ -45,6 +45,10 @@
#endif
#endif
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define sprintf sprintf_s
+#endif
+
bool Logger::should_log(bool p_err) {
return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled);
}
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index e5741014a4..aa73d7bc5c 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -1309,7 +1309,7 @@ void ResourceFormatSaverBinaryInstance::write_variant(FileAccess *f, const Varia
case Variant::INT: {
int64_t val = p_property;
- if (val > 0x7FFFFFFF || val < -0x80000000) {
+ if (val > 0x7FFFFFFF || val < -(int64_t)0x80000000) {
f->store_32(VARIANT_INT64);
f->store_64(val);
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index 7f788c90a7..abfc73407a 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -338,6 +338,7 @@ MessageQueue::MessageQueue() {
buffer_end = 0;
buffer_max_used = 0;
buffer_size = GLOBAL_DEF_RST("memory/limits/message_queue/max_size_kb", DEFAULT_QUEUE_SIZE_KB);
+ ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/message_queue/max_size_kb", PropertyInfo(Variant::INT, "memory/limits/message_queue/max_size_kb", PROPERTY_HINT_RANGE, "0,2048,1,or_greater"));
buffer_size *= 1024;
buffer = memnew_arr(uint8_t, buffer_size);
}
diff --git a/core/project_settings.cpp b/core/project_settings.cpp
index 99a23bbee1..407bb78375 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;
@@ -1133,6 +1162,7 @@ ProjectSettings::ProjectSettings() {
custom_prop_info["rendering/quality/intended_usage/framebuffer_allocation"] = PropertyInfo(Variant::INT, "rendering/quality/intended_usage/framebuffer_allocation", PROPERTY_HINT_ENUM, "2D,2D Without Sampling,3D,3D Without Effects");
GLOBAL_DEF("debug/settings/profiler/max_functions", 16384);
+ custom_prop_info["debug/settings/profiler/max_functions"] = PropertyInfo(Variant::INT, "debug/settings/profiler/max_functions", PROPERTY_HINT_RANGE, "128,65535,1");
//assigning here, because using GLOBAL_GET on every block for compressing can be slow
Compression::zstd_long_distance_matching = GLOBAL_DEF("compression/formats/zstd/long_distance_matching", false);
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index b0023b4c26..430004bb96 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -199,6 +199,7 @@ void register_core_types() {
void register_core_settings() {
//since in register core types, globals may not e present
GLOBAL_DEF_RST("network/limits/packet_peer_stream/max_buffer_po2", (16));
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/packet_peer_stream/max_buffer_po2", PropertyInfo(Variant::INT, "network/limits/packet_peer_stream/max_buffer_po2", PROPERTY_HINT_RANGE, "0,64,1,or_greater"));
}
void register_core_singletons() {
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 3e984fae32..621a94ab1a 100644
--- a/core/script_debugger_remote.cpp
+++ b/core/script_debugger_remote.cpp
@@ -1100,7 +1100,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
eh.userdata = this;
add_error_handler(&eh);
- profile_info.resize(CLAMP(int(ProjectSettings::get_singleton()->get("debug/settings/profiler/max_functions")), 128, 65535));
+ profile_info.resize(GLOBAL_GET("debug/settings/profiler/max_functions"));
profile_info_ptrs.resize(profile_info.size());
}
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 28bbe1d834..1195cd0719 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -49,7 +49,7 @@
#endif
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
-#define snprintf _snprintf
+#define snprintf _snprintf_s
#endif
#define MAX_DIGITS 6
@@ -586,6 +586,8 @@ String String::camelcase_to_underscore(bool lowercase) const {
bool is_upper = cstr[i] >= A && cstr[i] <= Z;
bool is_number = cstr[i] >= '0' && cstr[i] <= '9';
bool are_next_2_lower = false;
+ bool is_next_lower = false;
+ bool is_next_number = false;
bool was_precedent_upper = cstr[i - 1] >= A && cstr[i - 1] <= Z;
bool was_precedent_number = cstr[i - 1] >= '0' && cstr[i - 1] <= '9';
@@ -593,7 +595,18 @@ String String::camelcase_to_underscore(bool lowercase) const {
are_next_2_lower = cstr[i + 1] >= a && cstr[i + 1] <= z && cstr[i + 2] >= a && cstr[i + 2] <= z;
}
- bool should_split = ((is_upper && !was_precedent_upper && !was_precedent_number) || (was_precedent_upper && is_upper && are_next_2_lower) || (is_number && !was_precedent_number));
+ if (i + 1 < this->size()) {
+ is_next_lower = cstr[i + 1] >= a && cstr[i + 1] <= z;
+ is_next_number = cstr[i + 1] >= '0' && cstr[i + 1] <= '9';
+ }
+
+ const bool a = is_upper && !was_precedent_upper && !was_precedent_number;
+ const bool b = was_precedent_upper && is_upper && are_next_2_lower;
+ const bool c = is_number && !was_precedent_number;
+ const bool can_break_number_letter = is_number && !was_precedent_number && is_next_lower;
+ const bool can_break_letter_number = !is_number && was_precedent_number && (is_next_lower || is_next_number);
+
+ bool should_split = a || b || c || can_break_number_letter || can_break_letter_number;
if (should_split) {
new_string += this->substr(start_index, i - start_index) + "_";
start_index = i;
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 37756bcfd8..8f654441b2 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -385,6 +385,8 @@
<constant name="SPEAKER_MODE_STEREO" value="0" enum="SpeakerMode">
Two or fewer speakers are detected.
</constant>
+ <constant name="SPEAKER_SURROUND_31" value="1" enum="SpeakerMode">
+ </constant>
<constant name="SPEAKER_SURROUND_51" value="2" enum="SpeakerMode">
A 5.1 channel surround setup detected.
</constant>
diff --git a/doc/classes/GridContainer.xml b/doc/classes/GridContainer.xml
index 8a8a9a2d24..346ab9d357 100644
--- a/doc/classes/GridContainer.xml
+++ b/doc/classes/GridContainer.xml
@@ -11,16 +11,6 @@
<demos>
</demos>
<methods>
- <method name="get_child_control_at_cell">
- <return type="Control">
- </return>
- <argument index="0" name="row" type="int">
- </argument>
- <argument index="1" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
</methods>
<members>
<member name="columns" type="int" setter="set_columns" getter="get_columns">
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/KinematicBody2D.xml b/doc/classes/KinematicBody2D.xml
index e48660a889..6511b2f182 100644
--- a/doc/classes/KinematicBody2D.xml
+++ b/doc/classes/KinematicBody2D.xml
@@ -116,7 +116,7 @@
</argument>
<description>
Moves the body while keeping it attached to slopes. Similar to [method move_and_slide].
- As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting[code]snap[/code] to[code](0, 0)[/code] or by using [method move_and_slide] instead.
+ As long as the [code]snap[/code] vector is in contact with the ground, the body will remain attached to the surface. This means you must disable snap in order to jump, for example. You can do this by setting [code]snap[/code] to [code](0, 0)[/code] or by using [method move_and_slide] instead.
</description>
</method>
<method name="test_move">
diff --git a/doc/classes/MeshInstance.xml b/doc/classes/MeshInstance.xml
index ef42726ca9..bcc9a7cad9 100644
--- a/doc/classes/MeshInstance.xml
+++ b/doc/classes/MeshInstance.xml
@@ -41,6 +41,12 @@
Returns the [Material] for a surface of the [Mesh] resource.
</description>
</method>
+ <method name="get_surface_material_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
<method name="set_surface_material">
<return type="void">
</return>
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/NetworkedMultiplayerPeer.xml b/doc/classes/NetworkedMultiplayerPeer.xml
index ea6fe6d11c..3b76861afd 100644
--- a/doc/classes/NetworkedMultiplayerPeer.xml
+++ b/doc/classes/NetworkedMultiplayerPeer.xml
@@ -92,7 +92,7 @@
</signals>
<constants>
<constant name="TRANSFER_MODE_UNRELIABLE" value="0" enum="TransferMode">
- Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [code]TRANSFER_MODE_UNRELIABLE_ORDERED[/code]. Use for non-critical data, and always consider whether the order matters.
+ Packets are not acknowledged, no resend attempts are made for lost packets. Packets may arrive in any order. Potentially faster than [code]TRANSFER_MODE_UNRELIABLE_ORDERED[/code]. Use for non-critical data, and always consider whether the order matters.
</constant>
<constant name="TRANSFER_MODE_UNRELIABLE_ORDERED" value="1" enum="TransferMode">
Packets are not acknowledged, no resend attempts are made for lost packets. Packets are received in the order they were sent in. Potentially faster than [code]TRANSFER_MODE_RELIABLE[/code]. Use for non-critical data or data that would be outdated if received late due to resend attempt(s) anyway, for example movement and positional data.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index a33ee5c363..19aa2e9f5e 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -179,6 +179,15 @@
If [code]owned[/code] is [code]true[/code], this method only finds nodes whose owner is this node. This is especially important for scenes instantiated through script, because those scenes don't have an owner.
</description>
</method>
+ <method name="find_parent" qualifiers="const">
+ <return type="Node">
+ </return>
+ <argument index="0" name="mask" type="String">
+ </argument>
+ <description>
+ Finds the first parent of the current node whose name matches [code]mask[/code] as in [method String.match] (i.e. case sensitive, but '*' matches zero or more characters and '?' matches any single character except '.'). Note that it does not match against the full path, just against individual node names.
+ </description>
+ </method>
<method name="get_child" qualifiers="const">
<return type="Node">
</return>
@@ -267,15 +276,6 @@
Returns the parent node of the current node, or an empty [code]Node[/code] if the node lacks a parent.
</description>
</method>
- <method name="find_parent" qualifiers="const">
- <return type="Node">
- </return>
- <argument index="0" name="mask" type="String">
- </argument>
- <description>
- Finds the first parent of the current node whose name matches [code]mask[/code] as in [method String.match] (i.e. case sensitive, but '*' matches zero or more characters and '?' matches any single character except '.'). Note that it does not match against the full path, just against individual node names.
- </description>
- </method>
<method name="get_path" qualifiers="const">
<return type="NodePath">
</return>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index 08df3f0ad6..19f85fae4c 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -6,10 +6,23 @@
<description>
A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself.
Can be used to save a node to a file. When saving, the node as well as all the node it owns get saved (see [code]owner[/code] property on [Node]). Note that the node doesn't need to own itself.
- Example of saving a node:
+ Example of saving a node with different owners: The following example creates 3 objects: [code]Node2D[/code] ([code]node[/code]), [code]RigidBody2D[/code] ([code]rigid[/code]) and [code]CollisionObject2D[/code] ([code]collision[/code]). [code]collision[/code] is a child of [code]rigid[/code] which is a child of [code]node[/code]. Only [code]rigid[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
[codeblock]
+ # create the objects
+ var node = Node2D.new()
+ var rigid = RigidBody2D.new()
+ var collision = CollisionShape2D.new()
+
+ # create the object hierachy
+ rigid.add_child(collision)
+ node.add_child(rigid)
+
+ # change owner of rigid, but not of collision
+ rigid.set_owner(node)
+
var scene = PackedScene.new()
- var result = scene.pack(child)
+ # only node and rigid are now packed
+ var result = scene.pack(node)
if result == OK:
ResourceSaver.save("res://path/name.scn", scene) # or user://...
[/codeblock]
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..3b7356ab39 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.
@@ -213,6 +213,8 @@
<member name="audio/mix_rate" type="int" setter="" getter="">
Mix rate used for audio. In general, it's better to not touch this and leave it to the host operating system.
</member>
+ <member name="audio/output_latency" type="int" setter="" getter="">
+ </member>
<member name="audio/video_delay_compensation_ms" type="int" setter="" getter="">
Setting to hardcode audio delay when playing video. Best to leave this untouched unless you know what you are doing.
</member>
@@ -230,6 +232,8 @@
</member>
<member name="compression/formats/zstd/window_log_size" type="int" setter="" getter="">
</member>
+ <member name="debug/gdscript/completion/autocomplete_setters_and_getters" type="bool" setter="" getter="">
+ </member>
<member name="debug/gdscript/warnings/constant_used_as_function" type="bool" setter="" getter="">
</member>
<member name="debug/gdscript/warnings/deprecated_keyword" type="bool" setter="" getter="">
@@ -372,7 +376,7 @@
<member name="gui/timers/incremental_search_max_interval_msec" type="int" setter="" getter="">
Timer setting for incremental search in Tree, IntemList, etc. controls.
</member>
- <member name="gui/timers/text_edit_idle_detect_sec" type="int" setter="" getter="">
+ <member name="gui/timers/text_edit_idle_detect_sec" type="float" setter="" getter="">
Timer for detecting idle in the editor.
</member>
<member name="input/ui_accept" type="Dictionary" setter="" getter="">
@@ -604,9 +608,6 @@
<member name="network/limits/packet_peer_stream/max_buffer_po2" type="int" setter="" getter="">
Default size of packet peer stream for deserializing godot data. Over this size, data is dropped.
</member>
- <member name="network/remote_fs/max_pages" type="int" setter="" getter="">
- Maximum amount of pages used for remote filesystem (used by debugging).
- </member>
<member name="network/remote_fs/page_read_ahead" type="int" setter="" getter="">
Amount of read ahead used by remote filesystem. Improves latency.
</member>
@@ -652,7 +653,7 @@
<member name="rendering/limits/rendering/max_renderable_elements" type="int" setter="" getter="">
Max amount of elements renderable in a frame. If more than this are visible per frame, they will be dropped. Keep in mind elements refer to mesh surfaces and not mesh themselves.
</member>
- <member name="rendering/limits/time/time_rollover_secs" type="int" setter="" getter="">
+ <member name="rendering/limits/time/time_rollover_secs" type="float" setter="" getter="">
Shaders have a time variable that constantly increases. At some point it needs to be rolled back to zero to avoid numerical errors on shader animations. This setting specifies when.
</member>
<member name="rendering/quality/2d/use_pixel_snap" type="bool" setter="" getter="">
@@ -691,7 +692,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 +705,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/ResourceSaver.xml b/doc/classes/ResourceSaver.xml
index bf3ea95bce..f388667891 100644
--- a/doc/classes/ResourceSaver.xml
+++ b/doc/classes/ResourceSaver.xml
@@ -47,5 +47,7 @@
</constant>
<constant name="FLAG_COMPRESS" value="32" enum="SaverFlags">
</constant>
+ <constant name="FLAG_REPLACE_SUBRESOURCE_PATHS" value="64" enum="SaverFlags">
+ </constant>
</constants>
</class>
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/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 4f9ac68e47..2e5d5d81c9 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -149,7 +149,7 @@
<argument index="2" name="transform" type="Transform">
</argument>
<description>
- Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform].
+ Append vertices from a given [Mesh] surface onto the current vertex array with specified [Transform].
</description>
</method>
<method name="begin">
@@ -187,7 +187,7 @@
<argument index="1" name="surface" type="int">
</argument>
<description>
- Creates a vertex array from an existing [Mesh].
+ Creates a vertex array from an existing [Mesh].
</description>
</method>
<method name="deindex">
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index 5acfd6194e..f17c10b31e 100644
--- a/doc/classes/TabContainer.xml
+++ b/doc/classes/TabContainer.xml
@@ -82,6 +82,7 @@
<return type="int">
</return>
<description>
+ Returns the [code]TabContainer[/code] rearrange group id.
</description>
</method>
<method name="set_popup">
@@ -132,6 +133,7 @@
<argument index="0" name="group_id" type="int">
</argument>
<description>
+ Defines rearrange group id, choose for each [code]TabContainer[/code] the same value to enable tab drag between [code]TabContainer[/code]. Enable drag with [code]set_drag_to_rearrange_enabled(true)[/code].
</description>
</method>
</methods>
@@ -140,6 +142,7 @@
The current tab index. When set, this index's [Control] node's [code]visible[/code] property is set to [code]true[/code] and all others are set to [code]false[/code].
</member>
<member name="drag_to_rearrange_enabled" type="bool" setter="set_drag_to_rearrange_enabled" getter="get_drag_to_rearrange_enabled">
+ If [code]true[/code], tabs can be rearranged with mouse drag.
</member>
<member name="tab_align" type="int" setter="set_tab_align" getter="get_tab_align" enum="TabContainer.TabAlign">
The alignment of all tabs in the tab container. See the [code]ALIGN_*[/code] constants for details.
@@ -171,10 +174,13 @@
</signals>
<constants>
<constant name="ALIGN_LEFT" value="0" enum="TabAlign">
+ Align the tabs to the left.
</constant>
<constant name="ALIGN_CENTER" value="1" enum="TabAlign">
+ Align the tabs to the center.
</constant>
<constant name="ALIGN_RIGHT" value="2" enum="TabAlign">
+ Align the tabs to the right.
</constant>
</constants>
<theme_items>
diff --git a/doc/classes/Tabs.xml b/doc/classes/Tabs.xml
index fc1d0476ed..350b49513d 100644
--- a/doc/classes/Tabs.xml
+++ b/doc/classes/Tabs.xml
@@ -19,6 +19,7 @@
<argument index="1" name="icon" type="Texture" default="null">
</argument>
<description>
+ Adds a new tab.
</description>
</method>
<method name="ensure_tab_visible">
@@ -27,6 +28,7 @@
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Moves the Scroll view to make the tab visible.
</description>
</method>
<method name="get_offset_buttons_visible" qualifiers="const">
@@ -39,12 +41,14 @@
<return type="bool">
</return>
<description>
+ Returns [code]true[/code] if select with right mouse button is enabled.
</description>
</method>
<method name="get_tab_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of tabs.
</description>
</method>
<method name="get_tab_disabled" qualifiers="const">
@@ -53,6 +57,7 @@
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
+ Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled.
</description>
</method>
<method name="get_tab_icon" qualifiers="const">
@@ -61,6 +66,7 @@
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
+ Returns the [Texture] for the tab at index [code]tab_idx[/code] or null if the tab has no [Texture].
</description>
</method>
<method name="get_tab_offset" qualifiers="const">
@@ -84,12 +90,14 @@
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
+ Returns the title of the tab at index [code]tab_idx[/code]. Tab titles default to the name of the indexed child node, but this can be overridden with [method set_tab_title].
</description>
</method>
<method name="get_tabs_rearrange_group" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the [code]Tabs[/code] rearrange group id.
</description>
</method>
<method name="move_tab">
@@ -109,6 +117,7 @@
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
+ Removes tab at index [code]tab_idx[/code]
</description>
</method>
<method name="set_select_with_rmb">
@@ -117,6 +126,7 @@
<argument index="0" name="enabled" type="bool">
</argument>
<description>
+ If [code]true[/code] enables selecting a tab with right mouse button.
</description>
</method>
<method name="set_tab_disabled">
@@ -127,6 +137,7 @@
<argument index="1" name="disabled" type="bool">
</argument>
<description>
+ If [code]disabled[/code] is false, hides the tab at index [code]tab_idx[/code]. Note that its title text will remain, unless also removed with [method set_tab_title].
</description>
</method>
<method name="set_tab_icon">
@@ -137,6 +148,7 @@
<argument index="1" name="icon" type="Texture">
</argument>
<description>
+ Sets an icon for the tab at index [code]tab_idx[/code].
</description>
</method>
<method name="set_tab_title">
@@ -147,6 +159,7 @@
<argument index="1" name="title" type="String">
</argument>
<description>
+ Sets a title for the tab at index [code]tab_idx[/code].
</description>
</method>
<method name="set_tabs_rearrange_group">
@@ -155,17 +168,21 @@
<argument index="0" name="group_id" type="int">
</argument>
<description>
+ Defines rearrange group id, choose for each [code]Tabs[/code] the same value to enable tab drag between [code]Tabs[/code]. Enable drag with [code]set_drag_to_rearrange_enabled(true)[/code].
</description>
</method>
</methods>
<members>
<member name="current_tab" type="int" setter="set_current_tab" getter="get_current_tab">
+ Select tab at index [code]tab_idx[/code].
</member>
<member name="drag_to_rearrange_enabled" type="bool" setter="set_drag_to_rearrange_enabled" getter="get_drag_to_rearrange_enabled">
+ If [code]true[/code], tabs can be rearranged with mouse drag.
</member>
<member name="scrolling_enabled" type="bool" setter="set_scrolling_enabled" getter="get_scrolling_enabled">
</member>
<member name="tab_align" type="int" setter="set_tab_align" getter="get_tab_align" enum="Tabs.TabAlign">
+ The alignment of all tabs. See enum [code]TabAlign[/code] constants for details.
</member>
<member name="tab_close_display_policy" type="int" setter="set_tab_close_display_policy" getter="get_tab_close_display_policy" enum="Tabs.CloseButtonDisplayPolicy">
</member>
@@ -210,10 +227,13 @@
</signals>
<constants>
<constant name="ALIGN_LEFT" value="0" enum="TabAlign">
+ Align the tabs to the left.
</constant>
<constant name="ALIGN_CENTER" value="1" enum="TabAlign">
+ Align the tabs to the center.
</constant>
<constant name="ALIGN_RIGHT" value="2" enum="TabAlign">
+ Align the tabs to the right.
</constant>
<constant name="ALIGN_MAX" value="3" enum="TabAlign">
</constant>
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 cf8fb08f76..850b90d59b 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -95,11 +95,6 @@ Error AudioDriverCoreAudio::init() {
result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
ERR_FAIL_COND_V(result != noErr, FAILED);
-
- prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
-
- result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
- ERR_FAIL_COND_V(result != noErr, FAILED);
#endif
AudioStreamBasicDescription strdesc;
@@ -123,26 +118,6 @@ Error AudioDriverCoreAudio::init() {
break;
}
- zeromem(&strdesc, sizeof(strdesc));
- size = sizeof(strdesc);
- result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
- ERR_FAIL_COND_V(result != noErr, FAILED);
-
- switch (strdesc.mChannelsPerFrame) {
- case 1: // Mono
- capture_channels = 1;
- break;
-
- case 2: // Stereo
- capture_channels = 2;
- break;
-
- default:
- // Unknown number of channels, default to stereo
- capture_channels = 2;
- break;
- }
-
mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
zeromem(&strdesc, sizeof(strdesc));
@@ -158,11 +133,6 @@ Error AudioDriverCoreAudio::init() {
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
ERR_FAIL_COND_V(result != noErr, FAILED);
- strdesc.mChannelsPerFrame = capture_channels;
-
- result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
- ERR_FAIL_COND_V(result != noErr, FAILED);
-
int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
@@ -175,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");
@@ -189,16 +156,10 @@ Error AudioDriverCoreAudio::init() {
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
ERR_FAIL_COND_V(result != noErr, FAILED);
- zeromem(&callback, sizeof(AURenderCallbackStruct));
- callback.inputProc = &AudioDriverCoreAudio::input_callback;
- callback.inputProcRefCon = this;
- result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
- ERR_FAIL_COND_V(result != noErr, FAILED);
-
result = AudioUnitInitialize(audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
- return OK;
+ return capture_init();
}
OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
@@ -265,7 +226,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
bufferList.mBuffers[0].mNumberChannels = ad->capture_channels;
bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t);
- OSStatus result = AudioUnitRender(ad->audio_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
+ OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);
if (result == noErr) {
for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
int32_t sample = ad->input_buf[i] << 16;
@@ -332,6 +293,8 @@ bool AudioDriverCoreAudio::try_lock() {
}
void AudioDriverCoreAudio::finish() {
+ capture_finish();
+
if (audio_unit) {
OSStatus result;
@@ -375,6 +338,7 @@ void AudioDriverCoreAudio::finish() {
ERR_PRINT("AudioComponentInstanceDispose failed");
}
+ audio_unit = NULL;
unlock();
}
@@ -384,20 +348,160 @@ void AudioDriverCoreAudio::finish() {
}
}
-Error AudioDriverCoreAudio::capture_start() {
+Error AudioDriverCoreAudio::capture_init() {
+ AudioComponentDescription desc;
+ zeromem(&desc, sizeof(desc));
+ desc.componentType = kAudioUnitType_Output;
+#ifdef OSX_ENABLED
+ desc.componentSubType = kAudioUnitSubType_HALOutput;
+#else
+ desc.componentSubType = kAudioUnitSubType_RemoteIO;
+#endif
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+
+ AudioComponent comp = AudioComponentFindNext(NULL, &desc);
+ ERR_FAIL_COND_V(comp == NULL, FAILED);
+
+ OSStatus result = AudioComponentInstanceNew(comp, &input_unit);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+#ifdef OSX_ENABLED
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = kAudioObjectPropertyElementMaster;
+
+ result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+#endif
UInt32 flag = 1;
- OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
+ result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+ flag = 0;
+ result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ UInt32 size;
+#ifdef OSX_ENABLED
+ AudioDeviceID deviceId;
+ size = sizeof(AudioDeviceID);
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+#endif
+
+ AudioStreamBasicDescription strdesc;
+ zeromem(&strdesc, sizeof(strdesc));
+ size = sizeof(strdesc);
+ result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size);
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ switch (strdesc.mChannelsPerFrame) {
+ case 1: // Mono
+ capture_channels = 1;
+ break;
+
+ case 2: // Stereo
+ capture_channels = 2;
+ break;
+
+ default:
+ // Unknown number of channels, default to stereo
+ capture_channels = 2;
+ break;
+ }
+
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
+
+ zeromem(&strdesc, sizeof(strdesc));
+ strdesc.mFormatID = kAudioFormatLinearPCM;
+ strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
+ strdesc.mChannelsPerFrame = capture_channels;
+ strdesc.mSampleRate = mix_rate;
+ strdesc.mFramesPerPacket = 1;
+ strdesc.mBitsPerChannel = 16;
+ strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8;
+ strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket;
+
+ result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ AURenderCallbackStruct callback;
+ zeromem(&callback, sizeof(AURenderCallbackStruct));
+ callback.inputProc = &AudioDriverCoreAudio::input_callback;
+ callback.inputProcRefCon = this;
+ result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ result = AudioUnitInitialize(input_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
return OK;
}
+void AudioDriverCoreAudio::capture_finish() {
+ if (input_unit) {
+ lock();
+
+ AURenderCallbackStruct callback;
+ zeromem(&callback, sizeof(AURenderCallbackStruct));
+ OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback));
+ if (result != noErr) {
+ ERR_PRINT("AudioUnitSetProperty failed");
+ }
+
+ result = AudioUnitUninitialize(input_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioUnitUninitialize failed");
+ }
+
+#ifdef OSX_ENABLED
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDefaultInputDevice;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = kAudioObjectPropertyElementMaster;
+
+ result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this);
+ if (result != noErr) {
+ ERR_PRINT("AudioObjectRemovePropertyListener failed");
+ }
+#endif
+
+ result = AudioComponentInstanceDispose(input_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioComponentInstanceDispose failed");
+ }
+
+ input_unit = NULL;
+ unlock();
+ }
+}
+
+Error AudioDriverCoreAudio::capture_start() {
+
+ input_buffer_init(buffer_frames);
+
+ OSStatus result = AudioOutputUnitStart(input_unit);
+ if (result != noErr) {
+ ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result));
+ }
+
+ return OK;
+}
+
Error AudioDriverCoreAudio::capture_stop() {
- UInt32 flag = 0;
- OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
- ERR_FAIL_COND_V(result != noErr, FAILED);
+ if (input_unit) {
+ OSStatus result = AudioOutputUnitStop(input_unit);
+ if (result != noErr) {
+ ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result));
+ }
+ }
return OK;
}
@@ -531,12 +635,14 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
}
if (found) {
- OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID));
+ OSStatus result = AudioUnitSetProperty(capture ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
ERR_FAIL_COND(result != noErr);
- // Reset audio input to keep synchronisation.
- input_position = 0;
- input_size = 0;
+ if (capture) {
+ // Reset audio input to keep synchronisation.
+ input_position = 0;
+ input_size = 0;
+ }
}
}
@@ -580,6 +686,7 @@ String AudioDriverCoreAudio::capture_get_device() {
AudioDriverCoreAudio::AudioDriverCoreAudio() {
audio_unit = NULL;
+ input_unit = NULL;
active = false;
mutex = NULL;
diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h
index d3f7c8d596..474a9e43ae 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.h
+++ b/drivers/coreaudio/audio_driver_coreaudio.h
@@ -43,6 +43,7 @@
class AudioDriverCoreAudio : public AudioDriver {
AudioComponentInstance audio_unit;
+ AudioComponentInstance input_unit;
bool active;
Mutex *mutex;
@@ -83,6 +84,9 @@ class AudioDriverCoreAudio : public AudioDriver {
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData);
+ Error capture_init();
+ void capture_finish();
+
public:
const char *get_name() const {
return "CoreAudio";
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index 18b5dd3483..9227c04e71 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -1111,6 +1111,7 @@ void RasterizerCanvasGLES2::initialize() {
// polygon buffer
{
uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
poly_size *= 1024;
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
glGenBuffers(1, &data.polygon_buffer);
@@ -1122,6 +1123,7 @@ void RasterizerCanvasGLES2::initialize() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
index_size *= 1024; // kb
glGenBuffers(1, &data.polygon_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 848ac8b78f..175587b1bb 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -74,6 +74,10 @@
#include <EGL/eglext.h>
#endif
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define strcpy strcpy_s
+#endif
+
#ifndef IPHONE_ENABLED
static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) {
@@ -84,6 +88,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL
return; //these are ultimately annoying, so removing for now
char debSource[256], debType[256], debSev[256];
+
if (source == _EXT_DEBUG_SOURCE_API_ARB)
strcpy(debSource, "OpenGL");
else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB)
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index fbcbebc88c..c4b6c607a2 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);
}
@@ -3037,6 +3046,7 @@ void RasterizerSceneGLES2::initialize() {
{
uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
glGenBuffers(1, &state.immediate_buffer);
glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index b42e2dfb1f..c928f753b1 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -43,7 +43,6 @@
/*
#include "shaders/blend_shape.glsl.gen.h"
#include "shaders/canvas.glsl.gen.h"
-#include "shaders/copy.glsl.gen.h"
#include "shaders/particles.glsl.gen.h"
*/
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..2a781605d1 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
@@ -1307,8 +1307,7 @@ LIGHT_SHADER_CODE
#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r)
#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r)
-float sample_shadow(
- highp sampler2D shadow, highp vec4 spos) {
+float sample_shadow(highp sampler2D shadow, highp vec4 spos) {
#ifdef SHADOW_MODE_PCF_13
@@ -1923,12 +1922,12 @@ FRAGMENT_SHADER_CODE
highp vec4 splane = shadow_coord;
splane.xyz /= splane.w;
- float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z);
+ float shadow = sample_shadow(light_shadow_atlas, splane);
light_att *= shadow;
}
#endif
-#endif
+#endif // LIGHT_MODE_SPOT
#ifdef USE_VERTEX_LIGHTING
//vertex lighting
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index a9b46baf53..f0932c2f80 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -2027,6 +2027,7 @@ void RasterizerCanvasGLES3::initialize() {
{
uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
poly_size *= 1024; //kb
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
glGenBuffers(1, &data.polygon_buffer);
@@ -2074,6 +2075,7 @@ void RasterizerCanvasGLES3::initialize() {
glGenVertexArrays(1, &data.polygon_buffer_pointer_array);
uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater"));
index_size *= 1024; //kb
glGenBuffers(1, &data.polygon_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 2b3be9d0bd..2f6a556773 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -73,6 +73,10 @@ RasterizerScene *RasterizerGLES3::get_scene() {
#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148
#define _EXT_DEBUG_OUTPUT 0x92E0
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define strcpy strcpy_s
+#endif
+
#ifdef GLAD_ENABLED
// Restricting to GLAD as only used in initialize() with GLAD_GL_ARB_debug_output
#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED)
@@ -432,6 +436,7 @@ void RasterizerGLES3::register_config() {
GLOBAL_DEF("rendering/quality/filters/anisotropic_filter_level", 4);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/anisotropic_filter_level", PropertyInfo(Variant::INT, "rendering/quality/filters/anisotropic_filter_level", PROPERTY_HINT_RANGE, "1,16,1"));
GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::REAL, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"));
}
RasterizerGLES3::RasterizerGLES3() {
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index ed2b39a17d..0d4c83e0db 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1246,14 +1246,11 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
case ShaderLanguage::TYPE_SAMPLER3D: {
target = GL_TEXTURE_3D;
+ tex = storage->resources.white_tex_3d;
- switch (texture_hints[i]) {
-
- // TODO
- default: {
- tex = storage->resources.white_tex_3d;
- } break;
- }
+ //switch (texture_hints[i]) {
+ // TODO
+ //}
} break;
@@ -4855,10 +4852,7 @@ void RasterizerSceneGLES3::initialize() {
glBindBuffer(GL_UNIFORM_BUFFER, 0);
render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)RenderList::DEFAULT_MAX_ELEMENTS);
- if (render_list.max_elements > 1000000)
- render_list.max_elements = 1000000;
- if (render_list.max_elements < 1024)
- render_list.max_elements = 1024;
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_elements", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_elements", PROPERTY_HINT_RANGE, "1024,1000000,1"));
{
//quad buffers
@@ -5057,6 +5051,7 @@ void RasterizerSceneGLES3::initialize() {
{
uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
glGenBuffers(1, &state.immediate_buffer);
glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index a9aa152f10..406ef6af78 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -7686,6 +7686,8 @@ void RasterizerStorageGLES3::initialize() {
{
//transform feedback buffers
uint32_t xf_feedback_size = GLOBAL_DEF_RST("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/blend_shape_max_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/blend_shape_max_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
+
for (int i = 0; i < 2; i++) {
glGenBuffers(1, &resources.transform_feedback_buffers[i]);
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/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp
index 10ba0663f2..bc6ceb1e7e 100644
--- a/drivers/rtaudio/audio_driver_rtaudio.cpp
+++ b/drivers/rtaudio/audio_driver_rtaudio.cpp
@@ -114,11 +114,12 @@ Error AudioDriverRtAudio::init() {
unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
print_verbose("Audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
- short int tries = 2;
+ short int tries = 4;
- while (tries >= 0) {
+ while (tries > 0) {
switch (speaker_mode) {
case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break;
+ case SPEAKER_SURROUND_31: parameters.nChannels = 4; break;
case SPEAKER_SURROUND_51: parameters.nChannels = 6; break;
case SPEAKER_SURROUND_71: parameters.nChannels = 8; break;
};
@@ -128,12 +129,14 @@ Error AudioDriverRtAudio::init() {
active = true;
break;
- } catch (RtAudioError &e) {
+ } catch (RtAudioError) {
// try with less channels
ERR_PRINT("Unable to open audio, retrying with fewer channels...");
switch (speaker_mode) {
- case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_MODE_STEREO; break;
+ case SPEAKER_MODE_STEREO: break; // Required to silence unhandled enum value warning.
+ case SPEAKER_SURROUND_31: speaker_mode = SPEAKER_MODE_STEREO; break;
+ case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_SURROUND_31; break;
case SPEAKER_SURROUND_71: speaker_mode = SPEAKER_SURROUND_51; break;
}
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/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index b4492a2022..2582478259 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -114,7 +114,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) {
path = path + ".tmp";
}
- f = _wfopen(path.c_str(), mode_string);
+ _wfopen_s(&f, path.c_str(), mode_string);
if (f == NULL) {
last_error = ERR_FILE_CANT_OPEN;
@@ -278,7 +278,7 @@ bool FileAccessWindows::file_exists(const String &p_name) {
FILE *g;
//printf("opening file %s\n", p_fname.c_str());
String filename = fix_path(p_name);
- g = _wfopen(filename.c_str(), L"rb");
+ _wfopen_s(&g, filename.c_str(), L"rb");
if (g == NULL) {
return false;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 77be561477..3997469e95 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -4086,6 +4086,8 @@ void AnimationTrackEditor::_move_selection_commit() {
for (int i = 0; i < track_edits.size(); i++) {
track_edits[i]->update();
}
+
+ _update_key_edit();
}
void AnimationTrackEditor::_move_selection_cancel() {
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 79c22f667a..aeb304d3b9 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -1039,6 +1039,8 @@ void CodeTextEditor::delete_lines() {
int to_line = text_editor->get_selection_to_line();
int from_line = text_editor->get_selection_from_line();
int count = Math::abs(to_line - from_line) + 1;
+
+ text_editor->cursor_set_line(to_line, false);
while (count) {
text_editor->set_line(text_editor->cursor_get_line(), "");
text_editor->backspace_at_cursor();
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 1374c8c9aa..64742ff74c 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -185,6 +185,7 @@ void EditorAutoloadSettings::_autoload_edited() {
if (path.begins_with("*"))
path = path.substr(1, path.length());
+ // Singleton autoloads are represented with a leading "*" in their path.
if (checked)
path = "*" + path;
@@ -651,6 +652,7 @@ void EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(TTR("Add AutoLoad"));
+ // Singleton autoloads are represented with a leading "*" in their path.
undo_redo->add_do_property(ProjectSettings::get_singleton(), name, "*" + path);
if (ProjectSettings::get_singleton()->has_setting(name)) {
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..3899fcf83f 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);
+ }
}
}
@@ -4970,7 +4972,7 @@ EditorNode::EditorNode() {
dock_vb->add_child(dock_hb);
dock_select = memnew(Control);
- dock_select->set_custom_minimum_size(Size2(128, 64) * EDSCALE);
+ dock_select->set_custom_minimum_size(Size2(64, 0) * EDSCALE);
dock_select->connect("gui_input", this, "_dock_select_input");
dock_select->connect("draw", this, "_dock_select_draw");
dock_select->connect("mouse_exited", this, "_dock_popup_exit");
@@ -4981,7 +4983,7 @@ EditorNode::EditorNode() {
dock_select_rect_over = -1;
dock_popup_selected = -1;
for (int i = 0; i < DOCK_SLOT_MAX; i++) {
- dock_slot[i]->set_custom_minimum_size(Size2(230, 220) * EDSCALE);
+ dock_slot[i]->set_custom_minimum_size(Size2(0, 64) * EDSCALE);
dock_slot[i]->set_v_size_flags(Control::SIZE_EXPAND_FILL);
dock_slot[i]->set_popup(dock_select_popup);
dock_slot[i]->connect("pre_popup_pressed", this, "_dock_pre_popup", varray(i));
@@ -5497,8 +5499,8 @@ EditorNode::EditorNode() {
right_r_vsplit->hide();
// Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize
- left_r_hsplit->set_split_offset(40 * EDSCALE);
- main_hsplit->set_split_offset(-40 * EDSCALE);
+ left_r_hsplit->set_split_offset(100 * EDSCALE);
+ main_hsplit->set_split_offset(-100 * EDSCALE);
// Define corresponding default layout
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index d078cfcc91..5148c12160 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -477,33 +477,16 @@ EditorPropertyCheck::EditorPropertyCheck() {
void EditorPropertyEnum::_option_selected(int p_which) {
- String text = options->get_item_text(p_which);
- Vector<String> text_split = text.split(":");
- if (text_split.size() == 1) {
- emit_signal("property_changed", get_edited_property(), p_which);
- return;
- }
- String name = text_split[1];
- emit_signal("property_changed", get_edited_property(), name.to_int());
+ int val = options->get_item_metadata(p_which);
+ emit_signal("property_changed", get_edited_property(), val);
}
void EditorPropertyEnum::update_property() {
int which = get_edited_object()->get(get_edited_property());
- if (which == 0) {
- options->select(which);
- return;
- }
for (int i = 0; i < options->get_item_count(); i++) {
- String text = options->get_item_text(i);
- Vector<String> text_split = text.split(":");
- if (text_split.size() == 1) {
- options->select(which);
- return;
- }
- String name = text_split[1];
- if (itos(which) == name) {
+ if (which == (int)options->get_item_metadata(i)) {
options->select(i);
return;
}
@@ -511,8 +494,15 @@ void EditorPropertyEnum::update_property() {
}
void EditorPropertyEnum::setup(const Vector<String> &p_options) {
+
+ int current_val = 0;
for (int i = 0; i < p_options.size(); i++) {
- options->add_item(p_options[i], i);
+ Vector<String> text_split = p_options[i].split(":");
+ if (text_split.size() != 1)
+ current_val = text_split[1].to_int();
+ options->add_item(text_split[0]);
+ options->set_item_metadata(i, current_val);
+ current_val += 1;
}
}
@@ -1870,6 +1860,12 @@ void EditorPropertyNodePath::update_property() {
Node *target_node = base_node->get_node(p);
ERR_FAIL_COND(!target_node);
+ if (String(target_node->get_name()).find("@") != -1) {
+ assign->set_icon(Ref<Texture>());
+ assign->set_text(p);
+ return;
+ }
+
assign->set_text(target_node->get_name());
assign->set_icon(EditorNode::get_singleton()->get_object_icon(target_node, "Node"));
}
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 4d386c1af6..ef960f74ea 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,11 @@ void FileSystemDock::_notification(int p_what) {
tree->set_drop_mode_flags(0);
} break;
+ case NOTIFICATION_THEME_CHANGED: {
+ if (tree->is_visible_in_tree()) {
+ _update_display_mode(true);
+ }
+ } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
// Update icons
String ei = "EditorIcons";
@@ -360,6 +365,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);
@@ -412,7 +422,7 @@ void FileSystemDock::_tree_multi_selected(Object *p_item, int p_column, bool p_s
return;
TreeItem *favorites_item = tree->get_root()->get_children();
- if (selected->get_parent() == favorites_item) {
+ if (selected->get_parent() == favorites_item && !String(selected->get_metadata(0)).ends_with("/")) {
// Go to the favorites if we click in the favorites and the path has changed
path = "Favorites";
} else {
@@ -1172,6 +1182,23 @@ void FileSystemDock::_update_project_settings_after_move(const Map<String, Strin
}
};
}
+
+ // Also search for the file in autoload, as they are stored differently from normal files.
+ List<PropertyInfo> property_list;
+ ProjectSettings::get_singleton()->get_property_list(&property_list);
+ for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
+ if (E->get().name.begins_with("autoload/")) {
+ // If the autoload resource paths has a leading "*", it indicates that it is a Singleton,
+ // so we have to handle both cases when updating.
+ String autoload = GLOBAL_GET(E->get().name);
+ String autoload_singleton = autoload.substr(1, autoload.length());
+ if (p_renames.has(autoload)) {
+ ProjectSettings::get_singleton()->set_setting(E->get().name, p_renames[autoload]);
+ } else if (autoload.begins_with("*") && p_renames.has(autoload_singleton)) {
+ ProjectSettings::get_singleton()->set_setting(E->get().name, "*" + p_renames[autoload_singleton]);
+ }
+ }
+ }
ProjectSettings::get_singleton()->save();
}
@@ -1200,7 +1227,8 @@ void FileSystemDock::_make_dir_confirm() {
if (dir_name.length() == 0) {
EditorNode::get_singleton()->show_warning(TTR("No name provided"));
return;
- } else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
+ } else if (dir_name.find("/") != -1 || dir_name.find("\\") != -1 || dir_name.find(":") != -1 || dir_name.find("*") != -1 ||
+ dir_name.find("|") != -1 || dir_name.find(">") != -1 || dir_name.ends_with(".") || dir_name.ends_with(" ")) {
EditorNode::get_singleton()->show_warning(TTR("Provided name contains invalid characters"));
return;
}
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/icons/icon_GUI_viewport_hdiagsplitter.svg b/editor/icons/icon_GUI_viewport_hdiagsplitter.svg
index 36769768fd..90a0f56c43 100644
--- a/editor/icons/icon_GUI_viewport_hdiagsplitter.svg
+++ b/editor/icons/icon_GUI_viewport_hdiagsplitter.svg
@@ -1,64 +1,5 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="64"
- height="34"
- version="1.1"
- viewBox="0 0 64 34"
- id="svg6"
- sodipodi:docname="icon_GUI_vsplitter1.svg"
- inkscape:version="0.92.2 2405546, 2018-03-11">
- <metadata
- id="metadata12">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs10" />
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1366"
- inkscape:window-height="714"
- id="namedview8"
- showgrid="false"
- inkscape:zoom="5.6568543"
- inkscape:cx="37.006499"
- inkscape:cy="15.680715"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg6" />
- <g
- transform="translate(0,-1018.4)"
- id="g4" />
- <g
- transform="rotate(90,541.2,539.2)"
- id="g4-3">
- <path
- id="path2-6"
- style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-opacity:0.39216003"
- d="M 4.0306826,1048.4 H 34 m -30,30 v -60"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cccc" />
- </g>
+<svg width="64" height="34" version="1.1" viewBox="0 0 64 34" xmlns="http://www.w3.org/2000/svg">
+<g transform="rotate(90,541.2,539.2)">
+<path d="m4.0307 1048.4h29.969m-30 30v-60" fill="none" stroke="#fff" stroke-linecap="round" stroke-opacity=".39216" stroke-width="2"/>
+</g>
</svg>
diff --git a/editor/icons/icon_GUI_viewport_vdiagsplitter.svg b/editor/icons/icon_GUI_viewport_vdiagsplitter.svg
index f23b4a0a74..481f895d46 100644
--- a/editor/icons/icon_GUI_viewport_vdiagsplitter.svg
+++ b/editor/icons/icon_GUI_viewport_vdiagsplitter.svg
@@ -1,68 +1,7 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="34"
- height="64"
- version="1.1"
- viewBox="0 0 34 64"
- id="svg6"
- sodipodi:docname="icon_GUI_vsplitter2.svg"
- inkscape:version="0.92.2 2405546, 2018-03-11">
- <metadata
- id="metadata12">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs10" />
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1366"
- inkscape:window-height="714"
- id="namedview8"
- showgrid="false"
- inkscape:zoom="4"
- inkscape:cx="32.245723"
- inkscape:cy="44.255214"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg6" />
- <g
- transform="translate(0,-988.4)"
- id="g4" />
- <g
- id="g839"
- transform="rotate(90,32.003536,32.003535)">
- <g
- id="g4-3"
- transform="rotate(90,526.2,554.2)">
- <path
- sodipodi:nodetypes="cccc"
- inkscape:connector-curvature="0"
- d="M 4.0306826,1048.4 H 34 m -30,30 v -60"
- style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-opacity:0.39216003"
- id="path2-6" />
- </g>
- </g>
+<svg width="34" height="64" version="1.1" viewBox="0 0 34 64" xmlns="http://www.w3.org/2000/svg">
+<g transform="rotate(90 32.004 32.004)">
+<g transform="rotate(90,526.2,554.2)">
+<path d="m4.0307 1048.4h29.969m-30 30v-60" fill="none" stroke="#fff" stroke-linecap="round" stroke-opacity=".39216" stroke-width="2"/>
+</g>
+</g>
</svg>
diff --git a/editor/icons/icon_GUI_viewport_vhsplitter.svg b/editor/icons/icon_GUI_viewport_vhsplitter.svg
index 429cf909ae..52d7d8f0b7 100644
--- a/editor/icons/icon_GUI_viewport_vhsplitter.svg
+++ b/editor/icons/icon_GUI_viewport_vhsplitter.svg
@@ -1,63 +1,5 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="64"
- height="64"
- version="1.1"
- viewBox="0 0 64 64"
- id="svg6"
- sodipodi:docname="icon_GUI_vsplitter.svg"
- inkscape:version="0.92.2 2405546, 2018-03-11">
- <metadata
- id="metadata12">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <defs
- id="defs10" />
- <sodipodi:namedview
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1"
- objecttolerance="10"
- gridtolerance="10"
- guidetolerance="10"
- inkscape:pageopacity="0"
- inkscape:pageshadow="2"
- inkscape:window-width="1366"
- inkscape:window-height="714"
- id="namedview8"
- showgrid="false"
- inkscape:zoom="4.65625"
- inkscape:cx="9.8488117"
- inkscape:cy="20.04653"
- inkscape:window-x="0"
- inkscape:window-y="0"
- inkscape:window-maximized="1"
- inkscape:current-layer="svg6" />
- <g
- transform="translate(0,-988.4)"
- id="g4" />
- <g
- transform="rotate(90,526.2,554.2)"
- id="g4-3">
- <path
- id="path2-6"
- style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-opacity:0.39216003"
- d="m -26,1048.4 h 60 m -30,30 v -60"
- inkscape:connector-curvature="0" />
- </g>
+<svg width="64" height="64" version="1.1" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
+<g transform="rotate(90,526.2,554.2)">
+<path d="m-26 1048.4h60m-30 30v-60" fill="none" stroke="#fff" stroke-linecap="round" stroke-opacity=".39216" stroke-width="2"/>
+</g>
</svg>
diff --git a/editor/icons/icon_script_extend.svg b/editor/icons/icon_script_extend.svg
new file mode 100644
index 0000000000..ef3d48af9f
--- /dev/null
+++ b/editor/icons/icon_script_extend.svg
@@ -0,0 +1,8 @@
+<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
+<g transform="translate(0 -1036.4)">
+<path transform="translate(0 1036.4)" d="m6 1v1c-0.55228 0-1 0.44772-1 1v10h-1v-2h-2v2c2.826e-4 0.35698 0.19084 0.68674 0.5 0.86523 0.15194 0.088045 0.32439 0.13452 0.5 0.13477v1h7c0.73866 0 1.3763-0.40437 1.7227-1h-3.7227v-4h4v-5h3v-2c0-1.1046-0.89543-2-2-2z" fill="#e0e0e0"/>
+<path transform="translate(0 1036.4)" d="m6 1c-1.1046 0-2 0.89543-2 2v7h-2-1v1 2c0 1.1046 0.89543 2 2 2s2-0.89543 2-2v-10c0-0.55228 0.44772-1 1-1s1 0.44772 1 1v1 1 1h1 4v-1h-4v-1-1c0-1.1046-0.89543-2-2-2zm-4 10h2v2c0 0.55228-0.44772 1-1 1s-1-0.44772-1-1v-2z" fill="#b4b4b4"/>
+<circle cx="3" cy="1048.4" rx="1" ry="1" fill="#e0e0e0"/>
+<path d="m16 1048.4-3-3v2h-4v2h4v2z" fill="#68b6ff" fill-rule="evenodd"/>
+</g>
+</svg>
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/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index f7e59e2beb..71a5d73b2f 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -132,8 +132,8 @@ Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const {
void AbstractPolygon2DEditor::_commit_action() {
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
}
@@ -218,7 +218,7 @@ void AbstractPolygon2DEditor::_node_removed(Node *p_node) {
edit(NULL);
hide();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
@@ -334,7 +334,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
edited_point = PosVertex(closest, xform.affine_inverse().xform(closest.pos));
selected_point = closest;
edge_point = PosVertex();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
} else {
@@ -403,7 +403,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
wip_active = true;
_wip_changed();
edited_point = PosVertex(-1, 1, cpoint);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
hover_point = Vertex();
selected_point = Vertex(0);
edge_point = PosVertex();
@@ -424,7 +424,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
_wip_changed();
edited_point = PosVertex(-1, wip.size(), cpoint);
selected_point = Vertex(wip.size() - 1);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
}
@@ -453,7 +453,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
_set_polygon(edited_point.polygon, vertices);
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
const PosVertex onEdgeVertex = closest_edge_point(gpoint);
@@ -462,20 +462,20 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
hover_point = Vertex();
edge_point = onEdgeVertex;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else {
if (edge_point.valid()) {
edge_point = PosVertex();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
const PosVertex new_hover_point = closest_point(gpoint);
if (hover_point != new_hover_point) {
hover_point = new_hover_point;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
}
@@ -494,7 +494,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
wip.remove(selected_point.vertex);
_wip_changed();
selected_point = wip.size() - 1;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
} else {
@@ -627,7 +627,7 @@ void AbstractPolygon2DEditor::edit(Node *p_polygon) {
hover_point = Vertex();
selected_point = Vertex();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else {
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 66770d98e5..138b8a491c 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -962,6 +962,9 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int
HBoxContainer *hbc = memnew(HBoxContainer);
+ if (p_page_count < 2)
+ return hbc;
+
//do the mario
int from = p_page - 5;
if (from < 0)
diff --git a/editor/plugins/camera_editor_plugin.cpp b/editor/plugins/camera_editor_plugin.cpp
index 37fbb54c30..3d8b24ccc7 100644
--- a/editor/plugins/camera_editor_plugin.cpp
+++ b/editor/plugins/camera_editor_plugin.cpp
@@ -32,18 +32,6 @@
#include "spatial_editor_plugin.h"
-void CameraEditor::_notification(int p_what) {
-
- switch (p_what) {
-
- /* case NOTIFICATION_PROCESS: {
-
- if (preview->is_pressed() && node)
- node->call("make_current");
-
- } break;*/
- }
-}
void CameraEditor::_node_removed(Node *p_node) {
if (p_node == node) {
diff --git a/editor/plugins/camera_editor_plugin.h b/editor/plugins/camera_editor_plugin.h
index 275624beeb..0340808c9a 100644
--- a/editor/plugins/camera_editor_plugin.h
+++ b/editor/plugins/camera_editor_plugin.h
@@ -50,7 +50,6 @@ class CameraEditor : public Control {
void _pressed();
protected:
- void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index a9bc5e77ac..31dd20e453 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1025,8 +1025,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Scroll or pan down
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.y += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
} else {
_zoom_on_position(zoom * (1 - (0.05 * b->get_factor())), b->get_position());
}
@@ -1037,8 +1036,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Scroll or pan up
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.y -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
} else {
_zoom_on_position(zoom * ((0.95 + (0.05 * b->get_factor())) / 0.95), b->get_position());
}
@@ -1049,8 +1047,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Pan left
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.x -= int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
}
@@ -1059,8 +1056,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
// Pan right
if (bool(EditorSettings::get_singleton()->get("editors/2d/scroll_to_pan"))) {
view_offset.x += int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom * b->get_factor();
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
}
@@ -1112,8 +1108,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
}
view_offset.x -= relative.x / zoom;
view_offset.y -= relative.y / zoom;
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
}
@@ -1131,8 +1126,7 @@ bool CanvasItemEditor::_gui_input_zoom_or_pan(const Ref<InputEvent> &p_event) {
const Vector2 delta = (int(EditorSettings::get_singleton()->get("editors/2d/pan_speed")) / zoom) * pan_gesture->get_delta();
view_offset.x += delta.x;
view_offset.y += delta.y;
- _update_scrollbars();
- viewport->update();
+ update_viewport();
return true;
}
@@ -3168,6 +3162,11 @@ void CanvasItemEditor::_draw_viewport() {
_draw_hover();
}
+void CanvasItemEditor::update_viewport() {
+ _update_scrollbars();
+ viewport->update();
+}
+
void CanvasItemEditor::_notification(int p_what) {
if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
@@ -3574,8 +3573,7 @@ void CanvasItemEditor::_zoom_on_position(float p_zoom, Point2 p_position) {
view_offset.x = Math::round(view_offset.x + ofs.x);
view_offset.y = Math::round(view_offset.y + ofs.y);
- _update_scrollbars();
- viewport->update();
+ update_viewport();
}
void CanvasItemEditor::_button_zoom_minus() {
@@ -4172,8 +4170,7 @@ void CanvasItemEditor::_focus_selection(int p_op) {
Vector2 offset = viewport->get_size() / 2 - editor->get_scene_root()->get_global_canvas_transform().xform(center);
view_offset.x -= offset.x / zoom;
view_offset.y -= offset.y / zoom;
- _update_scrollbars();
- viewport->update();
+ update_viewport();
} else { // VIEW_FRAME_TO_SELECTION
@@ -4210,6 +4207,7 @@ void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_selection_result_pressed"), &CanvasItemEditor::_selection_result_pressed);
ClassDB::bind_method(D_METHOD("_selection_menu_hide"), &CanvasItemEditor::_selection_menu_hide);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
+ ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
ADD_SIGNAL(MethodInfo("item_group_status_changed"));
@@ -4608,6 +4606,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
skeleton_menu = memnew(MenuButton);
hb->add_child(skeleton_menu);
+ skeleton_menu->set_tooltip(TTR("Skeleton Options"));
p = skeleton_menu->get_popup();
p->set_hide_on_checkable_item_selection(false);
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 4f8cc6ab5e..dc7b74112f 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -547,6 +547,8 @@ public:
Control *get_viewport_control() { return viewport; }
+ void update_viewport();
+
Tool get_current_tool() { return tool; }
void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo = p_undo_redo; }
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index d1a94f5b49..5d85a64b9c 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -129,7 +129,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
capsule->set_height(parameter * 2 - capsule->get_radius() * 2);
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -138,7 +138,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
Ref<CircleShape2D> circle = node->get_shape();
circle->set_radius(p_point.length());
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} break;
@@ -160,7 +160,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
line->set_normal(p_point.normalized());
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -170,7 +170,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
ray->set_length(Math::abs(p_point.y));
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} break;
@@ -183,7 +183,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
rect->set_extents(extents.abs());
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -198,7 +198,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
seg->set_b(p_point);
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
} break;
@@ -207,7 +207,6 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
- Control *c = canvas_item_editor->get_viewport_control();
undo_redo->create_action(TTR("Set Handle"));
switch (shape_type) {
@@ -216,14 +215,14 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
if (idx == 0) {
undo_redo->add_do_method(capsule.ptr(), "set_radius", capsule->get_radius());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(capsule.ptr(), "set_radius", p_org);
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
} else if (idx == 1) {
undo_redo->add_do_method(capsule.ptr(), "set_height", capsule->get_height());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(capsule.ptr(), "set_height", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
} break;
@@ -232,9 +231,9 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<CircleShape2D> circle = node->get_shape();
undo_redo->add_do_method(circle.ptr(), "set_radius", circle->get_radius());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(circle.ptr(), "set_radius", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} break;
@@ -251,14 +250,14 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
if (idx == 0) {
undo_redo->add_do_method(line.ptr(), "set_d", line->get_d());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(line.ptr(), "set_d", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} else {
undo_redo->add_do_method(line.ptr(), "set_normal", line->get_normal());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(line.ptr(), "set_normal", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
} break;
@@ -267,9 +266,9 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<RayShape2D> ray = node->get_shape();
undo_redo->add_do_method(ray.ptr(), "set_length", ray->get_length());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(ray.ptr(), "set_length", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} break;
@@ -277,9 +276,9 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<RectangleShape2D> rect = node->get_shape();
undo_redo->add_do_method(rect.ptr(), "set_extents", rect->get_extents());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(rect.ptr(), "set_extents", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} break;
@@ -287,14 +286,14 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
Ref<SegmentShape2D> seg = node->get_shape();
if (idx == 0) {
undo_redo->add_do_method(seg.ptr(), "set_a", seg->get_a());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(seg.ptr(), "set_a", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
} else if (idx == 1) {
undo_redo->add_do_method(seg.ptr(), "set_b", seg->get_b());
- undo_redo->add_do_method(c, "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(seg.ptr(), "set_b", p_org);
- undo_redo->add_undo_method(c, "update");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
}
} break;
@@ -411,7 +410,7 @@ void CollisionShape2DEditor::_get_current_shape_type() {
shape_type = -1;
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
void CollisionShape2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) {
@@ -538,7 +537,7 @@ void CollisionShape2DEditor::edit(Node *p_node) {
node = NULL;
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
void CollisionShape2DEditor::_bind_methods() {
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index 2f2e1dae81..6a16cf0989 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -57,7 +57,7 @@ void LightOccluder2DEditor::_node_removed(Node *p_node) {
if (p_node == node) {
node = NULL;
hide();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
@@ -88,8 +88,8 @@ void LightOccluder2DEditor::_wip_close(bool p_closed) {
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_closed", node->get_occluder_polygon()->is_closed());
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_closed", p_closed);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
wip.clear();
wip_active = false;
@@ -139,7 +139,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
wip.push_back(cpoint);
wip_active = true;
edited_point_pos = cpoint;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
edited_point = 1;
return true;
} else {
@@ -158,7 +158,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
wip.push_back(cpoint);
edited_point = wip.size();
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
//add wip point
@@ -183,8 +183,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
poly.push_back(cpoint);
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
}
@@ -217,7 +217,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
edited_point = closest_idx + 1;
edited_point_pos = xform.affine_inverse().xform(closest_pos);
node->get_occluder_polygon()->set_polygon(Variant(poly));
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
} else {
@@ -244,7 +244,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
pre_move_edit = poly;
edited_point = closest_idx;
edited_point_pos = xform.affine_inverse().xform(closest_pos);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
}
@@ -259,8 +259,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", pre_move_edit);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
edited_point = -1;
@@ -290,8 +290,8 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_undo_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
poly.remove(closest_idx);
undo_redo->add_do_method(node->get_occluder_polygon().ptr(), "set_polygon", poly);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
}
@@ -312,7 +312,7 @@ bool LightOccluder2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
cpoint = canvas_item_editor->snap_point(cpoint);
edited_point_pos = node->get_global_transform().affine_inverse().xform(cpoint);
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
}
@@ -369,7 +369,7 @@ void LightOccluder2DEditor::edit(Node *p_collision_polygon) {
wip.clear();
wip_active = false;
edited_point = -1;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
} else {
node = NULL;
}
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 88b3194490..c67c96798a 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -130,8 +130,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(curve.ptr(), "remove_point", i);
undo_redo->add_undo_method(curve.ptr(), "add_point", curve->get_point_position(i), curve->get_point_in(i), curve->get_point_out(i), i);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
} else if (dist_to_p_out < grab_threshold) {
@@ -139,8 +139,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Remove Out-Control from Curve"));
undo_redo->add_do_method(curve.ptr(), "set_point_out", i, Vector2());
undo_redo->add_undo_method(curve.ptr(), "set_point_out", i, curve->get_point_out(i));
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
} else if (dist_to_p_in < grab_threshold) {
@@ -148,8 +148,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Remove In-Control from Curve"));
undo_redo->add_do_method(curve.ptr(), "set_point_in", i, Vector2());
undo_redo->add_undo_method(curve.ptr(), "set_point_in", i, curve->get_point_in(i));
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return true;
}
@@ -165,8 +165,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Add Point to Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", cpoint);
undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count());
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
action = ACTION_MOVING_POINT;
@@ -174,7 +174,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
moving_from = curve->get_point_position(action_point);
moving_screen_from = gpoint;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
@@ -196,8 +196,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Move Point in Curve"));
undo_redo->add_do_method(curve.ptr(), "set_point_position", action_point, cpoint);
undo_redo->add_undo_method(curve.ptr(), "set_point_position", action_point, moving_from);
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
} break;
@@ -212,8 +212,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length));
undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_out_length));
}
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
} break;
@@ -228,8 +228,8 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length));
undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_in_length));
}
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
} break;
@@ -280,7 +280,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
} break;
}
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
return true;
}
}
@@ -331,7 +331,7 @@ void Path2DEditor::_node_visibility_changed() {
if (!node)
return;
- canvas_item_editor->get_viewport_control()->update();
+ canvas_item_editor->update_viewport();
}
void Path2DEditor::edit(Node *p_path2d) {
@@ -406,8 +406,8 @@ void Path2DEditor::_mode_selected(int p_mode) {
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin);
undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count());
- undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update");
- undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update");
+ undo_redo->add_do_method(canvas_item_editor, "update_viewport");
+ undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
return;
}
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/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index e97da67ddd..27f5910d94 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -817,6 +817,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
if (tx->get_selection_to_column() == 0)
end -= 1;
+ int col_to = tx->get_selection_to_column();
+ int cursor_pos = tx->cursor_get_column();
+
// Check if all lines in the selected block are commented
bool is_commented = true;
for (int i = begin; i <= end; i++) {
@@ -839,19 +842,42 @@ void ScriptTextEditor::_edit_option(int p_op) {
}
tx->set_line(i, line_text);
}
+
+ // Adjust selection & cursor position.
+ int offset = is_commented ? -1 : 1;
+ int col_from = tx->get_selection_from_column() > 0 ? tx->get_selection_from_column() + offset : 0;
+
+ if (is_commented && tx->cursor_get_column() == tx->get_line(tx->cursor_get_line()).length() + 1)
+ cursor_pos += 1;
+
+ if (tx->get_selection_to_column() != 0 && col_to != tx->get_line(tx->get_selection_to_line()).length() + 1)
+ col_to += offset;
+
+ if (tx->cursor_get_column() != 0)
+ cursor_pos += offset;
+
+ tx->select(begin, col_from, tx->get_selection_to_line(), col_to);
+ tx->cursor_set_column(cursor_pos);
+
} else {
int begin = tx->cursor_get_line();
String line_text = tx->get_line(begin);
- if (line_text.begins_with(delimiter))
+ int col = tx->cursor_get_column();
+ if (line_text.begins_with(delimiter)) {
line_text = line_text.substr(delimiter.length(), line_text.length());
- else
+ col -= 1;
+ } else {
line_text = delimiter + line_text;
+ col += 1;
+ }
+
tx->set_line(begin, line_text);
+ tx->cursor_set_column(col);
}
tx->end_complex_operation();
tx->update();
- //tx->deselect();
+
} break;
case EDIT_COMPLETE: {
diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index f57614b3b3..ab89d170da 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -952,8 +952,10 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (b->is_pressed()) {
int mod = _get_key_modifier(b);
- if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
- set_freelook_active(true);
+ if (!orthogonal) {
+ if (mod == _get_key_modifier_setting("editors/3d/freelook/freelook_activation_modifier")) {
+ set_freelook_active(true);
+ }
}
} else {
set_freelook_active(false);
@@ -1134,7 +1136,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
}
if (clicked) {
_select_clicked(clicked_wants_append, true);
- //clickd processing was deferred
+ // Processing was deferred.
clicked = 0;
}
@@ -1241,7 +1243,7 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (!clicked_includes_current) {
_select_clicked(clicked_wants_append, true);
- //clickd processing was deferred
+ // Processing was deferred.
}
_compute_edit(_edit.mouse_pos);
@@ -1339,7 +1341,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
float snap = 0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1468,7 +1471,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
List<Node *> &selection = editor_selection->get_selected_node_list();
- bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW); // Disable local transformation for TRANSFORM_VIEW
+ // Disable local transformation for TRANSFORM_VIEW
+ bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);
float snap = 0;
if (_edit.snap || spatial_editor->is_snap_enabled()) {
@@ -1643,6 +1647,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_ZOOM;
} else if (freelook_active) {
nav_mode = NAVIGATION_LOOK;
+ } else if (orthogonal) {
+ nav_mode = NAVIGATION_PAN;
}
} else if (m->get_button_mask() & BUTTON_MASK_MIDDLE) {
@@ -1793,7 +1799,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
if (ED_IS_SHORTCUT("spatial_editor/focus_selection", p_event)) {
_menu_option(VIEW_CENTER_TO_SELECTION);
}
- if (ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
+ // Orthgonal mode doesn't work in freelook.
+ if (!freelook_active && ED_IS_SHORTCUT("spatial_editor/switch_perspective_orthogonal", p_event)) {
_menu_option(orthogonal ? VIEW_PERSPECTIVE : VIEW_ORTHOGONAL);
_update_name();
}
@@ -1823,7 +1830,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
set_message(TTR("Animation Key Inserted."));
}
- if (ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
+ // Freelook doesn't work in orthogonal mode.
+ if (!orthogonal && ED_IS_SHORTCUT("spatial_editor/freelook_toggle", p_event)) {
set_freelook_active(!is_freelook_active());
} else if (k->get_scancode() == KEY_ESCAPE) {
@@ -1911,37 +1919,38 @@ void SpatialEditorViewport::_nav_orbit(Ref<InputEventWithModifiers> p_event, con
void SpatialEditorViewport::_nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative) {
- // Freelook only works properly in perspective.
- // It could technically work in ortho, but it's terrible for a user due to FOV being a fixed width.
- if (!orthogonal) {
- real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
- real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
- bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis");
-
- // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
- Transform prev_camera_transform = to_camera_transform(cursor);
+ if (orthogonal) {
+ _nav_pan(p_event, p_relative);
+ return;
+ }
- if (invert_y_axis) {
- cursor.x_rot -= p_relative.y * radians_per_pixel;
- } else {
- cursor.x_rot += p_relative.y * radians_per_pixel;
- }
- cursor.y_rot += p_relative.x * radians_per_pixel;
- if (cursor.x_rot > Math_PI / 2.0)
- cursor.x_rot = Math_PI / 2.0;
- if (cursor.x_rot < -Math_PI / 2.0)
- cursor.x_rot = -Math_PI / 2.0;
+ real_t degrees_per_pixel = EditorSettings::get_singleton()->get("editors/3d/navigation_feel/orbit_sensitivity");
+ real_t radians_per_pixel = Math::deg2rad(degrees_per_pixel);
+ bool invert_y_axis = EditorSettings::get_singleton()->get("editors/3d/navigation/invert_y-axis");
- // Look is like the opposite of Orbit: the focus point rotates around the camera
- Transform camera_transform = to_camera_transform(cursor);
- Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
- Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
- Vector3 diff = prev_pos - pos;
- cursor.pos += diff;
+ // Note: do NOT assume the camera has the "current" transform, because it is interpolated and may have "lag".
+ Transform prev_camera_transform = to_camera_transform(cursor);
- name = "";
- _update_name();
+ if (invert_y_axis) {
+ cursor.x_rot -= p_relative.y * radians_per_pixel;
+ } else {
+ cursor.x_rot += p_relative.y * radians_per_pixel;
}
+ cursor.y_rot += p_relative.x * radians_per_pixel;
+ if (cursor.x_rot > Math_PI / 2.0)
+ cursor.x_rot = Math_PI / 2.0;
+ if (cursor.x_rot < -Math_PI / 2.0)
+ cursor.x_rot = -Math_PI / 2.0;
+
+ // Look is like the opposite of Orbit: the focus point rotates around the camera
+ Transform camera_transform = to_camera_transform(cursor);
+ Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
+ Vector3 diff = prev_pos - pos;
+ cursor.pos += diff;
+
+ name = "";
+ _update_name();
}
void SpatialEditorViewport::set_freelook_active(bool active_now) {
@@ -2250,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) {
@@ -2260,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"));
}
}
@@ -2521,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());
@@ -2570,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;
@@ -2642,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: {
@@ -2760,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 {
@@ -2768,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();
}
}
@@ -3425,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);
@@ -3477,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();
@@ -3502,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);
@@ -3520,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;
@@ -5443,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/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 27c3ff960b..ed1fa9b217 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -43,8 +43,8 @@ void TileMapEditor::_notification(int p_what) {
case NOTIFICATION_PROCESS: {
- if (bucket_queue.size() && canvas_item_editor_viewport) {
- canvas_item_editor_viewport->update();
+ if (bucket_queue.size()) {
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} break;
@@ -97,27 +97,27 @@ void TileMapEditor::_menu_option(int p_option) {
// immediately without pressing the left mouse button first
tool = TOOL_NONE;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_BUCKET: {
tool = TOOL_BUCKET;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_PICK_TILE: {
tool = TOOL_PICKING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_SELECT: {
tool = TOOL_SELECTING;
selection_active = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_COPY: {
@@ -126,7 +126,7 @@ void TileMapEditor::_menu_option(int p_option) {
if (selection_active) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} break;
case OPTION_ERASE_SELECTION: {
@@ -141,7 +141,7 @@ void TileMapEditor::_menu_option(int p_option) {
selection_active = false;
copydata.clear();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} break;
case OPTION_FIX_INVALID: {
@@ -165,7 +165,7 @@ void TileMapEditor::_menu_option(int p_option) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} break;
}
@@ -182,13 +182,13 @@ void TileMapEditor::_palette_multi_selected(int index, bool selected) {
void TileMapEditor::_canvas_mouse_enter() {
mouse_over = true;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_canvas_mouse_exit() {
mouse_over = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
Vector<int> TileMapEditor::get_selected_tiles() const {
@@ -524,7 +524,7 @@ void TileMapEditor::_pick_tile(const Point2 &p_pos) {
transp->set_pressed(node->is_cell_transposed(p_pos.x, p_pos.y));
_update_transform_buttons();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool erase, bool preview) {
@@ -671,7 +671,7 @@ void TileMapEditor::_select(const Point2i &p_from, const Point2i &p_to) {
rectangle.position = begin;
rectangle.size = end - begin;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_erase_selection() {
@@ -978,7 +978,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
paint_undo.clear();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} else if (tool == TOOL_RECTANGLE_PAINT) {
@@ -995,7 +995,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
_finish_undo();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
} else if (tool == TOOL_PASTING) {
@@ -1011,12 +1011,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
_finish_undo();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true; // We want to keep the Pasting tool
} else if (tool == TOOL_SELECTING) {
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
} else if (tool == TOOL_BUCKET) {
@@ -1055,7 +1055,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_NONE;
selection_active = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1065,7 +1065,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_NONE;
copydata.clear();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1106,7 +1106,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_finish_undo();
if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) {
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
tool = TOOL_NONE;
@@ -1149,7 +1149,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (new_over_tile != over_tile) {
over_tile = new_over_tile;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
if (show_tile_info) {
@@ -1235,7 +1235,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_set_cell(points[i], invalid_cell);
}
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
return true;
@@ -1294,7 +1294,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_NONE;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1308,13 +1308,13 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
// NOTE: We do not set tool = TOOL_PAINTING as this begins painting
// immediately without pressing the left mouse button first
tool = TOOL_NONE;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/bucket_fill", p_event)) {
tool = TOOL_BUCKET;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1327,7 +1327,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_SELECTING;
selection_active = false;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1337,7 +1337,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (selection_active) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
@@ -1354,7 +1354,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
tool = TOOL_PASTING;
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
}
@@ -1368,21 +1368,21 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
flip_h = !flip_h;
mirror_x->set_pressed(flip_h);
_update_transform_buttons();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/mirror_y", p_event)) {
flip_v = !flip_v;
mirror_y->set_pressed(flip_v);
_update_transform_buttons();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
if (ED_IS_SHORTCUT("tile_map_editor/transpose", p_event)) {
transpose = !transpose;
transp->set_pressed(transpose);
_update_transform_buttons();
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
return true;
}
}
@@ -1643,9 +1643,7 @@ void TileMapEditor::edit(Node *p_tile_map) {
void TileMapEditor::_tileset_settings_changed() {
_update_palette();
-
- if (canvas_item_editor_viewport)
- canvas_item_editor_viewport->update();
+ CanvasItemEditor::get_singleton()->update_viewport();
}
void TileMapEditor::_icon_size_changed(float p_value) {
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index c611327a31..9ef6e4332c 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -132,7 +132,7 @@ void CustomPropertyEditor::_menu_option(int p_which) {
emit_signal("variant_changed");
} else if (hint == PROPERTY_HINT_ENUM) {
- v = p_which;
+ v = menu->get_item_metadata(p_which);
emit_signal("variant_changed");
}
} break;
@@ -427,12 +427,14 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
} else if (hint == PROPERTY_HINT_ENUM) {
Vector<String> options = hint_text.split(",");
+ int current_val = 0;
for (int i = 0; i < options.size(); i++) {
- if (options[i].find(":") != -1) {
- menu->add_item(options[i].get_slicec(':', 0), options[i].get_slicec(':', 1).to_int());
- } else {
- menu->add_item(options[i], i);
- }
+ Vector<String> text_split = options[i].split(":");
+ if (text_split.size() != 1)
+ current_val = text_split[1].to_int();
+ menu->add_item(text_split[0]);
+ menu->set_item_metadata(i, current_val);
+ current_val += 1;
}
menu->set_position(get_position());
menu->popup();
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index a6a014f3bd..f908641bab 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -53,6 +53,13 @@ void SceneTreeDock::_nodes_drag_begin() {
}
}
+void SceneTreeDock::_quick_open() {
+ Vector<String> files = quick_open->get_selected_files();
+ for (int i = 0; i < files.size(); i++) {
+ instance(files[i]);
+ }
+}
+
void SceneTreeDock::_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> mb = p_event;
@@ -319,16 +326,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
- List<String> extensions;
- ResourceLoader::get_recognized_extensions_for_type("PackedScene", &extensions);
- file->clear_filters();
- for (int i = 0; i < extensions.size(); i++) {
-
- file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
- }
-
- file->popup_centered_ratio();
+ quick_open->popup_dialog("PackedScene", true);
+ quick_open->set_title(TTR("Instance Child Scene"));
} break;
case TOOL_REPLACE: {
@@ -574,6 +573,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_do_method(editor, "set_edited_scene", node);
editor_data->get_undo_redo().add_do_method(node, "set_filename", root->get_filename());
editor_data->get_undo_redo().add_do_method(root, "set_filename", String());
+ editor_data->get_undo_redo().add_do_method(node, "set_owner", (Object *)NULL);
+ editor_data->get_undo_redo().add_do_method(root, "set_owner", node);
_node_replace_owner(root, root, node, MODE_DO);
editor_data->get_undo_redo().add_undo_method(root, "set_filename", root->get_filename());
@@ -581,6 +582,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_undo_method(node, "remove_child", root);
editor_data->get_undo_redo().add_undo_method(editor, "set_edited_scene", root);
editor_data->get_undo_redo().add_undo_method(node->get_parent(), "add_child", node);
+ editor_data->get_undo_redo().add_undo_method(root, "set_owner", (Object *)NULL);
+ editor_data->get_undo_redo().add_undo_method(node, "set_owner", root);
+
_node_replace_owner(root, root, root, MODE_UNDO);
editor_data->get_undo_redo().add_do_method(scene_tree, "update_tree");
@@ -982,7 +986,7 @@ void SceneTreeDock::_notification(int p_what) {
void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) {
- if (p_node->get_owner() == p_base || !p_node->get_owner()) {
+ if (p_node->get_owner() == p_base && p_node != p_root) {
UndoRedo *undo_redo = &editor_data->get_undo_redo();
switch (p_mode) {
case MODE_BIDI: {
@@ -1302,6 +1306,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!"));
@@ -1608,6 +1619,14 @@ void SceneTreeDock::_delete_confirm() {
void SceneTreeDock::_update_script_button() {
if (EditorNode::get_singleton()->get_editor_selection()->get_selection().size() == 1) {
button_create_script->show();
+ Node *n = EditorNode::get_singleton()->get_editor_selection()->get_selected_node_list()[0];
+ if (n->get_script().is_null()) {
+ button_create_script->set_icon(get_icon("ScriptCreate", "EditorIcons"));
+ button_create_script->set_tooltip(TTR("Attach a new or existing script for the selected node."));
+ } else {
+ button_create_script->set_icon(get_icon("ScriptExtend", "EditorIcons"));
+ button_create_script->set_tooltip(TTR("Extend the selected node's script with a new or existing script."));
+ }
} else {
button_create_script->hide();
}
@@ -2283,6 +2302,7 @@ void SceneTreeDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_new_scene_from"), &SceneTreeDock::_new_scene_from);
ClassDB::bind_method(D_METHOD("_nodes_dragged"), &SceneTreeDock::_nodes_dragged);
ClassDB::bind_method(D_METHOD("_files_dropped"), &SceneTreeDock::_files_dropped);
+ ClassDB::bind_method(D_METHOD("_quick_open"), &SceneTreeDock::_quick_open);
ClassDB::bind_method(D_METHOD("_script_dropped"), &SceneTreeDock::_script_dropped);
ClassDB::bind_method(D_METHOD("_tree_rmb"), &SceneTreeDock::_tree_rmb);
ClassDB::bind_method(D_METHOD("_filter_changed"), &SceneTreeDock::_filter_changed);
@@ -2354,7 +2374,6 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
tb = memnew(ToolButton);
tb->connect("pressed", this, "_tool_selected", make_binds(TOOL_ATTACH_SCRIPT, false));
- tb->set_tooltip(TTR("Attach a new or existing script for the selected node."));
tb->set_shortcut(ED_GET_SHORTCUT("scene_tree/attach_script"));
filter_hbc->add_child(tb);
tb->hide();
@@ -2433,9 +2452,9 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel
accept = memnew(AcceptDialog);
add_child(accept);
- file = memnew(EditorFileDialog);
- add_child(file);
- file->connect("file_selected", this, "instance");
+ quick_open = memnew(EditorQuickOpen);
+ add_child(quick_open);
+ quick_open->connect("quick_open", this, "_quick_open");
set_process_unhandled_key_input(true);
delete_dialog = memnew(ConfirmationDialog);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index eea34a3ec5..3939f4f361 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -36,6 +36,7 @@
#include "editor/editor_data.h"
#include "editor/editor_sub_scene.h"
#include "editor/groups_editor.h"
+#include "editor/quick_open.h"
#include "editor/rename_dialog.h"
#include "editor/reparent_dialog.h"
#include "editor/script_create_dialog.h"
@@ -125,7 +126,7 @@ class SceneTreeDock : public VBoxContainer {
ConfirmationDialog *editable_instance_remove_dialog;
ReparentDialog *reparent_dialog;
- EditorFileDialog *file;
+ EditorQuickOpen *quick_open;
EditorSubScene *import_subscene_dialog;
EditorFileDialog *new_scene_from_dialog;
@@ -194,6 +195,7 @@ class SceneTreeDock : public VBoxContainer {
void _nodes_dragged(Array p_nodes, NodePath p_to, int p_type);
void _files_dropped(Vector<String> p_files, NodePath p_to, int p_type);
void _script_dropped(String p_file, NodePath p_to);
+ void _quick_open();
void _tree_rmb(const Vector2 &p_menu_pos);
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index 07670bb420..848e4def6d 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -73,7 +73,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
undo_redo->create_action(TTR("Toggle Visible"));
_toggle_visible(n);
List<Node *> selection = editor_selection->get_selected_node_list();
- if (selection.size() > 1) {
+ if (selection.size() > 1 && selection.find(n) != NULL) {
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
Node *nv = E->get();
ERR_FAIL_COND(!nv);
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/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp
index a321cb16c5..881f20cecb 100644
--- a/editor/spatial_editor_gizmos.cpp
+++ b/editor/spatial_editor_gizmos.cpp
@@ -3454,10 +3454,9 @@ void CollisionShapeSpatialGizmoPlugin::redraw(EditorSpatialGizmo *p_gizmo) {
if (points.size() > 3) {
- QuickHull qh;
Vector<Vector3> varr = Variant(points);
Geometry::MeshData md;
- Error err = qh.build(varr, md);
+ Error err = QuickHull::build(varr, md);
if (err == OK) {
Vector<Vector3> points;
points.resize(md.edges.size() * 2);
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/main/main.cpp b/main/main.cpp
index 41ae368087..6310281ff8 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -729,16 +729,22 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef TOOLS_ENABLED
editor = false;
#else
- OS::get_singleton()->print("Error: Could not load game path '%s'.\n", project_path.ascii().get_data());
+ String error_msg = "Error: Could not load game data at path '" + project_path + "'. Is the .pck file missing?\n";
+ OS::get_singleton()->print(error_msg.ascii().get_data());
+ OS::get_singleton()->alert(error_msg);
goto error;
#endif
}
GLOBAL_DEF("memory/limits/multithreaded_server/rid_pool_prealloc", 60);
+ ProjectSettings::get_singleton()->set_custom_property_info("memory/limits/multithreaded_server/rid_pool_prealloc", PropertyInfo(Variant::INT, "memory/limits/multithreaded_server/rid_pool_prealloc", PROPERTY_HINT_RANGE, "0,500,1")); // No negative and limit to 500 due to crashes
GLOBAL_DEF("network/limits/debugger_stdout/max_chars_per_second", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_chars_per_second", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_chars_per_second", PROPERTY_HINT_RANGE, "0, 4096, 1, or_greater"));
GLOBAL_DEF("network/limits/debugger_stdout/max_messages_per_frame", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_messages_per_frame", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_messages_per_frame", PROPERTY_HINT_RANGE, "0, 20, 1, or_greater"));
GLOBAL_DEF("network/limits/debugger_stdout/max_errors_per_frame", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("network/limits/debugger_stdout/max_errors_per_frame", PropertyInfo(Variant::INT, "network/limits/debugger_stdout/max_errors_per_frame", PROPERTY_HINT_RANGE, "0, 20, 1, or_greater"));
if (debug_mode == "remote") {
@@ -811,6 +817,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF("logging/file_logging/enable_file_logging", false);
GLOBAL_DEF("logging/file_logging/log_path", "user://logs/log.txt");
GLOBAL_DEF("logging/file_logging/max_log_files", 10);
+ ProjectSettings::get_singleton()->set_custom_property_info("logging/file_logging/max_log_files", PropertyInfo(Variant::INT, "logging/file_logging/max_log_files", PROPERTY_HINT_RANGE, "0,20,1,or_greater")); //no negative numbers
if (FileAccess::get_create_func(FileAccess::ACCESS_USERDATA) && GLOBAL_GET("logging/file_logging/enable_file_logging")) {
String base_path = GLOBAL_GET("logging/file_logging/log_path");
int max_files = GLOBAL_GET("logging/file_logging/max_log_files");
@@ -1001,6 +1008,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
Engine::get_singleton()->set_iterations_per_second(GLOBAL_DEF("physics/common/physics_fps", 60));
Engine::get_singleton()->set_physics_jitter_fix(GLOBAL_DEF("physics/common/physics_jitter_fix", 0.5));
Engine::get_singleton()->set_target_fps(GLOBAL_DEF("debug/settings/fps/force_fps", 0));
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/fps/force_fps", PropertyInfo(Variant::INT, "debug/settings/fps/force_fps", PROPERTY_HINT_RANGE, "0,120,1,or_greater"));
GLOBAL_DEF("debug/settings/stdout/print_fps", false);
@@ -1009,10 +1017,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
if (frame_delay == 0) {
frame_delay = GLOBAL_DEF("application/run/frame_delay_msec", 0);
+ ProjectSettings::get_singleton()->set_custom_property_info("application/run/frame_delay_msec", PropertyInfo(Variant::INT, "application/run/frame_delay_msec", PROPERTY_HINT_RANGE, "0,100,1,or_greater")); // No negative numbers
}
OS::get_singleton()->set_low_processor_usage_mode(GLOBAL_DEF("application/run/low_processor_mode", false));
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(GLOBAL_DEF("application/run/low_processor_mode_sleep_usec", 8000));
+ ProjectSettings::get_singleton()->set_custom_property_info("application/run/low_processor_mode_sleep_usec", PropertyInfo(Variant::INT, "application/run/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "0,33200,1,or_greater")); // No negative numbers
Engine::get_singleton()->set_frame_delay(frame_delay);
@@ -1641,7 +1651,7 @@ bool Main::start() {
GLOBAL_DEF("display/window/stretch/aspect", "ignore");
ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"));
GLOBAL_DEF("display/window/stretch/shrink", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::STRING, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1,8,1"));
+ ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::REAL, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "1,8,1"));
sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);
diff --git a/main/tests/test_string.cpp b/main/tests/test_string.cpp
index 74157d63c9..7e19c7bf3e 100644
--- a/main/tests/test_string.cpp
+++ b/main/tests/test_string.cpp
@@ -480,7 +480,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish % frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
//////// INTS
@@ -491,7 +491,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 5 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Int left padded with zeroes.
format = "fish %05d frog";
@@ -500,7 +500,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 00005 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Int left padded with spaces.
format = "fish %5d frog";
@@ -509,7 +509,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 5 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Int right padded with spaces.
format = "fish %-5d frog";
@@ -518,7 +518,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 5 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Int with sign (positive).
format = "fish %+d frog";
@@ -527,7 +527,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish +5 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Negative int.
format = "fish %d frog";
@@ -536,7 +536,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish -5 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Hex (lower)
format = "fish %x frog";
@@ -545,7 +545,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 2d frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Hex (upper)
format = "fish %X frog";
@@ -554,7 +554,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 2D frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Octal
format = "fish %o frog";
@@ -563,7 +563,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 143 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
////// REALS
@@ -574,7 +574,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99.990000 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real left-padded
format = "fish %11f frog";
@@ -583,7 +583,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99.990000 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real right-padded
format = "fish %-11f frog";
@@ -592,7 +592,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99.990000 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real given int.
format = "fish %f frog";
@@ -601,7 +601,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99.000000 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real with sign (positive).
format = "fish %+f frog";
@@ -610,7 +610,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish +99.990000 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real with 1 decimals.
format = "fish %.1f frog";
@@ -619,7 +619,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 100.0 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real with 12 decimals.
format = "fish %.12f frog";
@@ -628,7 +628,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99.990000000000 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Real with no decimals.
format = "fish %.f frog";
@@ -637,7 +637,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 100 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
/////// Strings.
@@ -648,7 +648,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish cheese frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// String left-padded
format = "fish %10s frog";
@@ -657,7 +657,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish cheese frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// String right-padded
format = "fish %-10s frog";
@@ -666,7 +666,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish cheese frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
///// Characters
@@ -677,7 +677,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish A frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Character as int.
format = "fish %c frog";
@@ -686,7 +686,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish A frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
///// Dynamic width
@@ -698,7 +698,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish cheese frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Int dynamic width
format = "fish %*d frog";
@@ -708,7 +708,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Float dynamic width
format = "fish %*.*f frog";
@@ -719,7 +719,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == String("fish 99.990 frog") && !error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
///// Errors
@@ -730,7 +730,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "not enough arguments for format string" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// More arguments than formats.
format = "fish %s frog";
@@ -740,7 +740,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "not all arguments converted during string formatting" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Incomplete format.
format = "fish %10";
@@ -749,7 +749,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "incomplete format" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Bad character in format string
format = "fish %&f frog";
@@ -758,7 +758,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "unsupported format character" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Too many decimals.
format = "fish %2.2.2f frog";
@@ -767,7 +767,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "too many decimal points in format" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// * not a number
format = "fish %*f frog";
@@ -777,7 +777,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "* wants number" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Character too long.
format = "fish %c frog";
@@ -786,7 +786,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "%c requires number or single-character string" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
// Character bad type.
format = "fish %c frog";
@@ -795,7 +795,7 @@ bool test_28() {
output = format.sprintf(args, &error);
success = (output == "%c requires number or single-character string" && error);
OS::get_singleton()->print(output_format, format.c_str(), output.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
return state;
}
@@ -819,37 +819,127 @@ bool test_29() {
String ip4 = "192.168.0.1";
bool success = ip4.is_valid_ip_address();
OS::get_singleton()->print("Is valid ipv4: %ls, %s\n", ip4.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
ip4 = "192.368.0.1";
success = (!ip4.is_valid_ip_address());
OS::get_singleton()->print("Is invalid ipv4: %ls, %s\n", ip4.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
String ip6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
success = ip6.is_valid_ip_address();
OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
ip6 = "2001:0db8:85j3:0000:0000:8a2e:0370:7334";
success = (!ip6.is_valid_ip_address());
OS::get_singleton()->print("Is invalid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
ip6 = "2001:0db8:85f345:0000:0000:8a2e:0370:7334";
success = (!ip6.is_valid_ip_address());
OS::get_singleton()->print("Is invalid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
ip6 = "2001:0db8::0:8a2e:370:7334";
success = (ip6.is_valid_ip_address());
OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
ip6 = "::ffff:192.168.0.1";
success = (ip6.is_valid_ip_address());
OS::get_singleton()->print("Is valid ipv6: %ls, %s\n", ip6.c_str(), success ? "OK" : "FAIL");
- if (!success) state = false;
+ state = state && success;
+
+ return state;
+};
+
+bool test_30() {
+ bool state = true;
+ bool success = true;
+ String input = "bytes2var";
+ String output = "Bytes 2 Var";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "linear2db";
+ output = "Linear 2 Db";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "vector3";
+ output = "Vector 3";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "sha256";
+ output = "Sha 256";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "2db";
+ output = "2 Db";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "PascalCase";
+ output = "Pascal Case";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "PascalPascalCase";
+ output = "Pascal Pascal Case";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "snake_case";
+ output = "Snake Case";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "snake_snake_case";
+ output = "Snake Snake Case";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "sha256sum";
+ output = "Sha 256 Sum";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "cat2dog";
+ output = "Cat 2 Dog";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "function(name)";
+ output = "Function(name)";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls (existing incorrect behavior): %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "snake_case_function(snake_case_arg)";
+ output = "Snake Case Function(snake Case Arg)";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls (existing incorrect behavior): %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
+
+ input = "snake_case_function( snake_case_arg )";
+ output = "Snake Case Function( Snake Case Arg )";
+ success = (input.capitalize() == output);
+ state = state && success;
+ OS::get_singleton()->print("Capitalize %ls: %ls, %s\n", input.c_str(), output.c_str(), success ? "OK" : "FAIL");
return state;
};
@@ -887,6 +977,7 @@ TestFunc test_funcs[] = {
test_27,
test_28,
test_29,
+ test_30,
0
};
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/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index c199667270..e4aee842ba 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -72,6 +72,7 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
bool in_word = false;
bool in_function_name = false;
bool in_variable_declaration = false;
+ bool in_function_args = false;
bool in_member_variable = false;
bool in_node_path = false;
bool is_hex_notation = false;
@@ -220,17 +221,24 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
}
if (is_symbol) {
- in_function_name = false;
- in_member_variable = false;
- if (expect_type && str[j] != ' ' && str[j] != '\t' && str[j] != ':') {
+ if (in_function_name) {
+ in_function_args = true;
+ }
+
+ if (in_function_args && str[j] == ')') {
+ in_function_args = false;
+ }
+
+ if (expect_type && prev_is_char) {
expect_type = false;
}
+
if (j > 0 && str[j] == '>' && str[j - 1] == '-') {
expect_type = true;
}
- if (in_variable_declaration || previous_text == "(" || previous_text == ",") {
+ if (in_variable_declaration || in_function_args) {
int k = j;
// Skip space
while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
@@ -244,6 +252,8 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
}
in_variable_declaration = false;
+ in_function_name = false;
+ in_member_variable = false;
}
if (!in_node_path && in_region == -1 && str[j] == '$') {
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 48c1760662..ef86ccae14 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -2065,12 +2065,12 @@ GDScriptLanguage::GDScriptLanguage() {
_debug_call_stack_pos = 0;
int dmcs = GLOBAL_DEF("debug/settings/gdscript/max_call_stack", 1024);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/gdscript/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
+
if (ScriptDebugger::get_singleton()) {
//debugging enabled!
_debug_max_call_stack = dmcs;
- if (_debug_max_call_stack < 1024)
- _debug_max_call_stack = 1024;
_call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
} else {
@@ -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/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 77e1b7290e..c37142b3c1 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -128,8 +128,8 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
"'.'",
"'?'",
"':'",
- "'->'",
"'$'",
+ "'->'",
"'\\n'",
"PI",
"TAU",
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/SCsub b/modules/mono/SCsub
index e4691ee5c8..9a62b0fdc9 100644
--- a/modules/mono/SCsub
+++ b/modules/mono/SCsub
@@ -88,9 +88,6 @@ vars.Update(env_mono)
if env_mono['mono_glue']:
env_mono.Append(CPPDEFINES=['MONO_GLUE_ENABLED'])
-if ARGUMENTS.get('yolo_copy', False):
- env_mono.Append(CPPDEFINES=['YOLO_COPY'])
-
# Configure TLS checks
import tls_configure
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index bcf08026bc..710682d3aa 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -97,7 +97,7 @@
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
-#define BINDINGS_GENERATOR_VERSION UINT32_C(3)
+#define BINDINGS_GENERATOR_VERSION UINT32_C(5)
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN = "\t%0 %1_in = %1;\n";
@@ -173,23 +173,74 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up
return ret;
}
-String BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
+int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
CRASH_COND(p_ienum.constants.empty());
- const List<ConstantInterface>::Element *front = p_ienum.constants.front();
- int candidate_len = front->get().name.length();
+ const ConstantInterface &front_iconstant = p_ienum.constants.front()->get();
+ Vector<String> front_parts = front_iconstant.name.split("_", /* p_allow_empty: */ true);
+ int candidate_len = front_parts.size() - 1;
- for (const List<ConstantInterface>::Element *E = front->next(); E; E = E->next()) {
- int j = 0;
- for (j = 0; j < candidate_len && j < E->get().name.length(); j++) {
- if (front->get().name[j] != E->get().name[j])
- break;
+ if (candidate_len == 0)
+ return 0;
+
+ for (const List<ConstantInterface>::Element *E = p_ienum.constants.front()->next(); E; E = E->next()) {
+ const ConstantInterface &iconstant = E->get();
+
+ Vector<String> parts = iconstant.name.split("_", /* p_allow_empty: */ true);
+
+ int i;
+ for (i = 0; i < candidate_len && i < parts.size(); i++) {
+ if (front_parts[i] != parts[i]) {
+ // HARDCODED: Some Flag enums have the prefix 'FLAG_' for everything except 'FLAGS_DEFAULT' (same for 'METHOD_FLAG_' and'METHOD_FLAGS_DEFAULT').
+ bool hardcoded_exc = (i == candidate_len - 1 && ((front_parts[i] == "FLAGS" && parts[i] == "FLAG") || (front_parts[i] == "FLAG" && parts[i] == "FLAGS")));
+ if (!hardcoded_exc)
+ break;
+ }
}
- candidate_len = j;
+ candidate_len = i;
+
+ if (candidate_len == 0)
+ return 0;
}
- return front->get().name.substr(0, candidate_len);
+ return candidate_len;
+}
+
+void BindingsGenerator::_apply_prefix_to_enum_constants(BindingsGenerator::EnumInterface &p_ienum, int p_prefix_length) {
+
+ if (p_prefix_length > 0) {
+ for (List<ConstantInterface>::Element *E = p_ienum.constants.front(); E; E = E->next()) {
+ int curr_prefix_length = p_prefix_length;
+
+ ConstantInterface &curr_const = E->get();
+
+ String constant_name = curr_const.name;
+
+ Vector<String> parts = constant_name.split("_", /* p_allow_empty: */ true);
+
+ if (parts.size() <= curr_prefix_length)
+ continue;
+
+ if (parts[curr_prefix_length][0] >= '0' && parts[curr_prefix_length][0] <= '9') {
+ // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
+ // so we make the prefix for this constant one word shorter in those cases.
+ for (curr_prefix_length = curr_prefix_length - 1; curr_prefix_length > 0; curr_prefix_length--) {
+ if (parts[curr_prefix_length][0] < '0' || parts[curr_prefix_length][0] > '9')
+ break;
+ }
+ }
+
+ constant_name = "";
+ for (int i = curr_prefix_length; i < parts.size(); i++) {
+ if (i > curr_prefix_length)
+ constant_name += "_";
+ constant_name += parts[i];
+ }
+
+ curr_const.proxy_name = snake_to_pascal_case(constant_name, true);
+ }
+ }
}
void BindingsGenerator::_generate_method_icalls(const TypeInterface &p_itype) {
@@ -272,7 +323,7 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
}
p_output.push_back(MEMBER_BEGIN "public const int ");
- p_output.push_back(iconstant.name);
+ p_output.push_back(iconstant.proxy_name);
p_output.push_back(" = ");
p_output.push_back(itos(iconstant.value));
p_output.push_back(";");
@@ -334,25 +385,8 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
p_output.push_back(INDENT2 "/// </summary>\n");
}
- String constant_name = iconstant.name;
-
- if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) {
- constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length());
- }
-
- if (constant_name[0] >= '0' && constant_name[0] <= '9') {
- // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
- // so we make the prefix one word shorter in those cases.
- int i = 0;
- for (i = ienum.prefix.length() - 1; i >= 0; i--) {
- if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z')
- break;
- }
- constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name;
- }
-
p_output.push_back(INDENT2);
- p_output.push_back(constant_name);
+ p_output.push_back(iconstant.proxy_name);
p_output.push_back(" = ");
p_output.push_back(itos(iconstant.value));
p_output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
@@ -646,8 +680,11 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
List<String> output;
output.push_back("using System;\n"); // IntPtr
+ output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
+
output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
"'Missing XML comment for publicly visible type or member'\n");
+
output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
const DocData::ClassDoc *class_doc = itype.class_doc;
@@ -717,7 +754,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
}
output.push_back(MEMBER_BEGIN "public const int ");
- output.push_back(iconstant.name);
+ output.push_back(iconstant.proxy_name);
output.push_back(" = ");
output.push_back(itos(iconstant.value));
output.push_back(";");
@@ -757,25 +794,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.push_back(INDENT3 "/// </summary>\n");
}
- String constant_name = iconstant.name;
-
- if (!ienum.prefix.empty() && constant_name.begins_with(ienum.prefix)) {
- constant_name = constant_name.substr(ienum.prefix.length(), constant_name.length());
- }
-
- if (constant_name[0] >= '0' && constant_name[0] <= '9') {
- // The name of enum constants may begin with a numeric digit when strip from the enum prefix,
- // so we make the prefix one word shorter in those cases.
- int i = 0;
- for (i = ienum.prefix.length() - 1; i >= 0; i--) {
- if (ienum.prefix[i] >= 'A' && ienum.prefix[i] <= 'Z')
- break;
- }
- constant_name = ienum.prefix.substr(i, ienum.prefix.length()) + constant_name;
- }
-
output.push_back(INDENT3);
- output.push_back(constant_name);
+ output.push_back(iconstant.proxy_name);
output.push_back(" = ");
output.push_back(itos(iconstant.value));
output.push_back(E != ienum.constants.back() ? ",\n" : "\n");
@@ -1086,7 +1106,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
// Generate method
{
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
- p_output.push_back(MEMBER_BEGIN "private static IntPtr ");
+ p_output.push_back(MEMBER_BEGIN "[DebuggerBrowsable(DebuggerBrowsableState.Never)]" MEMBER_BEGIN "private static IntPtr ");
p_output.push_back(method_bind_field + " = Object." ICALL_GET_METHODBIND "(" BINDINGS_NATIVE_NAME_FIELD ", \"");
p_output.push_back(p_imethod.name);
p_output.push_back("\");\n");
@@ -1843,11 +1863,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
EnumInterface ienum(enum_proxy_cname);
const List<StringName> &constants = enum_map.get(*k);
for (const List<StringName>::Element *E = constants.front(); E; E = E->next()) {
- int *value = class_info->constant_map.getptr(E->get());
+ const StringName &constant_cname = E->get();
+ String constant_name = constant_cname.operator String();
+ int *value = class_info->constant_map.getptr(constant_cname);
ERR_FAIL_NULL(value);
- constant_list.erase(E->get().operator String());
+ constant_list.erase(constant_name);
- ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value);
+ ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
iconstant.const_doc = NULL;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
@@ -1862,7 +1884,9 @@ void BindingsGenerator::_populate_object_type_interfaces() {
ienum.constants.push_back(iconstant);
}
- ienum.prefix = _determine_enum_prefix(ienum);
+ int prefix_length = _determine_enum_prefix(ienum);
+
+ _apply_prefix_to_enum_constants(ienum, prefix_length);
itype.enums.push_back(ienum);
@@ -1876,10 +1900,11 @@ void BindingsGenerator::_populate_object_type_interfaces() {
}
for (const List<String>::Element *E = constant_list.front(); E; E = E->next()) {
- int *value = class_info->constant_map.getptr(E->get());
+ const String &constant_name = E->get();
+ int *value = class_info->constant_map.getptr(StringName(E->get()));
ERR_FAIL_NULL(value);
- ConstantInterface iconstant(snake_to_pascal_case(E->get(), true), *value);
+ ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), *value);
iconstant.const_doc = NULL;
for (int i = 0; i < itype.class_doc->constants.size(); i++) {
@@ -1990,18 +2015,18 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
TypeInterface itype;
-#define INSERT_STRUCT_TYPE(m_type, m_type_in) \
- { \
- itype = TypeInterface::create_value_type(String(#m_type)); \
- itype.c_in = "\tMARSHALLED_IN(" #m_type ", %1, %1_in);\n"; \
- itype.c_out = "\tMARSHALLED_OUT(" #m_type ", %1, ret_out)\n" \
- "\treturn mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(%2), ret_out);\n"; \
- itype.c_arg_in = "&%s_in"; \
- itype.c_type_in = m_type_in; \
- itype.cs_in = "ref %s"; \
- itype.cs_out = "return (%1)%0;"; \
- itype.im_type_out = "object"; \
- builtin_types.insert(itype.cname, itype); \
+#define INSERT_STRUCT_TYPE(m_type, m_type_in) \
+ { \
+ itype = TypeInterface::create_value_type(String(#m_type)); \
+ itype.c_in = "\t%0 %1_in = MARSHALLED_IN(" #m_type ", %1);\n"; \
+ itype.c_out = "\treturn MARSHALLED_OUT(" #m_type ", %1);\n"; \
+ itype.c_arg_in = "&%s_in"; \
+ itype.c_type_in = "GDMonoMarshal::M_" #m_type "*"; \
+ itype.c_type_out = "GDMonoMarshal::M_" #m_type; \
+ itype.cs_in = "ref %s"; \
+ itype.cs_out = "return (%1)%0;"; \
+ itype.im_type_out = itype.cs_type; \
+ builtin_types.insert(itype.cname, itype); \
}
INSERT_STRUCT_TYPE(Vector2, "real_t*")
@@ -2019,26 +2044,31 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// bool
itype = TypeInterface::create_value_type(String("bool"));
- itype.c_arg_in = "&%s_in";
- // /* MonoBoolean <---> bool
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "bool";
- // */
- itype.c_type_in = "MonoBoolean";
- itype.c_type_out = itype.c_type_in;
+
+ {
+ // MonoBoolean <---> bool
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "bool";
+ itype.c_type_in = "MonoBoolean";
+ itype.c_type_out = itype.c_type_in;
+ itype.c_arg_in = "&%s_in";
+ }
itype.im_type_in = itype.name;
itype.im_type_out = itype.name;
builtin_types.insert(itype.cname, itype);
// int
+ // C interface is the same as that of enums. Remember to apply any
+ // changes done here to TypeInterface::postsetup_enum_type as well
itype = TypeInterface::create_value_type(String("int"));
itype.c_arg_in = "&%s_in";
- // /* ptrcall only supports int64_t and uint64_t
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "int64_t";
- // */
+ {
+ // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "int64_t";
+ }
itype.c_type_in = "int32_t";
itype.c_type_out = itype.c_type_in;
itype.im_type_in = itype.name;
@@ -2047,21 +2077,22 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
// real_t
itype = TypeInterface();
+ itype.name = "float"; // The name is always "float" in Variant, even with REAL_T_IS_DOUBLE.
+ itype.cname = itype.name;
#ifdef REAL_T_IS_DOUBLE
- itype.name = "double";
+ itype.proxy_name = "double";
#else
- itype.name = "float";
+ itype.proxy_name = "float";
#endif
- itype.cname = itype.name;
- itype.proxy_name = itype.name;
- itype.c_arg_in = "&%s_in";
- //* ptrcall only supports double
- itype.c_in = "\t%0 %1_in = (%0)%1;\n";
- itype.c_out = "\treturn (%0)%1;\n";
- itype.c_type = "double";
- //*/
- itype.c_type_in = "real_t";
- itype.c_type_out = "real_t";
+ {
+ // The expected type for parameters and return value in ptrcall is 'double'.
+ itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ itype.c_out = "\treturn (%0)%1;\n";
+ itype.c_type = "double";
+ itype.c_type_in = "real_t";
+ itype.c_type_out = "real_t";
+ itype.c_arg_in = "&%s_in";
+ }
itype.cs_type = itype.proxy_name;
itype.im_type_in = itype.proxy_name;
itype.im_type_out = itype.proxy_name;
@@ -2256,7 +2287,7 @@ void BindingsGenerator::_populate_global_constants() {
int constant_value = GlobalConstants::get_global_constant_value(i);
StringName enum_name = GlobalConstants::get_global_constant_enum(i);
- ConstantInterface iconstant(snake_to_pascal_case(constant_name, true), constant_value);
+ ConstantInterface iconstant(constant_name, snake_to_pascal_case(constant_name, true), constant_value);
iconstant.const_doc = const_doc;
if (enum_name != StringName()) {
@@ -2284,16 +2315,18 @@ void BindingsGenerator::_populate_global_constants() {
TypeInterface::postsetup_enum_type(enum_itype);
enum_types.insert(enum_itype.cname, enum_itype);
- ienum.prefix = _determine_enum_prefix(ienum);
+ int prefix_length = _determine_enum_prefix(ienum);
- // HARDCODED
+ // HARDCODED: The Error enum have the prefix 'ERR_' for everything except 'OK' and 'FAILED'.
if (ienum.cname == name_cache.enum_Error) {
- if (!ienum.prefix.empty()) { // Just in case it ever changes
+ if (prefix_length > 0) { // Just in case it ever changes
ERR_PRINTS("Prefix for enum 'Error' is not empty");
}
- ienum.prefix = "Err";
+ prefix_length = 1; // 'ERR_'
}
+
+ _apply_prefix_to_enum_constants(ienum, prefix_length);
}
}
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index ad89255ba5..38cf99c294 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -43,20 +43,21 @@ class BindingsGenerator {
struct ConstantInterface {
String name;
+ String proxy_name;
int value;
const DocData::ConstantDoc *const_doc;
ConstantInterface() {}
- ConstantInterface(const String &p_name, int p_value) {
+ ConstantInterface(const String &p_name, const String &p_proxy_name, int p_value) {
name = p_name;
+ proxy_name = p_proxy_name;
value = p_value;
}
};
struct EnumInterface {
StringName cname;
- String prefix;
List<ConstantInterface> constants;
_FORCE_INLINE_ bool operator==(const EnumInterface &p_ienum) const {
@@ -223,7 +224,7 @@ class BindingsGenerator {
String c_in;
/**
- * Determines the name of the variable that will be passed as argument to a ptrcall.
+ * Determines the expression that will be passed as argument to ptrcall.
* By default the value equals the name of the parameter,
* this varies for types that require special manipulation via [c_in].
* Formatting elements:
@@ -333,8 +334,6 @@ class BindingsGenerator {
itype.proxy_name = itype.name;
itype.c_type = itype.name;
- itype.c_type_in = "void*";
- itype.c_type_out = "MonoObject*";
itype.cs_type = itype.proxy_name;
itype.im_type_in = "ref " + itype.proxy_name;
itype.im_type_out = itype.proxy_name;
@@ -385,10 +384,19 @@ class BindingsGenerator {
}
static void postsetup_enum_type(TypeInterface &r_enum_itype) {
- r_enum_itype.c_arg_in = "&%s";
- r_enum_itype.c_type = "int";
- r_enum_itype.c_type_in = "int";
- r_enum_itype.c_type_out = "int";
+ // C interface is the same as that of 'int'. Remember to apply any
+ // changes done here to the 'int' type interface as well
+
+ r_enum_itype.c_arg_in = "&%s_in";
+ {
+ // The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
+ r_enum_itype.c_in = "\t%0 %1_in = (%0)%1;\n";
+ r_enum_itype.c_out = "\treturn (%0)%1;\n";
+ r_enum_itype.c_type = "int64_t";
+ }
+ r_enum_itype.c_type_in = "int32_t";
+ r_enum_itype.c_type_out = r_enum_itype.c_type_in;
+
r_enum_itype.cs_type = r_enum_itype.proxy_name;
r_enum_itype.cs_in = "(int)%s";
r_enum_itype.cs_out = "return (%1)%0;";
@@ -513,7 +521,8 @@ class BindingsGenerator {
return p_type.name;
}
- String _determine_enum_prefix(const EnumInterface &p_ienum);
+ int _determine_enum_prefix(const EnumInterface &p_ienum);
+ void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
void _generate_method_icalls(const TypeInterface &p_itype);
diff --git a/modules/mono/editor/godotsharp_builds.cpp b/modules/mono/editor/godotsharp_builds.cpp
index 8fe6e46b60..b504cfe712 100644
--- a/modules/mono/editor/godotsharp_builds.cpp
+++ b/modules/mono/editor/godotsharp_builds.cpp
@@ -306,6 +306,16 @@ String GodotSharpBuilds::_api_folder_name(APIAssembly::Type p_api_type) {
bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
String api_name = p_api_type == APIAssembly::API_CORE ? API_ASSEMBLY_NAME : EDITOR_API_ASSEMBLY_NAME;
+
+ String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+
+ if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(api_name + ".dll"))) {
+ EditorProgress pr("mono_copy_prebuilt_api_assembly", "Copying prebuilt " + api_name + " assembly...", 1);
+ pr.step("Copying " + api_name + " assembly", 0);
+ return GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir, api_name, p_api_type);
+ }
+
String api_build_config = "Release";
EditorProgress pr("mono_build_release_" + api_name, "Building " + api_name + " solution...", 3);
@@ -357,7 +367,6 @@ bool GodotSharpBuilds::make_api_sln(APIAssembly::Type p_api_type) {
// Copy the built assembly to the assemblies directory
String api_assembly_dir = api_sln_dir.plus_file("bin").plus_file(api_build_config);
- String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
if (!GodotSharpBuilds::copy_api_assembly(api_assembly_dir, res_assemblies_dir, api_name, p_api_type))
return false;
@@ -369,36 +378,11 @@ bool GodotSharpBuilds::build_project_blocking(const String &p_config) {
if (!FileAccess::exists(GodotSharpDirs::get_project_sln_path()))
return true; // No solution to build
- String editor_prebuilt_api_dir = GodotSharpDirs::get_data_editor_prebuilt_api_dir();
- String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
-
- if (FileAccess::exists(editor_prebuilt_api_dir.plus_file(API_ASSEMBLY_NAME ".dll"))) {
- EditorProgress pr("mono_copy_prebuilt_api_assemblies",
- "Copying prebuilt " API_ASSEMBLY_NAME " assemblies...", 1);
- pr.step("Copying " API_ASSEMBLY_NAME " assembly", 0);
-
- if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir,
- API_ASSEMBLY_NAME, APIAssembly::API_CORE)) {
- return false;
- }
- } else {
- if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
- return false;
- }
-
- if (DirAccess::exists(editor_prebuilt_api_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll"))) {
- EditorProgress pr("mono_copy_prebuilt_api_assemblies",
- "Copying prebuilt " EDITOR_API_ASSEMBLY_NAME " assemblies...", 1);
- pr.step("Copying " EDITOR_API_ASSEMBLY_NAME " assembly", 0);
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
+ return false;
- if (!GodotSharpBuilds::copy_api_assembly(editor_prebuilt_api_dir, res_assemblies_dir,
- EDITOR_API_ASSEMBLY_NAME, APIAssembly::API_EDITOR)) {
- return false;
- }
- } else {
- if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
- return false;
- }
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
+ return false;
EditorProgress pr("mono_project_debug_build", "Building project solution...", 1);
pr.step("Building project solution", 0);
diff --git a/modules/mono/editor/godotsharp_editor.cpp b/modules/mono/editor/godotsharp_editor.cpp
index fca88a7164..9df4e10266 100644
--- a/modules/mono/editor/godotsharp_editor.cpp
+++ b/modules/mono/editor/godotsharp_editor.cpp
@@ -108,6 +108,33 @@ bool GodotSharpEditor::_create_project_solution() {
return true;
}
+void GodotSharpEditor::_make_api_solutions_if_needed() {
+ // I'm sick entirely of ProgressDialog
+ static bool recursion_guard = false;
+ if (!recursion_guard) {
+ recursion_guard = true;
+ _make_api_solutions_if_needed_impl();
+ recursion_guard = false;
+ }
+}
+
+void GodotSharpEditor::_make_api_solutions_if_needed_impl() {
+ // If the project has a solution and C# project make sure the API assemblies are present and up to date
+ String res_assemblies_dir = GodotSharpDirs::get_res_assemblies_dir();
+
+ if (!FileAccess::exists(res_assemblies_dir.plus_file(API_ASSEMBLY_NAME ".dll")) ||
+ GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_CORE)) {
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_CORE))
+ return;
+ }
+
+ if (!FileAccess::exists(res_assemblies_dir.plus_file(EDITOR_API_ASSEMBLY_NAME ".dll")) ||
+ GDMono::get_singleton()->metadata_is_api_assembly_invalidated(APIAssembly::API_EDITOR)) {
+ if (!GodotSharpBuilds::make_api_sln(APIAssembly::API_EDITOR))
+ return; // Redundant? I don't think so
+ }
+}
+
void GodotSharpEditor::_remove_create_sln_menu_option() {
menu_popup->remove_item(menu_popup->get_item_index(MENU_CREATE_SLN));
@@ -169,6 +196,7 @@ void GodotSharpEditor::_notification(int p_notification) {
void GodotSharpEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_create_project_solution"), &GodotSharpEditor::_create_project_solution);
+ ClassDB::bind_method(D_METHOD("_make_api_solutions_if_needed"), &GodotSharpEditor::_make_api_solutions_if_needed);
ClassDB::bind_method(D_METHOD("_remove_create_sln_menu_option"), &GodotSharpEditor::_remove_create_sln_menu_option);
ClassDB::bind_method(D_METHOD("_toggle_about_dialog_on_start"), &GodotSharpEditor::_toggle_about_dialog_on_start);
ClassDB::bind_method(D_METHOD("_menu_option_pressed", "id"), &GodotSharpEditor::_menu_option_pressed);
@@ -390,7 +418,10 @@ GodotSharpEditor::GodotSharpEditor(EditorNode *p_editor) {
String sln_path = GodotSharpDirs::get_project_sln_path();
String csproj_path = GodotSharpDirs::get_project_csproj_path();
- if (!FileAccess::exists(sln_path) || !FileAccess::exists(csproj_path)) {
+ if (FileAccess::exists(sln_path) && FileAccess::exists(csproj_path)) {
+ // We can't use EditorProgress here. It calls Main::iterarion() and the main loop is not initialized yet.
+ call_deferred("_make_api_solutions_if_needed");
+ } else {
bottom_panel_btn->hide();
menu_popup->add_item(TTR("Create C# solution"), MENU_CREATE_SLN);
}
diff --git a/modules/mono/editor/godotsharp_editor.h b/modules/mono/editor/godotsharp_editor.h
index 46b6bd5ebf..9fb0e40132 100644
--- a/modules/mono/editor/godotsharp_editor.h
+++ b/modules/mono/editor/godotsharp_editor.h
@@ -56,6 +56,8 @@ class GodotSharpEditor : public Node {
#endif
bool _create_project_solution();
+ void _make_api_solutions_if_needed();
+ void _make_api_solutions_if_needed_impl();
void _remove_create_sln_menu_option();
void _show_about_dialog();
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/mono/mono_gd/gd_mono_field.cpp b/modules/mono/mono_gd/gd_mono_field.cpp
index d3a673dc1b..fe41722af0 100644
--- a/modules/mono/mono_gd/gd_mono_field.cpp
+++ b/modules/mono/mono_gd/gd_mono_field.cpp
@@ -40,65 +40,71 @@ void GDMonoField::set_value_raw(MonoObject *p_object, void *p_ptr) {
}
void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_value) {
-#define SET_FROM_STRUCT_AND_BREAK(m_type) \
- { \
- const m_type &val = p_value.operator ::m_type(); \
- MARSHALLED_OUT(m_type, val, raw); \
- mono_field_set_value(p_object, mono_field, raw); \
- break; \
+#define SET_FROM_STRUCT(m_type) \
+ { \
+ GDMonoMarshal::M_##m_type from = MARSHALLED_OUT(m_type, p_value.operator ::m_type()); \
+ mono_field_set_value(p_object, mono_field, &from); \
}
-#define SET_FROM_PRIMITIVE(m_type) \
- { \
- m_type val = p_value.operator m_type(); \
- mono_field_set_value(p_object, mono_field, &val); \
- break; \
- }
-
-#define SET_FROM_ARRAY_AND_BREAK(m_type) \
- { \
- MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator m_type()); \
- mono_field_set_value(p_object, mono_field, &managed); \
- break; \
+#define SET_FROM_ARRAY(m_type) \
+ { \
+ MonoArray *managed = GDMonoMarshal::m_type##_to_mono_array(p_value.operator ::m_type()); \
+ mono_field_set_value(p_object, mono_field, &managed); \
}
switch (type.type_encoding) {
case MONO_TYPE_BOOLEAN: {
- SET_FROM_PRIMITIVE(bool);
+ MonoBoolean val = p_value.operator bool();
+ mono_field_set_value(p_object, mono_field, &val);
+ } break;
+
+ case MONO_TYPE_CHAR: {
+ int16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I1: {
- SET_FROM_PRIMITIVE(signed char);
+ int8_t val = p_value.operator signed char();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I2: {
- SET_FROM_PRIMITIVE(signed short);
+ int16_t val = p_value.operator signed short();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I4: {
- SET_FROM_PRIMITIVE(signed int);
+ int32_t val = p_value.operator signed int();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_I8: {
- SET_FROM_PRIMITIVE(int64_t);
+ int64_t val = p_value.operator int64_t();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U1: {
- SET_FROM_PRIMITIVE(unsigned char);
+ uint8_t val = p_value.operator unsigned char();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U2: {
- SET_FROM_PRIMITIVE(unsigned short);
+ uint16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U4: {
- SET_FROM_PRIMITIVE(unsigned int);
+ uint32_t val = p_value.operator unsigned int();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_U8: {
- SET_FROM_PRIMITIVE(uint64_t);
+ uint64_t val = p_value.operator uint64_t();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_R4: {
- SET_FROM_PRIMITIVE(float);
+ float val = p_value.operator float();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_R8: {
- SET_FROM_PRIMITIVE(double);
+ double val = p_value.operator double();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case MONO_TYPE_STRING: {
@@ -109,38 +115,115 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_VALUETYPE: {
GDMonoClass *tclass = type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
- SET_FROM_STRUCT_AND_BREAK(Vector2);
+ if (tclass == CACHED_CLASS(Vector2)) {
+ SET_FROM_STRUCT(Vector2);
+ break;
+ }
- if (tclass == CACHED_CLASS(Rect2))
- SET_FROM_STRUCT_AND_BREAK(Rect2);
+ if (tclass == CACHED_CLASS(Rect2)) {
+ SET_FROM_STRUCT(Rect2);
+ break;
+ }
- if (tclass == CACHED_CLASS(Transform2D))
- SET_FROM_STRUCT_AND_BREAK(Transform2D);
+ if (tclass == CACHED_CLASS(Transform2D)) {
+ SET_FROM_STRUCT(Transform2D);
+ break;
+ }
- if (tclass == CACHED_CLASS(Vector3))
- SET_FROM_STRUCT_AND_BREAK(Vector3);
+ if (tclass == CACHED_CLASS(Vector3)) {
+ SET_FROM_STRUCT(Vector3);
+ break;
+ }
- if (tclass == CACHED_CLASS(Basis))
- SET_FROM_STRUCT_AND_BREAK(Basis);
+ if (tclass == CACHED_CLASS(Basis)) {
+ SET_FROM_STRUCT(Basis);
+ break;
+ }
- if (tclass == CACHED_CLASS(Quat))
- SET_FROM_STRUCT_AND_BREAK(Quat);
+ if (tclass == CACHED_CLASS(Quat)) {
+ SET_FROM_STRUCT(Quat);
+ break;
+ }
- if (tclass == CACHED_CLASS(Transform))
- SET_FROM_STRUCT_AND_BREAK(Transform);
+ if (tclass == CACHED_CLASS(Transform)) {
+ SET_FROM_STRUCT(Transform);
+ break;
+ }
- if (tclass == CACHED_CLASS(AABB))
- SET_FROM_STRUCT_AND_BREAK(AABB);
+ if (tclass == CACHED_CLASS(AABB)) {
+ SET_FROM_STRUCT(AABB);
+ break;
+ }
- if (tclass == CACHED_CLASS(Color))
- SET_FROM_STRUCT_AND_BREAK(Color);
+ if (tclass == CACHED_CLASS(Color)) {
+ SET_FROM_STRUCT(Color);
+ break;
+ }
- if (tclass == CACHED_CLASS(Plane))
- SET_FROM_STRUCT_AND_BREAK(Plane);
+ if (tclass == CACHED_CLASS(Plane)) {
+ SET_FROM_STRUCT(Plane);
+ break;
+ }
- if (mono_class_is_enum(tclass->get_mono_ptr()))
- SET_FROM_PRIMITIVE(signed int);
+ if (mono_class_is_enum(tclass->get_mono_ptr())) {
+ MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN: {
+ MonoBoolean val = p_value.operator bool();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I1: {
+ int8_t val = p_value.operator signed char();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I2: {
+ int16_t val = p_value.operator signed short();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I4: {
+ int32_t val = p_value.operator signed int();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_value.operator int64_t();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U1: {
+ uint8_t val = p_value.operator unsigned char();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U2: {
+ uint16_t val = p_value.operator unsigned short();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U4: {
+ uint32_t val = p_value.operator unsigned int();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_value.operator uint64_t();
+ mono_field_set_value(p_object, mono_field, &val);
+ break;
+ }
+ default: {
+ ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL();
+ }
+ }
+ }
ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
ERR_FAIL();
@@ -150,29 +233,45 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
case MONO_TYPE_SZARRAY: {
MonoArrayType *array_type = mono_type_get_array_type(type.type_class->get_mono_type());
- if (array_type->eklass == CACHED_CLASS_RAW(MonoObject))
- SET_FROM_ARRAY_AND_BREAK(Array);
+ if (array_type->eklass == CACHED_CLASS_RAW(MonoObject)) {
+ SET_FROM_ARRAY(Array);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(uint8_t))
- SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(uint8_t)) {
+ SET_FROM_ARRAY(PoolByteArray);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(int32_t))
- SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(int32_t)) {
+ SET_FROM_ARRAY(PoolIntArray);
+ break;
+ }
- if (array_type->eklass == REAL_T_MONOCLASS)
- SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
+ if (array_type->eklass == REAL_T_MONOCLASS) {
+ SET_FROM_ARRAY(PoolRealArray);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(String))
- SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(String)) {
+ SET_FROM_ARRAY(PoolStringArray);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(Vector2))
- SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector2)) {
+ SET_FROM_ARRAY(PoolVector2Array);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(Vector3))
- SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
+ if (array_type->eklass == CACHED_CLASS_RAW(Vector3)) {
+ SET_FROM_ARRAY(PoolVector3Array);
+ break;
+ }
- if (array_type->eklass == CACHED_CLASS_RAW(Color))
- SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
+ if (array_type->eklass == CACHED_CLASS_RAW(Color)) {
+ SET_FROM_ARRAY(PoolColorArray);
+ break;
+ }
ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
ERR_FAIL();
@@ -220,32 +319,56 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
// Variant
switch (p_value.get_type()) {
case Variant::BOOL: {
- SET_FROM_PRIMITIVE(bool);
+ MonoBoolean val = p_value.operator bool();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case Variant::INT: {
- SET_FROM_PRIMITIVE(int);
+ int32_t val = p_value.operator signed int();
+ mono_field_set_value(p_object, mono_field, &val);
} break;
case Variant::REAL: {
#ifdef REAL_T_IS_DOUBLE
- SET_FROM_PRIMITIVE(double);
+ double val = p_value.operator double();
+ mono_field_set_value(p_object, mono_field, &val);
#else
- SET_FROM_PRIMITIVE(float);
+ float val = p_value.operator float();
+ mono_field_set_value(p_object, mono_field, &val);
#endif
} break;
case Variant::STRING: {
MonoString *mono_string = GDMonoMarshal::mono_string_from_godot(p_value);
mono_field_set_value(p_object, mono_field, mono_string);
} break;
- case Variant::VECTOR2: SET_FROM_STRUCT_AND_BREAK(Vector2);
- case Variant::RECT2: SET_FROM_STRUCT_AND_BREAK(Rect2);
- case Variant::VECTOR3: SET_FROM_STRUCT_AND_BREAK(Vector3);
- case Variant::TRANSFORM2D: SET_FROM_STRUCT_AND_BREAK(Transform2D);
- case Variant::PLANE: SET_FROM_STRUCT_AND_BREAK(Plane);
- case Variant::QUAT: SET_FROM_STRUCT_AND_BREAK(Quat);
- case Variant::AABB: SET_FROM_STRUCT_AND_BREAK(AABB);
- case Variant::BASIS: SET_FROM_STRUCT_AND_BREAK(Basis);
- case Variant::TRANSFORM: SET_FROM_STRUCT_AND_BREAK(Transform);
- case Variant::COLOR: SET_FROM_STRUCT_AND_BREAK(Color);
+ case Variant::VECTOR2: {
+ SET_FROM_STRUCT(Vector2);
+ } break;
+ case Variant::RECT2: {
+ SET_FROM_STRUCT(Rect2);
+ } break;
+ case Variant::VECTOR3: {
+ SET_FROM_STRUCT(Vector3);
+ } break;
+ case Variant::TRANSFORM2D: {
+ SET_FROM_STRUCT(Transform2D);
+ } break;
+ case Variant::PLANE: {
+ SET_FROM_STRUCT(Plane);
+ } break;
+ case Variant::QUAT: {
+ SET_FROM_STRUCT(Quat);
+ } break;
+ case Variant::AABB: {
+ SET_FROM_STRUCT(AABB);
+ } break;
+ case Variant::BASIS: {
+ SET_FROM_STRUCT(Basis);
+ } break;
+ case Variant::TRANSFORM: {
+ SET_FROM_STRUCT(Transform);
+ } break;
+ case Variant::COLOR: {
+ SET_FROM_STRUCT(Color);
+ } break;
case Variant::NODE_PATH: {
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator NodePath());
mono_field_set_value(p_object, mono_field, managed);
@@ -267,14 +390,27 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
MonoObject *managed = GDMonoUtils::create_managed_from(p_value.operator Array(), CACHED_CLASS(Array));
mono_field_set_value(p_object, mono_field, managed);
} break;
- case Variant::POOL_BYTE_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolByteArray);
- case Variant::POOL_INT_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolIntArray);
- case Variant::POOL_REAL_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolRealArray);
- case Variant::POOL_STRING_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolStringArray);
- case Variant::POOL_VECTOR2_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector2Array);
- case Variant::POOL_VECTOR3_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolVector3Array);
- case Variant::POOL_COLOR_ARRAY: SET_FROM_ARRAY_AND_BREAK(PoolColorArray);
-#undef SET_FROM_ARRAY_AND_BREAK
+ case Variant::POOL_BYTE_ARRAY: {
+ SET_FROM_ARRAY(PoolByteArray);
+ } break;
+ case Variant::POOL_INT_ARRAY: {
+ SET_FROM_ARRAY(PoolIntArray);
+ } break;
+ case Variant::POOL_REAL_ARRAY: {
+ SET_FROM_ARRAY(PoolRealArray);
+ } break;
+ case Variant::POOL_STRING_ARRAY: {
+ SET_FROM_ARRAY(PoolStringArray);
+ } break;
+ case Variant::POOL_VECTOR2_ARRAY: {
+ SET_FROM_ARRAY(PoolVector2Array);
+ } break;
+ case Variant::POOL_VECTOR3_ARRAY: {
+ SET_FROM_ARRAY(PoolVector3Array);
+ } break;
+ case Variant::POOL_COLOR_ARRAY: {
+ SET_FROM_ARRAY(PoolColorArray);
+ } break;
default: break;
}
} break;
@@ -312,8 +448,8 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
} break;
}
+#undef SET_FROM_ARRAY_AND_BREAK
#undef SET_FROM_STRUCT_AND_BREAK
-#undef SET_FROM_PRIMITIVE
}
MonoObject *GDMonoField::get_value(MonoObject *p_object) {
diff --git a/modules/mono/mono_gd/gd_mono_header.h b/modules/mono/mono_gd/gd_mono_header.h
index 4f2efc7b92..51d0c9b356 100644
--- a/modules/mono/mono_gd/gd_mono_header.h
+++ b/modules/mono/mono_gd/gd_mono_header.h
@@ -55,14 +55,4 @@ struct ManagedType {
}
};
-typedef union {
- uint32_t _uint32;
- float _float;
-} mono_float;
-
-typedef union {
- uint64_t _uint64;
- float _double;
-} mono_double;
-
#endif // GD_MONO_HEADER_H
diff --git a/modules/mono/mono_gd/gd_mono_marshal.cpp b/modules/mono/mono_gd/gd_mono_marshal.cpp
index de91e71bab..2543f5dc47 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.cpp
+++ b/modules/mono/mono_gd/gd_mono_marshal.cpp
@@ -35,20 +35,6 @@
namespace GDMonoMarshal {
-#define RETURN_BOXED_STRUCT(m_t, m_var_in) \
- { \
- const m_t &m_in = m_var_in->operator ::m_t(); \
- MARSHALLED_OUT(m_t, m_in, raw); \
- return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(m_t), raw); \
- }
-
-#define RETURN_UNBOXED_STRUCT(m_t, m_var_in) \
- { \
- float *raw = (float *)mono_object_unbox(m_var_in); \
- MARSHALLED_IN(m_t, raw, ret); \
- return ret; \
- }
-
Variant::Type managed_to_variant_type(const ManagedType &p_type) {
switch (p_type.type_encoding) {
case MONO_TYPE_BOOLEAN:
@@ -252,16 +238,21 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return BOX_BOOLEAN(val);
}
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_var->operator unsigned short();
+ return BOX_UINT16(val);
+ }
+
case MONO_TYPE_I1: {
- char val = p_var->operator signed char();
+ int8_t val = p_var->operator signed char();
return BOX_INT8(val);
}
case MONO_TYPE_I2: {
- short val = p_var->operator signed short();
+ int16_t val = p_var->operator signed short();
return BOX_INT16(val);
}
case MONO_TYPE_I4: {
- int val = p_var->operator signed int();
+ int32_t val = p_var->operator signed int();
return BOX_INT32(val);
}
case MONO_TYPE_I8: {
@@ -270,15 +261,15 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
case MONO_TYPE_U1: {
- char val = p_var->operator unsigned char();
+ uint8_t val = p_var->operator unsigned char();
return BOX_UINT8(val);
}
case MONO_TYPE_U2: {
- short val = p_var->operator unsigned short();
+ uint16_t val = p_var->operator unsigned short();
return BOX_UINT16(val);
}
case MONO_TYPE_U4: {
- int val = p_var->operator unsigned int();
+ uint32_t val = p_var->operator unsigned int();
return BOX_UINT32(val);
}
case MONO_TYPE_U8: {
@@ -302,39 +293,105 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
case MONO_TYPE_VALUETYPE: {
GDMonoClass *tclass = p_type.type_class;
- if (tclass == CACHED_CLASS(Vector2))
- RETURN_BOXED_STRUCT(Vector2, p_var);
+ if (tclass == CACHED_CLASS(Vector2)) {
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+ }
- if (tclass == CACHED_CLASS(Rect2))
- RETURN_BOXED_STRUCT(Rect2, p_var);
+ if (tclass == CACHED_CLASS(Rect2)) {
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+ }
- if (tclass == CACHED_CLASS(Transform2D))
- RETURN_BOXED_STRUCT(Transform2D, p_var);
+ if (tclass == CACHED_CLASS(Transform2D)) {
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+ }
- if (tclass == CACHED_CLASS(Vector3))
- RETURN_BOXED_STRUCT(Vector3, p_var);
+ if (tclass == CACHED_CLASS(Vector3)) {
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+ }
- if (tclass == CACHED_CLASS(Basis))
- RETURN_BOXED_STRUCT(Basis, p_var);
+ if (tclass == CACHED_CLASS(Basis)) {
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+ }
- if (tclass == CACHED_CLASS(Quat))
- RETURN_BOXED_STRUCT(Quat, p_var);
+ if (tclass == CACHED_CLASS(Quat)) {
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ }
- if (tclass == CACHED_CLASS(Transform))
- RETURN_BOXED_STRUCT(Transform, p_var);
+ if (tclass == CACHED_CLASS(Transform)) {
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ }
- if (tclass == CACHED_CLASS(AABB))
- RETURN_BOXED_STRUCT(AABB, p_var);
+ if (tclass == CACHED_CLASS(AABB)) {
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+ }
- if (tclass == CACHED_CLASS(Color))
- RETURN_BOXED_STRUCT(Color, p_var);
+ if (tclass == CACHED_CLASS(Color)) {
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+ }
- if (tclass == CACHED_CLASS(Plane))
- RETURN_BOXED_STRUCT(Plane, p_var);
+ if (tclass == CACHED_CLASS(Plane)) {
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+ }
if (mono_class_is_enum(tclass->get_mono_ptr())) {
- int val = p_var->operator signed int();
- return BOX_ENUM(tclass->get_mono_ptr(), val);
+ MonoType *enum_basetype = mono_class_enum_basetype(tclass->get_mono_ptr());
+ MonoClass *enum_baseclass = mono_class_from_mono_type(enum_basetype);
+ switch (mono_type_get_type(enum_basetype)) {
+ case MONO_TYPE_BOOLEAN: {
+ MonoBoolean val = p_var->operator bool();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_CHAR: {
+ uint16_t val = p_var->operator unsigned short();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I1: {
+ int8_t val = p_var->operator signed char();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I2: {
+ int16_t val = p_var->operator signed short();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I4: {
+ int32_t val = p_var->operator signed int();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_I8: {
+ int64_t val = p_var->operator int64_t();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U1: {
+ uint8_t val = p_var->operator unsigned char();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U2: {
+ uint16_t val = p_var->operator unsigned short();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U4: {
+ uint32_t val = p_var->operator unsigned int();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ case MONO_TYPE_U8: {
+ uint64_t val = p_var->operator uint64_t();
+ return BOX_ENUM(enum_baseclass, val);
+ }
+ default: {
+ ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
+ ERR_FAIL_V(NULL);
+ }
+ }
}
} break;
@@ -402,7 +459,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
return BOX_BOOLEAN(val);
}
case Variant::INT: {
- int val = p_var->operator signed int();
+ int32_t val = p_var->operator signed int();
return BOX_INT32(val);
}
case Variant::REAL: {
@@ -416,33 +473,52 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
}
case Variant::STRING:
return (MonoObject *)mono_string_from_godot(p_var->operator String());
- case Variant::VECTOR2:
- RETURN_BOXED_STRUCT(Vector2, p_var);
- case Variant::RECT2:
- RETURN_BOXED_STRUCT(Rect2, p_var);
- case Variant::VECTOR3:
- RETURN_BOXED_STRUCT(Vector3, p_var);
- case Variant::TRANSFORM2D:
- RETURN_BOXED_STRUCT(Transform2D, p_var);
- case Variant::PLANE:
- RETURN_BOXED_STRUCT(Plane, p_var);
- case Variant::QUAT:
- RETURN_BOXED_STRUCT(Quat, p_var);
- case Variant::AABB:
- RETURN_BOXED_STRUCT(AABB, p_var);
- case Variant::BASIS:
- RETURN_BOXED_STRUCT(Basis, p_var);
- case Variant::TRANSFORM:
- RETURN_BOXED_STRUCT(Transform, p_var);
- case Variant::COLOR:
- RETURN_BOXED_STRUCT(Color, p_var);
+ case Variant::VECTOR2: {
+ GDMonoMarshal::M_Vector2 from = MARSHALLED_OUT(Vector2, p_var->operator ::Vector2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector2), &from);
+ }
+ case Variant::RECT2: {
+ GDMonoMarshal::M_Rect2 from = MARSHALLED_OUT(Rect2, p_var->operator ::Rect2());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Rect2), &from);
+ }
+ case Variant::VECTOR3: {
+ GDMonoMarshal::M_Vector3 from = MARSHALLED_OUT(Vector3, p_var->operator ::Vector3());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Vector3), &from);
+ }
+ case Variant::TRANSFORM2D: {
+ GDMonoMarshal::M_Transform2D from = MARSHALLED_OUT(Transform2D, p_var->operator ::Transform2D());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform2D), &from);
+ }
+ case Variant::PLANE: {
+ GDMonoMarshal::M_Plane from = MARSHALLED_OUT(Plane, p_var->operator ::Plane());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Plane), &from);
+ }
+ case Variant::QUAT: {
+ GDMonoMarshal::M_Quat from = MARSHALLED_OUT(Quat, p_var->operator ::Quat());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Quat), &from);
+ }
+ case Variant::AABB: {
+ GDMonoMarshal::M_AABB from = MARSHALLED_OUT(AABB, p_var->operator ::AABB());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(AABB), &from);
+ }
+ case Variant::BASIS: {
+ GDMonoMarshal::M_Basis from = MARSHALLED_OUT(Basis, p_var->operator ::Basis());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Basis), &from);
+ }
+ case Variant::TRANSFORM: {
+ GDMonoMarshal::M_Transform from = MARSHALLED_OUT(Transform, p_var->operator ::Transform());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Transform), &from);
+ }
+ case Variant::COLOR: {
+ GDMonoMarshal::M_Color from = MARSHALLED_OUT(Color, p_var->operator ::Color());
+ return mono_value_box(mono_domain_get(), CACHED_CLASS_RAW(Color), &from);
+ }
case Variant::NODE_PATH:
return GDMonoUtils::create_managed_from(p_var->operator NodePath());
case Variant::_RID:
return GDMonoUtils::create_managed_from(p_var->operator RID());
- case Variant::OBJECT: {
+ case Variant::OBJECT:
return GDMonoUtils::unmanaged_get_managed(p_var->operator Object *());
- }
case Variant::DICTIONARY:
return GDMonoUtils::create_managed_from(p_var->operator Dictionary(), CACHED_CLASS(Dictionary));
case Variant::ARRAY:
@@ -512,6 +588,9 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
case MONO_TYPE_BOOLEAN:
return (bool)unbox<MonoBoolean>(p_obj);
+ case MONO_TYPE_CHAR:
+ return unbox<uint16_t>(p_obj);
+
case MONO_TYPE_I1:
return unbox<int8_t>(p_obj);
case MONO_TYPE_I2:
@@ -545,34 +624,34 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
GDMonoClass *tclass = type.type_class;
if (tclass == CACHED_CLASS(Vector2))
- RETURN_UNBOXED_STRUCT(Vector2, p_obj);
+ return MARSHALLED_IN(Vector2, (GDMonoMarshal::M_Vector2 *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Rect2))
- RETURN_UNBOXED_STRUCT(Rect2, p_obj);
+ return MARSHALLED_IN(Rect2, (GDMonoMarshal::M_Rect2 *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Transform2D))
- RETURN_UNBOXED_STRUCT(Transform2D, p_obj);
+ return MARSHALLED_IN(Transform2D, (GDMonoMarshal::M_Transform2D *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Vector3))
- RETURN_UNBOXED_STRUCT(Vector3, p_obj);
+ return MARSHALLED_IN(Vector3, (GDMonoMarshal::M_Vector3 *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Basis))
- RETURN_UNBOXED_STRUCT(Basis, p_obj);
+ return MARSHALLED_IN(Basis, (GDMonoMarshal::M_Basis *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Quat))
- RETURN_UNBOXED_STRUCT(Quat, p_obj);
+ return MARSHALLED_IN(Quat, (GDMonoMarshal::M_Quat *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Transform))
- RETURN_UNBOXED_STRUCT(Transform, p_obj);
+ return MARSHALLED_IN(Transform, (GDMonoMarshal::M_Transform *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(AABB))
- RETURN_UNBOXED_STRUCT(AABB, p_obj);
+ return MARSHALLED_IN(AABB, (GDMonoMarshal::M_AABB *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Color))
- RETURN_UNBOXED_STRUCT(Color, p_obj);
+ return MARSHALLED_IN(Color, (GDMonoMarshal::M_Color *)mono_object_unbox(p_obj));
if (tclass == CACHED_CLASS(Plane))
- RETURN_UNBOXED_STRUCT(Plane, p_obj);
+ return MARSHALLED_IN(Plane, (GDMonoMarshal::M_Plane *)mono_object_unbox(p_obj));
if (mono_class_is_enum(tclass->get_mono_ptr()))
return unbox<int32_t>(p_obj);
@@ -708,13 +787,13 @@ Array mono_array_to_Array(MonoArray *p_array) {
return ret;
}
-// TODO Optimize reading/writing from/to PoolArrays
-
MonoArray *PoolIntArray_to_mono_array(const PoolIntArray &p_array) {
+ PoolIntArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(int32_t), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, int32_t, i, p_array[i]);
+ mono_array_set(ret, int32_t, i, r[i]);
}
return ret;
@@ -726,19 +805,22 @@ PoolIntArray mono_array_to_PoolIntArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolIntArray::Write w = ret.write();
+
for (int i = 0; i < length; i++) {
- int32_t elem = mono_array_get(p_array, int32_t, i);
- ret.set(i, elem);
+ w[i] = mono_array_get(p_array, int32_t, i);
}
return ret;
}
MonoArray *PoolByteArray_to_mono_array(const PoolByteArray &p_array) {
+ PoolByteArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(uint8_t), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, uint8_t, i, p_array[i]);
+ mono_array_set(ret, uint8_t, i, r[i]);
}
return ret;
@@ -750,20 +832,22 @@ PoolByteArray mono_array_to_PoolByteArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolByteArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
- uint8_t elem = mono_array_get(p_array, uint8_t, i);
- ret.set(i, elem);
+ w[i] = mono_array_get(p_array, uint8_t, i);
}
return ret;
}
MonoArray *PoolRealArray_to_mono_array(const PoolRealArray &p_array) {
+ PoolRealArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), REAL_T_MONOCLASS, p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- mono_array_set(ret, real_t, i, p_array[i]);
+ mono_array_set(ret, real_t, i, r[i]);
}
return ret;
@@ -775,20 +859,22 @@ PoolRealArray mono_array_to_PoolRealArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolRealArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t elem = mono_array_get(p_array, real_t, i);
- ret.set(i, elem);
+ w[i] = mono_array_get(p_array, real_t, i);
}
return ret;
}
MonoArray *PoolStringArray_to_mono_array(const PoolStringArray &p_array) {
+ PoolStringArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(String), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
- MonoString *boxed = mono_string_from_godot(p_array[i]);
+ MonoString *boxed = mono_string_from_godot(r[i]);
mono_array_set(ret, MonoString *, i, boxed);
}
@@ -801,29 +887,24 @@ PoolStringArray mono_array_to_PoolStringArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolStringArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
MonoString *elem = mono_array_get(p_array, MonoString *, i);
- ret.set(i, mono_string_to_godot(elem));
+ w[i] = mono_string_to_godot(elem);
}
return ret;
}
MonoArray *PoolColorArray_to_mono_array(const PoolColorArray &p_array) {
+ PoolColorArray::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Color), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
- mono_array_set(ret, Color, i, p_array[i]);
-#else
- real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 4, i);
- const Color &elem = p_array[i];
- raw[0] = elem.r;
- raw[1] = elem.g;
- raw[2] = elem.b;
- raw[3] = elem.a;
-#endif
+ M_Color *raw = (M_Color *)mono_array_addr_with_size(ret, sizeof(M_Color), i);
+ *raw = MARSHALLED_OUT(Color, r[i]);
}
return ret;
@@ -835,28 +916,23 @@ PoolColorArray mono_array_to_PoolColorArray(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolColorArray::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 4, i);
- MARSHALLED_IN(Color, raw_elem, elem);
- ret.set(i, elem);
+ w[i] = MARSHALLED_IN(Color, (M_Color *)mono_array_addr_with_size(p_array, sizeof(M_Color), i));
}
return ret;
}
MonoArray *PoolVector2Array_to_mono_array(const PoolVector2Array &p_array) {
+ PoolVector2Array::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector2), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
- mono_array_set(ret, Vector2, i, p_array[i]);
-#else
- real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 2, i);
- const Vector2 &elem = p_array[i];
- raw[0] = elem.x;
- raw[1] = elem.y;
-#endif
+ M_Vector2 *raw = (M_Vector2 *)mono_array_addr_with_size(ret, sizeof(M_Vector2), i);
+ *raw = MARSHALLED_OUT(Vector2, r[i]);
}
return ret;
@@ -868,29 +944,23 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolVector2Array::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 2, i);
- MARSHALLED_IN(Vector2, raw_elem, elem);
- ret.set(i, elem);
+ w[i] = MARSHALLED_IN(Vector2, (M_Vector2 *)mono_array_addr_with_size(p_array, sizeof(M_Vector2), i));
}
return ret;
}
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array) {
+ PoolVector3Array::Read r = p_array.read();
+
MonoArray *ret = mono_array_new(mono_domain_get(), CACHED_CLASS_RAW(Vector3), p_array.size());
for (int i = 0; i < p_array.size(); i++) {
-#ifdef YOLOCOPY
- mono_array_set(ret, Vector3, i, p_array[i]);
-#else
- real_t *raw = (real_t *)mono_array_addr_with_size(ret, sizeof(real_t) * 3, i);
- const Vector3 &elem = p_array[i];
- raw[0] = elem.x;
- raw[1] = elem.y;
- raw[2] = elem.z;
-#endif
+ M_Vector3 *raw = (M_Vector3 *)mono_array_addr_with_size(ret, sizeof(M_Vector3), i);
+ *raw = MARSHALLED_OUT(Vector3, r[i]);
}
return ret;
@@ -902,11 +972,10 @@ PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array) {
return ret;
int length = mono_array_length(p_array);
ret.resize(length);
+ PoolVector3Array::Write w = ret.write();
for (int i = 0; i < length; i++) {
- real_t *raw_elem = (real_t *)mono_array_addr_with_size(p_array, sizeof(real_t) * 3, i);
- MARSHALLED_IN(Vector3, raw_elem, elem);
- ret.set(i, elem);
+ w[i] = MARSHALLED_IN(Vector3, (M_Vector3 *)mono_array_addr_with_size(p_array, sizeof(M_Vector3), i));
}
return ret;
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index cc0ab5fa05..4002f2a225 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -147,78 +147,271 @@ PoolVector2Array mono_array_to_PoolVector2Array(MonoArray *p_array);
MonoArray *PoolVector3Array_to_mono_array(const PoolVector3Array &p_array);
PoolVector3Array mono_array_to_PoolVector3Array(MonoArray *p_array);
-#ifdef YOLO_COPY
-#define MARSHALLED_OUT(m_t, m_in, m_out) m_t *m_out = (m_t *)&m_in;
-#define MARSHALLED_IN(m_t, m_in, m_out) m_t m_out = *reinterpret_cast<m_t *>(m_in);
+// Structures
+
+namespace InteropLayout {
+
+enum {
+ MATCHES_float = (sizeof(float) == sizeof(uint32_t)),
+
+ MATCHES_double = (sizeof(double) == sizeof(uint64_t)),
+
+#ifdef REAL_T_IS_DOUBLE
+ MATCHES_real_t = (sizeof(real_t) == sizeof(uint64_t)),
#else
+ MATCHES_real_t = (sizeof(real_t) == sizeof(uint32_t)),
+#endif
-// Expects m_in to be of type float*
+ MATCHES_Vector2 = (MATCHES_real_t && (sizeof(Vector2) == (sizeof(real_t) * 2)) &&
+ offsetof(Vector2, x) == (sizeof(real_t) * 0) &&
+ offsetof(Vector2, y) == (sizeof(real_t) * 1)),
-#define MARSHALLED_OUT(m_t, m_in, m_out) MARSHALLED_OUT_##m_t(m_in, m_out)
-#define MARSHALLED_IN(m_t, m_in, m_out) MARSHALLED_IN_##m_t(m_in, m_out)
+ MATCHES_Rect2 = (MATCHES_Vector2 && (sizeof(Rect2) == (sizeof(Vector2) * 2)) &&
+ offsetof(Rect2, position) == (sizeof(Vector2) * 0) &&
+ offsetof(Rect2, size) == (sizeof(Vector2) * 1)),
-// Vector2
+ MATCHES_Transform2D = (MATCHES_Vector2 && (sizeof(Transform2D) == (sizeof(Vector2) * 3))), // No field offset required, it stores an array
-#define MARSHALLED_OUT_Vector2(m_in, m_out) real_t m_out[2] = { m_in.x, m_in.y };
-#define MARSHALLED_IN_Vector2(m_in, m_out) Vector2 m_out(m_in[0], m_in[1]);
+ MATCHES_Vector3 = (MATCHES_real_t && (sizeof(Vector3) == (sizeof(real_t) * 3)) &&
+ offsetof(Vector3, x) == (sizeof(real_t) * 0) &&
+ offsetof(Vector3, y) == (sizeof(real_t) * 1) &&
+ offsetof(Vector3, z) == (sizeof(real_t) * 2)),
-// Rect2
+ MATCHES_Basis = (MATCHES_Vector3 && (sizeof(Basis) == (sizeof(Vector3) * 3))), // No field offset required, it stores an array
-#define MARSHALLED_OUT_Rect2(m_in, m_out) real_t m_out[4] = { m_in.position.x, m_in.position.y, m_in.size.width, m_in.size.height };
-#define MARSHALLED_IN_Rect2(m_in, m_out) Rect2 m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+ MATCHES_Quat = (MATCHES_real_t && (sizeof(Quat) == (sizeof(real_t) * 4)) &&
+ offsetof(Quat, x) == (sizeof(real_t) * 0) &&
+ offsetof(Quat, y) == (sizeof(real_t) * 1) &&
+ offsetof(Quat, z) == (sizeof(real_t) * 2) &&
+ offsetof(Quat, w) == (sizeof(real_t) * 3)),
-// Transform2D
+ MATCHES_Transform = (MATCHES_Basis && MATCHES_Vector3 && (sizeof(Transform) == (sizeof(Basis) + sizeof(Vector3))) &&
+ offsetof(Transform, basis) == 0 &&
+ offsetof(Transform, origin) == sizeof(Basis)),
-#define MARSHALLED_OUT_Transform2D(m_in, m_out) real_t m_out[6] = { m_in[0].x, m_in[0].y, m_in[1].x, m_in[1].y, m_in[2].x, m_in[2].y };
-#define MARSHALLED_IN_Transform2D(m_in, m_out) Transform2D m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5]);
+ MATCHES_AABB = (MATCHES_Vector3 && (sizeof(AABB) == (sizeof(Vector3) * 2)) &&
+ offsetof(AABB, position) == (sizeof(Vector3) * 0) &&
+ offsetof(AABB, size) == (sizeof(Vector3) * 1)),
-// Vector3
+ MATCHES_Color = (MATCHES_float && (sizeof(Color) == (sizeof(float) * 4)) &&
+ offsetof(Color, r) == (sizeof(float) * 0) &&
+ offsetof(Color, g) == (sizeof(float) * 1) &&
+ offsetof(Color, b) == (sizeof(float) * 2) &&
+ offsetof(Color, a) == (sizeof(float) * 3)),
+
+ MATCHES_Plane = (MATCHES_Vector3 && MATCHES_real_t && (sizeof(Plane) == (sizeof(Vector3) + sizeof(real_t))) &&
+ offsetof(Plane, normal) == 0 &&
+ offsetof(Plane, d) == sizeof(Vector3))
+};
+
+// In the future we may force this if we want to ref return these structs
+#ifdef GD_MONO_FORCE_INTEROP_STRUCT_COPY
+// Sometimes clang-format can be an ass
+GD_STATIC_ASSERT(MATCHES_Vector2 &&MATCHES_Rect2 &&MATCHES_Transform2D &&MATCHES_Vector3 &&
+ MATCHES_Basis &&MATCHES_Quat &&MATCHES_Transform &&MATCHES_AABB &&MATCHES_Color &&MATCHES_Plane);
+#endif
-#define MARSHALLED_OUT_Vector3(m_in, m_out) real_t m_out[3] = { m_in.x, m_in.y, m_in.z };
-#define MARSHALLED_IN_Vector3(m_in, m_out) Vector3 m_out(m_in[0], m_in[1], m_in[2]);
+} // namespace InteropLayout
-// Basis
+#pragma pack(push, 1)
-#define MARSHALLED_OUT_Basis(m_in, m_out) real_t m_out[9] = { \
- m_in[0].x, m_in[0].y, m_in[0].z, \
- m_in[1].x, m_in[1].y, m_in[1].z, \
- m_in[2].x, m_in[2].y, m_in[2].z \
+struct M_Vector2 {
+ real_t x, y;
+
+ static _FORCE_INLINE_ Vector2 convert_to(const M_Vector2 &p_from) {
+ return Vector2(p_from.x, p_from.y);
+ }
+
+ static _FORCE_INLINE_ M_Vector2 convert_from(const Vector2 &p_from) {
+ M_Vector2 ret = { p_from.x, p_from.y };
+ return ret;
+ }
};
-#define MARSHALLED_IN_Basis(m_in, m_out) Basis m_out(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]);
-// Quat
+struct M_Rect2 {
+ M_Vector2 position;
+ M_Vector2 size;
-#define MARSHALLED_OUT_Quat(m_in, m_out) real_t m_out[4] = { m_in.x, m_in.y, m_in.z, m_in.w };
-#define MARSHALLED_IN_Quat(m_in, m_out) Quat m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+ static _FORCE_INLINE_ Rect2 convert_to(const M_Rect2 &p_from) {
+ return Rect2(M_Vector2::convert_to(p_from.position),
+ M_Vector2::convert_to(p_from.size));
+ }
-// Transform
+ static _FORCE_INLINE_ M_Rect2 convert_from(const Rect2 &p_from) {
+ M_Rect2 ret = { M_Vector2::convert_from(p_from.position), M_Vector2::convert_from(p_from.size) };
+ return ret;
+ }
+};
-#define MARSHALLED_OUT_Transform(m_in, m_out) real_t m_out[12] = { \
- m_in.basis[0].x, m_in.basis[0].y, m_in.basis[0].z, \
- m_in.basis[1].x, m_in.basis[1].y, m_in.basis[1].z, \
- m_in.basis[2].x, m_in.basis[2].y, m_in.basis[2].z, \
- m_in.origin.x, m_in.origin.y, m_in.origin.z \
+struct M_Transform2D {
+ M_Vector2 elements[3];
+
+ static _FORCE_INLINE_ Transform2D convert_to(const M_Transform2D &p_from) {
+ return Transform2D(p_from.elements[0].x, p_from.elements[0].y,
+ p_from.elements[1].x, p_from.elements[1].y,
+ p_from.elements[2].x, p_from.elements[2].y);
+ }
+
+ static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
+ M_Transform2D ret = {
+ M_Vector2::convert_from(p_from.elements[0]),
+ M_Vector2::convert_from(p_from.elements[1]),
+ M_Vector2::convert_from(p_from.elements[2])
+ };
+ return ret;
+ }
};
-#define MARSHALLED_IN_Transform(m_in, m_out) Transform m_out( \
- Basis(m_in[0], m_in[1], m_in[2], m_in[3], m_in[4], m_in[5], m_in[6], m_in[7], m_in[8]), \
- Vector3(m_in[9], m_in[10], m_in[11]));
-// AABB
+struct M_Vector3 {
+ real_t x, y, z;
+
+ static _FORCE_INLINE_ Vector3 convert_to(const M_Vector3 &p_from) {
+ return Vector3(p_from.x, p_from.y, p_from.z);
+ }
-#define MARSHALLED_OUT_AABB(m_in, m_out) real_t m_out[6] = { m_in.position.x, m_in.position.y, m_in.position.z, m_in.size.x, m_in.size.y, m_in.size.z };
-#define MARSHALLED_IN_AABB(m_in, m_out) AABB m_out(Vector3(m_in[0], m_in[1], m_in[2]), Vector3(m_in[3], m_in[4], m_in[5]));
+ static _FORCE_INLINE_ M_Vector3 convert_from(const Vector3 &p_from) {
+ M_Vector3 ret = { p_from.x, p_from.y, p_from.z };
+ return ret;
+ }
+};
-// Color
+struct M_Basis {
+ M_Vector3 elements[3];
+
+ static _FORCE_INLINE_ Basis convert_to(const M_Basis &p_from) {
+ return Basis(M_Vector3::convert_to(p_from.elements[0]),
+ M_Vector3::convert_to(p_from.elements[1]),
+ M_Vector3::convert_to(p_from.elements[2]));
+ }
+
+ static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
+ M_Basis ret = {
+ M_Vector3::convert_from(p_from.elements[0]),
+ M_Vector3::convert_from(p_from.elements[1]),
+ M_Vector3::convert_from(p_from.elements[2])
+ };
+ return ret;
+ }
+};
-#define MARSHALLED_OUT_Color(m_in, m_out) real_t m_out[4] = { m_in.r, m_in.g, m_in.b, m_in.a };
-#define MARSHALLED_IN_Color(m_in, m_out) Color m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+struct M_Quat {
+ real_t x, y, z, w;
-// Plane
+ static _FORCE_INLINE_ Quat convert_to(const M_Quat &p_from) {
+ return Quat(p_from.x, p_from.y, p_from.z, p_from.w);
+ }
-#define MARSHALLED_OUT_Plane(m_in, m_out) real_t m_out[4] = { m_in.normal.x, m_in.normal.y, m_in.normal.z, m_in.d };
-#define MARSHALLED_IN_Plane(m_in, m_out) Plane m_out(m_in[0], m_in[1], m_in[2], m_in[3]);
+ static _FORCE_INLINE_ M_Quat convert_from(const Quat &p_from) {
+ M_Quat ret = { p_from.x, p_from.y, p_from.z, p_from.w };
+ return ret;
+ }
+};
-#endif
+struct M_Transform {
+ M_Basis basis;
+ M_Vector3 origin;
+
+ static _FORCE_INLINE_ Transform convert_to(const M_Transform &p_from) {
+ return Transform(M_Basis::convert_to(p_from.basis), M_Vector3::convert_to(p_from.origin));
+ }
+
+ static _FORCE_INLINE_ M_Transform convert_from(const Transform &p_from) {
+ M_Transform ret = { M_Basis::convert_from(p_from.basis), M_Vector3::convert_from(p_from.origin) };
+ return ret;
+ }
+};
+
+struct M_AABB {
+ M_Vector3 position;
+ M_Vector3 size;
+
+ static _FORCE_INLINE_ AABB convert_to(const M_AABB &p_from) {
+ return AABB(M_Vector3::convert_to(p_from.position), M_Vector3::convert_to(p_from.size));
+ }
+
+ static _FORCE_INLINE_ M_AABB convert_from(const AABB &p_from) {
+ M_AABB ret = { M_Vector3::convert_from(p_from.position), M_Vector3::convert_from(p_from.size) };
+ return ret;
+ }
+};
+
+struct M_Color {
+ float r, g, b, a;
+
+ static _FORCE_INLINE_ Color convert_to(const M_Color &p_from) {
+ return Color(p_from.r, p_from.g, p_from.b, p_from.a);
+ }
+
+ static _FORCE_INLINE_ M_Color convert_from(const Color &p_from) {
+ M_Color ret = { p_from.r, p_from.g, p_from.b, p_from.a };
+ return ret;
+ }
+};
+
+struct M_Plane {
+ M_Vector3 normal;
+ real_t d;
+
+ static _FORCE_INLINE_ Plane convert_to(const M_Plane &p_from) {
+ return Plane(M_Vector3::convert_to(p_from.normal), p_from.d);
+ }
+
+ static _FORCE_INLINE_ M_Plane convert_from(const Plane &p_from) {
+ M_Plane ret = { M_Vector3::convert_from(p_from.normal), p_from.d };
+ return ret;
+ }
+};
+
+#pragma pack(pop)
+
+#define DECL_TYPE_MARSHAL_TEMPLATES(m_type) \
+ template <int> \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl(const M_##m_type *p_from); \
+ \
+ template <> \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<0>(const M_##m_type *p_from) { \
+ return M_##m_type::convert_to(*p_from); \
+ } \
+ \
+ template <> \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type##_impl<1>(const M_##m_type *p_from) { \
+ return *reinterpret_cast<const m_type *>(p_from); \
+ } \
+ \
+ _FORCE_INLINE_ m_type marshalled_in_##m_type(const M_##m_type *p_from) { \
+ return marshalled_in_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
+ } \
+ \
+ template <int> \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl(const m_type &p_from); \
+ \
+ template <> \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<0>(const m_type &p_from) { \
+ return M_##m_type::convert_from(p_from); \
+ } \
+ \
+ template <> \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type##_impl<1>(const m_type &p_from) { \
+ return *reinterpret_cast<const M_##m_type *>(&p_from); \
+ } \
+ \
+ _FORCE_INLINE_ M_##m_type marshalled_out_##m_type(const m_type &p_from) { \
+ return marshalled_out_##m_type##_impl<InteropLayout::MATCHES_##m_type>(p_from); \
+ }
+
+DECL_TYPE_MARSHAL_TEMPLATES(Vector2)
+DECL_TYPE_MARSHAL_TEMPLATES(Rect2)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform2D)
+DECL_TYPE_MARSHAL_TEMPLATES(Vector3)
+DECL_TYPE_MARSHAL_TEMPLATES(Basis)
+DECL_TYPE_MARSHAL_TEMPLATES(Quat)
+DECL_TYPE_MARSHAL_TEMPLATES(Transform)
+DECL_TYPE_MARSHAL_TEMPLATES(AABB)
+DECL_TYPE_MARSHAL_TEMPLATES(Color)
+DECL_TYPE_MARSHAL_TEMPLATES(Plane)
+
+#define MARSHALLED_IN(m_type, m_from_ptr) (GDMonoMarshal::marshalled_in_##m_type(m_from_ptr))
+#define MARSHALLED_OUT(m_type, m_from) (GDMonoMarshal::marshalled_out_##m_type(m_from))
} // namespace GDMonoMarshal
diff --git a/modules/mono/utils/macros.h b/modules/mono/utils/macros.h
index 337a86870e..40b47e8648 100644
--- a/modules/mono/utils/macros.h
+++ b/modules/mono/utils/macros.h
@@ -33,6 +33,15 @@
// noreturn
+#if __cpp_static_assert
+#define GD_STATIC_ASSERT(m_cond) static_assert((m_cond), "Condition '" #m_cond "' failed")
+#else
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT_B(m_ignore, m_name) m_name
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_B(hello there, m_a##m_b)
+#define _GD_STATIC_ASSERT_VARNAME_CONCAT(m_a, m_b) GD_STATIC_ASSERT_VARNAME_CONCAT_A(m_a, m_b)
+#define GD_STATIC_ASSERT(m_cond) typedef int GD_STATIC_ASSERT_VARNAME_CONCAT(godot_static_assert_, __COUNTER__)[((m_cond) ? 1 : -1)]
+#endif
+
#undef _NO_RETURN_
#ifdef __GNUC__
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index d88abb3180..ba54160a90 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -17,6 +17,9 @@
<member name="as_normalmap" type="bool" setter="set_as_normalmap" getter="is_normalmap">
If true, the resulting texture contains a normal map created from the original noise interpreted as a bump map.
</member>
+ <member name="height" type="int" setter="set_height" getter="get_height">
+ Height of the generated texture.
+ </member>
<member name="noise" type="OpenSimplexNoise" setter="set_noise" getter="get_noise">
The [OpenSimplexNoise] instance used to generate the noise.
</member>
@@ -26,9 +29,6 @@
<member name="width" type="int" setter="set_width" getter="get_width">
Width of the generated texture.
</member>
- <member name="height" type="int" setter="set_height" getter="get_height">
- Height of the generated texture.
- </member>
</members>
<constants>
</constants>
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index ff97c21fd9..186e9e63b1 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -48,20 +48,22 @@ bool VisualScriptNode::is_breakpoint() const {
void VisualScriptNode::_notification(int p_what) {
if (p_what == NOTIFICATION_POSTINITIALIZE) {
-
- int dvc = get_input_value_port_count();
- for (int i = 0; i < dvc; i++) {
- Variant::Type expected = get_input_value_port_info(i).type;
- Variant::CallError ce;
- default_input_values.push_back(Variant::construct(expected, NULL, 0, ce, false));
- }
+ _update_input_ports();
}
}
-void VisualScriptNode::ports_changed_notify() {
-
+void VisualScriptNode::_update_input_ports() {
default_input_values.resize(MAX(default_input_values.size(), get_input_value_port_count())); //let it grow as big as possible, we don't want to lose values on resize
+ int port_count = get_input_value_port_count();
+ for (int i = 0; i < port_count; i++) {
+ Variant::Type expected = get_input_value_port_info(i).type;
+ Variant::CallError ce;
+ set_default_input_value(i, Variant::construct(expected, NULL, 0, ce, false));
+ }
+}
+void VisualScriptNode::ports_changed_notify() {
+ _update_input_ports();
emit_signal("ports_changed");
}
@@ -2697,11 +2699,11 @@ VisualScriptLanguage::VisualScriptLanguage() {
_debug_parse_err_file = "";
_debug_call_stack_pos = 0;
int dmcs = GLOBAL_DEF("debug/settings/visual_script/max_call_stack", 1024);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/settings/visual_script/max_call_stack", PropertyInfo(Variant::INT, "debug/settings/visual_script/max_call_stack", PROPERTY_HINT_RANGE, "1024,4096,1,or_greater")); //minimum is 1024
+
if (ScriptDebugger::get_singleton()) {
//debugging enabled!
_debug_max_call_stack = dmcs;
- if (_debug_max_call_stack < 1024)
- _debug_max_call_stack = 1024;
_call_stack = memnew_arr(CallLevel, _debug_max_call_stack + 1);
} else {
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index ea99ce4970..bd666447a3 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -52,6 +52,7 @@ class VisualScriptNode : public Resource {
Array _get_default_input_values() const;
void validate_input_default_values();
+ void _update_input_ports();
protected:
void _notification(int p_what);
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 865f93a148..99748af8a1 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -3708,18 +3708,18 @@ void register_visual_script_nodes() {
for (List<MethodInfo>::Element *E = constructors.front(); E; E = E->next()) {
if (E->get().arguments.size() > 0) {
-
- String name = "functions/constructors/" + Variant::get_type_name(Variant::Type(i)) + " ( ";
+ String name = "functions/constructors/" + Variant::get_type_name(Variant::Type(i)) + "(";
for (int j = 0; j < E->get().arguments.size(); j++) {
- if (j > 0)
+ if (j > 0) {
name += ", ";
- if (E->get().arguments.size() == 1)
+ }
+ if (E->get().arguments.size() == 1) {
name += Variant::get_type_name(E->get().arguments[j].type);
- else
+ } else {
name += E->get().arguments[j].name;
+ }
}
- name += ") ";
-
+ name += ")";
VisualScriptLanguage::singleton->add_register_func(name, create_constructor_node);
Pair<Variant::Type, MethodInfo> pair;
pair.first = Variant::Type(i);
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index d3637939c9..e5d12cb495 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -304,31 +304,36 @@ void VisualScriptPropertySelector::_update_search() {
continue;
MethodInfo mi = E->get();
- String desc = mi.name.capitalize() + " (";
+ String desc_arguments;
+ if (mi.arguments.size() > 0) {
+ desc_arguments = "(";
+ for (int i = 0; i < mi.arguments.size(); i++) {
+
+ if (i > 0) {
+ desc_arguments += ", ";
+ }
+ if (mi.arguments[i].type == Variant::NIL) {
+ desc_arguments += "var";
+ } else if (mi.arguments[i].name.find(":") != -1) {
+ desc_arguments += mi.arguments[i].name.get_slice(":", 1);
+ mi.arguments[i].name = mi.arguments[i].name.get_slice(":", 0);
+ } else {
+ desc_arguments += Variant::get_type_name(mi.arguments[i].type);
+ }
+ }
+ desc_arguments += ")";
+ }
+ String desc_raw = mi.name + desc_arguments;
+ String desc = desc_raw.capitalize().replace("( ", "(");
if (search_box->get_text() != String() &&
name.findn(search_box->get_text()) == -1 &&
- desc.findn(search_box->get_text()) == -1)
+ desc.findn(search_box->get_text()) == -1 &&
+ desc_raw.findn(search_box->get_text()) == -1) {
continue;
-
- TreeItem *item = search_options->create_item(category ? category : root);
-
- for (int i = 0; i < mi.arguments.size(); i++) {
-
- if (i > 0)
- desc += ", ";
-
- if (mi.arguments[i].type == Variant::NIL)
- desc += "var";
- else if (mi.arguments[i].name.find(":") != -1) {
- desc += mi.arguments[i].name.get_slice(":", 1);
- mi.arguments[i].name = mi.arguments[i].name.get_slice(":", 0);
- } else
- desc += Variant::get_type_name(mi.arguments[i].type);
}
- desc += ")";
-
+ TreeItem *item = search_options->create_item(category ? category : root);
item->set_text(0, desc);
item->set_icon(0, get_icon("MemberMethod", "EditorIcons"));
item->set_metadata(0, name);
@@ -414,11 +419,16 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt
String basic_type = Variant::get_type_name(vnode_function_call->get_basic_type());
type_name = basic_type.capitalize() + " ";
}
- VisualScriptBuiltinFunc *vnode_builtin_function_call = Object::cast_to<VisualScriptBuiltinFunc>(*VisualScriptLanguage::singleton->create_node_from_name(E->get()));
- if (vnode_builtin_function_call != NULL) {
- type_name = "Builtin ";
+
+ Vector<String> desc = path[path.size() - 1].replace("(", "( ").replace(")", " )").replace(",", ", ").split(" ");
+ for (size_t i = 0; i < desc.size(); i++) {
+ desc.write[i] = desc[i].capitalize();
+ if (desc[i].ends_with(",")) {
+ desc.write[i] = desc[i].replace(",", ", ");
+ }
}
- item->set_text(0, type_name + path[path.size() - 1].capitalize());
+
+ item->set_text(0, type_name + String("").join(desc));
item->set_icon(0, get_icon("VisualScript", "EditorIcons"));
item->set_selectable(0, true);
item->set_metadata(0, E->get());
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 b3e5f6ffab..d71d091720 100644
--- a/modules/websocket/lws_client.cpp
+++ b/modules/websocket/lws_client.cpp
@@ -76,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;
@@ -105,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/modules/websocket/websocket_multiplayer.cpp b/modules/websocket/websocket_multiplayer.cpp
index b948c439df..873658559a 100644
--- a/modules/websocket/websocket_multiplayer.cpp
+++ b/modules/websocket/websocket_multiplayer.cpp
@@ -313,7 +313,7 @@ void WebSocketMultiplayerPeer::_process_multiplayer(Ref<WebSocketPeer> p_peer, u
} else if (to < 0) {
// All but one, for us if not excluded
- if (_peer_id != -p_peer_id)
+ if (_peer_id != -(int32_t)p_peer_id)
_store_pkt(from, to, in_buffer, data_size);
} else {
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index ad8f21785d..07e4048c12 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -883,6 +883,8 @@ static void _initialize_java_modules() {
ERR_EXPLAIN("Couldn't find proper initialize function 'public static Godot.SingletonBase Class::initialize(Activity p_activity)' initializer for singleton class: " + m);
ERR_CONTINUE(!initialize);
}
+ jobject obj = env->CallStaticObjectMethod(singletonClass, initialize, _godot_instance);
+ env->NewGlobalRef(obj);
}
}
}
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/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index 794f6df31f..2d70b00dda 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -91,18 +91,18 @@ Error ContextGL_Win::initialize() {
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER,
- PFD_TYPE_RGBA,
- OS::get_singleton()->is_layered_allowed() ? 32 : 24,
- 0, 0, 0, 0, 0, 0, // Color Bits Ignored
- OS::get_singleton()->is_layered_allowed() ? 8 : 0, // Alpha Buffer
- 0, // Shift Bit Ignored
- 0, // No Accumulation Buffer
- 0, 0, 0, 0, // Accumulation Bits Ignored
- 24, // 24Bit Z-Buffer (Depth Buffer)
- 0, // No Stencil Buffer
- 0, // No Auxiliary Buffer
- PFD_MAIN_PLANE, // Main Drawing Layer
- 0, // Reserved
+ (BYTE)PFD_TYPE_RGBA,
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24),
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer
+ (BYTE)0, // Shift Bit Ignored
+ (BYTE)0, // No Accumulation Buffer
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored
+ (BYTE)24, // 24Bit Z-Buffer (Depth Buffer)
+ (BYTE)0, // No Stencil Buffer
+ (BYTE)0, // No Auxiliary Buffer
+ (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer
+ (BYTE)0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
diff --git a/platform/windows/joypad.cpp b/platform/windows/joypad.cpp
index b56fb6509e..7201714fb8 100644
--- a/platform/windows/joypad.cpp
+++ b/platform/windows/joypad.cpp
@@ -163,7 +163,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
const GUID &guid = instance->guidProduct;
char uid[128];
- sprintf(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+ sprintf_s(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
__builtin_bswap32(guid.Data1), guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
@@ -172,7 +172,7 @@ bool JoypadWindows::setup_dinput_joypad(const DIDEVICEINSTANCE *instance) {
joy->di_joy->SetDataFormat(&c_dfDIJoystick2);
joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND);
- joy->di_joy->EnumObjects(objectsCallback, this, NULL);
+ joy->di_joy->EnumObjects(objectsCallback, this, 0);
joy->joy_axis.sort();
joy->guid = instance->guidInstance;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 739fcbacda..3bbffd8fb7 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -763,7 +763,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
RECT r;
GetWindowRect(hWnd, &r);
- dib_size = Size2(r.right - r.left, r.bottom - r.top);
+ dib_size = Size2i(r.right - r.left, r.bottom - r.top);
BITMAPINFO bmi;
ZeroMemory(&bmi, sizeof(BITMAPINFO));
@@ -773,7 +773,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
- bmi.bmiHeader.biSizeImage = dib_size.x, dib_size.y * 4;
+ bmi.bmiHeader.biSizeImage = dib_size.x * dib_size.y * 4;
hBitmap = CreateDIBSection(hDC_dib, &bmi, DIB_RGB_COLORS, (void **)&dib_data, NULL, 0x0);
SelectObject(hDC_dib, hBitmap);
@@ -1050,7 +1050,6 @@ static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Defau
UINT x = 0, y = 0;
HRESULT hr = E_FAIL;
- bool bSet = false;
if (hmon && (Shcore != (HMODULE)INVALID_HANDLE_VALUE)) {
hr = getDPIForMonitor(hmon, dpiType /*MDT_Effective_DPI*/, &x, &y);
if (SUCCEEDED(hr) && (x > 0) && (y > 0)) {
@@ -1204,7 +1203,14 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
- char *windowid = getenv("GODOT_WINDOWID");
+ char *windowid;
+#ifdef MINGW_ENABLED
+ windowid = getenv("GODOT_WINDOWID");
+#else
+ size_t len;
+ _dupenv_s(&windowid, &len, "GODOT_WINDOWID");
+#endif
+
if (windowid) {
// strtoull on mingw
@@ -1213,6 +1219,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
#else
hWnd = (HWND)_strtoui64(windowid, NULL, 0);
#endif
+ free(windowid);
SetLastError(0);
user_proc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)(WNDPROC)::WndProc);
@@ -1221,7 +1228,7 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
printf("Error setting WNDPROC: %li\n", le);
};
- LONG_PTR proc = GetWindowLongPtr(hWnd, GWLP_WNDPROC);
+ GetWindowLongPtr(hWnd, GWLP_WNDPROC);
RECT rect;
if (!GetClientRect(hWnd, &rect)) {
@@ -1720,14 +1727,18 @@ void OS_Windows::set_window_position(const Point2 &p_position) {
Size2 OS_Windows::get_window_size() const {
RECT r;
- GetClientRect(hWnd, &r);
- return Vector2(r.right - r.left, r.bottom - r.top);
+ if (GetClientRect(hWnd, &r)) { // Only area inside of window border
+ return Size2(r.right - r.left, r.bottom - r.top);
+ }
+ return Size2();
}
Size2 OS_Windows::get_real_window_size() const {
RECT r;
- GetWindowRect(hWnd, &r);
- return Vector2(r.right - r.left, r.bottom - r.top);
+ if (GetWindowRect(hWnd, &r)) { // Includes area of the window border
+ return Size2(r.right - r.left, r.bottom - r.top);
+ }
+ return Size2();
}
void OS_Windows::set_window_size(const Size2 p_size) {
@@ -2266,7 +2277,6 @@ void OS_Windows::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shap
ERR_FAIL_COND(!image.is_valid());
UINT image_size = texture_size.width * texture_size.height;
- UINT size = sizeof(UINT) * image_size;
// Create the BITMAP with alpha channel
COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
@@ -2546,7 +2556,16 @@ void OS_Windows::set_icon(const Ref<Image> &p_icon) {
bool OS_Windows::has_environment(const String &p_var) const {
+#ifdef MINGW_ENABLED
return _wgetenv(p_var.c_str()) != NULL;
+#else
+ wchar_t *env;
+ size_t len;
+ _wdupenv_s(&env, &len, p_var.c_str());
+ const bool has_env = env != NULL;
+ free(env);
+ return has_env;
+#endif
};
String OS_Windows::get_environment(const String &p_var) const {
@@ -2729,11 +2748,6 @@ void OS_Windows::run() {
main_loop->init();
- uint64_t last_ticks = get_ticks_usec();
-
- int frames = 0;
- uint64_t frame = 0;
-
while (!force_quit) {
process_events(); // get rid of pending events
@@ -2926,7 +2940,7 @@ bool OS_Windows::is_disable_crash_handler() const {
Error OS_Windows::move_to_trash(const String &p_path) {
SHFILEOPSTRUCTW sf;
WCHAR *from = new WCHAR[p_path.length() + 2];
- wcscpy(from, p_path.c_str());
+ wcscpy_s(from, p_path.length() + 1, p_path.c_str());
from[p_path.length() + 1] = 0;
sf.hwnd = hWnd;
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/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index a1ae05d971..9de72a4fcd 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -179,7 +179,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {
Physics2DDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS];
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask);
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
for (int i = 0; i < areas; i++) {
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 29065a89b3..2f94c3c6f5 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -204,12 +204,6 @@ Size2 Node2D::get_scale() const {
return _scale;
}
-void Node2D::_notification(int p_what) {
-
- switch (p_what) {
- }
-}
-
Transform2D Node2D::get_transform() const {
return _mat;
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 725686cdf8..924a84fb88 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -52,8 +52,6 @@ class Node2D : public CanvasItem {
void _update_xform_values();
protected:
- void _notification(int p_what);
-
static void _bind_methods();
public:
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index a60ce47f5c..67e25ec508 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -593,7 +593,7 @@ void TileMap::update_dirty_quadrants() {
if (quadrant_order_dirty) {
- int index = -0x80000000; //always must be drawn below children
+ int index = -(int64_t)0x80000000; //always must be drawn below children
for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) {
Quadrant &q = E->get();
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/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index abf022ecb3..3046cad624 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -290,7 +290,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
PhysicsDirectSpaceState::ShapeResult sr[MAX_INTERSECT_AREAS];
- int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask);
+ int areas = space_state->intersect_point(global_pos, sr, MAX_INTERSECT_AREAS, Set<RID>(), area_mask, false, true);
Area *area = NULL;
for (int i = 0; i < areas; i++) {
@@ -448,7 +448,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
//float dist_att_db = -20 * Math::log(dist + 0.00001); //logarithmic attenuation, like in real life
- float center_val[3] = { 0.5, 0.25, 0.16666 };
+ float center_val[3] = { 0.5f, 0.25f, 0.16666f };
AudioFrame center_frame(center_val[vol_index_max - 1], center_val[vol_index_max - 1]);
if (attenuation < 1.0) {
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 f9bd905181..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;
@@ -1619,7 +1619,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3(-0.700629, -0.509037, 0.5),
Vector3(0.267617, -0.823639, 0.5)
};
- static const float weights[6] = { 0.25, 0.15, 0.15, 0.15, 0.15, 0.15 };
+ static const float weights[6] = { 0.25f, 0.15f, 0.15f, 0.15f, 0.15f, 0.15f };
//
cone_dirs = dirs;
cone_dir_count = 6;
@@ -1641,7 +1641,7 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
Vector3(0.19124006749743122, 0.39355745585016605, 0.8991883926788214),
Vector3(0.19124006749743122, -0.39355745585016605, 0.8991883926788214),
};
- static const float weights[10] = { 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.08571, 0.133333, 0.133333, 0.13333 };
+ static const float weights[10] = { 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.08571f, 0.133333f, 0.133333f, 0.13333f };
cone_dirs = dirs;
cone_dir_count = 10;
cone_aperture = 0.404; // tan(angle) 45 degrees
@@ -1875,7 +1875,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
if (bake_mode == BAKE_MODE_RAY_TRACE) {
//blur
//gauss kernel, 7 step sigma 2
- static const float gauss_kernel[4] = { 0.214607, 0.189879, 0.131514, 0.071303 };
+ static const float gauss_kernel[4] = { 0.214607f, 0.189879f, 0.131514f, 0.071303f };
//horizontal pass
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
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/graph_edit.cpp b/scene/gui/graph_edit.cpp
index b4fd7484e9..b3bebc88ec 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -406,7 +406,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(to)->get_connection_input_color(E->get().to_port);
connecting_target = false;
connecting_to = pos;
- just_disconected = true;
+ just_disconnected = true;
emit_signal("disconnection_request", E->get().from, E->get().from_port, E->get().to, E->get().to_port);
to = get_node(String(connecting_from)); //maybe it was erased
@@ -427,7 +427,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_output_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconected = false;
+ just_disconnected = false;
return;
}
}
@@ -453,7 +453,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = Object::cast_to<GraphNode>(fr)->get_connection_output_color(E->get().from_port);
connecting_target = false;
connecting_to = pos;
- just_disconected = true;
+ just_disconnected = true;
emit_signal("disconnection_request", E->get().from, E->get().from_port, E->get().to, E->get().to_port);
fr = get_node(String(connecting_from)); //maybe it was erased
@@ -474,7 +474,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
connecting_color = gn->get_connection_input_color(j);
connecting_target = false;
connecting_to = pos;
- just_disconected = true;
+ just_disconnected = true;
return;
}
@@ -544,7 +544,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
emit_signal("connection_request", from, from_slot, to, to_slot);
- } else if (!just_disconected) {
+ } else if (!just_disconnected) {
String from = connecting_from;
int from_slot = connecting_index;
Vector2 ofs = Vector2(mb->get_position().x, mb->get_position().y);
@@ -1368,6 +1368,6 @@ GraphEdit::GraphEdit() {
zoom_hb->add_child(snap_amount);
setting_scroll_ofs = false;
- just_disconected = false;
+ just_disconnected = false;
set_clip_contents(true);
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 31a449eb59..71165e3dc9 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -94,7 +94,7 @@ private:
Vector2 connecting_to;
String connecting_target_to;
int connecting_target_index;
- bool just_disconected;
+ bool just_disconnected;
bool dragging;
bool just_selected;
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 0d5fbee9ee..494995fb85 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -1524,6 +1524,7 @@ void ItemList::_bind_methods() {
ADD_SIGNAL(MethodInfo("nothing_selected"));
GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers
}
ItemList::ItemList() {
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/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 32580a5ae6..bb56eea98e 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2331,9 +2331,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
// no need to indent if we are going upwards.
if (auto_indent && !(k->get_command() && k->get_shift())) {
- // indent once again if previous line will end with ':' or '{'
+ // indent once again if previous line will end with ':' or '{' and the line is not a comment
// (i.e. colon/brace precedes current cursor position)
- if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{')) {
+ if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{') && !is_line_comment(cursor.line)) {
if (indent_using_spaces) {
ins += space_indent;
} else {
@@ -6232,6 +6232,7 @@ void TextEdit::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_MAX);
GLOBAL_DEF("gui/timers/text_edit_idle_detect_sec", 3);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/text_edit_idle_detect_sec", PropertyInfo(Variant::REAL, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater")); // No negative numbers
}
TextEdit::TextEdit() {
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/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index fdbe3b57f0..f7dec77ce4 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1944,6 +1944,7 @@ SceneTree::SceneTree() {
debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
+ ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative
tree_version = 1;
physics_process_time = 1;
@@ -1977,7 +1978,9 @@ SceneTree::SceneTree() {
current_scene = NULL;
int ref_atlas_size = GLOBAL_DEF("rendering/quality/reflections/atlas_size", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_size", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_size", PROPERTY_HINT_RANGE, "0,8192,or_greater")); //next_power_of_2 will return a 0 as min value
int ref_atlas_subdiv = GLOBAL_DEF("rendering/quality/reflections/atlas_subdiv", 8);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/reflections/atlas_subdiv", PropertyInfo(Variant::INT, "rendering/quality/reflections/atlas_subdiv", PROPERTY_HINT_RANGE, "0,32,or_greater")); //next_power_of_2 will return a 0 as min value
int msaa_mode = GLOBAL_DEF("rendering/quality/filters/msaa", 0);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/msaa", PropertyInfo(Variant::INT, "rendering/quality/filters/msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x"));
root->set_msaa(Viewport::MSAA(msaa_mode));
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index bb379ff4af..6bf1d12086 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -629,10 +629,8 @@ Rect2 Viewport::get_visible_rect() const {
Rect2 r;
if (size == Size2()) {
-
- r = Rect2(Point2(), Size2(OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height));
+ r = Rect2(Point2(), OS::get_singleton()->get_window_size());
} else {
-
r = Rect2(Point2(), size);
}
@@ -2945,6 +2943,7 @@ Viewport::Viewport() {
//gui.tooltip_timer->force_parent_owned();
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.7);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::REAL, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
gui.tooltip = NULL;
gui.tooltip_label = NULL;
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index 9d47bca5ed..39488760cd 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -38,10 +38,9 @@ Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() {
if (points.size() > 3) {
- QuickHull qh;
Vector<Vector3> varr = Variant(points);
Geometry::MeshData md;
- Error err = qh.build(varr, md);
+ Error err = QuickHull::build(varr, md);
if (err == OK) {
Vector<Vector3> lines;
lines.resize(md.edges.size() * 2);
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index 6790c35c4b..458cbf6718 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -201,10 +201,10 @@ Error DynamicFontAtSize::_load() {
if (FT_HAS_COLOR(face)) {
int best_match = 0;
- int diff = ABS(id.size - face->available_sizes[0].width);
+ int diff = ABS(id.size - ((int64_t)face->available_sizes[0].width));
scale_color_font = float(id.size) / face->available_sizes[0].width;
for (int i = 1; i < face->num_fixed_sizes; i++) {
- int ndiff = ABS(id.size - face->available_sizes[i].width);
+ int ndiff = ABS(id.size - ((int64_t)face->available_sizes[i].width));
if (ndiff < diff) {
best_match = i;
diff = ndiff;
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/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 69d85eeef3..05050a5ea2 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -565,8 +565,6 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
vert_offset = 0;
}
int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
- int rings = (border_width[0] == 0 && border_width[1] == 0 && border_width[2] == 0 && border_width[3] == 0) ? 1 : 2;
- rings = 2;
int ring_corner_radius[4];
set_inner_corner_radius(style_rect, ring_rect, corner_radius, ring_corner_radius);
@@ -592,7 +590,7 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
//calculate the vert array
for (int corner_index = 0; corner_index < 4; corner_index++) {
for (int detail = 0; detail <= adapted_corner_detail; detail++) {
- for (int inner_outer = (2 - rings); inner_outer < 2; inner_outer++) {
+ for (int inner_outer = 0; inner_outer < 2; inner_outer++) {
float radius;
Color color;
Point2 corner_point;
@@ -613,19 +611,17 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
}
}
- if (rings == 2) {
- int vert_count = (adapted_corner_detail + 1) * 4 * rings;
- //fill the indices and the colors for the border
- for (int i = 0; i < vert_count; i++) {
- //poly 1
- indices.push_back(vert_offset + ((i + 0) % vert_count));
- indices.push_back(vert_offset + ((i + 2) % vert_count));
- indices.push_back(vert_offset + ((i + 1) % vert_count));
- //poly 2
- indices.push_back(vert_offset + ((i + 1) % vert_count));
- indices.push_back(vert_offset + ((i + 2) % vert_count));
- indices.push_back(vert_offset + ((i + 3) % vert_count));
- }
+ int vert_count = (adapted_corner_detail + 1) * 4 * 2;
+ //fill the indices and the colors for the border
+ for (int i = 0; i < vert_count; i++) {
+ //poly 1
+ indices.push_back(vert_offset + ((i + 0) % vert_count));
+ indices.push_back(vert_offset + ((i + 2) % vert_count));
+ indices.push_back(vert_offset + ((i + 1) % vert_count));
+ //poly 2
+ indices.push_back(vert_offset + ((i + 1) % vert_count));
+ indices.push_back(vert_offset + ((i + 2) % vert_count));
+ indices.push_back(vert_offset + ((i + 3) % vert_count));
}
}
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/effects/reverb.cpp b/servers/audio/effects/reverb.cpp
index ef23e4aaf3..b032c91da2 100644
--- a/servers/audio/effects/reverb.cpp
+++ b/servers/audio/effects/reverb.cpp
@@ -36,22 +36,22 @@
const float Reverb::comb_tunings[MAX_COMBS] = {
//freeverb comb tunings
- 0.025306122448979593,
- 0.026938775510204082,
- 0.028956916099773241,
- 0.03074829931972789,
- 0.032244897959183672,
- 0.03380952380952381,
- 0.035306122448979592,
- 0.036666666666666667
+ 0.025306122448979593f,
+ 0.026938775510204082f,
+ 0.028956916099773241f,
+ 0.03074829931972789f,
+ 0.032244897959183672f,
+ 0.03380952380952381f,
+ 0.035306122448979592f,
+ 0.036666666666666667f
};
const float Reverb::allpass_tunings[MAX_ALLPASS] = {
//freeverb allpass tunings
- 0.0051020408163265302,
- 0.007732426303854875,
- 0.01,
- 0.012607709750566893
+ 0.0051020408163265302f,
+ 0.007732426303854875f,
+ 0.01f,
+ 0.012607709750566893f
};
void Reverb::process(float *p_src, float *p_dst, int p_frames) {
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index d36057b465..b41fcac8fa 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;
@@ -926,6 +934,7 @@ void AudioServer::init() {
channel_disable_threshold_db = GLOBAL_DEF_RST("audio/channel_disable_threshold_db", -60.0);
channel_disable_frames = float(GLOBAL_DEF_RST("audio/channel_disable_time", 2.0)) * get_mix_rate();
+ ProjectSettings::get_singleton()->set_custom_property_info("audio/channel_disable_time", PropertyInfo(Variant::REAL, "audio/channel_disable_time", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
buffer_size = 1024; //hardcoded for now
init_channels_and_buffers();
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..
diff --git a/servers/physics/collision_solver_sw.cpp b/servers/physics/collision_solver_sw.cpp
index 2f2f6d2908..86ef719f6f 100644
--- a/servers/physics/collision_solver_sw.cpp
+++ b/servers/physics/collision_solver_sw.cpp
@@ -31,7 +31,6 @@
#include "collision_solver_sw.h"
#include "collision_solver_sat.h"
-#include "collision_solver_sat.h"
#include "gjk_epa.h"
#define collision_solver sat_calculate_penetration
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index 731749b8ce..feb96d8054 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -1183,6 +1183,7 @@ SpaceSW::SpaceSW() {
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_linear", 0.1);
body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/3d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI));
body_time_to_sleep = GLOBAL_DEF("physics/3d/time_before_sleep", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/time_before_sleep", PropertyInfo(Variant::REAL, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
body_angular_velocity_damp_ratio = 10;
broadphase = BroadPhaseSW::create_func();
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 950f0f9d24..95195c8fff 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -635,11 +635,15 @@ BroadPhase2DSW *BroadPhase2DHashGrid::_create() {
BroadPhase2DHashGrid::BroadPhase2DHashGrid() {
hash_table_size = GLOBAL_DEF("physics/2d/bp_hash_table_size", 4096);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/bp_hash_table_size", PropertyInfo(Variant::INT, "physics/2d/bp_hash_table_size", PROPERTY_HINT_RANGE, "0,8192,1,or_greater"));
hash_table_size = Math::larger_prime(hash_table_size);
hash_table = memnew_arr(PosBin *, hash_table_size);
cell_size = GLOBAL_DEF("physics/2d/cell_size", 128);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/cell_size", PropertyInfo(Variant::INT, "physics/2d/cell_size", PROPERTY_HINT_RANGE, "0,512,1,or_greater"));
+
large_object_min_surface = GLOBAL_DEF("physics/2d/large_object_surface_threshold_in_cells", 512);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/large_object_surface_threshold_in_cells", PropertyInfo(Variant::INT, "physics/2d/large_object_surface_threshold_in_cells", PROPERTY_HINT_RANGE, "0,1024,1,or_greater"));
for (uint32_t i = 0; i < hash_table_size; i++)
hash_table[i] = NULL;
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index f36328c985..adcc99aae8 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -1233,6 +1233,7 @@ Space2DSW::Space2DSW() {
body_linear_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_linear", 2.0);
body_angular_velocity_sleep_threshold = GLOBAL_DEF("physics/2d/sleep_threshold_angular", (8.0 / 180.0 * Math_PI));
body_time_to_sleep = GLOBAL_DEF("physics/2d/time_before_sleep", 0.5);
+ ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/time_before_sleep", PropertyInfo(Variant::REAL, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"));
broadphase = BroadPhase2DSW::create_func();
broadphase->set_pair_callback(_broadphase_pair, this);
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 67a810bf1c..d52e121a13 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -3506,6 +3506,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
nv.sint = -cn->values[i].sint;
} break;
case TYPE_UINT: {
+ // FIXME: This can't work on uint
nv.uint = -cn->values[i].uint;
} break;
case TYPE_FLOAT: {
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
index 16cda0326d..3c8088c75c 100644
--- a/servers/visual/visual_server_canvas.cpp
+++ b/servers/visual/visual_server_canvas.cpp
@@ -689,7 +689,7 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2
if (indices.empty()) {
ERR_EXPLAIN("Bad Polygon!");
- ERR_FAIL_V();
+ ERR_FAIL();
}
Item::CommandPolygon *polygon = memnew(Item::CommandPolygon);
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 9d684d33d6..164be132b8 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -2370,6 +2370,7 @@ VisualServer::VisualServer() {
GLOBAL_DEF("rendering/quality/directional_shadow/size", 4096);
GLOBAL_DEF("rendering/quality/directional_shadow/size.mobile", 2048);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/quality/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384"));
GLOBAL_DEF("rendering/quality/shadow_atlas/size", 4096);
GLOBAL_DEF("rendering/quality/shadow_atlas/size.mobile", 2048);
ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/quality/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384"));