summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/linux_builds.yml17
-rw-r--r--COPYRIGHT.txt5
-rw-r--r--SConstruct1
-rw-r--r--core/debugger/remote_debugger_peer.cpp2
-rw-r--r--core/input/input_event.cpp22
-rw-r--r--core/input/input_event.h6
-rw-r--r--core/input/input_map.cpp1
-rw-r--r--core/io/file_access_network.cpp2
-rw-r--r--core/io/http_client.cpp4
-rw-r--r--core/io/ip.cpp30
-rw-r--r--core/io/ip.h10
-rw-r--r--core/io/ip_address.cpp24
-rw-r--r--core/io/ip_address.h12
-rw-r--r--core/io/net_socket.h16
-rw-r--r--core/io/packed_data_container.cpp5
-rw-r--r--core/io/packet_peer_udp.cpp20
-rw-r--r--core/io/packet_peer_udp.h20
-rw-r--r--core/io/resource_loader.cpp11
-rw-r--r--core/io/stream_peer_tcp.cpp12
-rw-r--r--core/io/stream_peer_tcp.h10
-rw-r--r--core/io/tcp_server.cpp32
-rw-r--r--core/io/tcp_server.h10
-rw-r--r--core/io/udp_server.cpp6
-rw-r--r--core/io/udp_server.h6
-rw-r--r--core/math/math_funcs.h4
-rw-r--r--core/register_core_types.cpp2
-rw-r--r--core/string/optimized_translation.cpp1
-rw-r--r--core/variant/callable.cpp20
-rw-r--r--core/variant/callable.h3
-rw-r--r--core/variant/method_ptrcall.h4
-rw-r--r--core/variant/type_info.h2
-rw-r--r--core/variant/variant.cpp8
-rw-r--r--core/variant/variant.h4
-rw-r--r--core/variant/variant_call.cpp79
-rw-r--r--core/variant/variant_utility.cpp5
-rw-r--r--doc/classes/@GlobalScope.xml25
-rw-r--r--doc/classes/AudioStreamPlayer.xml1
-rw-r--r--doc/classes/AudioStreamPlayer2D.xml4
-rw-r--r--doc/classes/AudioStreamPlayer3D.xml4
-rw-r--r--doc/classes/Callable.xml16
-rw-r--r--doc/classes/EditorPlugin.xml19
-rw-r--r--doc/classes/File.xml1
-rw-r--r--doc/classes/IP.xml2
-rw-r--r--doc/classes/InputEventMouseButton.xml2
-rw-r--r--doc/classes/ProjectSettings.xml4
-rw-r--r--doc/classes/ScrollContainer.xml6
-rw-r--r--doc/classes/Shape3D.xml7
-rw-r--r--doc/classes/TCPServer.xml (renamed from doc/classes/TCP_Server.xml)2
-rw-r--r--drivers/unix/ip_unix.cpp28
-rw-r--r--drivers/unix/ip_unix.h8
-rw-r--r--drivers/unix/net_socket_posix.cpp28
-rw-r--r--drivers/unix/net_socket_posix.h24
-rw-r--r--drivers/unix/os_unix.cpp2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp4
-rw-r--r--drivers/vulkan/vulkan_context.cpp94
-rw-r--r--drivers/vulkan/vulkan_context.h8
-rw-r--r--editor/animation_bezier_editor.cpp10
-rw-r--r--editor/animation_track_editor.cpp28
-rw-r--r--editor/animation_track_editor_plugins.cpp2
-rw-r--r--editor/create_dialog.cpp1
-rw-r--r--editor/debugger/editor_debugger_server.cpp2
-rw-r--r--editor/editor_about.cpp29
-rw-r--r--editor/editor_about.h3
-rw-r--r--editor/editor_data.cpp12
-rw-r--r--editor/editor_data.h4
-rw-r--r--editor/editor_inspector.cpp16
-rw-r--r--editor/editor_log.cpp255
-rw-r--r--editor/editor_log.h108
-rw-r--r--editor/editor_node.cpp45
-rw-r--r--editor/editor_node.h4
-rw-r--r--editor/editor_plugin.cpp10
-rw-r--r--editor/editor_plugin.h3
-rw-r--r--editor/editor_properties.cpp2
-rw-r--r--editor/editor_properties_array_dict.cpp2
-rw-r--r--editor/editor_settings.cpp12
-rw-r--r--editor/editor_spin_slider.cpp3
-rw-r--r--editor/editor_themes.cpp340
-rw-r--r--editor/fileserver/editor_file_server.h2
-rw-r--r--editor/filesystem_dock.cpp2
-rw-r--r--editor/icons/CombineLines.svg1
-rw-r--r--editor/import/resource_importer_scene.cpp149
-rw-r--r--editor/import/resource_importer_scene.h2
-rw-r--r--editor/import/scene_importer_mesh.cpp130
-rw-r--r--editor/import/scene_importer_mesh.h2
-rw-r--r--editor/inspector_dock.cpp2
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp22
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp1
-rw-r--r--editor/plugins/audio_stream_editor_plugin.cpp17
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp13
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp7
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp3
-rw-r--r--editor/plugins/script_editor_plugin.cpp117
-rw-r--r--editor/plugins/script_editor_plugin.h1
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp29
-rw-r--r--editor/project_manager.cpp32
-rw-r--r--editor/project_manager.h2
-rw-r--r--editor/property_editor.cpp1
-rw-r--r--editor/scene_tree_editor.cpp4
-rw-r--r--editor/script_create_dialog.cpp2
-rw-r--r--editor/settings_config_dialog.cpp21
-rw-r--r--main/main.cpp2
-rw-r--r--modules/SCsub2
-rw-r--r--modules/enet/networked_multiplayer_enet.cpp16
-rw-r--r--modules/enet/networked_multiplayer_enet.h6
-rw-r--r--modules/gdscript/gdscript_editor.cpp7
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp2
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h4
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp2
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp86
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h2
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl7
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl21
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp2
-rw-r--r--modules/raycast/SCsub169
-rw-r--r--modules/raycast/lightmap_raycaster.cpp29
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp2
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp2
-rw-r--r--modules/visual_script/visual_script_editor.cpp58
-rw-r--r--modules/visual_script/visual_script_editor.h1
-rw-r--r--modules/websocket/emws_client.cpp4
-rw-r--r--modules/websocket/emws_client.h2
-rw-r--r--modules/websocket/emws_peer.cpp4
-rw-r--r--modules/websocket/emws_peer.h2
-rw-r--r--modules/websocket/emws_server.cpp4
-rw-r--r--modules/websocket/emws_server.h2
-rw-r--r--modules/websocket/websocket_client.h2
-rw-r--r--modules/websocket/websocket_peer.h2
-rw-r--r--modules/websocket/websocket_server.cpp6
-rw-r--r--modules/websocket/websocket_server.h8
-rw-r--r--modules/websocket/wsl_client.cpp6
-rw-r--r--modules/websocket/wsl_client.h2
-rw-r--r--modules/websocket/wsl_peer.cpp4
-rw-r--r--modules/websocket/wsl_peer.h2
-rw-r--r--modules/websocket/wsl_server.cpp4
-rw-r--r--modules/websocket/wsl_server.h4
-rw-r--r--modules/xatlas_unwrap/register_types.cpp210
-rw-r--r--platform/android/display_server_android.cpp2
-rw-r--r--platform/android/net_socket_android.cpp4
-rw-r--r--platform/android/net_socket_android.h4
-rw-r--r--platform/iphone/display_server_iphone.h2
-rw-r--r--platform/iphone/display_server_iphone.mm2
-rw-r--r--platform/javascript/display_server_javascript.cpp4
-rw-r--r--platform/javascript/export/export.cpp6
-rw-r--r--platform/javascript/http_client.h.inc3
-rw-r--r--platform/linuxbsd/detect.py4
-rw-r--r--platform/linuxbsd/display_server_x11.cpp4
-rw-r--r--platform/osx/display_server_osx.mm2
-rw-r--r--platform/uwp/os_uwp.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp8
-rw-r--r--platform/windows/os_windows.cpp2
-rw-r--r--scene/2d/tile_map.cpp11
-rw-r--r--scene/gui/gradient_edit.cpp2
-rw-r--r--scene/gui/item_list.cpp4
-rw-r--r--scene/gui/line_edit.cpp16
-rw-r--r--scene/gui/line_edit.h2
-rw-r--r--scene/gui/rich_text_label.cpp16
-rw-r--r--scene/gui/rich_text_label.h2
-rw-r--r--scene/gui/scroll_container.cpp115
-rw-r--r--scene/gui/scroll_container.h22
-rw-r--r--scene/gui/text_edit.cpp22
-rw-r--r--scene/gui/tree.cpp18
-rw-r--r--scene/gui/tree.h3
-rw-r--r--scene/main/canvas_item.cpp2
-rw-r--r--scene/main/viewport.cpp3
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/mesh.cpp134
-rw-r--r--scene/resources/mesh.h2
-rw-r--r--scene/resources/physics_material.cpp4
-rw-r--r--scene/resources/shape_3d.cpp2
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp102
-rw-r--r--servers/physics_2d/area_pair_2d_sw.h32
-rw-r--r--servers/physics_2d/body_2d_sw.cpp35
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp89
-rw-r--r--servers/physics_2d/body_pair_2d_sw.h24
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h4
-rw-r--r--servers/physics_2d/constraint_2d_sw.h1
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp92
-rw-r--r--servers/physics_2d/joints_2d_sw.h31
-rw-r--r--servers/physics_2d/step_2d_sw.cpp157
-rw-r--r--servers/physics_2d/step_2d_sw.h15
-rw-r--r--servers/physics_3d/area_pair_3d_sw.cpp102
-rw-r--r--servers/physics_3d/area_pair_3d_sw.h16
-rw-r--r--servers/physics_3d/body_3d_sw.cpp35
-rw-r--r--servers/physics_3d/body_pair_3d_sw.cpp137
-rw-r--r--servers/physics_3d/body_pair_3d_sw.h38
-rw-r--r--servers/physics_3d/constraint_3d_sw.h7
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp29
-rw-r--r--servers/physics_3d/joints/cone_twist_joint_3d_sw.h6
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp25
-rw-r--r--servers/physics_3d/joints/generic_6dof_joint_3d_sw.h9
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.cpp37
-rw-r--r--servers/physics_3d/joints/hinge_joint_3d_sw.h6
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.cpp13
-rw-r--r--servers/physics_3d/joints/pin_joint_3d_sw.h6
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.cpp45
-rw-r--r--servers/physics_3d/joints/slider_joint_3d_sw.h6
-rw-r--r--servers/physics_3d/joints_3d_sw.h9
-rw-r--r--servers/physics_3d/soft_body_3d_sw.h5
-rw-r--r--servers/physics_3d/step_3d_sw.cpp227
-rw-r--r--servers/physics_3d/step_3d_sw.h16
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp1
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp35
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h5
-rw-r--r--servers/rendering/renderer_rd/shaders/light_data_inc.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl12
-rw-r--r--servers/rendering/renderer_scene_cull.cpp2
-rw-r--r--servers/rendering/rendering_device.h4
-rw-r--r--servers/rendering_server.cpp4
-rw-r--r--tests/test_string.h8
-rw-r--r--thirdparty/enet/godot.cpp52
-rw-r--r--thirdparty/oidn/core/transfer_function.cpp107
-rw-r--r--thirdparty/oidn/patches/godot-changes-c58c5216.patch68
215 files changed, 3036 insertions, 1912 deletions
diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml
index 7b144e6e43..0982d768d6 100644
--- a/.github/workflows/linux_builds.yml
+++ b/.github/workflows/linux_builds.yml
@@ -70,6 +70,23 @@ jobs:
run: |
./bin/godot.linuxbsd.opt.tools.64 --test
+ # Download, unzip and setup SwiftShader library [d4550ab8d3f]
+ - name: Download SwiftShader
+ run: |
+ wget https://github.com/qarmin/gtk_library_store/releases/download/3.24.0/swiftshader.zip
+ unzip swiftshader.zip
+ rm swiftshader.zip
+ curr="$(pwd)/libvk_swiftshader.so"
+ sed -i "s|PATH_TO_CHANGE|$curr|" vk_swiftshader_icd.json
+
+ # Check class reference
+ - name: Check for class reference updates
+ run: |
+ echo "Running --doctool to see if this changes the public API without updating the documentation."
+ echo -e "If a diff is shown, it means that your code/doc changes are incomplete and you should update the class reference with --doctool.\n\n"
+ VK_ICD_FILENAMES=$(pwd)/vk_swiftshader_icd.json DRI_PRIME=0 xvfb-run bin/godot.linuxbsd.opt.tools.64 --doctool . 2>&1 > /dev/null || true
+ git diff --color --exit-code
+
- uses: actions/upload-artifact@v2
with:
name: ${{ github.job }}
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 9e63da3fc4..cfd983bb0a 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -131,6 +131,11 @@ Comment: doctest
Copyright: 2016-2020, Viktor Kirilov
License: Expat
+Files: ./thirdparty/embree-aarch64/
+Comment: Embree-aarch64
+Copyright: 2009-2021 Intel Corporation
+License: Apache-2.0
+
Files: ./thirdparty/enet/
Comment: ENet
Copyright: 2002-2020, Lee Salzman
diff --git a/SConstruct b/SConstruct
index 2d9802f293..6516b42e59 100644
--- a/SConstruct
+++ b/SConstruct
@@ -145,6 +145,7 @@ opts.Add(BoolVariable("use_precise_math_checks", "Math checks use very precise e
# Thirdparty libraries
opts.Add(BoolVariable("builtin_bullet", "Use the built-in Bullet library", True))
opts.Add(BoolVariable("builtin_certs", "Use the built-in SSL certificates bundles", True))
+opts.Add(BoolVariable("builtin_embree", "Use the built-in Embree library", True))
opts.Add(BoolVariable("builtin_enet", "Use the built-in ENet library", True))
opts.Add(BoolVariable("builtin_freetype", "Use the built-in FreeType library", True))
opts.Add(BoolVariable("builtin_glslang", "Use the built-in glslang library", True))
diff --git a/core/debugger/remote_debugger_peer.cpp b/core/debugger/remote_debugger_peer.cpp
index 90b0975159..39113eda14 100644
--- a/core/debugger/remote_debugger_peer.cpp
+++ b/core/debugger/remote_debugger_peer.cpp
@@ -152,7 +152,7 @@ void RemoteDebuggerPeerTCP::_read_in() {
}
Error RemoteDebuggerPeerTCP::connect_to_host(const String &p_host, uint16_t p_port) {
- IP_Address ip;
+ IPAddress ip;
if (p_host.is_valid_ip_address()) {
ip = p_host;
} else {
diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp
index 99cc51b95e..46629d742e 100644
--- a/core/input/input_event.cpp
+++ b/core/input/input_event.cpp
@@ -545,12 +545,12 @@ bool InputEventMouseButton::is_pressed() const {
return pressed;
}
-void InputEventMouseButton::set_doubleclick(bool p_doubleclick) {
- doubleclick = p_doubleclick;
+void InputEventMouseButton::set_double_click(bool p_double_click) {
+ double_click = p_double_click;
}
-bool InputEventMouseButton::is_doubleclick() const {
- return doubleclick;
+bool InputEventMouseButton::is_double_click() const {
+ return double_click;
}
Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs) const {
@@ -569,7 +569,7 @@ Ref<InputEvent> InputEventMouseButton::xformed_by(const Transform2D &p_xform, co
mb->set_button_mask(get_button_mask());
mb->set_pressed(pressed);
- mb->set_doubleclick(doubleclick);
+ mb->set_double_click(double_click);
mb->set_factor(factor);
mb->set_button_index(button_index);
@@ -636,7 +636,7 @@ String InputEventMouseButton::as_text() const {
}
// Double Click
- if (doubleclick) {
+ if (double_click) {
full_string += " (" + RTR("Double Click") + ")";
}
@@ -645,7 +645,7 @@ String InputEventMouseButton::as_text() const {
String InputEventMouseButton::to_string() {
String p = is_pressed() ? "true" : "false";
- String d = doubleclick ? "true" : "false";
+ String d = double_click ? "true" : "false";
int idx = get_button_index();
String button_string = itos(idx);
@@ -671,7 +671,7 @@ String InputEventMouseButton::to_string() {
// Work around the fact vformat can only take 5 substitutions but 6 need to be passed.
String index_and_mods = vformat("button_index=%s mods=%s", button_index, mods);
- return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s doubleclick=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d);
+ return vformat("InputEventMouseButton: %s pressed=%s position=(%s) button_mask=%s double_click=%s", index_and_mods, p, String(get_position()), itos(get_button_mask()), d);
}
void InputEventMouseButton::_bind_methods() {
@@ -684,13 +684,13 @@ void InputEventMouseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pressed", "pressed"), &InputEventMouseButton::set_pressed);
// ClassDB::bind_method(D_METHOD("is_pressed"), &InputEventMouseButton::is_pressed);
- ClassDB::bind_method(D_METHOD("set_doubleclick", "doubleclick"), &InputEventMouseButton::set_doubleclick);
- ClassDB::bind_method(D_METHOD("is_doubleclick"), &InputEventMouseButton::is_doubleclick);
+ ClassDB::bind_method(D_METHOD("set_double_click", "double_click"), &InputEventMouseButton::set_double_click);
+ ClassDB::bind_method(D_METHOD("is_double_click"), &InputEventMouseButton::is_double_click);
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "factor"), "set_factor", "get_factor");
ADD_PROPERTY(PropertyInfo(Variant::INT, "button_index"), "set_button_index", "get_button_index");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "doubleclick"), "set_doubleclick", "is_doubleclick");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "double_click"), "set_double_click", "is_double_click");
}
///////////////////////////////////
diff --git a/core/input/input_event.h b/core/input/input_event.h
index 94aa68db33..5a33ee7b9c 100644
--- a/core/input/input_event.h
+++ b/core/input/input_event.h
@@ -294,7 +294,7 @@ class InputEventMouseButton : public InputEventMouse {
float factor = 1;
int button_index = 0;
bool pressed = false; //otherwise released
- bool doubleclick = false; //last even less than doubleclick time
+ bool double_click = false; //last even less than double click time
protected:
static void _bind_methods();
@@ -309,8 +309,8 @@ public:
void set_pressed(bool p_pressed);
virtual bool is_pressed() const override;
- void set_doubleclick(bool p_doubleclick);
- bool is_doubleclick() const;
+ void set_double_click(bool p_double_click);
+ bool is_double_click() const;
virtual Ref<InputEvent> xformed_by(const Transform2D &p_xform, const Vector2 &p_local_ofs = Vector2()) const override;
virtual bool action_match(const Ref<InputEvent> &p_event, bool *p_pressed, float *p_strength, float *p_raw_strength, float p_deadzone) const override;
diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp
index aab4e6593c..7421909650 100644
--- a/core/input/input_map.cpp
+++ b/core/input/input_map.cpp
@@ -474,6 +474,7 @@ const OrderedHashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() {
inputs = List<Ref<InputEvent>>();
inputs.push_back(InputEventKey::create_reference(KEY_TAB));
+ inputs.push_back(InputEventKey::create_reference(KEY_ENTER));
default_builtin_cache.insert("ui_text_completion_accept", inputs);
// Newlines
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 31b7d658d0..4cc73bcd22 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -171,7 +171,7 @@ void FileAccessNetworkClient::_thread_func(void *s) {
}
Error FileAccessNetworkClient::connect(const String &p_host, int p_port, const String &p_password) {
- IP_Address ip;
+ IPAddress ip;
if (p_host.is_valid_ip_address()) {
ip = p_host;
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 4b053d576c..0cf870e7e7 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -77,7 +77,7 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
if (conn_host.is_valid_ip_address()) {
// Host contains valid IP
- Error err = tcp_connection->connect_to_host(IP_Address(conn_host), p_port);
+ Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port);
if (err) {
status = STATUS_CANT_CONNECT;
return err;
@@ -328,7 +328,7 @@ Error HTTPClient::poll() {
return OK; // Still resolving
case IP::RESOLVER_STATUS_DONE: {
- IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving);
+ IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving);
Error err = tcp_connection->connect_to_host(host, conn_port);
IP::get_singleton()->erase_resolve_item(resolving);
resolving = IP::RESOLVER_INVALID_ID;
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index e1d9c19f10..eb7814054b 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -41,13 +41,13 @@ VARIANT_ENUM_CAST(IP::ResolverStatus);
struct _IP_ResolverPrivate {
struct QueueItem {
SafeNumeric<IP::ResolverStatus> status;
- IP_Address response;
+ IPAddress response;
String hostname;
IP::Type type;
void clear() {
status.set(IP::RESOLVER_STATUS_NONE);
- response = IP_Address();
+ response = IPAddress();
type = IP::TYPE_NONE;
hostname = "";
};
@@ -101,23 +101,23 @@ struct _IP_ResolverPrivate {
}
}
- HashMap<String, IP_Address> cache;
+ HashMap<String, IPAddress> cache;
static String get_cache_key(String p_hostname, IP::Type p_type) {
return itos(p_type) + p_hostname;
}
};
-IP_Address IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
+IPAddress IP::resolve_hostname(const String &p_hostname, IP::Type p_type) {
MutexLock lock(resolver->mutex);
String key = _IP_ResolverPrivate::get_cache_key(p_hostname, p_type);
if (resolver->cache.has(key) && resolver->cache[key].is_valid()) {
- IP_Address res = resolver->cache[key];
+ IPAddress res = resolver->cache[key];
return res;
}
- IP_Address res = _resolve_hostname(p_hostname, p_type);
+ IPAddress res = _resolve_hostname(p_hostname, p_type);
resolver->cache[key] = res;
return res;
}
@@ -139,7 +139,7 @@ IP::ResolverID IP::resolve_hostname_queue_item(const String &p_hostname, IP::Typ
resolver->queue[id].response = resolver->cache[key];
resolver->queue[id].status.set(IP::RESOLVER_STATUS_DONE);
} else {
- resolver->queue[id].response = IP_Address();
+ resolver->queue[id].response = IPAddress();
resolver->queue[id].status.set(IP::RESOLVER_STATUS_WAITING);
if (resolver->thread.is_started()) {
resolver->sem.post();
@@ -164,15 +164,15 @@ IP::ResolverStatus IP::get_resolve_item_status(ResolverID p_id) const {
return resolver->queue[p_id].status.get();
}
-IP_Address IP::get_resolve_item_address(ResolverID p_id) const {
- ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IP_Address());
+IPAddress IP::get_resolve_item_address(ResolverID p_id) const {
+ ERR_FAIL_INDEX_V(p_id, IP::RESOLVER_MAX_QUERIES, IPAddress());
MutexLock lock(resolver->mutex);
if (resolver->queue[p_id].status.get() != IP::RESOLVER_STATUS_DONE) {
ERR_PRINT("Resolve of '" + resolver->queue[p_id].hostname + "'' didn't complete yet.");
resolver->mutex.unlock();
- return IP_Address();
+ return IPAddress();
}
return resolver->queue[p_id].response;
@@ -201,9 +201,9 @@ void IP::clear_cache(const String &p_hostname) {
Array IP::_get_local_addresses() const {
Array addresses;
- List<IP_Address> ip_addresses;
+ List<IPAddress> ip_addresses;
get_local_addresses(&ip_addresses);
- for (List<IP_Address>::Element *E = ip_addresses.front(); E; E = E->next()) {
+ for (List<IPAddress>::Element *E = ip_addresses.front(); E; E = E->next()) {
addresses.push_back(E->get());
}
@@ -222,7 +222,7 @@ Array IP::_get_local_interfaces() const {
rc["index"] = c.index;
Array ips;
- for (const List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
+ for (const List<IPAddress>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
ips.push_front(F->get());
}
rc["addresses"] = ips;
@@ -233,11 +233,11 @@ Array IP::_get_local_interfaces() const {
return results;
}
-void IP::get_local_addresses(List<IP_Address> *r_addresses) const {
+void IP::get_local_addresses(List<IPAddress> *r_addresses) const {
Map<String, Interface_Info> interfaces;
get_local_interfaces(&interfaces);
for (Map<String, Interface_Info>::Element *E = interfaces.front(); E; E = E->next()) {
- for (const List<IP_Address>::Element *F = E->get().ip_addresses.front(); F; F = F->next()) {
+ for (const List<IPAddress>::Element *F = E->get().ip_addresses.front(); F; F = F->next()) {
r_addresses->push_front(F->get());
}
}
diff --git a/core/io/ip.h b/core/io/ip.h
index ae080b8e26..0c4a83257d 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -69,7 +69,7 @@ protected:
static IP *singleton;
static void _bind_methods();
- virtual IP_Address _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0;
+ virtual IPAddress _resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY) = 0;
Array _get_local_addresses() const;
Array _get_local_interfaces() const;
@@ -80,15 +80,15 @@ public:
String name;
String name_friendly;
String index;
- List<IP_Address> ip_addresses;
+ List<IPAddress> ip_addresses;
};
- IP_Address resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
+ IPAddress resolve_hostname(const String &p_hostname, Type p_type = TYPE_ANY);
// async resolver hostname
ResolverID resolve_hostname_queue_item(const String &p_hostname, Type p_type = TYPE_ANY);
ResolverStatus get_resolve_item_status(ResolverID p_id) const;
- IP_Address get_resolve_item_address(ResolverID p_id) const;
- virtual void get_local_addresses(List<IP_Address> *r_addresses) const;
+ IPAddress get_resolve_item_address(ResolverID p_id) const;
+ virtual void get_local_addresses(List<IPAddress> *r_addresses) const;
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const = 0;
void erase_resolve_item(ResolverID p_id);
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index 5f98eb69e8..1c1ac8a88f 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -30,14 +30,14 @@
#include "ip_address.h"
/*
-IP_Address::operator Variant() const {
+IPAddress::operator Variant() const {
return operator String();
}*/
#include <stdio.h>
#include <string.h>
-IP_Address::operator String() const {
+IPAddress::operator String() const {
if (wildcard) {
return "*";
}
@@ -90,7 +90,7 @@ static void _parse_hex(const String &p_string, int p_start, uint8_t *p_dst) {
p_dst[1] = ret & 0xff;
}
-void IP_Address::_parse_ipv6(const String &p_string) {
+void IPAddress::_parse_ipv6(const String &p_string) {
static const int parts_total = 8;
int parts[parts_total] = { 0 };
int parts_count = 0;
@@ -146,7 +146,7 @@ void IP_Address::_parse_ipv6(const String &p_string) {
}
}
-void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) {
+void IPAddress::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret) {
String ip;
if (p_start != 0) {
ip = p_string.substr(p_start, p_string.length() - p_start);
@@ -161,33 +161,33 @@ void IP_Address::_parse_ipv4(const String &p_string, int p_start, uint8_t *p_ret
}
}
-void IP_Address::clear() {
+void IPAddress::clear() {
memset(&field8[0], 0, sizeof(field8));
valid = false;
wildcard = false;
}
-bool IP_Address::is_ipv4() const {
+bool IPAddress::is_ipv4() const {
return (field32[0] == 0 && field32[1] == 0 && field16[4] == 0 && field16[5] == 0xffff);
}
-const uint8_t *IP_Address::get_ipv4() const {
+const uint8_t *IPAddress::get_ipv4() const {
ERR_FAIL_COND_V_MSG(!is_ipv4(), &(field8[12]), "IPv4 requested, but current IP is IPv6."); // Not the correct IPv4 (it's an IPv6), but we don't want to return a null pointer risking an engine crash.
return &(field8[12]);
}
-void IP_Address::set_ipv4(const uint8_t *p_ip) {
+void IPAddress::set_ipv4(const uint8_t *p_ip) {
clear();
valid = true;
field16[5] = 0xffff;
field32[3] = *((const uint32_t *)p_ip);
}
-const uint8_t *IP_Address::get_ipv6() const {
+const uint8_t *IPAddress::get_ipv6() const {
return field8;
}
-void IP_Address::set_ipv6(const uint8_t *p_buf) {
+void IPAddress::set_ipv6(const uint8_t *p_buf) {
clear();
valid = true;
for (int i = 0; i < 16; i++) {
@@ -195,7 +195,7 @@ void IP_Address::set_ipv6(const uint8_t *p_buf) {
}
}
-IP_Address::IP_Address(const String &p_string) {
+IPAddress::IPAddress(const String &p_string) {
clear();
if (p_string == "*") {
@@ -225,7 +225,7 @@ _FORCE_INLINE_ static void _32_to_buf(uint8_t *p_dst, uint32_t p_n) {
p_dst[3] = (p_n >> 0) & 0xff;
}
-IP_Address::IP_Address(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6) {
+IPAddress::IPAddress(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6) {
clear();
valid = true;
if (!is_v6) {
diff --git a/core/io/ip_address.h b/core/io/ip_address.h
index 49bf83d72f..05da675704 100644
--- a/core/io/ip_address.h
+++ b/core/io/ip_address.h
@@ -33,7 +33,7 @@
#include "core/string/ustring.h"
-struct IP_Address {
+struct IPAddress {
private:
union {
uint8_t field8[16];
@@ -50,7 +50,7 @@ protected:
public:
//operator Variant() const;
- bool operator==(const IP_Address &p_ip) const {
+ bool operator==(const IPAddress &p_ip) const {
if (p_ip.valid != valid) {
return false;
}
@@ -65,7 +65,7 @@ public:
return true;
}
- bool operator!=(const IP_Address &p_ip) const {
+ bool operator!=(const IPAddress &p_ip) const {
if (p_ip.valid != valid) {
return true;
}
@@ -91,9 +91,9 @@ public:
void set_ipv6(const uint8_t *p_buf);
operator String() const;
- IP_Address(const String &p_string);
- IP_Address(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6 = false);
- IP_Address() { clear(); }
+ IPAddress(const String &p_string);
+ IPAddress(uint32_t p_a, uint32_t p_b, uint32_t p_c, uint32_t p_d, bool is_v6 = false);
+ IPAddress() { clear(); }
};
#endif // IP_ADDRESS_H
diff --git a/core/io/net_socket.h b/core/io/net_socket.h
index a632ad2ea7..98ff9562d9 100644
--- a/core/io/net_socket.h
+++ b/core/io/net_socket.h
@@ -55,27 +55,27 @@ public:
virtual Error open(Type p_type, IP::Type &ip_type) = 0;
virtual void close() = 0;
- virtual Error bind(IP_Address p_addr, uint16_t p_port) = 0;
+ virtual Error bind(IPAddress p_addr, uint16_t p_port) = 0;
virtual Error listen(int p_max_pending) = 0;
- virtual Error connect_to_host(IP_Address p_addr, uint16_t p_port) = 0;
+ virtual Error connect_to_host(IPAddress p_addr, uint16_t p_port) = 0;
virtual Error poll(PollType p_type, int timeout) const = 0;
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read) = 0;
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false) = 0;
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false) = 0;
virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent) = 0;
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
- virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port) = 0;
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) = 0;
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port) = 0;
virtual bool is_open() const = 0;
virtual int get_available_bytes() const = 0;
- virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) const = 0;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const = 0;
virtual Error set_broadcasting_enabled(bool p_enabled) = 0; // Returns OK if the socket option has been set successfully.
virtual void set_blocking_enabled(bool p_enabled) = 0;
virtual void set_ipv6_only_enabled(bool p_enabled) = 0;
virtual void set_tcp_no_delay_enabled(bool p_enabled) = 0;
virtual void set_reuse_address_enabled(bool p_enabled) = 0;
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0;
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) = 0;
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name) = 0;
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) = 0;
};
#endif // NET_SOCKET_H
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index c6354b11b7..52169987fd 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -123,6 +123,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
const uint8_t *rd = data.ptr();
+ ERR_FAIL_COND_V(!rd, 0);
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
@@ -149,6 +150,10 @@ int PackedDataContainer::_size(uint32_t p_ofs) const {
Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const {
const uint8_t *rd = data.ptr();
+ if (!rd) {
+ err = true;
+ ERR_FAIL_COND_V(!rd, Variant());
+ }
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
diff --git a/core/io/packet_peer_udp.cpp b/core/io/packet_peer_udp.cpp
index 40e4ce4f77..f951a5158c 100644
--- a/core/io/packet_peer_udp.cpp
+++ b/core/io/packet_peer_udp.cpp
@@ -45,7 +45,7 @@ void PacketPeerUDP::set_broadcast_enabled(bool p_enabled) {
}
}
-Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_if_name) {
+Error PacketPeerUDP::join_multicast_group(IPAddress p_multi_address, String p_if_name) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_multi_address.is_valid(), ERR_INVALID_PARAMETER);
@@ -60,7 +60,7 @@ Error PacketPeerUDP::join_multicast_group(IP_Address p_multi_address, String p_i
return _sock->join_multicast_group(p_multi_address, p_if_name);
}
-Error PacketPeerUDP::leave_multicast_group(IP_Address p_multi_address, String p_if_name) {
+Error PacketPeerUDP::leave_multicast_group(IPAddress p_multi_address, String p_if_name) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!_sock->is_open(), ERR_UNCONFIGURED);
@@ -72,7 +72,7 @@ String PacketPeerUDP::_get_packet_ip() const {
}
Error PacketPeerUDP::_set_dest_address(const String &p_address, int p_port) {
- IP_Address ip;
+ IPAddress ip;
if (p_address.is_valid_ip_address()) {
ip = p_address;
} else {
@@ -159,7 +159,7 @@ int PacketPeerUDP::get_max_packet_size() const {
return 512; // uhm maybe not
}
-Error PacketPeerUDP::bind(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) {
+Error PacketPeerUDP::bind(int p_port, const IPAddress &p_bind_address, int p_recv_buffer_size) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
@@ -190,7 +190,7 @@ Error PacketPeerUDP::bind(int p_port, const IP_Address &p_bind_address, int p_re
return OK;
}
-Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *p_server) {
+Error PacketPeerUDP::connect_shared_socket(Ref<NetSocket> p_sock, IPAddress p_ip, uint16_t p_port, UDPServer *p_server) {
udp_server = p_server;
connected = true;
_sock = p_sock;
@@ -207,7 +207,7 @@ void PacketPeerUDP::disconnect_shared_socket() {
close();
}
-Error PacketPeerUDP::connect_to_host(const IP_Address &p_host, int p_port) {
+Error PacketPeerUDP::connect_to_host(const IPAddress &p_host, int p_port) {
ERR_FAIL_COND_V(udp_server, ERR_LOCKED);
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
@@ -276,7 +276,7 @@ Error PacketPeerUDP::_poll() {
Error err;
int read;
- IP_Address ip;
+ IPAddress ip;
uint16_t port;
while (true) {
@@ -306,7 +306,7 @@ Error PacketPeerUDP::_poll() {
return OK;
}
-Error PacketPeerUDP::store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) {
+Error PacketPeerUDP::store_packet(IPAddress p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size) {
if (rb.space_left() < p_buf_size + 24) {
return ERR_OUT_OF_MEMORY;
}
@@ -322,7 +322,7 @@ bool PacketPeerUDP::is_bound() const {
return _sock.is_valid() && _sock->is_open();
}
-IP_Address PacketPeerUDP::get_packet_address() const {
+IPAddress PacketPeerUDP::get_packet_address() const {
return packet_ip;
}
@@ -336,7 +336,7 @@ int PacketPeerUDP::get_local_port() const {
return local_port;
}
-void PacketPeerUDP::set_dest_address(const IP_Address &p_address, int p_port) {
+void PacketPeerUDP::set_dest_address(const IPAddress &p_address, int p_port) {
ERR_FAIL_COND_MSG(connected, "Destination address cannot be set for connected sockets");
peer_addr = p_address;
peer_port = p_port;
diff --git a/core/io/packet_peer_udp.h b/core/io/packet_peer_udp.h
index b9d11c465c..40d3c44e40 100644
--- a/core/io/packet_peer_udp.h
+++ b/core/io/packet_peer_udp.h
@@ -48,11 +48,11 @@ protected:
RingBuffer<uint8_t> rb;
uint8_t recv_buffer[PACKET_BUFFER_SIZE];
uint8_t packet_buffer[PACKET_BUFFER_SIZE];
- IP_Address packet_ip;
+ IPAddress packet_ip;
int packet_port = 0;
int queue_count = 0;
- IP_Address peer_addr;
+ IPAddress peer_addr;
int peer_port = 0;
bool connected = false;
bool blocking = true;
@@ -70,29 +70,29 @@ protected:
public:
void set_blocking_mode(bool p_enable);
- Error bind(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536);
+ Error bind(int p_port, const IPAddress &p_bind_address = IPAddress("*"), int p_recv_buffer_size = 65536);
void close();
Error wait();
bool is_bound() const;
- Error connect_shared_socket(Ref<NetSocket> p_sock, IP_Address p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
+ Error connect_shared_socket(Ref<NetSocket> p_sock, IPAddress p_ip, uint16_t p_port, UDPServer *ref); // Used by UDPServer
void disconnect_shared_socket(); // Used by UDPServer
- Error store_packet(IP_Address p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
- Error connect_to_host(const IP_Address &p_host, int p_port);
+ Error store_packet(IPAddress p_ip, uint32_t p_port, uint8_t *p_buf, int p_buf_size); // Used internally and by UDPServer
+ Error connect_to_host(const IPAddress &p_host, int p_port);
bool is_connected_to_host() const;
- IP_Address get_packet_address() const;
+ IPAddress get_packet_address() const;
int get_packet_port() const;
int get_local_port() const;
- void set_dest_address(const IP_Address &p_address, int p_port);
+ void set_dest_address(const IPAddress &p_address, int p_port);
Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
int get_available_packet_count() const override;
int get_max_packet_size() const override;
void set_broadcast_enabled(bool p_enabled);
- Error join_multicast_group(IP_Address p_multi_address, String p_if_name);
- Error leave_multicast_group(IP_Address p_multi_address, String p_if_name);
+ Error join_multicast_group(IPAddress p_multi_address, String p_if_name);
+ Error leave_multicast_group(IPAddress p_multi_address, String p_if_name);
PacketPeerUDP();
~PacketPeerUDP();
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index dcf71bb4a9..040e55b9db 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -114,25 +114,24 @@ void ResourceFormatLoader::get_recognized_extensions(List<String> *p_extensions)
}
RES ResourceFormatLoader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ // Check user-defined loader if there's any. Hard fail if it returns an error.
if (get_script_instance() && get_script_instance()->has_method("load")) {
Variant res = get_script_instance()->call("load", p_path, p_original_path, p_use_sub_threads, p_cache_mode);
- if (res.get_type() == Variant::INT) {
+ if (res.get_type() == Variant::INT) { // Error code, abort.
if (r_error) {
*r_error = (Error)res.operator int64_t();
}
-
- } else {
+ return RES();
+ } else { // Success, pass on result.
if (r_error) {
*r_error = OK;
}
return res;
}
-
- return res;
}
- ERR_FAIL_V_MSG(RES(), "Failed to load resource '" + p_path + "', ResourceFormatLoader::load was not implemented for this resource type.");
+ ERR_FAIL_V_MSG(RES(), "Failed to load resource '" + p_path + "'. ResourceFormatLoader::load was not implemented for this resource type.");
}
void ResourceFormatLoader::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index 9906b9e4c3..5b794274ca 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -56,7 +56,7 @@ Error StreamPeerTCP::_poll_connection() {
return ERR_CONNECTION_ERROR;
}
-void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port) {
+void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint16_t p_port) {
_sock = p_sock;
_sock->set_blocking_enabled(false);
@@ -67,7 +67,7 @@ void StreamPeerTCP::accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint
peer_port = p_port;
}
-Error StreamPeerTCP::bind(int p_port, const IP_Address &p_host) {
+Error StreamPeerTCP::bind(int p_port, const IPAddress &p_host) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The local port number must be between 0 and 65535 (inclusive).");
@@ -84,7 +84,7 @@ Error StreamPeerTCP::bind(int p_port, const IP_Address &p_host) {
return _sock->bind(p_host, p_port);
}
-Error StreamPeerTCP::connect_to_host(const IP_Address &p_host, int p_port) {
+Error StreamPeerTCP::connect_to_host(const IPAddress &p_host, int p_port) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(status != STATUS_NONE, ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER);
@@ -283,7 +283,7 @@ void StreamPeerTCP::disconnect_from_host() {
timeout = 0;
status = STATUS_NONE;
- peer_host = IP_Address();
+ peer_host = IPAddress();
peer_port = 0;
}
@@ -315,7 +315,7 @@ int StreamPeerTCP::get_available_bytes() const {
return _sock->get_available_bytes();
}
-IP_Address StreamPeerTCP::get_connected_host() const {
+IPAddress StreamPeerTCP::get_connected_host() const {
return peer_host;
}
@@ -330,7 +330,7 @@ int StreamPeerTCP::get_local_port() const {
}
Error StreamPeerTCP::_connect(const String &p_address, int p_port) {
- IP_Address ip;
+ IPAddress ip;
if (p_address.is_valid_ip_address()) {
ip = p_address;
} else {
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 3bc7b252dc..a2a7f447d8 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -52,7 +52,7 @@ protected:
Ref<NetSocket> _sock;
uint64_t timeout = 0;
Status status = STATUS_NONE;
- IP_Address peer_host;
+ IPAddress peer_host;
uint16_t peer_port = 0;
Error _connect(const String &p_address, int p_port);
@@ -63,12 +63,12 @@ protected:
static void _bind_methods();
public:
- void accept_socket(Ref<NetSocket> p_sock, IP_Address p_host, uint16_t p_port);
+ void accept_socket(Ref<NetSocket> p_sock, IPAddress p_host, uint16_t p_port);
- Error bind(int p_port, const IP_Address &p_host);
- Error connect_to_host(const IP_Address &p_host, int p_port);
+ Error bind(int p_port, const IPAddress &p_host);
+ Error connect_to_host(const IPAddress &p_host, int p_port);
bool is_connected_to_host() const;
- IP_Address get_connected_host() const;
+ IPAddress get_connected_host() const;
int get_connected_port() const;
int get_local_port() const;
void disconnect_from_host();
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
index 348be66ba4..b760a9ef80 100644
--- a/core/io/tcp_server.cpp
+++ b/core/io/tcp_server.cpp
@@ -30,16 +30,16 @@
#include "tcp_server.h"
-void TCP_Server::_bind_methods() {
- ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCP_Server::listen, DEFVAL("*"));
- ClassDB::bind_method(D_METHOD("is_connection_available"), &TCP_Server::is_connection_available);
- ClassDB::bind_method(D_METHOD("is_listening"), &TCP_Server::is_listening);
- ClassDB::bind_method(D_METHOD("get_local_port"), &TCP_Server::get_local_port);
- ClassDB::bind_method(D_METHOD("take_connection"), &TCP_Server::take_connection);
- ClassDB::bind_method(D_METHOD("stop"), &TCP_Server::stop);
+void TCPServer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("listen", "port", "bind_address"), &TCPServer::listen, DEFVAL("*"));
+ ClassDB::bind_method(D_METHOD("is_connection_available"), &TCPServer::is_connection_available);
+ ClassDB::bind_method(D_METHOD("is_listening"), &TCPServer::is_listening);
+ ClassDB::bind_method(D_METHOD("get_local_port"), &TCPServer::get_local_port);
+ ClassDB::bind_method(D_METHOD("take_connection"), &TCPServer::take_connection);
+ ClassDB::bind_method(D_METHOD("stop"), &TCPServer::stop);
}
-Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
+Error TCPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
@@ -76,19 +76,19 @@ Error TCP_Server::listen(uint16_t p_port, const IP_Address &p_bind_address) {
return OK;
}
-int TCP_Server::get_local_port() const {
+int TCPServer::get_local_port() const {
uint16_t local_port;
_sock->get_socket_address(nullptr, &local_port);
return local_port;
}
-bool TCP_Server::is_listening() const {
+bool TCPServer::is_listening() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
return _sock->is_open();
}
-bool TCP_Server::is_connection_available() const {
+bool TCPServer::is_connection_available() const {
ERR_FAIL_COND_V(!_sock.is_valid(), false);
if (!_sock->is_open()) {
@@ -99,14 +99,14 @@ bool TCP_Server::is_connection_available() const {
return (err == OK);
}
-Ref<StreamPeerTCP> TCP_Server::take_connection() {
+Ref<StreamPeerTCP> TCPServer::take_connection() {
Ref<StreamPeerTCP> conn;
if (!is_connection_available()) {
return conn;
}
Ref<NetSocket> ns;
- IP_Address ip;
+ IPAddress ip;
uint16_t port = 0;
ns = _sock->accept(ip, port);
if (!ns.is_valid()) {
@@ -118,16 +118,16 @@ Ref<StreamPeerTCP> TCP_Server::take_connection() {
return conn;
}
-void TCP_Server::stop() {
+void TCPServer::stop() {
if (_sock.is_valid()) {
_sock->close();
}
}
-TCP_Server::TCP_Server() :
+TCPServer::TCPServer() :
_sock(Ref<NetSocket>(NetSocket::create())) {
}
-TCP_Server::~TCP_Server() {
+TCPServer::~TCPServer() {
stop();
}
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
index 58c04d87ec..abefa53c6f 100644
--- a/core/io/tcp_server.h
+++ b/core/io/tcp_server.h
@@ -36,8 +36,8 @@
#include "core/io/stream_peer.h"
#include "core/io/stream_peer_tcp.h"
-class TCP_Server : public Reference {
- GDCLASS(TCP_Server, Reference);
+class TCPServer : public Reference {
+ GDCLASS(TCPServer, Reference);
protected:
enum {
@@ -48,7 +48,7 @@ protected:
static void _bind_methods();
public:
- Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ Error listen(uint16_t p_port, const IPAddress &p_bind_address = IPAddress("*"));
int get_local_port() const;
bool is_listening() const;
bool is_connection_available() const;
@@ -56,8 +56,8 @@ public:
void stop(); // Stop listening
- TCP_Server();
- ~TCP_Server();
+ TCPServer();
+ ~TCPServer();
};
#endif // TCP_SERVER_H
diff --git a/core/io/udp_server.cpp b/core/io/udp_server.cpp
index 99642f4af4..6a1af0c2a9 100644
--- a/core/io/udp_server.cpp
+++ b/core/io/udp_server.cpp
@@ -50,7 +50,7 @@ Error UDPServer::poll() {
}
Error err;
int read;
- IP_Address ip;
+ IPAddress ip;
uint16_t port;
while (true) {
err = _sock->recvfrom(recv_buffer, sizeof(recv_buffer), read, ip, port);
@@ -87,7 +87,7 @@ Error UDPServer::poll() {
return OK;
}
-Error UDPServer::listen(uint16_t p_port, const IP_Address &p_bind_address) {
+Error UDPServer::listen(uint16_t p_port, const IPAddress &p_bind_address) {
ERR_FAIL_COND_V(!_sock.is_valid(), ERR_UNAVAILABLE);
ERR_FAIL_COND_V(_sock->is_open(), ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER);
@@ -168,7 +168,7 @@ Ref<PacketPeerUDP> UDPServer::take_connection() {
return peer.peer;
}
-void UDPServer::remove_peer(IP_Address p_ip, int p_port) {
+void UDPServer::remove_peer(IPAddress p_ip, int p_port) {
Peer peer;
peer.ip = p_ip;
peer.port = p_port;
diff --git a/core/io/udp_server.h b/core/io/udp_server.h
index 298d4d4b63..60d03f37f0 100644
--- a/core/io/udp_server.h
+++ b/core/io/udp_server.h
@@ -44,7 +44,7 @@ protected:
struct Peer {
PacketPeerUDP *peer;
- IP_Address ip;
+ IPAddress ip;
uint16_t port = 0;
bool operator==(const Peer &p_other) const {
@@ -61,8 +61,8 @@ protected:
static void _bind_methods();
public:
- void remove_peer(IP_Address p_ip, int p_port);
- Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*"));
+ void remove_peer(IPAddress p_ip, int p_port);
+ Error listen(uint16_t p_port, const IPAddress &p_bind_address = IPAddress("*"));
Error poll();
int get_local_port() const;
bool is_listening() const;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 8cf13efdb6..c0d7649b65 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -218,8 +218,8 @@ public:
return value;
}
- static _ALWAYS_INLINE_ int posmod(int p_x, int p_y) {
- int value = p_x % p_y;
+ static _ALWAYS_INLINE_ int64_t posmod(int64_t p_x, int64_t p_y) {
+ int64_t value = p_x % p_y;
if ((value < 0 && p_y > 0) || (value > 0 && p_y < 0)) {
value += p_y;
}
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index d6a5eff10d..f1b1b98bea 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -156,7 +156,7 @@ void register_core_types() {
ClassDB::register_virtual_class<StreamPeer>();
ClassDB::register_class<StreamPeerBuffer>();
ClassDB::register_class<StreamPeerTCP>();
- ClassDB::register_class<TCP_Server>();
+ ClassDB::register_class<TCPServer>();
ClassDB::register_class<PacketPeerUDP>();
ClassDB::register_class<UDPServer>();
ClassDB::register_custom_instance_class<PacketPeerDTLS>();
diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp
index 53d0a8924d..268562d971 100644
--- a/core/string/optimized_translation.cpp
+++ b/core/string/optimized_translation.cpp
@@ -46,6 +46,7 @@ void OptimizedTranslation::generate(const Ref<Translation> &p_from) {
// This method compresses a Translation instance.
// Right now, it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed.
#ifdef TOOLS_ENABLED
+ ERR_FAIL_COND(p_from.is_null());
List<StringName> keys;
p_from->get_message_list(&keys);
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index a1d9c5ed2f..e06b3e07ef 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -54,6 +54,20 @@ void Callable::call(const Variant **p_arguments, int p_argcount, Variant &r_retu
}
}
+void Callable::rpc(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const {
+ if (is_null()) {
+ r_call_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ } else if (!is_custom()) {
+ r_call_error.error = CallError::CALL_ERROR_INVALID_METHOD;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ } else {
+ custom->rpc(p_id, p_arguments, p_argcount, r_call_error);
+ }
+}
+
Callable Callable::bind(const Variant **p_arguments, int p_argcount) const {
Vector<Variant> args;
args.resize(p_argcount);
@@ -283,6 +297,12 @@ Callable::~Callable() {
}
}
+void CallableCustom::rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const {
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+}
+
const Callable *CallableCustom::get_base_comparator() const {
return nullptr;
}
diff --git a/core/variant/callable.h b/core/variant/callable.h
index 090fd888e2..d91bebfa5f 100644
--- a/core/variant/callable.h
+++ b/core/variant/callable.h
@@ -70,6 +70,8 @@ public:
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, CallError &r_call_error) const;
void call_deferred(const Variant **p_arguments, int p_argcount) const;
+ void rpc(int p_id, const Variant **p_arguments, int p_argcount, CallError &r_call_error) const;
+
_FORCE_INLINE_ bool is_null() const {
return method == StringName() && object == 0;
}
@@ -124,6 +126,7 @@ public:
virtual CompareLessFunc get_compare_less_func() const = 0;
virtual ObjectID get_object() const = 0; //must always be able to provide an object
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const = 0;
+ virtual void rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const;
virtual const Callable *get_base_comparator() const;
CallableCustom();
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index c294592b63..e91029f330 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -364,7 +364,7 @@ MAKE_VECARR(Plane);
} \
}
-// Special case for IP_Address.
+// Special case for IPAddress.
#define MAKE_STRINGCONV_BY_REFERENCE(m_type) \
template <> \
@@ -387,7 +387,7 @@ MAKE_VECARR(Plane);
} \
}
-MAKE_STRINGCONV_BY_REFERENCE(IP_Address);
+MAKE_STRINGCONV_BY_REFERENCE(IPAddress);
template <>
struct PtrToArg<Vector<Face3>> {
diff --git a/core/variant/type_info.h b/core/variant/type_info.h
index f61ff29b8f..d5b6d85dfb 100644
--- a/core/variant/type_info.h
+++ b/core/variant/type_info.h
@@ -168,7 +168,7 @@ MAKE_TYPE_INFO(PackedVector2Array, Variant::PACKED_VECTOR2_ARRAY)
MAKE_TYPE_INFO(PackedVector3Array, Variant::PACKED_VECTOR3_ARRAY)
MAKE_TYPE_INFO(PackedColorArray, Variant::PACKED_COLOR_ARRAY)
-MAKE_TYPE_INFO(IP_Address, Variant::STRING)
+MAKE_TYPE_INFO(IPAddress, Variant::STRING)
//objectID
template <>
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index 015cee09a7..333dd8e8d1 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -2346,15 +2346,15 @@ Variant::operator Orientation() const {
return (Orientation) operator int();
}
-Variant::operator IP_Address() const {
+Variant::operator IPAddress() const {
if (type == PACKED_FLOAT32_ARRAY || type == PACKED_INT32_ARRAY || type == PACKED_FLOAT64_ARRAY || type == PACKED_INT64_ARRAY || type == PACKED_BYTE_ARRAY) {
Vector<int> addr = operator Vector<int>();
if (addr.size() == 4) {
- return IP_Address(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
+ return IPAddress(addr.get(0), addr.get(1), addr.get(2), addr.get(3));
}
}
- return IP_Address(operator String());
+ return IPAddress(operator String());
}
Variant::Variant(bool p_bool) {
@@ -2831,7 +2831,7 @@ void Variant::operator=(const Variant &p_variant) {
}
}
-Variant::Variant(const IP_Address &p_address) {
+Variant::Variant(const IPAddress &p_address) {
type = STRING;
memnew_placement(_data._mem, String(p_address));
}
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 0acafc64fa..7f3c3477fc 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -359,7 +359,7 @@ public:
operator Side() const;
operator Orientation() const;
- operator IP_Address() const;
+ operator IPAddress() const;
Object *get_validated_object() const;
Object *get_validated_object_with_check(bool &r_previously_freed) const;
@@ -421,7 +421,7 @@ public:
Variant(const Vector<::RID> &p_array); // helper
Variant(const Vector<Vector2> &p_array); // helper
- Variant(const IP_Address &p_address);
+ Variant(const IPAddress &p_address);
// If this changes the table in variant_op must be updated
enum Operator {
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 8988a0c4ed..efaaa8cd19 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -493,6 +493,58 @@ static _FORCE_INLINE_ void vc_ptrcall(void (*method)(T *, P...), void *p_base, c
} \
};
+#define VARARG_CLASS1(m_class, m_method_name, m_method_ptr, m_arg_type) \
+ struct Method_##m_class##_##m_method_name { \
+ static void call(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) { \
+ m_method_ptr(base, p_args, p_argcount, r_ret, r_error); \
+ } \
+ static void validated_call(Variant *base, const Variant **p_args, int p_argcount, Variant *r_ret) { \
+ Callable::CallError ce; \
+ m_method_ptr(base, p_args, p_argcount, *r_ret, ce); \
+ } \
+ static void ptrcall(void *p_base, const void **p_args, void *r_ret, int p_argcount) { \
+ LocalVector<Variant> vars; \
+ vars.resize(p_argcount); \
+ LocalVector<const Variant *> vars_ptrs; \
+ vars_ptrs.resize(p_argcount); \
+ for (int i = 0; i < p_argcount; i++) { \
+ vars[i] = PtrToArg<Variant>::convert(p_args[i]); \
+ vars_ptrs[i] = &vars[i]; \
+ } \
+ Variant base = PtrToArg<m_class>::convert(p_base); \
+ Variant ret; \
+ Callable::CallError ce; \
+ m_method_ptr(&base, (const Variant **)&vars_ptrs[0], p_argcount, ret, ce); \
+ } \
+ static int get_argument_count() { \
+ return 1; \
+ } \
+ static Variant::Type get_argument_type(int p_arg) { \
+ return m_arg_type; \
+ } \
+ static Variant::Type get_return_type() { \
+ return Variant::NIL; \
+ } \
+ static bool has_return_type() { \
+ return false; \
+ } \
+ static bool is_const() { \
+ return true; \
+ } \
+ static bool is_static() { \
+ return false; \
+ } \
+ static bool is_vararg() { \
+ return true; \
+ } \
+ static Variant::Type get_base_type() { \
+ return GetTypeInfo<m_class>::VARIANT_TYPE; \
+ } \
+ static StringName get_name() { \
+ return #m_method_name; \
+ } \
+ };
+
struct _VariantCall {
static String func_PackedByteArray_get_string_from_ascii(PackedByteArray *p_instance) {
String s;
@@ -792,6 +844,27 @@ struct _VariantCall {
callable->call_deferred(p_args, p_argcount);
}
+ static void func_Callable_rpc(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->rpc(0, p_args, p_argcount, r_error);
+ }
+
+ static void func_Callable_rpc_id(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
+ if (p_argcount == 0) {
+ r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument = 0;
+ r_error.expected = 1;
+
+ } else if (p_args[0]->get_type() != Variant::INT) {
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument = 0;
+ r_error.expected = Variant::INT;
+ } else {
+ Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
+ callable->rpc(*p_args[0], &p_args[1], p_argcount - 1, r_error);
+ }
+ }
+
static void func_Callable_bind(Variant *v, const Variant **p_args, int p_argcount, Variant &r_ret, Callable::CallError &r_error) {
Callable *callable = VariantGetInternalPtr<Callable>::get_ptr(v);
r_ret = callable->bind(p_args, p_argcount);
@@ -1219,6 +1292,10 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va
VARARG_CLASS(m_type, m_name, m_method, m_has_return, m_ret_type) \
register_builtin_method<Method_##m_type##_##m_name>(sarray(), Vector<Variant>());
+#define bind_custom1(m_type, m_name, m_method, m_arg_type, m_arg_name) \
+ VARARG_CLASS1(m_type, m_name, m_method, m_arg_type) \
+ register_builtin_method<Method_##m_type##_##m_name>(sarray(m_arg_name), Vector<Variant>());
+
static void _register_variant_builtin_methods() {
_VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX);
builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX);
@@ -1532,6 +1609,8 @@ static void _register_variant_builtin_methods() {
bind_custom(Callable, call, _VariantCall::func_Callable_call, true, Variant);
bind_custom(Callable, call_deferred, _VariantCall::func_Callable_call_deferred, false, Variant);
+ bind_custom(Callable, rpc, _VariantCall::func_Callable_rpc, false, Variant);
+ bind_custom1(Callable, rpc_id, _VariantCall::func_Callable_rpc_id, Variant::INT, "peer_id");
bind_custom(Callable, bind, _VariantCall::func_Callable_bind, true, Callable);
/* Signal */
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index f154ab1ed6..553f2b23a2 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -93,6 +93,10 @@ struct VariantUtilityFunctions {
return Math::fposmod(b, r);
}
+ static inline int64_t posmod(int64_t b, int64_t r) {
+ return Math::posmod(b, r);
+ }
+
static inline double floor(double x) {
return Math::floor(x);
}
@@ -1154,6 +1158,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDR(sqrt, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(fposmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
+ FUNCBINDR(posmod, sarray("x", "y"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(floor, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(ceil, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
FUNCBINDR(round, sarray("x"), Variant::UTILITY_FUNC_TYPE_MATH);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 95108f1613..af66a11fe5 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -652,6 +652,31 @@
Converts a 2D point expressed in the polar coordinate system (a distance from the origin [code]r[/code] and an angle [code]th[/code]) to the cartesian coordinate system (X and Y axis).
</description>
</method>
+ <method name="posmod">
+ <return type="int">
+ </return>
+ <argument index="0" name="x" type="int">
+ </argument>
+ <argument index="1" name="y" type="int">
+ </argument>
+ <description>
+ Returns the integer modulus of [code]x/y[/code] that wraps equally in positive and negative.
+ [codeblock]
+ for i in range(-3, 4):
+ print("%2d %2d %2d" % [i, i % 3, posmod(i, 3)])
+ [/codeblock]
+ Produces:
+ [codeblock]
+ -3 0 0
+ -2 -2 1
+ -1 -1 2
+ 0 0 0
+ 1 1 1
+ 2 2 2
+ 3 0 0
+ [/codeblock]
+ </description>
+ </method>
<method name="pow">
<return type="float">
</return>
diff --git a/doc/classes/AudioStreamPlayer.xml b/doc/classes/AudioStreamPlayer.xml
index 55190c5f9f..113cc64b9d 100644
--- a/doc/classes/AudioStreamPlayer.xml
+++ b/doc/classes/AudioStreamPlayer.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Plays an audio stream non-positionally.
+ To play audio positionally, use [AudioStreamPlayer2D] or [AudioStreamPlayer3D] instead of [AudioStreamPlayer].
</description>
<tutorials>
<link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
diff --git a/doc/classes/AudioStreamPlayer2D.xml b/doc/classes/AudioStreamPlayer2D.xml
index d8b9385736..e7c276f463 100644
--- a/doc/classes/AudioStreamPlayer2D.xml
+++ b/doc/classes/AudioStreamPlayer2D.xml
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamPlayer2D" inherits="Node2D" version="4.0">
<brief_description>
- Plays audio in 2D.
+ Plays positional sound in 2D space.
</brief_description>
<description>
Plays audio that dampens with distance from screen center.
+ See also [AudioStreamPlayer] to play a sound non-positionally.
+ [b]Note:[/b] Hiding an [AudioStreamPlayer2D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer2D]'s audio output, set [member volume_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
<tutorials>
<link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
diff --git a/doc/classes/AudioStreamPlayer3D.xml b/doc/classes/AudioStreamPlayer3D.xml
index 7a8c4b2cc7..db46ed2778 100644
--- a/doc/classes/AudioStreamPlayer3D.xml
+++ b/doc/classes/AudioStreamPlayer3D.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamPlayer3D" inherits="Node3D" version="4.0">
<brief_description>
- Plays 3D sound in 3D space.
+ Plays positional sound in 3D space.
</brief_description>
<description>
Plays a sound effect with directed sound effects, dampens with distance if needed, generates effect of hearable position in space. For greater realism, a low-pass filter is automatically applied to distant sounds. This can be disabled by setting [member attenuation_filter_cutoff_hz] to [code]20500[/code].
By default, audio is heard from the camera position. This can be changed by adding a [Listener3D] node to the scene and enabling it by calling [method Listener3D.make_current] on it.
+ See also [AudioStreamPlayer] to play a sound non-positionally.
+ [b]Note:[/b] Hiding an [AudioStreamPlayer3D] node does not disable its audio output. To temporarily disable an [AudioStreamPlayer3D]'s audio output, set [member unit_db] to a very low value like [code]-100[/code] (which isn't audible to human hearing).
</description>
<tutorials>
<link title="Audio streams">https://docs.godotengine.org/en/latest/tutorials/audio/audio_streams.html</link>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index 0cfbd0270c..cbab1a8f50 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -151,6 +151,22 @@
Returns [code]true[/code] if both [Callable]s invoke the same custom target.
</description>
</method>
+ <method name="rpc" qualifiers="vararg const">
+ <return type="void">
+ </return>
+ <description>
+ Perform an RPC (Remote Procedure Call). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error.
+ </description>
+ </method>
+ <method name="rpc_id" qualifiers="vararg const">
+ <return type="void">
+ </return>
+ <argument index="0" name="peer_id" type="int">
+ </argument>
+ <description>
+ Perform an RPC (Remote Procedure Call) on a specific peer ID (see multiplayer documentation for reference). This is used for multiplayer and is normally not available unless the function being called has been marked as [i]RPC[/i]. Calling it on unsupported functions will result in an error.
+ </description>
+ </method>
<method name="unbind" qualifiers="const">
<return type="Callable">
</return>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 61f1761249..f6f51df7c0 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -157,6 +157,16 @@
Registers a custom translation parser plugin for extracting translatable strings from custom files.
</description>
</method>
+ <method name="add_undo_redo_inspector_hook_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callable" type="Callable">
+ </argument>
+ <description>
+ Hooks a callback into the undo/redo action creation when a property is modified in the inspector. This allows, for example, to save other properties that may be lost when a given property is modified.
+ The callback should have 4 arguments: [Object] [code]undo_redo[/code], [Object] [code]modified_object[/code], [String] [code]property[/code] and [Variant] [code]new_value[/code]. They are, respectively, the [UndoRedo] object used by the inspector, the currently modified object, the name of the modified property and the new value the property is about to take.
+ </description>
+ </method>
<method name="apply_changes" qualifiers="virtual">
<return type="void">
</return>
@@ -622,6 +632,15 @@
Removes a registered custom translation parser plugin.
</description>
</method>
+ <method name="remove_undo_redo_inspector_hook_callback">
+ <return type="void">
+ </return>
+ <argument index="0" name="callable" type="Callable">
+ </argument>
+ <description>
+ Removes a callback previsously added by [method add_undo_redo_inspector_hook_callback].
+ </description>
+ </method>
<method name="save_external_data" qualifiers="virtual">
<return type="void">
</return>
diff --git a/doc/classes/File.xml b/doc/classes/File.xml
index e0781e807f..f0b9156b89 100644
--- a/doc/classes/File.xml
+++ b/doc/classes/File.xml
@@ -275,6 +275,7 @@
</argument>
<description>
Opens a compressed file for reading or writing.
+ [b]Note:[/b] [method open_compressed] can only read files that were saved by Godot, not third-party compression formats. See [url=https://github.com/godotengine/godot/issues/28999]GitHub issue #28999[/url] for a workaround.
</description>
</method>
<method name="open_encrypted">
diff --git a/doc/classes/IP.xml b/doc/classes/IP.xml
index 849f036bbd..44da913492 100644
--- a/doc/classes/IP.xml
+++ b/doc/classes/IP.xml
@@ -4,7 +4,7 @@
Internet protocol (IP) support functions such as DNS resolution.
</brief_description>
<description>
- IP contains support functions for the Internet Protocol (IP). TCP/IP support is in different classes (see [StreamPeerTCP] and [TCP_Server]). IP provides DNS hostname resolution support, both blocking and threaded.
+ IP contains support functions for the Internet Protocol (IP). TCP/IP support is in different classes (see [StreamPeerTCP] and [TCPServer]). IP provides DNS hostname resolution support, both blocking and threaded.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/InputEventMouseButton.xml b/doc/classes/InputEventMouseButton.xml
index d7e92f8bca..be71b42567 100644
--- a/doc/classes/InputEventMouseButton.xml
+++ b/doc/classes/InputEventMouseButton.xml
@@ -15,7 +15,7 @@
<member name="button_index" type="int" setter="set_button_index" getter="get_button_index" default="0">
The mouse button identifier, one of the [enum MouseButton] button or button wheel constants.
</member>
- <member name="doubleclick" type="bool" setter="set_doubleclick" getter="is_doubleclick" default="false">
+ <member name="double_click" type="bool" setter="set_double_click" getter="is_double_click" default="false">
If [code]true[/code], the mouse button's state is a double-click.
</member>
<member name="factor" type="float" setter="set_factor" getter="get_factor" default="1.0">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index b123e17576..005873c2ff 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1579,6 +1579,10 @@
</member>
<member name="rendering/vulkan/descriptor_pools/max_descriptors_per_pool" type="int" setter="" getter="" default="64">
</member>
+ <member name="rendering/vulkan/rendering/back_end" type="int" setter="" getter="" default="0">
+ </member>
+ <member name="rendering/vulkan/rendering/back_end.mobile" type="int" setter="" getter="" default="1">
+ </member>
<member name="rendering/vulkan/staging_buffer/block_size_kb" type="int" setter="" getter="" default="256">
</member>
<member name="rendering/vulkan/staging_buffer/max_size_mb" type="int" setter="" getter="" default="128">
diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index 9c5634f43a..40e29ac74b 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -39,12 +39,18 @@
<member name="scroll_horizontal_enabled" type="bool" setter="set_enable_h_scroll" getter="is_h_scroll_enabled" default="true">
If [code]true[/code], enables horizontal scrolling.
</member>
+ <member name="scroll_horizontal_visible" type="bool" setter="set_h_scroll_visible" getter="is_h_scroll_visible" default="true">
+ If [code]false[/code], hides the horizontal scrollbar.
+ </member>
<member name="scroll_vertical" type="int" setter="set_v_scroll" getter="get_v_scroll" default="0">
The current vertical scroll value.
</member>
<member name="scroll_vertical_enabled" type="bool" setter="set_enable_v_scroll" getter="is_v_scroll_enabled" default="true">
If [code]true[/code], enables vertical scrolling.
</member>
+ <member name="scroll_vertical_visible" type="bool" setter="set_v_scroll_visible" getter="is_v_scroll_visible" default="true">
+ If [code]false[/code], hides the vertical scrollbar.
+ </member>
</members>
<signals>
<signal name="scroll_ended">
diff --git a/doc/classes/Shape3D.xml b/doc/classes/Shape3D.xml
index f8b749aebf..b5f70132d7 100644
--- a/doc/classes/Shape3D.xml
+++ b/doc/classes/Shape3D.xml
@@ -10,6 +10,13 @@
<link title="Physics introduction">https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html</link>
</tutorials>
<methods>
+ <method name="get_debug_mesh">
+ <return type="ArrayMesh">
+ </return>
+ <description>
+ Returns the [ArrayMesh] used to draw the debug collision for this [Shape3D].
+ </description>
+ </method>
</methods>
<members>
<member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.04">
diff --git a/doc/classes/TCP_Server.xml b/doc/classes/TCPServer.xml
index ec91d75d47..28f06ad3ae 100644
--- a/doc/classes/TCP_Server.xml
+++ b/doc/classes/TCPServer.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="TCP_Server" inherits="Reference" version="4.0">
+<class name="TCPServer" inherits="Reference" version="4.0">
<brief_description>
A TCP server.
</brief_description>
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 8ec1de4386..053e3fd9d6 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -75,8 +75,8 @@
#include <net/if.h> // Order is important on OpenBSD, leave as last
#endif
-static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
- IP_Address ip;
+static IPAddress _sockaddr2ip(struct sockaddr *p_addr) {
+ IPAddress ip;
if (p_addr->sa_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *)p_addr;
@@ -89,7 +89,7 @@ static IP_Address _sockaddr2ip(struct sockaddr *p_addr) {
return ip;
};
-IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
+IPAddress IPUnix::_resolve_hostname(const String &p_hostname, Type p_type) {
struct addrinfo hints;
struct addrinfo *result = nullptr;
@@ -108,7 +108,7 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
int s = getaddrinfo(p_hostname.utf8().get_data(), nullptr, &hints, &result);
if (s != 0) {
ERR_PRINT("getaddrinfo failed! Cannot resolve hostname.");
- return IP_Address();
+ return IPAddress();
};
if (result == nullptr || result->ai_addr == nullptr) {
@@ -116,10 +116,10 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
if (result) {
freeaddrinfo(result);
}
- return IP_Address();
+ return IPAddress();
};
- IP_Address ip = _sockaddr2ip(result->ai_addr);
+ IPAddress ip = _sockaddr2ip(result->ai_addr);
freeaddrinfo(result);
@@ -130,7 +130,7 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) {
#if defined(UWP_ENABLED)
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
using namespace Windows::Networking;
using namespace Windows::Networking::Connectivity;
@@ -156,14 +156,14 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
Interface_Info &info = E->get();
- IP_Address ip = IP_Address(hostname->CanonicalName->Data());
+ IPAddress ip = IPAddress(hostname->CanonicalName->Data());
info.ip_addresses.push_front(ip);
}
}
#else
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
ULONG buf_size = 1024;
IP_ADAPTER_ADDRESSES *addrs;
@@ -211,7 +211,7 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
#else // UNIX
-void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
+void IPUnix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const {
struct ifaddrs *ifAddrStruct = nullptr;
struct ifaddrs *ifa = nullptr;
int family;
@@ -249,15 +249,15 @@ void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) co
}
#endif
-void IP_Unix::make_default() {
+void IPUnix::make_default() {
_create = _create_unix;
}
-IP *IP_Unix::_create_unix() {
- return memnew(IP_Unix);
+IP *IPUnix::_create_unix() {
+ return memnew(IPUnix);
}
-IP_Unix::IP_Unix() {
+IPUnix::IPUnix() {
}
#endif
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index ca2ee17f4e..e6479be6e5 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -35,10 +35,10 @@
#if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED)
-class IP_Unix : public IP {
- GDCLASS(IP_Unix, IP);
+class IPUnix : public IP {
+ GDCLASS(IPUnix, IP);
- virtual IP_Address _resolve_hostname(const String &p_hostname, IP::Type p_type) override;
+ virtual IPAddress _resolve_hostname(const String &p_hostname, IP::Type p_type) override;
static IP *_create_unix();
@@ -46,7 +46,7 @@ public:
virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const override;
static void make_default();
- IP_Unix();
+ IPUnix();
};
#endif
diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp
index e2ad352c10..222aef998c 100644
--- a/drivers/unix/net_socket_posix.cpp
+++ b/drivers/unix/net_socket_posix.cpp
@@ -95,7 +95,7 @@
#endif
-size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) {
+size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type) {
memset(p_addr, 0, sizeof(struct sockaddr_storage));
if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket
@@ -130,7 +130,7 @@ size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const
}
}
-void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address *r_ip, uint16_t *r_port) {
+void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port) {
if (p_addr->ss_family == AF_INET) {
struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr;
if (r_ip) {
@@ -233,7 +233,7 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() const {
#pragma GCC diagnostic pop
#endif
-bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const {
+bool NetSocketPosix::_can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const {
if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) {
return false;
} else if (!p_for_bind && !p_ip.is_valid()) {
@@ -244,7 +244,7 @@ bool NetSocketPosix::_can_use_ip(const IP_Address &p_ip, const bool p_for_bind)
return !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type);
}
-_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) {
+_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER);
@@ -254,7 +254,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int ret = -1;
- IP_Address if_ip;
+ IPAddress if_ip;
uint32_t if_v6id = 0;
Map<String, IP::Interface_Info> if_info;
IP::get_singleton()->get_local_interfaces(&if_info);
@@ -269,7 +269,7 @@ _FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, St
break; // IPv6 uses index.
}
- for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
+ for (List<IPAddress>::Element *F = c.ip_addresses.front(); F; F = F->next()) {
if (!F->get().is_ipv4()) {
continue; // Wrong IP type
}
@@ -395,7 +395,7 @@ void NetSocketPosix::close() {
_is_stream = false;
}
-Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) {
+Error NetSocketPosix::bind(IPAddress p_addr, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER);
@@ -425,7 +425,7 @@ Error NetSocketPosix::listen(int p_max_pending) {
return OK;
}
-Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) {
+Error NetSocketPosix::connect_to_host(IPAddress p_host, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER);
@@ -559,7 +559,7 @@ Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) {
return OK;
}
-Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek) {
+Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage from;
@@ -616,7 +616,7 @@ Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) {
return OK;
}
-Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED);
struct sockaddr_storage addr;
@@ -735,7 +735,7 @@ int NetSocketPosix::get_available_bytes() const {
return len;
}
-Error NetSocketPosix::get_socket_address(IP_Address *r_ip, uint16_t *r_port) const {
+Error NetSocketPosix::get_socket_address(IPAddress *r_ip, uint16_t *r_port) const {
ERR_FAIL_COND_V(!is_open(), FAILED);
struct sockaddr_storage saddr;
@@ -749,7 +749,7 @@ Error NetSocketPosix::get_socket_address(IP_Address *r_ip, uint16_t *r_port) con
return OK;
}
-Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
+Ref<NetSocket> NetSocketPosix::accept(IPAddress &r_ip, uint16_t &r_port) {
Ref<NetSocket> out;
ERR_FAIL_COND_V(!is_open(), out);
@@ -770,11 +770,11 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) {
return Ref<NetSocket>(ns);
}
-Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketPosix::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, true);
}
-Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketPosix::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
return _change_multicast_group(p_multi_address, p_if_name, false);
}
#endif
diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h
index dbfe3a524e..38c8170a52 100644
--- a/drivers/unix/net_socket_posix.h
+++ b/drivers/unix/net_socket_posix.h
@@ -61,35 +61,35 @@ private:
NetError _get_socket_error() const;
void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream);
- _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add);
+ _FORCE_INLINE_ Error _change_multicast_group(IPAddress p_ip, String p_if_name, bool p_add);
_FORCE_INLINE_ void _set_close_exec_enabled(bool p_enabled);
protected:
static NetSocket *_create_func();
- bool _can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const;
+ bool _can_use_ip(const IPAddress &p_ip, const bool p_for_bind) const;
public:
static void make_default();
static void cleanup();
- static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address *r_ip, uint16_t *r_port);
- static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type);
+ static void _set_ip_port(struct sockaddr_storage *p_addr, IPAddress *r_ip, uint16_t *r_port);
+ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IPAddress &p_ip, uint16_t p_port, IP::Type p_ip_type);
virtual Error open(Type p_sock_type, IP::Type &ip_type);
virtual void close();
- virtual Error bind(IP_Address p_addr, uint16_t p_port);
+ virtual Error bind(IPAddress p_addr, uint16_t p_port);
virtual Error listen(int p_max_pending);
- virtual Error connect_to_host(IP_Address p_host, uint16_t p_port);
+ virtual Error connect_to_host(IPAddress p_host, uint16_t p_port);
virtual Error poll(PollType p_type, int timeout) const;
virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read);
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port, bool p_peek = false);
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port, bool p_peek = false);
virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent);
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port);
- virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port);
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port);
+ virtual Ref<NetSocket> accept(IPAddress &r_ip, uint16_t &r_port);
virtual bool is_open() const;
virtual int get_available_bytes() const;
- virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) const;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) const;
virtual Error set_broadcasting_enabled(bool p_enabled);
virtual void set_blocking_enabled(bool p_enabled);
@@ -97,8 +97,8 @@ public:
virtual void set_tcp_no_delay_enabled(bool p_enabled);
virtual void set_reuse_address_enabled(bool p_enabled);
virtual void set_reuse_port_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name);
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name);
NetSocketPosix();
~NetSocketPosix();
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index b9bd773c2e..15cd7bee92 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -129,7 +129,7 @@ void OS_Unix::initialize_core() {
#ifndef NO_NETWORK
NetSocketPosix::make_default();
- IP_Unix::make_default();
+ IPUnix::make_default();
#endif
_setup_clock();
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 30cc01fd10..43b2a24172 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -7844,6 +7844,10 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
device_capabilities.subgroup_size = subgroup_capabilities.size;
device_capabilities.subgroup_in_shaders = subgroup_capabilities.supported_stages_flags_rd();
device_capabilities.subgroup_operations = subgroup_capabilities.supported_operations_flags_rd();
+
+ // get info about further features
+ VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities();
+ device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
}
context = p_context;
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 0a8a5c746f..12a67c0e07 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -352,8 +352,6 @@ Error VulkanContext::_initialize_extensions() {
return OK;
}
-typedef void(VKAPI_PTR *_vkGetPhysicalDeviceProperties2)(VkPhysicalDevice, VkPhysicalDeviceProperties2 *);
-
uint32_t VulkanContext::SubgroupCapabilities::supported_stages_flags_rd() const {
uint32_t flags = 0;
@@ -496,20 +494,70 @@ String VulkanContext::SubgroupCapabilities::supported_operations_desc() const {
}
Error VulkanContext::_check_capabilities() {
- // check subgroups
+ // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_multiview.html
// https://www.khronos.org/blog/vulkan-subgroup-tutorial
+
// for Vulkan 1.0 vkGetPhysicalDeviceProperties2 is not available, including not in the loader we compile against on Android.
- _vkGetPhysicalDeviceProperties2 func = (_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
- if (func != nullptr) {
+
+ // so we check if the functions are accessible by getting their function pointers and skipping if not
+ // (note that the desktop loader does a better job here but the android loader doesn't)
+
+ // assume not supported until proven otherwise
+ multiview_capabilities.is_supported = false;
+ multiview_capabilities.max_view_count = 0;
+ multiview_capabilities.max_instance_count = 0;
+ subgroup_capabilities.size = 0;
+ subgroup_capabilities.supportedStages = 0;
+ subgroup_capabilities.supportedOperations = 0;
+ subgroup_capabilities.quadOperationsInAllStages = false;
+
+ // check for extended features
+ PFN_vkGetPhysicalDeviceFeatures2 device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2");
+ if (device_features_func == nullptr) {
+ // In Vulkan 1.0 might be accessible under its original extension name
+ device_features_func = (PFN_vkGetPhysicalDeviceFeatures2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceFeatures2KHR");
+ }
+ if (device_features_func != nullptr) {
+ // check our extended features
+ VkPhysicalDeviceMultiviewFeatures multiview_features;
+ multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
+ multiview_features.pNext = NULL;
+
+ VkPhysicalDeviceFeatures2 device_features;
+ device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
+ device_features.pNext = &multiview_features;
+
+ device_features_func(gpu, &device_features);
+ multiview_capabilities.is_supported = multiview_features.multiview;
+ // For now we ignore if multiview is available in geometry and tesselation as we do not currently support those
+ }
+
+ // check extended properties
+ PFN_vkGetPhysicalDeviceProperties2 device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2");
+ if (device_properties_func == nullptr) {
+ // In Vulkan 1.0 might be accessible under its original extension name
+ device_properties_func = (PFN_vkGetPhysicalDeviceProperties2)vkGetInstanceProcAddr(inst, "vkGetPhysicalDeviceProperties2KHR");
+ }
+ if (device_properties_func != nullptr) {
+ VkPhysicalDeviceMultiviewProperties multiviewProperties;
VkPhysicalDeviceSubgroupProperties subgroupProperties;
+ VkPhysicalDeviceProperties2 physicalDeviceProperties;
+
subgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
subgroupProperties.pNext = nullptr;
- VkPhysicalDeviceProperties2 physicalDeviceProperties;
physicalDeviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
- physicalDeviceProperties.pNext = &subgroupProperties;
- func(gpu, &physicalDeviceProperties);
+ if (multiview_capabilities.is_supported) {
+ multiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+ multiviewProperties.pNext = &subgroupProperties;
+
+ physicalDeviceProperties.pNext = &multiviewProperties;
+ } else {
+ physicalDeviceProperties.pNext = &subgroupProperties;
+ }
+
+ device_properties_func(gpu, &physicalDeviceProperties);
subgroup_capabilities.size = subgroupProperties.subgroupSize;
subgroup_capabilities.supportedStages = subgroupProperties.supportedStages;
@@ -519,18 +567,30 @@ Error VulkanContext::_check_capabilities() {
// - supportedOperations has VK_SUBGROUP_FEATURE_QUAD_BIT
subgroup_capabilities.quadOperationsInAllStages = subgroupProperties.quadOperationsInAllStages;
- // only output this when debugging?
- print_line("- Vulkan subgroup size " + itos(subgroup_capabilities.size));
- print_line("- Vulkan subgroup stages " + subgroup_capabilities.supported_stages_desc());
- print_line("- Vulkan subgroup supported ops " + subgroup_capabilities.supported_operations_desc());
+ if (multiview_capabilities.is_supported) {
+ multiview_capabilities.max_view_count = multiviewProperties.maxMultiviewViewCount;
+ multiview_capabilities.max_instance_count = multiviewProperties.maxMultiviewInstanceIndex;
+
+#ifdef DEBUG_ENABLED
+ print_line("- Vulkan multiview supported:");
+ print_line(" max views: " + itos(multiview_capabilities.max_view_count));
+ print_line(" max instances: " + itos(multiview_capabilities.max_instance_count));
+ } else {
+ print_line("- Vulkan multiview not supported");
+#endif
+ }
+
+#ifdef DEBUG_ENABLED
+ print_line("- Vulkan subgroup:");
+ print_line(" size: " + itos(subgroup_capabilities.size));
+ print_line(" stages: " + subgroup_capabilities.supported_stages_desc());
+ print_line(" supported ops: " + subgroup_capabilities.supported_operations_desc());
if (subgroup_capabilities.quadOperationsInAllStages) {
- print_line("- Vulkan subgroup quad operations in all stages");
+ print_line(" quad operations in all stages");
}
} else {
- subgroup_capabilities.size = 0;
- subgroup_capabilities.supportedStages = 0;
- subgroup_capabilities.supportedOperations = 0;
- subgroup_capabilities.quadOperationsInAllStages = false;
+ print_line("- Couldn't call vkGetPhysicalDeviceProperties2");
+#endif
}
return OK;
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 88e4f26bb1..3d9b295c5a 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -54,6 +54,12 @@ public:
String supported_operations_desc() const;
};
+ struct MultiviewCapabilities {
+ bool is_supported;
+ int32_t max_view_count;
+ int32_t max_instance_count;
+ };
+
private:
enum {
MAX_EXTENSIONS = 128,
@@ -75,6 +81,7 @@ private:
uint32_t vulkan_major = 1;
uint32_t vulkan_minor = 0;
SubgroupCapabilities subgroup_capabilities;
+ MultiviewCapabilities multiview_capabilities;
String device_vendor;
String device_name;
@@ -227,6 +234,7 @@ public:
uint32_t get_vulkan_major() const { return vulkan_major; };
uint32_t get_vulkan_minor() const { return vulkan_minor; };
SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
+ MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
VkDevice get_device();
VkPhysicalDevice get_physical_device();
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index ab8ae71904..67b52bf0ca 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -762,7 +762,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, time, new_point);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, time);
undo_redo->commit_action();
//then attempt to move
@@ -857,7 +857,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, newtime);
AnimMoveRestore amr;
amr.key = animation->track_get_key_value(track, idx);
@@ -888,7 +888,7 @@ void AnimationBezierTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
if (newpos<0)
continue; //no remove what no inserted
*/
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, newpos);
}
// 5-(undo) reinsert keys
@@ -1038,7 +1038,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, time, new_point);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, time);
undo_redo->commit_action();
} break;
@@ -1074,7 +1074,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
int existing_idx = animation->track_find_key(track, dst_time, true);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, dst_time, animation->track_get_key_value(track, E->get()), animation->track_get_key_transition(track, E->get()));
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, dst_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, dst_time);
Pair<int, float> p;
p.first = track;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 9db2f0a287..89f77f3c77 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -134,7 +134,7 @@ public:
undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, new_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
@@ -758,7 +758,7 @@ public:
undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, new_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
@@ -3979,7 +3979,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
p_next_tracks.normal++;
} else {
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_id.track_idx, time);
int existing = animation->track_find_key(p_id.track_idx, time, true);
if (existing != -1) {
Variant v = animation->track_get_key_value(p_id.track_idx, existing);
@@ -4568,7 +4568,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Transform Track Key"));
undo_redo->add_do_method(animation.ptr(), "transform_track_insert_key", p_track, p_ofs, loc, rot, scale);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
@@ -4580,7 +4580,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, value);
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
@@ -4611,7 +4611,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
@@ -4623,7 +4623,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, ak);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
case Animation::TYPE_ANIMATION: {
@@ -4631,7 +4631,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
undo_redo->create_action(TTR("Add Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, anim);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs);
undo_redo->commit_action();
} break;
}
@@ -4669,7 +4669,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
undo_redo->create_action(TTR("Add Method Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
undo_redo->commit_action();
return;
@@ -4879,7 +4879,7 @@ void AnimationTrackEditor::_move_selection_commit() {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime);
_AnimMoveRestore amr;
amr.key = animation->track_get_key_value(E->key().track, idx);
@@ -4899,7 +4899,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 4 - (undo) remove inserted keys
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = snap_time(E->get().pos + motion);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}
// 5 - (undo) reinsert keys
@@ -5096,7 +5096,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
int existing_idx = animation->track_find_key(dst_track, dst_time, true);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", dst_track, dst_time);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", dst_track, dst_time);
Pair<int, float> p;
p.first = dst_track;
@@ -5344,7 +5344,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
continue; //already in selection, don't save
}
- undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newtime);
+ undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime);
_AnimMoveRestore amr;
amr.key = animation->track_get_key_value(E->key().track, idx);
@@ -5365,7 +5365,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
// 4-(undo) remove inserted keys
for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = _NEW_POS(E->get().pos);
- undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newpos);
+ undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}
// 5-(undo) reinsert keys
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 506a327ffc..ae79299331 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -1024,7 +1024,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
get_undo_redo()->create_action(TTR("Add Audio Track Clip"));
get_undo_redo()->add_do_method(get_animation().ptr(), "audio_track_insert_key", get_track(), ofs, stream);
- get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_position", get_track(), ofs);
+ get_undo_redo()->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);
get_undo_redo()->commit_action();
update();
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 711072f4b2..1c0a55e4ec 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -708,7 +708,6 @@ CreateDialog::CreateDialog() {
search_hb->add_child(search_box);
favorite = memnew(Button);
- favorite->set_flat(true);
favorite->set_toggle_mode(true);
favorite->set_tooltip(TTR("(Un)favorite selected item."));
favorite->connect("pressed", callable_mp(this, &CreateDialog::_favorite_toggled));
diff --git a/editor/debugger/editor_debugger_server.cpp b/editor/debugger/editor_debugger_server.cpp
index 4add891bcb..662f247062 100644
--- a/editor/debugger/editor_debugger_server.cpp
+++ b/editor/debugger/editor_debugger_server.cpp
@@ -40,7 +40,7 @@
class EditorDebuggerServerTCP : public EditorDebuggerServer {
private:
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
public:
static EditorDebuggerServer *create(const String &p_protocol);
diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp
index d962658484..7527514dca 100644
--- a/editor/editor_about.cpp
+++ b/editor/editor_about.cpp
@@ -37,6 +37,9 @@
#include "core/version.h"
#include "core/version_hash.gen.h"
+// The metadata key used to store and retrieve the version text to copy to the clipboard.
+static const String META_TEXT_TO_COPY = "text_to_copy";
+
void EditorAbout::_theme_changed() {
const Ref<Font> font = get_theme_font("source", "EditorFonts");
const int font_size = get_theme_font_size("source_size", "EditorFonts");
@@ -63,7 +66,12 @@ void EditorAbout::_license_tree_selected() {
_tpl_text->set_text(selected->get_metadata(0));
}
+void EditorAbout::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
+}
+
void EditorAbout::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_version_button_pressed"), &EditorAbout::_version_button_pressed);
}
TextureRect *EditorAbout::get_logo() const {
@@ -124,17 +132,32 @@ EditorAbout::EditorAbout() {
_logo = memnew(TextureRect);
hbc->add_child(_logo);
+ VBoxContainer *version_info_vbc = memnew(VBoxContainer);
+
+ // Add a dummy control node for spacing.
+ Control *v_spacer = memnew(Control);
+ version_info_vbc->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
String hash = String(VERSION_HASH);
if (hash.length() != 0) {
hash = "." + hash.left(9);
}
+ version_btn->set_text(VERSION_FULL_NAME + hash);
+ // Set the text to copy in metadata as it slightly differs from the button's text.
+ version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash);
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &EditorAbout::_version_button_pressed));
+ version_info_vbc->add_child(version_btn);
Label *about_text = memnew(Label);
about_text->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
- about_text->set_text(VERSION_FULL_NAME + hash +
- String::utf8("\n\xc2\xa9 2007-2021 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2021 ") +
+ about_text->set_text(String::utf8("\xc2\xa9 2007-2021 Juan Linietsky, Ariel Manzur.\n\xc2\xa9 2014-2021 ") +
TTR("Godot Engine contributors") + "\n");
- hbc->add_child(about_text);
+ version_info_vbc->add_child(about_text);
+
+ hbc->add_child(version_info_vbc);
TabContainer *tc = memnew(TabContainer);
tc->set_custom_minimum_size(Size2(950, 400) * EDSCALE);
diff --git a/editor/editor_about.h b/editor/editor_about.h
index 2823220a8a..b76a2ada34 100644
--- a/editor/editor_about.h
+++ b/editor/editor_about.h
@@ -34,6 +34,7 @@
#include "scene/gui/control.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/item_list.h"
+#include "scene/gui/link_button.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/scroll_container.h"
#include "scene/gui/separator.h"
@@ -53,8 +54,10 @@ class EditorAbout : public AcceptDialog {
private:
void _license_tree_selected();
+ void _version_button_pressed();
ScrollContainer *_populate_list(const String &p_name, const List<String> &p_sections, const char *const *const p_src[], const int p_flag_single_column = 0);
+ LinkButton *version_btn;
Tree *_tpl_tree;
RichTextLabel *_license_text;
RichTextLabel *_tpl_text;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index fa4703d425..6405af3876 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -426,6 +426,18 @@ UndoRedo &EditorData::get_undo_redo() {
return undo_redo;
}
+void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) {
+ undo_redo_callbacks.push_back(p_callable);
+}
+
+void EditorData::remove_undo_redo_inspector_hook_callback(Callable p_callable) {
+ undo_redo_callbacks.erase(p_callable);
+}
+
+const Vector<Callable> EditorData::get_undo_redo_inspector_hook_callback() {
+ return undo_redo_callbacks;
+}
+
void EditorData::remove_editor_plugin(EditorPlugin *p_plugin) {
p_plugin->undo_redo = nullptr;
editor_plugins.erase(p_plugin);
diff --git a/editor/editor_data.h b/editor/editor_data.h
index dbe729d9d9..2ece94d6a3 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -132,6 +132,7 @@ private:
List<PropertyData> clipboard;
UndoRedo undo_redo;
+ Vector<Callable> undo_redo_callbacks;
void _cleanup_history();
@@ -166,6 +167,9 @@ public:
EditorPlugin *get_editor_plugin(int p_idx);
UndoRedo &get_undo_redo();
+ void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks shoud have 4 args: (Object* undo_redo, Object *modified_object, String property, Varian new_value)
+ void remove_undo_redo_inspector_hook_callback(Callable p_callable);
+ const Vector<Callable> get_undo_redo_inspector_hook_callback();
void save_editor_global_states();
void restore_editor_global_states();
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 738b2f9f82..5bb3c8b4d0 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -2266,6 +2266,22 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
undo_redo->add_do_property(object, p_name, p_value);
undo_redo->add_undo_property(object, p_name, object->get(p_name));
+ Variant v_undo_redo = (Object *)undo_redo;
+ Variant v_object = object;
+ Variant v_name = p_name;
+ for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback().size(); i++) {
+ const Callable &callback = EditorNode::get_singleton()->get_editor_data().get_undo_redo_inspector_hook_callback()[i];
+
+ const Variant *p_arguments[] = { &v_undo_redo, &v_object, &v_name, &p_value };
+ Variant return_value;
+ Callable::CallError call_error;
+
+ callback.call(p_arguments, 4, return_value, call_error);
+ if (call_error.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT("Invalid UndoRedo callback.");
+ }
+ }
+
if (p_refresh_all) {
undo_redo->add_do_method(this, "_edit_request_change", object, "");
undo_redo->add_undo_method(this, "_edit_request_change", object, "");
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 7b94016fb6..602035634a 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -63,6 +63,18 @@ void EditorLog::_notification(int p_what) {
log->add_theme_font_override("normal_font", get_theme_font("output_source", "EditorFonts"));
log->add_theme_font_size_override("normal_font_size", get_theme_font_size("output_source_size", "EditorFonts"));
log->add_theme_color_override("selection_color", get_theme_color("accent_color", "Editor") * Color(1, 1, 1, 0.4));
+ log->add_theme_font_override("bold_font", get_theme_font("bold", "EditorFonts"));
+
+ type_filter_map[MSG_TYPE_STD]->toggle_button->set_icon(get_theme_icon("Popup", "EditorIcons"));
+ type_filter_map[MSG_TYPE_ERROR]->toggle_button->set_icon(get_theme_icon("StatusError", "EditorIcons"));
+ type_filter_map[MSG_TYPE_WARNING]->toggle_button->set_icon(get_theme_icon("StatusWarning", "EditorIcons"));
+ type_filter_map[MSG_TYPE_EDITOR]->toggle_button->set_icon(get_theme_icon("Edit", "EditorIcons"));
+
+ clear_button->set_icon(get_theme_icon("Clear", "EditorIcons"));
+ copy_button->set_icon(get_theme_icon("ActionCopy", "EditorIcons"));
+ collapse_button->set_icon(get_theme_icon("CombineLines", "EditorIcons"));
+ show_search_button->set_icon(get_theme_icon("Search", "EditorIcons"));
+
} else if (p_what == NOTIFICATION_THEME_CHANGED) {
Ref<Font> df_output_code = get_theme_font("output_source", "EditorFonts");
if (df_output_code.is_valid()) {
@@ -75,8 +87,15 @@ void EditorLog::_notification(int p_what) {
}
}
+void EditorLog::_set_collapse(bool p_collapse) {
+ collapse = p_collapse;
+ _rebuild_log();
+}
+
void EditorLog::_clear_request() {
log->clear();
+ messages.clear();
+ _reset_message_counts();
tool_button->set_icon(Ref<Texture2D>());
}
@@ -96,13 +115,81 @@ void EditorLog::clear() {
_clear_request();
}
-void EditorLog::copy() {
- _copy_request();
+void EditorLog::_process_message(const String &p_msg, MessageType p_type) {
+ if (messages.size() > 0 && messages[messages.size() - 1].text == p_msg) {
+ // If previous message is the same as the new one, increase previous count rather than adding another
+ // instance to the messages list.
+ LogMessage &previous = messages.write[messages.size() - 1];
+ previous.count++;
+
+ _add_log_line(previous, collapse);
+ } else {
+ // Different message to the previous one received.
+ LogMessage message(p_msg, p_type);
+ _add_log_line(message);
+ messages.push_back(message);
+ }
+
+ type_filter_map[p_type]->set_message_count(type_filter_map[p_type]->get_message_count() + 1);
}
void EditorLog::add_message(const String &p_msg, MessageType p_type) {
- bool restore = p_type != MSG_TYPE_STD;
- switch (p_type) {
+ // Make text split by new lines their own message.
+ // See #41321 for reasoning. At time of writing, multiple print()'s in running projects
+ // get grouped together and sent to the editor log as one message. This can mess with the
+ // search functionality (see the comments on the PR above for more details). This behaviour
+ // also matches that of other IDE's.
+ Vector<String> lines = p_msg.split("\n", false);
+
+ for (int i = 0; i < lines.size(); i++) {
+ _process_message(lines[i], p_type);
+ }
+}
+
+void EditorLog::set_tool_button(Button *p_tool_button) {
+ tool_button = p_tool_button;
+}
+
+void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) {
+ EditorLog *self = (EditorLog *)p_self;
+ self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
+}
+
+void EditorLog::_rebuild_log() {
+ log->clear();
+
+ for (int msg_idx = 0; msg_idx < messages.size(); msg_idx++) {
+ LogMessage msg = messages[msg_idx];
+
+ if (collapse) {
+ // If collapsing, only log one instance of the message.
+ _add_log_line(msg);
+ } else {
+ // If not collapsing, log each instance on a line.
+ for (int i = 0; i < msg.count; i++) {
+ _add_log_line(msg);
+ }
+ }
+ }
+}
+
+void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) {
+ // Only add the message to the log if it passes the filters.
+ bool filter_active = type_filter_map[p_message.type]->active;
+ String search_text = search_box->get_text();
+ bool search_match = search_text == String() || p_message.text.findn(search_text) > -1;
+
+ if (!filter_active || !search_match) {
+ return;
+ }
+
+ if (p_replace_previous) {
+ // Remove last line if replacing, as it will be replace by the next added line.
+ log->remove_line(log->get_line_count() - 1);
+ log->increment_line_count();
+ }
+
+ switch (p_message.type) {
case MSG_TYPE_STD: {
} break;
case MSG_TYPE_ERROR: {
@@ -125,21 +212,43 @@ void EditorLog::add_message(const String &p_msg, MessageType p_type) {
} break;
}
- log->add_text(p_msg);
+ // If collapsing, add the count of this message in bold at the start of the line.
+ if (collapse && p_message.count > 1) {
+ log->push_bold();
+ log->add_text(vformat("(%s) ", itos(p_message.count)));
+ log->pop();
+ }
+
+ log->add_text(p_message.text);
log->add_newline();
- if (restore) {
+ // Need to use pop() to exit out of the RichTextLabels current "push" stack.
+ // We only "push" in the above switch when message type != STD, so only pop when that is the case.
+ if (p_message.type != MSG_TYPE_STD) {
log->pop();
}
}
-void EditorLog::set_tool_button(Button *p_tool_button) {
- tool_button = p_tool_button;
+void EditorLog::_set_filter_active(bool p_active, MessageType p_message_type) {
+ type_filter_map[p_message_type]->active = p_active;
+ _rebuild_log();
}
-void EditorLog::_undo_redo_cbk(void *p_self, const String &p_name) {
- EditorLog *self = (EditorLog *)p_self;
- self->add_message(p_name, EditorLog::MSG_TYPE_EDITOR);
+void EditorLog::_set_search_visible(bool p_visible) {
+ search_box->set_visible(p_visible);
+ if (p_visible) {
+ search_box->grab_focus();
+ }
+}
+
+void EditorLog::_search_changed(const String &p_text) {
+ _rebuild_log();
+}
+
+void EditorLog::_reset_message_counts() {
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ E->value()->set_message_count(0);
+ }
}
void EditorLog::_bind_methods() {
@@ -148,37 +257,108 @@ void EditorLog::_bind_methods() {
}
EditorLog::EditorLog() {
- VBoxContainer *vb = this;
-
- HBoxContainer *hb = memnew(HBoxContainer);
- vb->add_child(hb);
- title = memnew(Label);
- title->set_text(TTR("Output:"));
- title->set_h_size_flags(SIZE_EXPAND_FILL);
- hb->add_child(title);
-
- copybutton = memnew(Button);
- hb->add_child(copybutton);
- copybutton->set_text(TTR("Copy"));
- copybutton->set_shortcut(ED_SHORTCUT("editor/copy_output", TTR("Copy Selection"), KEY_MASK_CMD | KEY_C));
- copybutton->set_shortcut_context(this);
- copybutton->connect("pressed", callable_mp(this, &EditorLog::_copy_request));
-
- clearbutton = memnew(Button);
- hb->add_child(clearbutton);
- clearbutton->set_text(TTR("Clear"));
- clearbutton->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K));
- clearbutton->set_shortcut_context(this);
- clearbutton->connect("pressed", callable_mp(this, &EditorLog::_clear_request));
+ HBoxContainer *hb = this;
+
+ VBoxContainer *vb_left = memnew(VBoxContainer);
+ vb_left->set_custom_minimum_size(Size2(0, 180) * EDSCALE);
+ vb_left->set_v_size_flags(SIZE_EXPAND_FILL);
+ vb_left->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->add_child(vb_left);
+ // Log - Rich Text Label.
log = memnew(RichTextLabel);
log->set_scroll_follow(true);
log->set_selection_enabled(true);
log->set_focus_mode(FOCUS_CLICK);
- log->set_custom_minimum_size(Size2(0, 180) * EDSCALE);
log->set_v_size_flags(SIZE_EXPAND_FILL);
log->set_h_size_flags(SIZE_EXPAND_FILL);
- vb->add_child(log);
+ vb_left->add_child(log);
+
+ // Search box
+ search_box = memnew(LineEdit);
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_box->set_placeholder(TTR("Filter messages"));
+ search_box->set_right_icon(get_theme_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ search_box->set_visible(true);
+ search_box->connect("text_changed", callable_mp(this, &EditorLog::_search_changed));
+ vb_left->add_child(search_box);
+
+ VBoxContainer *vb_right = memnew(VBoxContainer);
+ hb->add_child(vb_right);
+
+ // Tools grid
+ HBoxContainer *hb_tools = memnew(HBoxContainer);
+ hb_tools->set_h_size_flags(SIZE_SHRINK_CENTER);
+ vb_right->add_child(hb_tools);
+
+ // Clear.
+ clear_button = memnew(Button);
+ clear_button->set_flat(true);
+ clear_button->set_focus_mode(FOCUS_NONE);
+ clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_K));
+ clear_button->set_shortcut_context(this);
+ clear_button->connect("pressed", callable_mp(this, &EditorLog::_clear_request));
+ hb_tools->add_child(clear_button);
+
+ // Copy.
+ copy_button = memnew(Button);
+ copy_button->set_flat(true);
+ copy_button->set_focus_mode(FOCUS_NONE);
+ copy_button->set_shortcut(ED_SHORTCUT("editor/copy_output", TTR("Copy Selection"), KEY_MASK_CMD | KEY_C));
+ copy_button->set_shortcut_context(this);
+ copy_button->connect("pressed", callable_mp(this, &EditorLog::_copy_request));
+ hb_tools->add_child(copy_button);
+
+ // A second hbox to make a 2x2 grid of buttons.
+ HBoxContainer *hb_tools2 = memnew(HBoxContainer);
+ hb_tools2->set_h_size_flags(SIZE_SHRINK_CENTER);
+ vb_right->add_child(hb_tools2);
+
+ // Collapse.
+ collapse_button = memnew(Button);
+ collapse_button->set_flat(true);
+ collapse_button->set_focus_mode(FOCUS_NONE);
+ collapse_button->set_tooltip(TTR("Collapse duplicate messages into one log entry. Shows number of occurences."));
+ collapse_button->set_toggle_mode(true);
+ collapse_button->set_pressed(false);
+ collapse_button->connect("toggled", callable_mp(this, &EditorLog::_set_collapse));
+ hb_tools2->add_child(collapse_button);
+
+ // Show Search.
+ show_search_button = memnew(Button);
+ show_search_button->set_flat(true);
+ show_search_button->set_focus_mode(FOCUS_NONE);
+ show_search_button->set_toggle_mode(true);
+ show_search_button->set_pressed(true);
+ show_search_button->set_shortcut(ED_SHORTCUT("editor/open_search", TTR("Open the search box."), KEY_MASK_CMD | KEY_F));
+ show_search_button->set_shortcut_context(this);
+ show_search_button->connect("toggled", callable_mp(this, &EditorLog::_set_search_visible));
+ hb_tools2->add_child(show_search_button);
+
+ // Message Type Filters.
+ vb_right->add_child(memnew(HSeparator));
+
+ LogFilter *std_filter = memnew(LogFilter(MSG_TYPE_STD));
+ std_filter->initialize_button("Toggle visibility of standard output messages.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(std_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_STD, std_filter);
+
+ LogFilter *error_filter = memnew(LogFilter(MSG_TYPE_ERROR));
+ error_filter->initialize_button("Toggle visibility of errors.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(error_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_ERROR, error_filter);
+
+ LogFilter *warning_filter = memnew(LogFilter(MSG_TYPE_WARNING));
+ warning_filter->initialize_button("Toggle visibility of warnings.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(warning_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_WARNING, warning_filter);
+
+ LogFilter *editor_filter = memnew(LogFilter(MSG_TYPE_EDITOR));
+ editor_filter->initialize_button("Toggle visibility of editor messages.", callable_mp(this, &EditorLog::_set_filter_active));
+ vb_right->add_child(editor_filter->toggle_button);
+ type_filter_map.insert(MSG_TYPE_EDITOR, editor_filter);
+
add_message(VERSION_FULL_NAME " (c) 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors.");
eh.errfunc = _error_handler;
@@ -187,8 +367,6 @@ EditorLog::EditorLog() {
current = Thread::get_caller_id();
- add_theme_constant_override("separation", get_theme_constant("separation", "VBoxContainer"));
-
EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk, this);
}
@@ -197,4 +375,7 @@ void EditorLog::deinit() {
}
EditorLog::~EditorLog() {
+ for (Map<MessageType, LogFilter *>::Element *E = type_filter_map.front(); E; E = E->next()) {
+ memdelete(E->get());
+ }
}
diff --git a/editor/editor_log.h b/editor/editor_log.h
index 79dfb3ffaa..89d00d0fa0 100644
--- a/editor/editor_log.h
+++ b/editor/editor_log.h
@@ -36,19 +36,92 @@
#include "scene/gui/button.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
#include "scene/gui/panel_container.h"
#include "scene/gui/rich_text_label.h"
#include "scene/gui/texture_button.h"
#include "scene/gui/texture_rect.h"
-class EditorLog : public VBoxContainer {
- GDCLASS(EditorLog, VBoxContainer);
+class EditorLog : public HBoxContainer {
+ GDCLASS(EditorLog, HBoxContainer);
+
+public:
+ enum MessageType {
+ MSG_TYPE_STD,
+ MSG_TYPE_ERROR,
+ MSG_TYPE_WARNING,
+ MSG_TYPE_EDITOR,
+ };
+
+private:
+ struct LogMessage {
+ String text;
+ MessageType type;
+ int count = 1;
+
+ LogMessage() {}
+
+ LogMessage(const String p_text, MessageType p_type) :
+ text(p_text),
+ type(p_type) {
+ }
+ };
+
+ // Encapsulates all data and functionality regarding filters.
+ struct LogFilter {
+ private:
+ // Force usage of set method since it has functionality built-in.
+ int message_count = 0;
+
+ public:
+ MessageType type;
+ Button *toggle_button = nullptr;
+ bool active = true;
+
+ void initialize_button(const String &p_tooltip, Callable p_toggled_callback) {
+ toggle_button = memnew(Button);
+ toggle_button->set_toggle_mode(true);
+ toggle_button->set_pressed(true);
+ toggle_button->set_text(itos(message_count));
+ toggle_button->set_tooltip(TTR(p_tooltip));
+ // Don't tint the icon even when in "pressed" state.
+ toggle_button->add_theme_color_override("icon_color_pressed", Color(1, 1, 1, 1));
+ toggle_button->set_focus_mode(FOCUS_NONE);
+ // When toggled call the callback and pass the MessageType this button is for.
+ toggle_button->connect("toggled", p_toggled_callback, varray(type));
+ }
+
+ int get_message_count() {
+ return message_count;
+ }
+
+ void set_message_count(int p_count) {
+ message_count = p_count;
+ toggle_button->set_text(itos(message_count));
+ }
+
+ LogFilter(MessageType p_type) :
+ type(p_type) {
+ }
+ };
+
+ Vector<LogMessage> messages;
+ // Maps MessageTypes to LogFilters for convenient access and storage (don't need 1 member per filter).
+ Map<MessageType, LogFilter *> type_filter_map;
- Button *clearbutton;
- Button *copybutton;
- Label *title;
RichTextLabel *log;
- HBoxContainer *title_hb;
+
+ Button *clear_button;
+ Button *copy_button;
+
+ Button *collapse_button;
+ bool collapse = false;
+
+ Button *show_search_button;
+ LineEdit *search_box;
+
+ // Reference to the "Output" button on the toolbar so we can update it's icon when
+ // Warnings or Errors are encounetered.
Button *tool_button;
static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, ErrorHandlerType p_type);
@@ -62,26 +135,33 @@ class EditorLog : public VBoxContainer {
void _copy_request();
static void _undo_redo_cbk(void *p_self, const String &p_name);
+ void _rebuild_log();
+ void _add_log_line(LogMessage &p_message, bool p_replace_previous = false);
+
+ void _set_filter_active(bool p_active, MessageType p_message_type);
+ void _set_search_visible(bool p_visible);
+ void _search_changed(const String &p_text);
+
+ void _process_message(const String &p_msg, MessageType p_type);
+ void _reset_message_counts();
+
+ void _set_collapse(bool p_collapse);
+
protected:
static void _bind_methods();
void _notification(int p_what);
public:
- enum MessageType {
- MSG_TYPE_STD,
- MSG_TYPE_ERROR,
- MSG_TYPE_WARNING,
- MSG_TYPE_EDITOR
- };
-
void add_message(const String &p_msg, MessageType p_type = MSG_TYPE_STD);
void set_tool_button(Button *p_tool_button);
void deinit();
void clear();
- void copy();
+
EditorLog();
~EditorLog();
};
+VARIANT_ENUM_CAST(EditorLog::MessageType);
+
#endif // EDITOR_LOG_H
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6137617564..ed670b1296 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -46,11 +46,13 @@
#include "core/string/print_string.h"
#include "core/string/translation.h"
#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "main/main.h"
#include "scene/gui/center_container.h"
#include "scene/gui/control.h"
#include "scene/gui/dialogs.h"
#include "scene/gui/file_dialog.h"
+#include "scene/gui/link_button.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
@@ -184,6 +186,9 @@
EditorNode *EditorNode::singleton = nullptr;
+// The metadata key used to store and retrieve the version text to copy to the clipboard.
+static const String META_TEXT_TO_COPY = "text_to_copy";
+
void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames) {
// Keep track of a list of "index sets," i.e. sets of indices
// within disambiguated_scene_names which contain the same name.
@@ -989,6 +994,10 @@ void EditorNode::_reload_project_settings() {
void EditorNode::_vp_resized() {
}
+void EditorNode::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_meta(META_TEXT_TO_COPY));
+}
+
void EditorNode::_node_renamed() {
if (get_inspector()) {
get_inspector()->update_tree();
@@ -1399,8 +1408,9 @@ void EditorNode::_save_scene_with_preview(String p_file, int p_idx) {
} else {
// The 3D editor may be disabled as a feature, but scenes can still be opened.
// This check prevents the preview from regenerating in case those scenes are then saved.
+ // The preview will be generated if no feature profile is set (as the 3D editor is enabled by default).
Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile();
- if (profile.is_valid() && !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
+ if (!profile.is_valid() || !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)) {
img = Node3DEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_texture()->get_image();
}
}
@@ -4855,7 +4865,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
_scene_tab_closed(scene_tabs->get_hovered_tab());
}
} else {
- if ((mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_doubleclick()) || (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed())) {
+ if ((mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_double_click()) || (mb->get_button_index() == MOUSE_BUTTON_MIDDLE && mb->is_pressed())) {
_menu_option_confirm(FILE_NEW_SCENE, true);
}
}
@@ -5559,6 +5569,8 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_screenshot", &EditorNode::_screenshot);
ClassDB::bind_method("_save_screenshot", &EditorNode::_save_screenshot);
+ ClassDB::bind_method("_version_button_pressed", &EditorNode::_version_button_pressed);
+
ADD_SIGNAL(MethodInfo("play_pressed"));
ADD_SIGNAL(MethodInfo("pause_pressed"));
ADD_SIGNAL(MethodInfo("stop_pressed"));
@@ -6479,7 +6491,6 @@ EditorNode::EditorNode() {
// Toggle for video driver
video_driver = memnew(OptionButton);
- video_driver->set_flat(true);
video_driver->set_focus_mode(Control::FOCUS_NONE);
video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected));
video_driver->add_theme_font_override("font", gui_base->get_theme_font("bold", "EditorFonts"));
@@ -6617,11 +6628,31 @@ EditorNode::EditorNode() {
bottom_panel_hb_editors->set_h_size_flags(Control::SIZE_EXPAND_FILL);
bottom_panel_hb->add_child(bottom_panel_hb_editors);
- version_label = memnew(Label);
- version_label->set_text(VERSION_FULL_CONFIG);
+ VBoxContainer *version_info_vbc = memnew(VBoxContainer);
+ bottom_panel_hb->add_child(version_info_vbc);
+
+ // Add a dummy control node for vertical spacing.
+ Control *v_spacer = memnew(Control);
+ version_info_vbc->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
+ version_btn->set_text(VERSION_FULL_CONFIG);
+ String hash = String(VERSION_HASH);
+ if (hash.length() != 0) {
+ hash = "." + hash.left(9);
+ }
+ // Set the text to copy in metadata as it slightly differs from the button's text.
+ version_btn->set_meta(META_TEXT_TO_COPY, "v" VERSION_FULL_BUILD + hash);
// Fade out the version label to be less prominent, but still readable
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- bottom_panel_hb->add_child(version_label);
+ version_btn->set_self_modulate(Color(1, 1, 1, 0.65));
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &EditorNode::_version_button_pressed));
+ version_info_vbc->add_child(version_btn);
+
+ // Add a dummy control node for horizontal spacing.
+ Control *h_spacer = memnew(Control);
+ bottom_panel_hb->add_child(h_spacer);
bottom_panel_raise = memnew(Button);
bottom_panel_raise->set_flat(true);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 7e16936f5d..d06851cb4f 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -40,6 +40,7 @@
#include "editor/inspector_dock.h"
#include "editor/property_editor.h"
#include "editor/scene_tree_dock.h"
+#include "scene/gui/link_button.h"
typedef void (*EditorNodeInitCallback)();
typedef void (*EditorPluginInitializeCallback)();
@@ -424,7 +425,7 @@ private:
HBoxContainer *bottom_panel_hb;
HBoxContainer *bottom_panel_hb_editors;
VBoxContainer *bottom_panel_vb;
- Label *version_label;
+ LinkButton *version_btn;
Button *bottom_panel_raise;
Tree *disk_changed_list;
@@ -477,6 +478,7 @@ private:
void _close_messages();
void _show_messages();
void _vp_resized();
+ void _version_button_pressed();
int _save_external_resources();
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index eabcbacd9a..6b96cb0f5c 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -703,6 +703,14 @@ bool EditorPlugin::get_remove_list(List<Node *> *p_list) {
void EditorPlugin::restore_global_state() {}
void EditorPlugin::save_global_state() {}
+void EditorPlugin::add_undo_redo_inspector_hook_callback(Callable p_callable) {
+ EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(p_callable);
+}
+
+void EditorPlugin::remove_undo_redo_inspector_hook_callback(Callable p_callable) {
+ EditorNode::get_singleton()->get_editor_data().remove_undo_redo_inspector_hook_callback(p_callable);
+}
+
void EditorPlugin::add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser) {
EditorTranslationParser::get_singleton()->add_parser(p_parser, EditorTranslationParser::CUSTOM);
}
@@ -862,6 +870,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("hide_bottom_panel"), &EditorPlugin::hide_bottom_panel);
ClassDB::bind_method(D_METHOD("get_undo_redo"), &EditorPlugin::_get_undo_redo);
+ ClassDB::bind_method(D_METHOD("add_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::add_undo_redo_inspector_hook_callback);
+ ClassDB::bind_method(D_METHOD("remove_undo_redo_inspector_hook_callback", "callable"), &EditorPlugin::remove_undo_redo_inspector_hook_callback);
ClassDB::bind_method(D_METHOD("queue_save_layout"), &EditorPlugin::queue_save_layout);
ClassDB::bind_method(D_METHOD("add_translation_parser_plugin", "parser"), &EditorPlugin::add_translation_parser_plugin);
ClassDB::bind_method(D_METHOD("remove_translation_parser_plugin", "parser"), &EditorPlugin::remove_translation_parser_plugin);
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 67b163eabf..37412e5ebe 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -225,6 +225,9 @@ public:
EditorInterface *get_editor_interface();
ScriptCreateDialog *get_script_create_dialog();
+ void add_undo_redo_inspector_hook_callback(Callable p_callable);
+ void remove_undo_redo_inspector_hook_callback(Callable p_callable);
+
int update_overlays() const;
void queue_save_layout();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 652deb1804..47c0e31da6 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -929,7 +929,7 @@ EditorPropertyFloat::EditorPropertyFloat() {
void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) {
const Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid()) {
- if (mb->is_doubleclick() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (mb->is_double_click() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
_setup_spin();
}
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index de688f2709..fb2980c948 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -575,7 +575,6 @@ EditorPropertyArray::EditorPropertyArray() {
object.instance();
page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
edit = memnew(Button);
- edit->set_flat(true);
edit->set_h_size_flags(SIZE_EXPAND_FILL);
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
@@ -1070,7 +1069,6 @@ EditorPropertyDictionary::EditorPropertyDictionary() {
object.instance();
page_len = int(EDITOR_GET("interface/inspector/max_array_dictionary_items_per_page"));
edit = memnew(Button);
- edit->set_flat(true);
edit->set_h_size_flags(SIZE_EXPAND_FILL);
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_edit_pressed));
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 4ddae7c062..7e450ed5fc 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -437,7 +437,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Theme
_initial_set("interface/theme/preset", "Default");
- hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Alien,Arc,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT);
+ hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Breeze Dark,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/icon_and_font_color", 0);
hints["interface/theme/icon_and_font_color"] = PropertyInfo(Variant::INT, "interface/theme/icon_and_font_color", PROPERTY_HINT_ENUM, "Auto,Dark,Light", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/base_color", Color(0.2, 0.23, 0.31));
@@ -450,10 +450,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
hints["interface/theme/icon_saturation"] = PropertyInfo(Variant::FLOAT, "interface/theme/icon_saturation", PROPERTY_HINT_RANGE, "0,2,0.01", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/relationship_line_opacity", 0.1);
hints["interface/theme/relationship_line_opacity"] = PropertyInfo(Variant::FLOAT, "interface/theme/relationship_line_opacity", PROPERTY_HINT_RANGE, "0.00, 1, 0.01");
- _initial_set("interface/theme/highlight_tabs", false);
- _initial_set("interface/theme/border_size", 1);
- _initial_set("interface/theme/use_graph_node_headers", false);
+ _initial_set("interface/theme/border_size", 0);
hints["interface/theme/border_size"] = PropertyInfo(Variant::INT, "interface/theme/border_size", PROPERTY_HINT_RANGE, "0,2,1", PROPERTY_USAGE_DEFAULT);
+ _initial_set("interface/theme/corner_radius", 3);
+ hints["interface/theme/corner_radius"] = PropertyInfo(Variant::INT, "interface/theme/corner_radius", PROPERTY_HINT_RANGE, "0,6,1", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/additional_spacing", 0);
hints["interface/theme/additional_spacing"] = PropertyInfo(Variant::FLOAT, "interface/theme/additional_spacing", PROPERTY_HINT_RANGE, "0,5,0.1", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/theme/custom_theme", "");
@@ -1138,14 +1138,14 @@ void EditorSettings::setup_language() {
}
void EditorSettings::setup_network() {
- List<IP_Address> local_ip;
+ List<IPAddress> local_ip;
IP::get_singleton()->get_local_addresses(&local_ip);
String hint;
String current = has_setting("network/debug/remote_host") ? get("network/debug/remote_host") : "";
String selected = "127.0.0.1";
// Check that current remote_host is a valid interface address and populate hints.
- for (List<IP_Address>::Element *E = local_ip.front(); E; E = E->next()) {
+ for (List<IPAddress>::Element *E = local_ip.front(); E; E = E->next()) {
String ip = E->get();
// link-local IPv6 addresses don't work, skipping them
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 8577ccb9db..dba53a9708 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -70,7 +70,6 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) {
grabbing_spinner_dist_cache = 0;
pre_grab_value = get_value();
grabbing_spinner = false;
- grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position();
}
} else {
if (grabbing_spinner_attempt) {
@@ -283,6 +282,8 @@ void EditorSpinSlider::_notification(int p_what) {
Rect2 grabber_rect = Rect2(ofs + gofs, svofs + 1, grabber_w, 2 * EDSCALE);
draw_rect(grabber_rect, c);
+ grabbing_spinner_mouse_pos = get_global_position() + grabber_rect.position + grabber_rect.size * 0.5;
+
bool display_grabber = (mouse_over_spin || mouse_over_grabber) && !grabbing_spinner && !value_input_popup->is_visible();
if (grabber->is_visible() != display_grabber) {
if (display_grabber) {
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 7cc9ebd63e..44b4a9f688 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -65,9 +65,12 @@ static Ref<StyleBoxEmpty> make_empty_stylebox(float p_margin_left = -1, float p_
return style;
}
-static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) {
+static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, int p_corner_width = 0) {
Ref<StyleBoxFlat> style(memnew(StyleBoxFlat));
style->set_bg_color(p_color);
+ // Adjust level of detail based on the corners' effective sizes.
+ style->set_corner_detail(Math::ceil(1.5 * p_corner_width * EDSCALE));
+ style->set_corner_radius_all(p_corner_width);
style->set_default_margin(SIDE_LEFT, p_margin_left * EDSCALE);
style->set_default_margin(SIDE_RIGHT, p_margin_right * EDSCALE);
style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * EDSCALE);
@@ -286,9 +289,9 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<Theme> theme = Ref<Theme>(memnew(Theme));
- const float default_contrast = 0.25;
+ const float default_contrast = 0.3;
- //Theme settings
+ // Theme settings
Color accent_color = EDITOR_GET("interface/theme/accent_color");
Color base_color = EDITOR_GET("interface/theme/base_color");
float contrast = EDITOR_GET("interface/theme/contrast");
@@ -297,56 +300,47 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
String preset = EDITOR_GET("interface/theme/preset");
- bool highlight_tabs = EDITOR_GET("interface/theme/highlight_tabs");
int border_size = EDITOR_GET("interface/theme/border_size");
-
- bool use_gn_headers = EDITOR_GET("interface/theme/use_graph_node_headers");
+ int corner_radius = EDITOR_GET("interface/theme/corner_radius");
Color preset_accent_color;
Color preset_base_color;
float preset_contrast = 0;
- // Please, use alphabet order if you've added new theme here(After "Default" and "Custom")
+ // Please use alphabetical order if you're adding a new theme here
+ // (after "Custom")
- if (preset == "Default") {
- preset_accent_color = Color(0.41, 0.61, 0.91);
- preset_base_color = Color(0.2, 0.23, 0.31);
- preset_contrast = default_contrast;
- } else if (preset == "Custom") {
+ if (preset == "Custom") {
accent_color = EDITOR_GET("interface/theme/accent_color");
base_color = EDITOR_GET("interface/theme/base_color");
contrast = EDITOR_GET("interface/theme/contrast");
- } else if (preset == "Alien") {
- preset_accent_color = Color(0.11, 1.0, 0.6);
- preset_base_color = Color(0.18, 0.22, 0.25);
- preset_contrast = 0.25;
- } else if (preset == "Arc") {
- preset_accent_color = Color(0.32, 0.58, 0.89);
- preset_base_color = Color(0.22, 0.24, 0.29);
- preset_contrast = 0.25;
+ } else if (preset == "Breeze Dark") {
+ preset_accent_color = Color(0.26, 0.76, 1.00);
+ preset_base_color = Color(0.24, 0.26, 0.28);
+ preset_contrast = default_contrast;
} else if (preset == "Godot 2") {
preset_accent_color = Color(0.53, 0.67, 0.89);
preset_base_color = Color(0.24, 0.23, 0.27);
- preset_contrast = 0.25;
+ preset_contrast = default_contrast;
} else if (preset == "Grey") {
- preset_accent_color = Color(0.72, 0.89, 1.0);
+ preset_accent_color = Color(0.72, 0.89, 1.00);
preset_base_color = Color(0.24, 0.24, 0.24);
- preset_contrast = 0.2;
+ preset_contrast = default_contrast;
} else if (preset == "Light") {
- preset_accent_color = Color(0.13, 0.44, 1.0);
- preset_base_color = Color(1, 1, 1);
+ preset_accent_color = Color(0.18, 0.50, 1.00);
+ preset_base_color = Color(1.00, 1.00, 1.00);
preset_contrast = 0.08;
} else if (preset == "Solarized (Dark)") {
preset_accent_color = Color(0.15, 0.55, 0.82);
- preset_base_color = Color(0.03, 0.21, 0.26);
- preset_contrast = 0.23;
+ preset_base_color = Color(0.04, 0.23, 0.27);
+ preset_contrast = default_contrast;
} else if (preset == "Solarized (Light)") {
preset_accent_color = Color(0.15, 0.55, 0.82);
preset_base_color = Color(0.99, 0.96, 0.89);
- preset_contrast = 0.06;
+ preset_contrast = 0.08;
} else { // Default
- preset_accent_color = Color(0.41, 0.61, 0.91);
- preset_base_color = Color(0.2, 0.23, 0.31);
+ preset_accent_color = Color(0.44, 0.73, 0.98);
+ preset_base_color = Color(0.21, 0.24, 0.29);
preset_contrast = default_contrast;
}
@@ -358,12 +352,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
EditorSettings::get_singleton()->set_initial_value("interface/theme/base_color", base_color);
EditorSettings::get_singleton()->set_initial_value("interface/theme/contrast", contrast);
}
+
EditorSettings::get_singleton()->set_manually("interface/theme/preset", preset);
EditorSettings::get_singleton()->set_manually("interface/theme/accent_color", accent_color);
EditorSettings::get_singleton()->set_manually("interface/theme/base_color", base_color);
EditorSettings::get_singleton()->set_manually("interface/theme/contrast", contrast);
- //Colors
+ // Colors
bool dark_theme = EditorSettings::get_singleton()->is_dark_theme();
const Color dark_color_1 = base_color.lerp(Color(0, 0, 0, 1), contrast);
@@ -372,14 +367,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color background_color = dark_color_2;
- // white (dark theme) or black (light theme), will be used to generate the rest of the colors
+ // White (dark theme) or black (light theme), will be used to generate the rest of the colors
const Color mono_color = dark_theme ? Color(1, 1, 1) : Color(0, 0, 0);
const Color contrast_color_1 = base_color.lerp(mono_color, MAX(contrast, default_contrast));
const Color contrast_color_2 = base_color.lerp(mono_color, MAX(contrast * 1.5, default_contrast * 1.5));
const Color font_color = mono_color.lerp(base_color, 0.25);
- const Color font_hover_color = mono_color.lerp(base_color, 0.15);
+ const Color font_hover_color = mono_color.lerp(base_color, 0.125);
const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3);
const Color selection_color = accent_color * Color(1, 1, 1, 0.4);
const Color disabled_color = mono_color.inverted().lerp(base_color, 0.7);
@@ -393,8 +388,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
icon_pressed_color.a = 1.0;
const Color separator_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.1);
-
- const Color highlight_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.2);
+ const Color highlight_color = Color(accent_color.r, accent_color.g, accent_color.b, 0.275);
float prev_icon_saturation = theme->has_color("icon_saturation", "Editor") ? theme->get_color("icon_saturation", "Editor").r : 1.0;
@@ -447,35 +441,35 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("thumb_size", "Editor", thumb_size);
theme->set_constant("dark_theme", "Editor", dark_theme);
- //Register icons + font
+ // Register icons + font
- // the resolution and the icon color (dark_theme bool) has not changed, so we do not regenerate the icons
+ // The resolution and the icon color (dark_theme bool) has not changed, so we do not regenerate the icons.
if (p_theme != nullptr && fabs(p_theme->get_constant("scale", "Editor") - EDSCALE) < 0.00001 && (bool)p_theme->get_constant("dark_theme", "Editor") == dark_theme && prev_icon_saturation == icon_saturation) {
- // register already generated icons
+ // Register already generated icons.
for (int i = 0; i < editor_icons_count; i++) {
theme->set_icon(editor_icons_names[i], "EditorIcons", p_theme->get_icon(editor_icons_names[i], "EditorIcons"));
}
} else {
editor_register_and_generate_icons(theme, dark_theme, thumb_size, false, icon_saturation);
}
- // thumbnail size has changed, so we regenerate the medium sizes
+ // Thumbnail size has changed, so we regenerate the medium sizes
if (p_theme != nullptr && fabs((double)p_theme->get_constant("thumb_size", "Editor") - thumb_size) > 0.00001) {
editor_register_and_generate_icons(p_theme, dark_theme, thumb_size, true);
}
editor_register_fonts(theme);
- // Highlighted tabs and border width
- Color tab_color = highlight_tabs ? base_color.lerp(font_color, contrast) : base_color;
// Ensure borders are visible when using an editor scale below 100%.
- const int border_width = CLAMP(border_size, 0, 3) * MAX(1, EDSCALE);
-
+ const int border_width = CLAMP(border_size, 0, 2) * MAX(1, EDSCALE);
+ const int corner_width = CLAMP(corner_radius, 0, 6) * EDSCALE;
const int default_margin_size = 4;
- const int margin_size_extra = default_margin_size + CLAMP(border_size, 0, 3);
+ const int margin_size_extra = default_margin_size + CLAMP(border_size, 0, 2);
- // styleboxes
- // this is the most commonly used stylebox, variations should be made as duplicate of this
- Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size);
+ // Styleboxes
+ // This is the most commonly used stylebox, variations should be made as duplicate of this
+ Ref<StyleBoxFlat> style_default = make_flat_stylebox(base_color, default_margin_size, default_margin_size, default_margin_size, default_margin_size, corner_width);
+ // Work around issue about antialiased edges being blurrier (GH-35279).
+ style_default->set_anti_aliased(false);
style_default->set_border_width_all(border_width);
style_default->set_border_color(base_color);
style_default->set_draw_center(true);
@@ -483,11 +477,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Button and widgets
const float extra_spacing = EDITOR_GET("interface/theme/additional_spacing");
+ const Vector2 widget_default_margin = Vector2(extra_spacing + 6, extra_spacing + default_margin_size + 1) * EDSCALE;
+
Ref<StyleBoxFlat> style_widget = style_default->duplicate();
- style_widget->set_default_margin(SIDE_LEFT, (extra_spacing + 6) * EDSCALE);
- style_widget->set_default_margin(SIDE_TOP, (extra_spacing + default_margin_size) * EDSCALE);
- style_widget->set_default_margin(SIDE_RIGHT, (extra_spacing + 6) * EDSCALE);
- style_widget->set_default_margin(SIDE_BOTTOM, (extra_spacing + default_margin_size) * EDSCALE);
+ style_widget->set_default_margin(SIDE_LEFT, widget_default_margin.x);
+ style_widget->set_default_margin(SIDE_TOP, widget_default_margin.y);
+ style_widget->set_default_margin(SIDE_RIGHT, widget_default_margin.x);
+ style_widget->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
style_widget->set_bg_color(dark_color_1);
style_widget->set_border_color(dark_color_2);
@@ -496,69 +492,82 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
style_widget_disabled->set_bg_color(disabled_bg_color);
Ref<StyleBoxFlat> style_widget_focus = style_widget->duplicate();
+ style_widget_focus->set_draw_center(false);
+ style_widget_focus->set_border_width_all(Math::round(2 * MAX(1, EDSCALE)));
style_widget_focus->set_border_color(accent_color);
Ref<StyleBoxFlat> style_widget_pressed = style_widget->duplicate();
- style_widget_pressed->set_border_color(accent_color);
+ style_widget_pressed->set_bg_color(dark_color_1.darkened(0.125));
Ref<StyleBoxFlat> style_widget_hover = style_widget->duplicate();
- style_widget_hover->set_border_color(contrast_color_1);
+ style_widget_hover->set_bg_color(mono_color * Color(1, 1, 1, 0.11));
+ style_widget_hover->set_border_color(mono_color * Color(1, 1, 1, 0.05));
- // style for windows, popups, etc..
+ // Style for windows, popups, etc..
Ref<StyleBoxFlat> style_popup = style_default->duplicate();
- const int popup_margin_size = default_margin_size * EDSCALE * 2;
+ const int popup_margin_size = default_margin_size * EDSCALE * 3;
style_popup->set_default_margin(SIDE_LEFT, popup_margin_size);
style_popup->set_default_margin(SIDE_TOP, popup_margin_size);
style_popup->set_default_margin(SIDE_RIGHT, popup_margin_size);
style_popup->set_default_margin(SIDE_BOTTOM, popup_margin_size);
style_popup->set_border_color(contrast_color_1);
- style_popup->set_border_width_all(MAX(EDSCALE, border_width));
const Color shadow_color = Color(0, 0, 0, dark_theme ? 0.3 : 0.1);
style_popup->set_shadow_color(shadow_color);
style_popup->set_shadow_size(4 * EDSCALE);
Ref<StyleBoxLine> style_popup_separator(memnew(StyleBoxLine));
style_popup_separator->set_color(separator_color);
- style_popup_separator->set_grow_begin(popup_margin_size - MAX(EDSCALE, border_width));
- style_popup_separator->set_grow_end(popup_margin_size - MAX(EDSCALE, border_width));
- style_popup_separator->set_thickness(MAX(EDSCALE, border_width));
+ style_popup_separator->set_grow_begin(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
+ style_popup_separator->set_grow_end(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
+ style_popup_separator->set_thickness(MAX(Math::round(EDSCALE), border_width));
Ref<StyleBoxLine> style_popup_labeled_separator_left(memnew(StyleBoxLine));
- style_popup_labeled_separator_left->set_grow_begin(popup_margin_size - MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_left->set_grow_begin(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
style_popup_labeled_separator_left->set_color(separator_color);
- style_popup_labeled_separator_left->set_thickness(MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_left->set_thickness(MAX(Math::round(EDSCALE), border_width));
Ref<StyleBoxLine> style_popup_labeled_separator_right(memnew(StyleBoxLine));
- style_popup_labeled_separator_right->set_grow_end(popup_margin_size - MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_right->set_grow_end(popup_margin_size - MAX(Math::round(EDSCALE), border_width));
style_popup_labeled_separator_right->set_color(separator_color);
- style_popup_labeled_separator_right->set_thickness(MAX(EDSCALE, border_width));
+ style_popup_labeled_separator_right->set_thickness(MAX(Math::round(EDSCALE), border_width));
Ref<StyleBoxEmpty> style_empty = make_empty_stylebox(default_margin_size, default_margin_size, default_margin_size, default_margin_size);
// Tabs
- const int tab_default_margin_side = 10 * EDSCALE + extra_spacing * EDSCALE;
- const int tab_default_margin_vertical = 5 * EDSCALE + extra_spacing * EDSCALE;
-
Ref<StyleBoxFlat> style_tab_selected = style_widget->duplicate();
- style_tab_selected->set_border_width_all(border_width);
- style_tab_selected->set_border_width(SIDE_BOTTOM, 0);
- style_tab_selected->set_border_color(dark_color_3);
- style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, border_width);
- style_tab_selected->set_default_margin(SIDE_LEFT, tab_default_margin_side);
- style_tab_selected->set_default_margin(SIDE_RIGHT, tab_default_margin_side);
- style_tab_selected->set_default_margin(SIDE_BOTTOM, tab_default_margin_vertical);
- style_tab_selected->set_default_margin(SIDE_TOP, tab_default_margin_vertical);
- style_tab_selected->set_bg_color(tab_color);
+ // Add a highlight line at the top of the selected tab.
+ style_tab_selected->set_border_width_all(0);
+ style_tab_selected->set_border_width(SIDE_TOP, Math::round(2 * EDSCALE));
+ // Make the highlight line prominent, but not too prominent as to not be distracting.
+ style_tab_selected->set_border_color(dark_color_2.lerp(accent_color, 0.75));
+ // Don't round the top corners to avoid creating a small blank space between the tabs and the main panel.
+ // This also makes the top highlight look better.
+ style_tab_selected->set_corner_radius_all(0);
+
+ // Prevent visible artifacts and cover the top-left rounded corner of the panel below the tab if selected
+ // We can't prevent them with both rounded corners and non-zero border width, though
+ style_tab_selected->set_expand_margin_size(SIDE_BOTTOM, corner_width > 0 ? corner_width : border_width);
+
+ style_tab_selected->set_default_margin(SIDE_LEFT, widget_default_margin.x + 2 * EDSCALE);
+ style_tab_selected->set_default_margin(SIDE_RIGHT, widget_default_margin.x + 2 * EDSCALE);
+ style_tab_selected->set_default_margin(SIDE_BOTTOM, widget_default_margin.y);
+ style_tab_selected->set_default_margin(SIDE_TOP, widget_default_margin.y);
+ style_tab_selected->set_bg_color(base_color);
Ref<StyleBoxFlat> style_tab_unselected = style_tab_selected->duplicate();
style_tab_unselected->set_bg_color(dark_color_1);
+ style_tab_unselected->set_expand_margin_size(SIDE_BOTTOM, 0);
+ // Add some spacing between unselected tabs to make them easier to distinguish from each other
style_tab_unselected->set_border_color(dark_color_2);
+ style_tab_unselected->set_border_width(SIDE_LEFT, Math::round(2 * EDSCALE));
+ style_tab_unselected->set_border_width(SIDE_RIGHT, Math::round(2 * EDSCALE));
Ref<StyleBoxFlat> style_tab_disabled = style_tab_selected->duplicate();
style_tab_disabled->set_bg_color(disabled_bg_color);
- style_tab_disabled->set_border_color(disabled_color);
+ style_tab_disabled->set_expand_margin_size(SIDE_BOTTOM, 0);
+ style_tab_disabled->set_border_color(disabled_bg_color);
// Editor background
Color background_color_opaque = background_color;
@@ -566,10 +575,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("Background", "EditorStyles", make_flat_stylebox(background_color_opaque, default_margin_size, default_margin_size, default_margin_size, default_margin_size));
// Focus
- Ref<StyleBoxFlat> style_focus = style_default->duplicate();
- style_focus->set_draw_center(false);
- style_focus->set_border_color(contrast_color_2);
- theme->set_stylebox("Focus", "EditorStyles", style_focus);
+ theme->set_stylebox("Focus", "EditorStyles", style_widget_focus);
// Menu
Ref<StyleBoxFlat> style_menu = style_widget->duplicate();
@@ -585,33 +591,25 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Play button group
theme->set_stylebox("PlayButtonPanel", "EditorStyles", style_empty);
- //MenuButton
- Ref<StyleBoxFlat> style_menu_hover_border = style_widget->duplicate();
- style_menu_hover_border->set_draw_center(false);
- style_menu_hover_border->set_border_width_all(0);
- style_menu_hover_border->set_border_width(SIDE_BOTTOM, border_width);
- style_menu_hover_border->set_border_color(accent_color);
-
- Ref<StyleBoxFlat> style_menu_hover_bg = style_widget->duplicate();
- style_menu_hover_bg->set_border_width_all(0);
- style_menu_hover_bg->set_bg_color(dark_color_1);
-
theme->set_stylebox("normal", "MenuButton", style_menu);
- theme->set_stylebox("hover", "MenuButton", style_menu);
+ theme->set_stylebox("hover", "MenuButton", style_widget_hover);
theme->set_stylebox("pressed", "MenuButton", style_menu);
theme->set_stylebox("focus", "MenuButton", style_menu);
theme->set_stylebox("disabled", "MenuButton", style_menu);
theme->set_stylebox("normal", "PopupMenu", style_menu);
- theme->set_stylebox("hover", "PopupMenu", style_menu_hover_bg);
- theme->set_stylebox("pressed", "PopupMenu", style_menu);
+
+ Ref<StyleBoxFlat> style_menu_hover = style_widget_hover->duplicate();
+ // Don't use rounded corners for hover highlights since the StyleBox touches the PopupMenu's edges.
+ style_menu_hover->set_corner_radius_all(0);
+ theme->set_stylebox("hover", "PopupMenu", style_menu_hover);
theme->set_stylebox("focus", "PopupMenu", style_menu);
theme->set_stylebox("disabled", "PopupMenu", style_menu);
theme->set_color("font_color", "MenuButton", font_color);
theme->set_color("font_hover_color", "MenuButton", font_hover_color);
- theme->set_stylebox("MenuHover", "EditorStyles", style_menu_hover_border);
+ theme->set_stylebox("MenuHover", "EditorStyles", style_widget_hover);
// Buttons
theme->set_stylebox("normal", "Button", style_widget);
@@ -646,7 +644,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_disabled_color", "OptionButton", font_disabled_color);
theme->set_color("icon_hover_color", "OptionButton", icon_hover_color);
theme->set_icon("arrow", "OptionButton", theme->get_icon("GuiOptionArrow", "EditorIcons"));
- theme->set_constant("arrow_margin", "OptionButton", default_margin_size * EDSCALE);
+ theme->set_constant("arrow_margin", "OptionButton", widget_default_margin.x - 2 * EDSCALE);
theme->set_constant("modulate_arrow", "OptionButton", true);
theme->set_constant("hseparation", "OptionButton", 4 * EDSCALE);
@@ -672,7 +670,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_disabled_color", "CheckButton", font_disabled_color);
theme->set_color("icon_hover_color", "CheckButton", icon_hover_color);
- theme->set_constant("hseparation", "CheckButton", 4 * EDSCALE);
+ theme->set_constant("hseparation", "CheckButton", 8 * EDSCALE);
theme->set_constant("check_vadjust", "CheckButton", 0 * EDSCALE);
// Checkbox
@@ -697,7 +695,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_disabled_color", "CheckBox", font_disabled_color);
theme->set_color("icon_hover_color", "CheckBox", icon_hover_color);
- theme->set_constant("hseparation", "CheckBox", 4 * EDSCALE);
+ theme->set_constant("hseparation", "CheckBox", 8 * EDSCALE);
theme->set_constant("check_vadjust", "CheckBox", 0 * EDSCALE);
// PopupDialog
@@ -794,12 +792,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// Tree & ItemList background
Ref<StyleBoxFlat> style_tree_bg = style_default->duplicate();
- style_tree_bg->set_bg_color(dark_color_1);
+ // Make Trees easier to distinguish from other controls by using a darker background color.
+ style_tree_bg->set_bg_color(dark_color_1.lerp(dark_color_2, 0.5));
style_tree_bg->set_border_color(dark_color_3);
theme->set_stylebox("bg", "Tree", style_tree_bg);
- const Color guide_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.05);
- Color relationship_line_color = Color(mono_color.r, mono_color.g, mono_color.b, relationship_line_opacity);
+ const Color guide_color = mono_color * Color(1, 1, 1, 0.05);
+ Color relationship_line_color = mono_color * Color(1, 1, 1, relationship_line_opacity);
// Tree
theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons"));
theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons"));
@@ -808,7 +807,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("arrow_collapsed_mirrored", "Tree", theme->get_icon("GuiTreeArrowLeft", "EditorIcons"));
theme->set_icon("updown", "Tree", theme->get_icon("GuiTreeUpdown", "EditorIcons"));
theme->set_icon("select_arrow", "Tree", theme->get_icon("GuiDropdown", "EditorIcons"));
- theme->set_stylebox("bg_focus", "Tree", style_focus);
+ theme->set_stylebox("bg_focus", "Tree", style_widget_focus);
theme->set_stylebox("custom_button", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_pressed", "Tree", make_empty_stylebox());
theme->set_stylebox("custom_button_hover", "Tree", style_widget);
@@ -819,8 +818,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("guide_color", "Tree", guide_color);
theme->set_color("relationship_line_color", "Tree", relationship_line_color);
theme->set_color("drop_position_color", "Tree", accent_color);
- theme->set_constant("vseparation", "Tree", (extra_spacing + default_margin_size) * EDSCALE);
- theme->set_constant("hseparation", "Tree", (extra_spacing + default_margin_size) * EDSCALE);
+ theme->set_constant("vseparation", "Tree", widget_default_margin.y - EDSCALE);
+ theme->set_constant("hseparation", "Tree", 6 * EDSCALE);
+ theme->set_constant("guide_width", "Tree", border_width);
theme->set_constant("item_margin", "Tree", 3 * default_margin_size * EDSCALE);
theme->set_constant("button_margin", "Tree", default_margin_size * EDSCALE);
theme->set_constant("draw_relationship_lines", "Tree", relationship_line_opacity >= 0.01);
@@ -829,7 +829,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("scroll_speed", "Tree", 12);
Ref<StyleBoxFlat> style_tree_btn = style_default->duplicate();
- style_tree_btn->set_bg_color(contrast_color_1);
+ style_tree_btn->set_bg_color(highlight_color);
style_tree_btn->set_border_width_all(0);
theme->set_stylebox("button_pressed", "Tree", style_tree_btn);
@@ -882,14 +882,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("cursor_unfocused", "ItemList", style_itemlist_cursor);
theme->set_stylebox("selected_focus", "ItemList", style_tree_focus);
theme->set_stylebox("selected", "ItemList", style_tree_selected);
- theme->set_stylebox("bg_focus", "ItemList", style_focus);
+ theme->set_stylebox("bg_focus", "ItemList", style_widget_focus);
theme->set_stylebox("bg", "ItemList", style_itemlist_bg);
theme->set_color("font_color", "ItemList", font_color);
theme->set_color("font_selected_color", "ItemList", mono_color);
theme->set_color("guide_color", "ItemList", guide_color);
- theme->set_constant("vseparation", "ItemList", 3 * EDSCALE);
- theme->set_constant("hseparation", "ItemList", 3 * EDSCALE);
- theme->set_constant("icon_margin", "ItemList", default_margin_size * EDSCALE);
+ theme->set_constant("vseparation", "ItemList", widget_default_margin.y - EDSCALE);
+ theme->set_constant("hseparation", "ItemList", 6 * EDSCALE);
+ theme->set_constant("icon_margin", "ItemList", 6 * EDSCALE);
theme->set_constant("line_separation", "ItemList", 3 * EDSCALE);
// Tabs & TabContainer
@@ -940,8 +940,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("Content", "EditorStyles", style_content_panel_vp);
// Separators
- theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, border_width));
- theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, border_width, 0, 0, true));
+ theme->set_stylebox("separator", "HSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width)));
+ theme->set_stylebox("separator", "VSeparator", make_line_stylebox(separator_color, MAX(Math::round(EDSCALE), border_width), 0, 0, true));
// Debugger
@@ -956,9 +956,23 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("BottomPanelDebuggerOverride", "EditorStyles", style_panel_invisible_top);
// LineEdit
- theme->set_stylebox("normal", "LineEdit", style_widget);
+
+ Ref<StyleBoxFlat> style_line_edit = style_widget->duplicate();
+ // Add a bottom line to make LineEdits more visible, especially in sectioned inspectors
+ // such as the Project Settings.
+ style_line_edit->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE));
+ style_line_edit->set_border_color(dark_color_2);
+ // Don't round the bottom corner to make the line look sharper.
+ style_tab_selected->set_corner_radius(CORNER_BOTTOM_LEFT, 0);
+ style_tab_selected->set_corner_radius(CORNER_BOTTOM_RIGHT, 0);
+
+ Ref<StyleBoxFlat> style_line_edit_disabled = style_line_edit->duplicate();
+ style_line_edit_disabled->set_border_color(disabled_color);
+ style_line_edit_disabled->set_bg_color(disabled_bg_color);
+
+ theme->set_stylebox("normal", "LineEdit", style_line_edit);
theme->set_stylebox("focus", "LineEdit", style_widget_focus);
- theme->set_stylebox("read_only", "LineEdit", style_widget_disabled);
+ theme->set_stylebox("read_only", "LineEdit", style_line_edit_disabled);
theme->set_icon("clear", "LineEdit", theme->get_icon("GuiClose", "EditorIcons"));
theme->set_color("read_only", "LineEdit", font_disabled_color);
theme->set_color("font_color", "LineEdit", font_color);
@@ -969,9 +983,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("clear_button_color_pressed", "LineEdit", accent_color);
// TextEdit
- theme->set_stylebox("normal", "TextEdit", style_widget);
- theme->set_stylebox("focus", "TextEdit", style_widget_hover);
- theme->set_stylebox("read_only", "TextEdit", style_widget_disabled);
+ theme->set_stylebox("normal", "TextEdit", style_line_edit);
+ theme->set_stylebox("focus", "TextEdit", style_widget_focus);
+ theme->set_stylebox("read_only", "TextEdit", style_line_edit_disabled);
theme->set_constant("side_margin", "TabContainer", 0);
theme->set_icon("tab", "TextEdit", theme->get_icon("GuiTab", "EditorIcons"));
theme->set_icon("space", "TextEdit", theme->get_icon("GuiSpace", "EditorIcons"));
@@ -1014,14 +1028,22 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_constant("hseparation", "GridContainer", default_margin_size * EDSCALE);
theme->set_constant("vseparation", "GridContainer", default_margin_size * EDSCALE);
- // WindowDialog
+ // Window
+
+ // Prevent corner artifacts between window title and body.
+ Ref<StyleBoxFlat> style_window_title = style_default->duplicate();
+ style_window_title->set_corner_radius(CORNER_TOP_LEFT, 0);
+ style_window_title->set_corner_radius(CORNER_TOP_RIGHT, 0);
+ // Prevent visible line between window title and body.
+ style_window_title->set_expand_margin_size(SIDE_BOTTOM, 2 * EDSCALE);
+ theme->set_stylebox("panel", "Window", style_window_title);
+
Ref<StyleBoxFlat> style_window = style_popup->duplicate();
- style_window->set_border_color(tab_color);
+ style_window->set_border_color(base_color);
style_window->set_border_width(SIDE_TOP, 24 * EDSCALE);
style_window->set_expand_margin_size(SIDE_TOP, 24 * EDSCALE);
-
- theme->set_stylebox("panel", "Window", style_default);
theme->set_stylebox("panel_window", "Window", style_window);
+
theme->set_color("title_color", "Window", font_color);
theme->set_icon("close", "Window", theme->get_icon("GuiClose", "EditorIcons"));
theme->set_icon("close_highlight", "Window", theme->get_icon("GuiClose", "EditorIcons"));
@@ -1032,10 +1054,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_font("title_font", "Window", theme->get_font("title", "EditorFonts"));
theme->set_font_size("title_font_size", "Window", theme->get_font_size("title_size", "EditorFonts"));
- // complex window, for now only Editor settings and Project settings
+ // Complex window (currently only Editor Settings and Project Settings)
Ref<StyleBoxFlat> style_complex_window = style_window->duplicate();
style_complex_window->set_bg_color(dark_color_2);
- style_complex_window->set_border_color(highlight_tabs ? tab_color : dark_color_2);
+ style_complex_window->set_border_color(dark_color_2);
theme->set_stylebox("panel", "EditorSettingsDialog", style_complex_window);
theme->set_stylebox("panel", "ProjectSettingsEditor", style_complex_window);
theme->set_stylebox("panel", "EditorAbout", style_complex_window);
@@ -1069,18 +1091,18 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// HSlider
theme->set_icon("grabber_highlight", "HSlider", theme->get_icon("GuiSliderGrabberHl", "EditorIcons"));
theme->set_icon("grabber", "HSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons"));
- theme->set_stylebox("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2));
- theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
+ theme->set_stylebox("slider", "HSlider", make_flat_stylebox(dark_color_3, 0, default_margin_size / 2, 0, default_margin_size / 2, corner_width));
+ theme->set_stylebox("grabber_area", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2, corner_width));
theme->set_stylebox("grabber_area_highlight", "HSlider", make_flat_stylebox(contrast_color_1, 0, default_margin_size / 2, 0, default_margin_size / 2));
// VSlider
theme->set_icon("grabber", "VSlider", theme->get_icon("GuiSliderGrabber", "EditorIcons"));
theme->set_icon("grabber_highlight", "VSlider", theme->get_icon("GuiSliderGrabberHl", "EditorIcons"));
- theme->set_stylebox("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0));
- theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
+ theme->set_stylebox("slider", "VSlider", make_flat_stylebox(dark_color_3, default_margin_size / 2, 0, default_margin_size / 2, 0, corner_width));
+ theme->set_stylebox("grabber_area", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0, corner_width));
theme->set_stylebox("grabber_area_highlight", "VSlider", make_flat_stylebox(contrast_color_1, default_margin_size / 2, 0, default_margin_size / 2, 0));
- //RichTextLabel
+ // RichTextLabel
theme->set_color("default_color", "RichTextLabel", font_color);
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * EDSCALE);
@@ -1092,7 +1114,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("headline_color", "EditorHelp", mono_color);
// Panel
- theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4));
+ theme->set_stylebox("panel", "Panel", make_flat_stylebox(dark_color_1, 6, 4, 6, 4, corner_width));
theme->set_stylebox("panel_fg", "Panel", style_default);
// Label
@@ -1113,16 +1135,15 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// TooltipPanel
Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate();
- float v = MAX(border_size * EDSCALE, 1.0);
- style_tooltip->set_default_margin(SIDE_LEFT, v);
- style_tooltip->set_default_margin(SIDE_TOP, v);
- style_tooltip->set_default_margin(SIDE_RIGHT, v);
- style_tooltip->set_default_margin(SIDE_BOTTOM, v);
- style_tooltip->set_bg_color(Color(mono_color.r, mono_color.g, mono_color.b, 0.9));
- style_tooltip->set_border_width_all(border_width);
- style_tooltip->set_border_color(mono_color);
- theme->set_color("font_color", "TooltipLabel", font_color.inverted());
- theme->set_color("font_shadow_color", "TooltipLabel", mono_color.inverted() * Color(1, 1, 1, 0.1));
+ style_tooltip->set_shadow_size(0);
+ style_tooltip->set_default_margin(SIDE_LEFT, default_margin_size * EDSCALE);
+ style_tooltip->set_default_margin(SIDE_TOP, default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_default_margin(SIDE_RIGHT, default_margin_size * EDSCALE);
+ style_tooltip->set_default_margin(SIDE_BOTTOM, default_margin_size * EDSCALE * 0.5);
+ style_tooltip->set_bg_color(mono_color.inverted() * Color(1, 1, 1, 0.8));
+ style_tooltip->set_border_width_all(0);
+ theme->set_color("font_color", "TooltipLabel", font_hover_color);
+ theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0));
theme->set_stylebox("panel", "TooltipPanel", style_tooltip);
// PopupPanel
@@ -1189,23 +1210,20 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("resizer_color", "GraphEditMinimap", minimap_resizer_color);
// GraphNode
- const float mv = dark_theme ? 0.0 : 1.0;
- const float mv2 = 1.0 - mv;
const int gn_margin_side = 28;
- Ref<StyleBoxFlat> graphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5);
+
+ Ref<StyleBoxFlat> graphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, 5, corner_width);
graphsb->set_border_width_all(border_width);
- graphsb->set_border_color(Color(mv2, mv2, mv2, 0.9));
- Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5);
- graphsbselected->set_border_width_all(border_width);
+ graphsb->set_border_color(dark_color_3);
+ Ref<StyleBoxFlat> graphsbselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+ graphsbselected->set_border_width_all(2 * EDSCALE + border_width);
graphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
- graphsbselected->set_shadow_size(8 * EDSCALE);
- graphsbselected->set_shadow_color(shadow_color);
- Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(Color(mv, mv, mv, 0.3), gn_margin_side, 24, gn_margin_side, 5);
+ Ref<StyleBoxFlat> graphsbcomment = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.3), gn_margin_side, 24, gn_margin_side, 5, corner_width);
graphsbcomment->set_border_width_all(border_width);
- graphsbcomment->set_border_color(Color(mv2, mv2, mv2, 0.9));
- Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(Color(mv, mv, mv, 0.4), gn_margin_side, 24, gn_margin_side, 5);
+ graphsbcomment->set_border_color(dark_color_3);
+ Ref<StyleBoxFlat> graphsbcommentselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.4), gn_margin_side, 24, gn_margin_side, 5, corner_width);
graphsbcommentselected->set_border_width_all(border_width);
- graphsbcommentselected->set_border_color(Color(mv2, mv2, mv2, 0.9));
+ graphsbcommentselected->set_border_color(dark_color_3);
Ref<StyleBoxFlat> graphsbbreakpoint = graphsbselected->duplicate();
graphsbbreakpoint->set_draw_center(false);
graphsbbreakpoint->set_border_color(warning_color);
@@ -1214,21 +1232,19 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
graphsbposition->set_draw_center(false);
graphsbposition->set_border_color(error_color);
graphsbposition->set_shadow_color(error_color * Color(1.0, 1.0, 1.0, 0.2));
- Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(Color(mv, mv, mv, 0.7), gn_margin_side, 24, gn_margin_side, 5);
+ Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), gn_margin_side, 24, gn_margin_side, 5, corner_width);
smgraphsb->set_border_width_all(border_width);
- smgraphsb->set_border_color(Color(mv2, mv2, mv2, 0.9));
- Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(Color(mv, mv, mv, 0.9), gn_margin_side, 24, gn_margin_side, 5);
- smgraphsbselected->set_border_width_all(border_width);
+ smgraphsb->set_border_color(dark_color_3);
+ Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.9), gn_margin_side, 24, gn_margin_side, 5, corner_width);
+ smgraphsbselected->set_border_width_all(2 * EDSCALE + border_width);
smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
smgraphsbselected->set_shadow_size(8 * EDSCALE);
smgraphsbselected->set_shadow_color(shadow_color);
- if (use_gn_headers) {
- graphsb->set_border_width(SIDE_TOP, 24 * EDSCALE);
- graphsbselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
- graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE);
- graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
- }
+ graphsb->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsbselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsbcomment->set_border_width(SIDE_TOP, 24 * EDSCALE);
+ graphsbcommentselected->set_border_width(SIDE_TOP, 24 * EDSCALE);
theme->set_stylebox("frame", "GraphNode", graphsb);
theme->set_stylebox("selectedframe", "GraphNode", graphsbselected);
@@ -1239,7 +1255,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_stylebox("state_machine_frame", "GraphNode", smgraphsb);
theme->set_stylebox("state_machine_selectedframe", "GraphNode", smgraphsbselected);
- Color default_node_color = Color(mv2, mv2, mv2);
+ Color default_node_color = dark_color_1.inverted();
theme->set_color("title_color", "GraphNode", default_node_color);
default_node_color.a = 0.7;
theme->set_color("close_color", "GraphNode", default_node_color);
@@ -1257,7 +1273,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("port", "GraphNode", theme->get_icon("GuiGraphNodePort", "EditorIcons"));
// GridContainer
- theme->set_constant("vseparation", "GridContainer", (extra_spacing + default_margin_size) * EDSCALE);
+ theme->set_constant("vseparation", "GridContainer", Math::round(widget_default_margin.y - 2 * EDSCALE));
// FileDialog
theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons"));
diff --git a/editor/fileserver/editor_file_server.h b/editor/fileserver/editor_file_server.h
index 8ffd4f9692..d0405e0bb7 100644
--- a/editor/fileserver/editor_file_server.h
+++ b/editor/fileserver/editor_file_server.h
@@ -54,7 +54,7 @@ class EditorFileServer : public Object {
bool quit = false;
};
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
Set<Thread *> to_wait;
static void _close_client(ClientData *cd);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 09424647fe..6cd45fdf97 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2806,7 +2806,6 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
toolbar_hbc->add_child(current_path);
button_reload = memnew(Button);
- button_reload->set_flat(true);
button_reload->connect("pressed", callable_mp(this, &FileSystemDock::_rescan));
button_reload->set_focus_mode(FOCUS_NONE);
button_reload->set_tooltip(TTR("Re-Scan Filesystem"));
@@ -2814,7 +2813,6 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
toolbar_hbc->add_child(button_reload);
button_toggle_display_mode = memnew(Button);
- button_toggle_display_mode->set_flat(true);
button_toggle_display_mode->set_toggle_mode(true);
button_toggle_display_mode->connect("toggled", callable_mp(this, &FileSystemDock::_toggle_split_mode));
button_toggle_display_mode->set_focus_mode(FOCUS_NONE);
diff --git a/editor/icons/CombineLines.svg b/editor/icons/CombineLines.svg
new file mode 100644
index 0000000000..124814ae88
--- /dev/null
+++ b/editor/icons/CombineLines.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 2v2h14V2zm7 5v2h7V7zm0 5v2h7v-2zM4.976 14V9h2l-1.5-2-1.5-2-1.5 2-1.5 2h2v5z" fill="#e0e0e0"/></svg>
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 4bb56beaeb..96002400f3 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1136,7 +1136,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
return importer->import_animation(p_path, p_flags, p_bake_fps);
}
-void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache) {
+void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
if (src_mesh_node) {
//is mesh
@@ -1216,7 +1216,28 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
n = n->get_parent_spatial();
}
- //use xf as transform for mesh, and bake it
+ Vector<uint8_t> lightmap_cache;
+ src_mesh_node->get_mesh()->lightmap_unwrap_cached(xf, p_lightmap_texel_size, p_src_lightmap_cache, lightmap_cache);
+
+ if (!lightmap_cache.is_empty()) {
+ if (r_lightmap_caches.is_empty()) {
+ r_lightmap_caches.push_back(lightmap_cache);
+ } else {
+ String new_md5 = String::md5(lightmap_cache.ptr()); // MD5 is stored at the beginning of the cache data
+
+ for (int i = 0; i < r_lightmap_caches.size(); i++) {
+ String md5 = String::md5(r_lightmap_caches[i].ptr());
+ if (new_md5 < md5) {
+ r_lightmap_caches.insert(i, lightmap_cache);
+ break;
+ }
+
+ if (new_md5 == md5) {
+ break;
+ }
+ }
+ }
+ }
}
if (save_to_file != String()) {
@@ -1265,7 +1286,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
}
for (int i = 0; i < p_node->get_child_count(); i++) {
- _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_dst_lightmap_cache);
+ _generate_meshes(p_node->get_child(i), p_mesh_data, p_generate_lods, p_create_shadow_meshes, p_light_bake_mode, p_lightmap_texel_size, p_src_lightmap_cache, r_lightmap_caches);
}
}
@@ -1433,7 +1454,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float lightmap_texel_size = MAX(0.001, texel_size);
Vector<uint8_t> src_lightmap_cache;
- Vector<uint8_t> dst_lightmap_cache;
+ Vector<Vector<uint8_t>> mesh_lightmap_caches;
{
src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err);
@@ -1446,124 +1467,20 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
if (subresources.has("meshes")) {
mesh_data = subresources["meshes"];
}
- _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, dst_lightmap_cache);
+ _generate_meshes(scene, mesh_data, gen_lods, create_shadow_meshes, LightBakeMode(light_bake_mode), lightmap_texel_size, src_lightmap_cache, mesh_lightmap_caches);
- if (dst_lightmap_cache.size()) {
+ if (mesh_lightmap_caches.size()) {
FileAccessRef f = FileAccess::open(p_source_file + ".unwrap_cache", FileAccess::WRITE);
if (f) {
- f->store_buffer(dst_lightmap_cache.ptr(), dst_lightmap_cache.size());
- }
- }
- err = OK;
-
-#if 0
- if (light_bake_mode == 2 /* || generate LOD */) {
- Map<Ref<ArrayMesh>, Transform> meshes;
- _find_meshes(scene, meshes);
-
- String file_id = src_path.get_file();
- String cache_file_path = base_path.plus_file(file_id + ".unwrap_cache");
-
- Vector<unsigned char> cache_data;
-
- if (FileAccess::exists(cache_file_path)) {
- Error err2;
- FileAccess *file = FileAccess::open(cache_file_path, FileAccess::READ, &err2);
-
- if (err2) {
- if (file) {
- memdelete(file);
- }
- } else {
- int cache_size = file->get_len();
- cache_data.resize(cache_size);
- file->get_buffer(cache_data.ptrw(), cache_size);
+ f->store_32(mesh_lightmap_caches.size());
+ for (int i = 0; i < mesh_lightmap_caches.size(); i++) {
+ String md5 = String::md5(mesh_lightmap_caches[i].ptr());
+ f->store_buffer(mesh_lightmap_caches[i].ptr(), mesh_lightmap_caches[i].size());
}
- }
-
- Map<String, unsigned int> used_unwraps;
-
- EditorProgress progress2("gen_lightmaps", TTR("Generating Lightmaps"), meshes.size());
- int step = 0;
- for (Map<Ref<ArrayMesh>, Transform>::Element *E = meshes.front(); E; E = E->next()) {
- Ref<ArrayMesh> mesh = E->key();
- String name = mesh->get_name();
- if (name == "") { //should not happen but..
- name = "Mesh " + itos(step);
- }
-
- progress2.step(TTR("Generating for Mesh: ") + name + " (" + itos(step) + "/" + itos(meshes.size()) + ")", step);
-
- int *ret_cache_data = (int *)cache_data.ptrw();
- unsigned int ret_cache_size = cache_data.size();
- bool ret_used_cache = true; // Tell the unwrapper to use the cache
- Error err2 = mesh->lightmap_unwrap_cached(ret_cache_data, ret_cache_size, ret_used_cache, E->get(), texel_size);
-
- if (err2 != OK) {
- EditorNode::add_io_error("Mesh '" + name + "' failed lightmap generation. Please fix geometry.");
- } else {
-` String hash = String::md5((unsigned char *)ret_cache_data);
- used_unwraps.insert(hash, ret_cache_size);
-
- if (!ret_used_cache) {
- // Cache was not used, add the generated entry to the current cache
- if (cache_data.is_empty()) {
- cache_data.resize(4 + ret_cache_size);
- int *data = (int *)cache_data.ptrw();
- data[0] = 1;
- memcpy(&data[1], ret_cache_data, ret_cache_size);
- } else {
- int current_size = cache_data.size();
- cache_data.resize(cache_data.size() + ret_cache_size);
- unsigned char *ptrw = cache_data.ptrw();
- memcpy(&ptrw[current_size], ret_cache_data, ret_cache_size);
- int *data = (int *)ptrw;
- data[0] += 1;
- }
- }
- }
- step++;
- }
-
- Error err2;
- FileAccess *file = FileAccess::open(cache_file_path, FileAccess::WRITE, &err2);
-
- if (err2) {
- if (file) {
- memdelete(file);
- }
- } else {
- // Store number of entries
- file->store_32(used_unwraps.size());
-
- // Store cache entries
- const int *cache = (int *)cache_data.ptr();
- unsigned int r_idx = 1;
- for (int i = 0; i < cache[0]; ++i) {
- unsigned char *entry_start = (unsigned char *)&cache[r_idx];
- String entry_hash = String::md5(entry_start);
- if (used_unwraps.has(entry_hash)) {
- unsigned int entry_size = used_unwraps[entry_hash];
- file->store_buffer(entry_start, entry_size);
- }
-
- r_idx += 4; // hash
- r_idx += 2; // size hint
-
- int vertex_count = cache[r_idx];
- r_idx += 1; // vertex count
- r_idx += vertex_count; // vertex
- r_idx += vertex_count * 2; // uvs
-
- int index_count = cache[r_idx];
- r_idx += 1; // index count
- r_idx += index_count; // indices
- }
-
- file->close();
+ f->close();
}
}
-#endif
+ err = OK;
progress.step(TTR("Running Custom Script..."), 2);
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 00039f2ac6..8cb84abce2 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -119,7 +119,7 @@ class ResourceImporterScene : public ResourceImporter {
};
void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner);
- void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<uint8_t> &r_dst_lightmap_cache);
+ void _generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches);
void _add_shapes(Node *p_node, const List<Ref<Shape3D>> &p_shapes);
public:
diff --git a/editor/import/scene_importer_mesh.cpp b/editor/import/scene_importer_mesh.cpp
index 28fdd4ddbd..bc7e8a1626 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/editor/import/scene_importer_mesh.cpp
@@ -583,7 +583,7 @@ Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
return nm;
}
-extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
+extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
struct EditorSceneImporterMeshLightmapSurface {
Ref<Material> material;
@@ -593,22 +593,24 @@ struct EditorSceneImporterMeshLightmapSurface {
String name;
};
-Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
+Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
- Vector<float> vertices;
- Vector<float> normals;
- Vector<int> indices;
- Vector<float> uv;
- Vector<Pair<int, int>> uv_indices;
+ LocalVector<float> vertices;
+ LocalVector<float> normals;
+ LocalVector<int> indices;
+ LocalVector<float> uv;
+ LocalVector<Pair<int, int>> uv_indices;
Vector<EditorSceneImporterMeshLightmapSurface> lightmap_surfaces;
// Keep only the scale
- Transform transform = p_base_transform;
- transform.origin = Vector3();
- transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
+ Basis basis = p_base_transform.get_basis();
+ Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
+
+ Transform transform;
+ transform.scale(scale);
Basis normal_basis = transform.basis.inverse().transposed();
@@ -623,15 +625,10 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
- Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
+ PackedVector3Array rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
- const Vector3 *r = rvertices.ptr();
-
- Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
-
- ERR_FAIL_COND_V_MSG(rnormals.size() == 0, ERR_UNAVAILABLE, "Normals are required for lightmap unwrap.");
- const Vector3 *rn = rnormals.ptr();
+ PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
int vertex_ofs = vertices.size() / 3;
@@ -640,24 +637,29 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
uv_indices.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) {
- Vector3 v = transform.xform(r[j]);
- Vector3 n = normal_basis.xform(rn[j]).normalized();
-
- vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
- vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
- vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
- normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
- normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
- normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
- uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
+ Vector3 v = transform.xform(rvertices[j]);
+ Vector3 n = normal_basis.xform(rnormals[j]).normalized();
+
+ vertices[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_indices[j + vertex_ofs] = Pair<int, int>(i, j);
}
- Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
+ PackedInt32Array rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size();
+ float eps = 1.19209290e-7F; // Taken from xatlas.h
if (ic == 0) {
for (int j = 0; j < vc / 3; j++) {
- if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[j * 3 + 0]);
+ Vector3 p1 = transform.xform(rvertices[j * 3 + 1]);
+ Vector3 p2 = transform.xform(rvertices[j * 3 + 2]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
@@ -667,15 +669,18 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
}
} else {
- const int *ri = rindices.ptr();
-
for (int j = 0; j < ic / 3; j++) {
- if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
+ Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
+ Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
- indices.push_back(vertex_ofs + ri[j * 3 + 0]);
- indices.push_back(vertex_ofs + ri[j * 3 + 1]);
- indices.push_back(vertex_ofs + ri[j * 3 + 2]);
+
+ indices.push_back(vertex_ofs + rindices[j * 3 + 0]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 1]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 2]);
}
}
@@ -684,6 +689,9 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
//unwrap
+ bool use_cache = true; // Used to request cache generation and to know if cache was used
+ uint8_t *gen_cache;
+ int gen_cache_size;
float *gen_uvs;
int *gen_vertices;
int *gen_indices;
@@ -692,7 +700,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
int size_x;
int size_y;
- bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
+ bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), p_src_cache.ptr(), &use_cache, &gen_cache, &gen_cache_size, &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) {
return ERR_CANT_CREATE;
@@ -702,7 +710,7 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
clear();
//create surfacetools for each surface..
- Vector<Ref<SurfaceTool>> surfaces_tools;
+ LocalVector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st;
@@ -714,11 +722,12 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
}
print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
+
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
@@ -728,49 +737,54 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(int *&r_cache_data, unsign
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_COLOR) {
- surfaces_tools.write[surface]->set_color(v.color);
+ surfaces_tools[surface]->set_color(v.color);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TEX_UV) {
- surfaces_tools.write[surface]->set_uv(v.uv);
+ surfaces_tools[surface]->set_uv(v.uv);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_NORMAL) {
- surfaces_tools.write[surface]->set_normal(v.normal);
+ surfaces_tools[surface]->set_normal(v.normal);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
- surfaces_tools.write[surface]->set_tangent(t);
+ surfaces_tools[surface]->set_tangent(t);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_BONES) {
- surfaces_tools.write[surface]->set_bones(v.bones);
+ surfaces_tools[surface]->set_bones(v.bones);
}
if (lightmap_surfaces[surface].format & Mesh::ARRAY_FORMAT_WEIGHTS) {
- surfaces_tools.write[surface]->set_weights(v.weights);
+ surfaces_tools[surface]->set_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
- surfaces_tools.write[surface]->set_uv2(uv2);
+ surfaces_tools[surface]->set_uv2(uv2);
- surfaces_tools.write[surface]->add_vertex(v.vertex);
+ surfaces_tools[surface]->add_vertex(v.vertex);
}
}
//generate surfaces
-
- for (int i = 0; i < surfaces_tools.size(); i++) {
- surfaces_tools.write[i]->index();
- Array arrays = surfaces_tools.write[i]->commit_to_arrays();
- add_surface(surfaces_tools.write[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools.write[i]->get_material(), surfaces_tools.write[i]->get_meta("name"));
+ for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
+ surfaces_tools[i]->index();
+ Array arrays = surfaces_tools[i]->commit_to_arrays();
+ add_surface(surfaces_tools[i]->get_primitive(), arrays, Array(), Dictionary(), surfaces_tools[i]->get_material(), surfaces_tools[i]->get_meta("name"));
}
set_lightmap_size_hint(Size2(size_x, size_y));
- if (!r_used_cache) {
- //free stuff
- ::free(gen_vertices);
- ::free(gen_indices);
- ::free(gen_uvs);
+ if (gen_cache_size > 0) {
+ r_dst_cache.resize(gen_cache_size);
+ memcpy(r_dst_cache.ptrw(), gen_cache, gen_cache_size);
+ memfree(gen_cache);
+ }
+
+ if (!use_cache) {
+ // Cache was not used, free the buffers
+ memfree(gen_vertices);
+ memfree(gen_indices);
+ memfree(gen_uvs);
}
return OK;
diff --git a/editor/import/scene_importer_mesh.h b/editor/import/scene_importer_mesh.h
index 3326fab55d..b3e8137e0a 100644
--- a/editor/import/scene_importer_mesh.h
+++ b/editor/import/scene_importer_mesh.h
@@ -105,7 +105,7 @@ public:
Vector<Ref<Shape3D>> convex_decompose() const;
Ref<Shape3D> create_trimesh_shape() const;
Ref<NavigationMesh> create_navigation_mesh();
- Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size);
+ Error lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache);
void set_lightmap_size_hint(const Size2i &p_size);
Size2i get_lightmap_size_hint() const;
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index fbcd76a95f..6265dfc2e4 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -535,7 +535,6 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
} else {
backward_button->set_icon(get_theme_icon("Back", "EditorIcons"));
}
- backward_button->set_flat(true);
backward_button->set_tooltip(TTR("Go to the previous edited object in history."));
backward_button->set_disabled(true);
backward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_back));
@@ -548,7 +547,6 @@ InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) {
} else {
forward_button->set_icon(get_theme_icon("Forward", "EditorIcons"));
}
- forward_button->set_flat(true);
forward_button->set_tooltip(TTR("Go to the next edited object in history."));
forward_button->set_disabled(true);
forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 48fb507bb1..78c30df04b 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -231,18 +231,16 @@ void AnimationNodeBlendTreeEditor::_update_graph() {
mb->get_popup()->connect("index_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_anim_selected), varray(options, E->get()), CONNECT_DEFERRED);
}
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color();
- Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
- mono_color.a = 0.85;
- c = mono_color;
-
- node->add_theme_color_override("title_color", c);
- c.a = 0.7;
- node->add_theme_color_override("close_color", c);
- node->add_theme_color_override("resizer_color", c);
- }
+ Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
+ Color c = sb->get_border_color();
+ Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
+ mono_color.a = 0.85;
+ c = mono_color;
+
+ node->add_theme_color_override("title_color", c);
+ c.a = 0.7;
+ node->add_theme_color_override("close_color", c);
+ node->add_theme_color_override("resizer_color", c);
}
List<AnimationNodeBlendTree::NodeConnection> connections;
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index fd47d9964e..a0d9afee74 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -240,7 +240,6 @@ void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, cons
preview.video_link = p_url;
preview.is_video = p_video;
preview.button = memnew(Button);
- preview.button->set_flat(true);
preview.button->set_icon(previews->get_theme_icon("ThumbnailWait", "EditorIcons"));
preview.button->set_toggle_mode(true);
preview.button->connect("pressed", callable_mp(this, &EditorAssetLibraryItemDescription::_preview_click), varray(p_id));
diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp
index 3553450672..3b54b30b54 100644
--- a/editor/plugins/audio_stream_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/io/resource_loader.h"
+#include "core/os/keyboard.h"
#include "editor/audio_stream_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
@@ -144,23 +145,26 @@ void AudioStreamEditor::_draw_indicator() {
Rect2 rect = _preview->get_rect();
float len = stream->get_length();
float ofs_x = _current / len * rect.size.width;
- _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), get_theme_color("accent_color", "Editor"), 1);
+ const Color color = get_theme_color("accent_color", "Editor");
+ _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), color, Math::round(2 * EDSCALE));
+ _indicator->draw_texture(
+ get_theme_icon("TimelineIndicator", "EditorIcons"),
+ Point2(ofs_x - get_theme_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0),
+ color);
_current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /");
}
void AudioStreamEditor::_on_input_indicator(Ref<InputEvent> p_event) {
- Ref<InputEventMouseButton> mb = p_event;
-
- if (mb.is_valid()) {
+ const Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
if (mb->is_pressed()) {
_seek_to(mb->get_position().x);
}
_dragging = mb->is_pressed();
}
- Ref<InputEventMouseMotion> mm = p_event;
-
+ const Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (_dragging) {
_seek_to(mm->get_position().x);
@@ -228,6 +232,7 @@ AudioStreamEditor::AudioStreamEditor() {
hbox->add_child(_play_button);
_play_button->set_focus_mode(Control::FOCUS_NONE);
_play_button->connect("pressed", callable_mp(this, &AudioStreamEditor::_play));
+ _play_button->set_shortcut(ED_SHORTCUT("inspector/audio_preview_play_pause", TTR("Audio Preview Play/Pause"), KEY_SPACE));
_stop_button = memnew(Button);
_stop_button->set_flat(true);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 6ac47595dc..852c615dc8 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -1654,7 +1654,7 @@ bool CanvasItemEditor::_gui_input_open_scene_on_double_click(const Ref<InputEven
Ref<InputEventMouseButton> b = p_event;
// Open a sub-scene on double-click
- if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_doubleclick() && tool == TOOL_SELECT) {
+ if (b.is_valid() && b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed() && b->is_double_click() && tool == TOOL_SELECT) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *canvas_item = selection[0];
@@ -5853,6 +5853,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
updating_scroll = false;
+ // Add some margin to the left for better aesthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ Control *margin_left = memnew(Control);
+ hb->add_child(margin_left);
+ margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE);
+
select_button = memnew(Button);
select_button->set_flat(true);
hb->add_child(select_button);
@@ -6089,7 +6096,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_loc_button = memnew(Button);
key_loc_button->set_toggle_mode(true);
- key_loc_button->set_flat(true);
key_loc_button->set_pressed(true);
key_loc_button->set_focus_mode(FOCUS_NONE);
key_loc_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_POS));
@@ -6098,7 +6104,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_rot_button = memnew(Button);
key_rot_button->set_toggle_mode(true);
- key_rot_button->set_flat(true);
key_rot_button->set_pressed(true);
key_rot_button->set_focus_mode(FOCUS_NONE);
key_rot_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_ROT));
@@ -6107,14 +6112,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
key_scale_button = memnew(Button);
key_scale_button->set_toggle_mode(true);
- key_scale_button->set_flat(true);
key_scale_button->set_focus_mode(FOCUS_NONE);
key_scale_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_SCALE));
key_scale_button->set_tooltip(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
key_insert_button = memnew(Button);
- key_insert_button->set_flat(true);
key_insert_button->set_focus_mode(FOCUS_NONE);
key_insert_button->connect("pressed", callable_mp(this, &CanvasItemEditor::_popup_callback), varray(ANIM_INSERT_KEY));
key_insert_button->set_tooltip(TTR("Insert keys (based on mask)."));
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 023d91be30..81f1852fba 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -6692,6 +6692,13 @@ Node3DEditor::Node3DEditor(EditorNode *p_editor) {
button_binds.resize(1);
String sct;
+ // Add some margin to the left for better aesthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ Control *margin_left = memnew(Control);
+ hbc_menu->add_child(margin_left);
+ margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE);
+
tool_button[TOOL_MODE_SELECT] = memnew(Button);
hbc_menu->add_child(tool_button[TOOL_MODE_SELECT]);
tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index 50f4d8493f..1e6237ced1 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -205,7 +205,6 @@ void EditorPropertyRootMotion::update_property() {
assign->set_flat(false);
return;
}
- assign->set_flat(true);
Node *base_node = nullptr;
if (base_hint != NodePath()) {
@@ -247,14 +246,12 @@ EditorPropertyRootMotion::EditorPropertyRootMotion() {
HBoxContainer *hbc = memnew(HBoxContainer);
add_child(hbc);
assign = memnew(Button);
- assign->set_flat(true);
assign->set_h_size_flags(SIZE_EXPAND_FILL);
assign->set_clip_text(true);
assign->connect("pressed", callable_mp(this, &EditorPropertyRootMotion::_node_assign));
hbc->add_child(assign);
clear = memnew(Button);
- clear->set_flat(true);
clear->connect("pressed", callable_mp(this, &EditorPropertyRootMotion::_node_clear));
hbc->add_child(clear);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 58e6717a3d..bc33d03d8b 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -698,7 +698,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
// Do not try to save internal scripts, but prompt to save in-memory
// scripts which are not saved to disk yet (have empty path).
if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) {
- _menu_option(FILE_SAVE);
+ _save_current_script();
}
}
if (script.is_valid()) {
@@ -1096,6 +1096,59 @@ bool ScriptEditor::is_scripts_panel_toggled() {
return list_split->is_visible();
}
+void ScriptEditor::_save_current_script() {
+ ScriptEditorBase *current = _get_current_editor();
+
+ if (_test_script_times_on_disk()) {
+ return;
+ }
+
+ if (trim_trailing_whitespace_on_save) {
+ current->trim_trailing_whitespace();
+ }
+
+ current->insert_final_newline();
+
+ if (convert_indent_on_save) {
+ if (use_space_indentation) {
+ current->convert_indent_to_spaces();
+ } else {
+ current->convert_indent_to_tabs();
+ }
+ }
+
+ RES resource = current->get_edited_resource();
+ Ref<TextFile> text_file = resource;
+ Ref<Script> script = resource;
+
+ if (text_file != nullptr) {
+ current->apply_code();
+ _save_text_file(text_file, text_file->get_path());
+ return;
+ }
+
+ if (script != nullptr) {
+ const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ for (int j = 0; j < documentations.size(); j++) {
+ const DocData::ClassDoc &doc = documentations.get(j);
+ if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
+ EditorHelp::get_doc_data()->remove_doc(doc.name);
+ }
+ }
+ }
+
+ editor->save_resource(resource);
+
+ if (script != nullptr) {
+ const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
+ for (int j = 0; j < documentations.size(); j++) {
+ const DocData::ClassDoc &doc = documentations.get(j);
+ EditorHelp::get_doc_data()->add_doc(doc);
+ update_doc(doc.name);
+ }
+ }
+}
+
void ScriptEditor::_menu_option(int p_option) {
ScriptEditorBase *current = _get_current_editor();
switch (p_option) {
@@ -1224,55 +1277,7 @@ void ScriptEditor::_menu_option(int p_option) {
if (current) {
switch (p_option) {
case FILE_SAVE: {
- if (_test_script_times_on_disk()) {
- return;
- }
-
- if (trim_trailing_whitespace_on_save) {
- current->trim_trailing_whitespace();
- }
-
- current->insert_final_newline();
-
- if (convert_indent_on_save) {
- if (use_space_indentation) {
- current->convert_indent_to_spaces();
- } else {
- current->convert_indent_to_tabs();
- }
- }
-
- RES resource = current->get_edited_resource();
- Ref<TextFile> text_file = resource;
- Ref<Script> script = resource;
-
- if (text_file != nullptr) {
- current->apply_code();
- _save_text_file(text_file, text_file->get_path());
- break;
- }
-
- if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- if (EditorHelp::get_doc_data()->has_doc(doc.name)) {
- EditorHelp::get_doc_data()->remove_doc(doc.name);
- }
- }
- }
-
- editor->save_resource(resource);
-
- if (script != nullptr) {
- const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
- for (int j = 0; j < documentations.size(); j++) {
- const DocData::ClassDoc &doc = documentations.get(j);
- EditorHelp::get_doc_data()->add_doc(doc);
- update_doc(doc.name);
- }
- }
-
+ _save_current_script();
} break;
case FILE_SAVE_AS: {
if (trim_trailing_whitespace_on_save) {
@@ -1827,7 +1832,6 @@ void ScriptEditor::_update_help_overview() {
void ScriptEditor::_update_script_colors() {
bool script_temperature_enabled = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_enabled");
- bool highlight_current = EditorSettings::get_singleton()->get("text_editor/script_list/highlight_current_script");
int hist_size = EditorSettings::get_singleton()->get("text_editor/script_list/script_temperature_history_size");
Color hot_color = get_theme_color("accent_color", "Editor");
@@ -1842,11 +1846,7 @@ void ScriptEditor::_update_script_colors() {
script_list->set_item_custom_bg_color(i, Color(0, 0, 0, 0));
- bool current = tab_container->get_current_tab() == c;
- if (current && highlight_current) {
- script_list->set_item_custom_bg_color(i, EditorSettings::get_singleton()->get("text_editor/script_list/current_script_background_color"));
-
- } else if (script_temperature_enabled) {
+ if (script_temperature_enabled) {
if (!n->has_meta("__editor_pass")) {
continue;
}
@@ -2439,6 +2439,9 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const
script_list->select(script_list->find_metadata(i));
+ // Save the current script so the changes can be picked up by an external editor.
+ _save_current_script();
+
break;
}
}
@@ -3672,9 +3675,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
EDITOR_DEF("text_editor/external/use_external_editor", false);
EDITOR_DEF("text_editor/external/exec_path", "");
EDITOR_DEF("text_editor/script_list/script_temperature_enabled", true);
- EDITOR_DEF("text_editor/script_list/highlight_current_script", true);
EDITOR_DEF("text_editor/script_list/script_temperature_history_size", 15);
- EDITOR_DEF("text_editor/script_list/current_script_background_color", Color(1, 1, 1, 0.3));
EDITOR_DEF("text_editor/script_list/group_help_pages", true);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/script_list/sort_scripts_by", PROPERTY_HINT_ENUM, "Name,Path,None"));
EDITOR_DEF("text_editor/script_list/sort_scripts_by", 0);
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index b2172e7f10..c70fd2e555 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -312,6 +312,7 @@ class ScriptEditor : public PanelContainer {
String _get_debug_tooltip(const String &p_text, Node *_se);
+ void _save_current_script();
void _resave_scripts(const String &p_str);
void _reload_scripts();
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index acc77bd098..7d5e72ff8e 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -1175,26 +1175,15 @@ void VisualShaderEditor::_draw_color_over_button(Object *obj, Color p_color) {
}
void VisualShaderEditor::_update_created_node(GraphNode *node) {
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
- Color c = sb->get_border_color();
- Color ic;
- Color mono_color;
- if (((c.r + c.g + c.b) / 3) < 0.7) {
- mono_color = Color(1.0, 1.0, 1.0);
- ic = Color(0.0, 0.0, 0.0, 0.7);
- } else {
- mono_color = Color(0.0, 0.0, 0.0);
- ic = Color(1.0, 1.0, 1.0, 0.7);
- }
- mono_color.a = 0.85;
- c = mono_color;
-
- node->add_theme_color_override("title_color", c);
- c.a = 0.7;
- node->add_theme_color_override("close_color", c);
- node->add_theme_color_override("resizer_color", ic);
- }
+ const Ref<StyleBoxFlat> sb = node->get_theme_stylebox("frame", "GraphNode");
+ Color c = sb->get_border_color();
+ const Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85);
+ c = mono_color;
+
+ node->add_theme_color_override("title_color", c);
+ c.a = 0.7;
+ node->add_theme_color_override("close_color", c);
+ node->add_theme_color_override("resizer_color", c);
}
void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index e51e8ee82e..2b75144ac7 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1762,7 +1762,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
emit_signal(SIGNAL_SELECTION_CHANGED);
- if (!mb->get_control() && mb->is_doubleclick()) {
+ if (!mb->get_control() && mb->is_double_click()) {
emit_signal(SIGNAL_PROJECT_ASK_OPEN);
}
}
@@ -2371,6 +2371,7 @@ void ProjectManager::_on_search_term_changed(const String &p_term) {
void ProjectManager::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &ProjectManager::_unhandled_key_input);
ClassDB::bind_method("_update_project_buttons", &ProjectManager::_update_project_buttons);
+ ClassDB::bind_method("_version_button_pressed", &ProjectManager::_version_button_pressed);
}
void ProjectManager::_open_asset_library() {
@@ -2378,6 +2379,10 @@ void ProjectManager::_open_asset_library() {
tabs->set_current_tab(1);
}
+void ProjectManager::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_text());
+}
+
ProjectManager::ProjectManager() {
// load settings
if (!EditorSettings::get_singleton()) {
@@ -2601,15 +2606,30 @@ ProjectManager::ProjectManager() {
settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
- Label *version_label = memnew(Label);
+ // A VBoxContainer that contains a dummy Control node to adjust the LinkButton's vertical position.
+ VBoxContainer *spacer_vb = memnew(VBoxContainer);
+ settings_hb->add_child(spacer_vb);
+
+ Control *v_spacer = memnew(Control);
+ spacer_vb->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
String hash = String(VERSION_HASH);
if (hash.length() != 0) {
hash = "." + hash.left(9);
}
- version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- version_label->set_align(Label::ALIGN_CENTER);
- settings_hb->add_child(version_label);
+ version_btn->set_text("v" VERSION_FULL_BUILD + hash);
+ // Fade the version label to be less prominent, but still readable.
+ version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
+ spacer_vb->add_child(version_btn);
+
+ // Add a small horizontal spacer between the version and language buttons
+ // to distinguish them.
+ Control *h_spacer = memnew(Control);
+ settings_hb->add_child(h_spacer);
language_btn = memnew(OptionButton);
language_btn->set_flat(true);
diff --git a/editor/project_manager.h b/editor/project_manager.h
index a66b7c4ab6..0fc69bd313 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -89,6 +89,7 @@ class ProjectManager : public Control {
ProjectDialog *npdialog;
OptionButton *language_btn;
+ LinkButton *version_btn;
void _open_asset_library();
void _scan_projects();
@@ -123,6 +124,7 @@ class ProjectManager : public Control {
void _unhandled_key_input(const Ref<InputEvent> &p_ev);
void _files_dropped(PackedStringArray p_files, int p_screen);
+ void _version_button_pressed();
void _on_order_option_changed(int p_idx);
void _on_tab_changed(int p_tab);
void _on_search_term_changed(const String &p_term);
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index 1a010b9168..8b0d9ae0fc 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -1823,7 +1823,6 @@ CustomPropertyEditor::CustomPropertyEditor() {
Vector<Variant> binds;
binds.push_back(i);
action_buttons[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed), binds);
- action_buttons[i]->set_flat(true);
}
color_picker = nullptr;
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index f979f61196..d0bf83eb2d 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -540,6 +540,10 @@ void SceneTreeEditor::_update_tree(bool p_scroll_to_selected) {
return;
}
+ if (tree->is_editing()) {
+ return;
+ }
+
updating_tree = true;
tree->clear();
if (get_scene_node()) {
diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp
index f3addd8904..c2bfdaae96 100644
--- a/editor/script_create_dialog.cpp
+++ b/editor/script_create_dialog.cpp
@@ -838,7 +838,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
parent_search_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_class_in_tree));
hb->add_child(parent_search_button);
parent_browse_button = memnew(Button);
- parent_browse_button->set_flat(true);
parent_browse_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_path), varray(true, false));
hb->add_child(parent_browse_button);
gc->add_child(memnew(Label(TTR("Inherits:"))));
@@ -877,7 +876,6 @@ ScriptCreateDialog::ScriptCreateDialog() {
file_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
hb->add_child(file_path);
path_button = memnew(Button);
- path_button->set_flat(true);
path_button->connect("pressed", callable_mp(this, &ScriptCreateDialog::_browse_path), varray(false, true));
hb->add_child(path_button);
gc->add_child(memnew(Label(TTR("Path:"))));
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 81af4996ed..541ec224b9 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -270,16 +270,17 @@ void EditorSettingsDialog::_update_shortcuts() {
Array events; // Need to get the list of events into an array so it can be set as metadata on the item.
Vector<String> event_strings;
- List<Ref<InputEvent>> defaults = InputMap::get_singleton()->get_builtins().find(action_name).value();
- // Remove all non-key events from the defaults.
- for (List<Ref<InputEvent>>::Element *I = defaults.front(); I; I = I->next()) {
+ List<Ref<InputEvent>> all_default_events = InputMap::get_singleton()->get_builtins().find(action_name).value();
+ List<Ref<InputEventKey>> key_default_events;
+ // Remove all non-key events from the defaults. Only check keys, since we are in the editor.
+ for (List<Ref<InputEvent>>::Element *I = all_default_events.front(); I; I = I->next()) {
Ref<InputEventKey> k = I->get();
- if (k.is_null()) {
- I->erase();
+ if (k.is_valid()) {
+ key_default_events.push_back(k);
}
}
- bool same_as_defaults = defaults.size() == action.inputs.size(); // Initially this is set to just whether the arrays are equal. Later we check the events if needed.
+ bool same_as_defaults = key_default_events.size() == action.inputs.size(); // Initially this is set to just whether the arrays are equal. Later we check the events if needed.
int count = 0;
for (List<Ref<InputEvent>>::Element *I = action.inputs.front(); I; I = I->next()) {
@@ -288,12 +289,8 @@ void EditorSettingsDialog::_update_shortcuts() {
event_strings.push_back(I->get()->as_text());
// Only check if the events have been the same so far - once one fails, we don't need to check any more.
- if (same_as_defaults) {
- Ref<InputEventKey> k = defaults[count];
- // Only check keys, since we are in the editor.
- if (k.is_valid() && !defaults[count]->shortcut_match(I->get())) {
- same_as_defaults = false;
- }
+ if (same_as_defaults && !key_default_events[count]->shortcut_match(I->get())) {
+ same_as_defaults = false;
}
count++;
}
diff --git a/main/main.cpp b/main/main.cpp
index bb16c49983..67d8d93728 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -2252,7 +2252,7 @@ bool Main::start() {
ProjectSettings::get_singleton()->set_custom_property_info(
"rendering/textures/canvas_textures/default_texture_filter",
PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM,
- "Nearest,Linear,MipmapLinear,MipmapNearest"));
+ "Nearest,Linear,Linear Mipmap,Nearest Mipmap"));
GLOBAL_DEF_BASIC("rendering/textures/canvas_textures/default_texture_repeat", 0);
ProjectSettings::get_singleton()->set_custom_property_info(
"rendering/textures/canvas_textures/default_texture_repeat",
diff --git a/modules/SCsub b/modules/SCsub
index 64da3bd0be..5ff4623743 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -10,6 +10,7 @@ env_modules = env.Clone()
Export("env_modules")
# Header with MODULE_*_ENABLED defines.
+env.Depends("modules_enabled.gen.h", Value(env.module_list))
env.CommandNoCache(
"modules_enabled.gen.h",
Value(env.module_list),
@@ -23,6 +24,7 @@ env.CommandNoCache(
# Header to be included in `tests/test_main.cpp` to run module-specific tests.
if env["tests"]:
+ env.Depends("modules_tests.gen.h", Value(env.module_list))
env.CommandNoCache(
"modules_tests.gen.h",
Value(env.module_list),
diff --git a/modules/enet/networked_multiplayer_enet.cpp b/modules/enet/networked_multiplayer_enet.cpp
index 1cf77b307d..9491373013 100644
--- a/modules/enet/networked_multiplayer_enet.cpp
+++ b/modules/enet/networked_multiplayer_enet.cpp
@@ -157,7 +157,7 @@ Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_por
_setup_compressor();
- IP_Address ip;
+ IPAddress ip;
if (p_address.is_valid_ip_address()) {
ip = p_address;
} else {
@@ -749,12 +749,12 @@ void NetworkedMultiplayerENet::enet_compressor_destroy(void *context) {
// Nothing to do
}
-IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const {
- ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IP_Address(), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
- ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IP_Address(), "Can't get the address of peers other than the server (ID -1) when acting as a client.");
- ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
+IPAddress NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const {
+ ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IPAddress(), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
+ ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IPAddress(), "Can't get the address of peers other than the server (ID -1) when acting as a client.");
+ ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == nullptr, IPAddress(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
- IP_Address out;
+ IPAddress out;
#ifdef GODOT_ENET
out.set_ipv6((uint8_t *)&(peer_map[p_peer_id]->address.host));
#else
@@ -877,7 +877,7 @@ NetworkedMultiplayerENet::NetworkedMultiplayerENet() {
enet_compressor.decompress = enet_decompress;
enet_compressor.destroy = enet_compressor_destroy;
- bind_ip = IP_Address("*");
+ bind_ip = IPAddress("*");
}
NetworkedMultiplayerENet::~NetworkedMultiplayerENet() {
@@ -888,7 +888,7 @@ NetworkedMultiplayerENet::~NetworkedMultiplayerENet() {
// Sets IP for ENet to bind when using create_server or create_client
// if no IP is set, then ENet bind to ENET_HOST_ANY
-void NetworkedMultiplayerENet::set_bind_ip(const IP_Address &p_ip) {
+void NetworkedMultiplayerENet::set_bind_ip(const IPAddress &p_ip) {
ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip)));
bind_ip = p_ip;
diff --git a/modules/enet/networked_multiplayer_enet.h b/modules/enet/networked_multiplayer_enet.h
index c589cd9fbf..2d928859fa 100644
--- a/modules/enet/networked_multiplayer_enet.h
+++ b/modules/enet/networked_multiplayer_enet.h
@@ -108,7 +108,7 @@ private:
static void enet_compressor_destroy(void *context);
void _setup_compressor();
- IP_Address bind_ip;
+ IPAddress bind_ip;
bool dtls_enabled = false;
Ref<CryptoKey> dtls_key;
@@ -125,7 +125,7 @@ public:
virtual int get_packet_peer() const override;
- virtual IP_Address get_peer_address(int p_peer_id) const;
+ virtual IPAddress get_peer_address(int p_peer_id) const;
virtual int get_peer_port(int p_peer_id) const;
virtual int get_local_port() const;
void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
@@ -171,7 +171,7 @@ public:
NetworkedMultiplayerENet();
~NetworkedMultiplayerENet();
- void set_bind_ip(const IP_Address &p_ip);
+ void set_bind_ip(const IPAddress &p_ip);
void set_dtls_enabled(bool p_enabled);
bool is_dtls_enabled() const;
void set_dtls_verify_enabled(bool p_enabled);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index f70020d165..099abd35a7 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -738,7 +738,12 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptCodeCompletionOption> &r_result) {
for (int i = 0; i < p_suite->locals.size(); i++) {
- ScriptCodeCompletionOption option(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ ScriptCodeCompletionOption option;
+ if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) {
+ option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_CONSTANT);
+ } else {
+ option = ScriptCodeCompletionOption(p_suite->locals[i].name, ScriptCodeCompletionOption::KIND_VARIABLE);
+ }
r_result.insert(option.display, option);
}
if (p_suite->parent_block) {
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 2e6388d92f..3f14156dfa 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -643,6 +643,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
push_error(error);
}
previous_was_underscore = true;
+ } else {
+ previous_was_underscore = false;
}
_advance();
}
@@ -714,6 +716,8 @@ GDScriptTokenizer::Token GDScriptTokenizer::number() {
push_error(error);
}
previous_was_underscore = true;
+ } else {
+ previous_was_underscore = false;
}
_advance();
}
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 0432e7caea..c16a7fa889 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -255,7 +255,7 @@ void GDScriptLanguageProtocol::poll() {
}
}
-Error GDScriptLanguageProtocol::start(int p_port, const IP_Address &p_bind_ip) {
+Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) {
return server->listen(p_port, p_bind_ip);
}
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index 8b08ae0655..a5c5a233b1 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -69,7 +69,7 @@ private:
static GDScriptLanguageProtocol *singleton;
HashMap<int, Ref<LSPeer>> clients;
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
int latest_client_id = 0;
int next_client_id = 0;
@@ -97,7 +97,7 @@ public:
_FORCE_INLINE_ bool is_initialized() const { return _initialized; }
void poll();
- Error start(int p_port, const IP_Address &p_bind_ip);
+ Error start(int p_port, const IPAddress &p_bind_ip);
void stop();
void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1);
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 98ada9de4d..340a7b9343 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -78,7 +78,7 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
void GDScriptLanguageServer::start() {
port = (int)_EDITOR_GET("network/language_server/remote_port");
use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
- if (protocol.start(port, IP_Address("127.0.0.1")) == OK) {
+ if (protocol.start(port, IPAddress("127.0.0.1")) == OK) {
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
thread_running = true;
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 9394e5c47e..3b0fbb1c47 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -162,8 +162,8 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
MeshInstance &mi = mesh_instances.write[m_i];
Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height());
sizes.push_back(s);
- atlas_size.width = MAX(atlas_size.width, s.width);
- atlas_size.height = MAX(atlas_size.height, s.height);
+ atlas_size.width = MAX(atlas_size.width, s.width + 2);
+ atlas_size.height = MAX(atlas_size.height, s.height + 2);
}
int max = nearest_power_of_2_templated(atlas_size.width);
@@ -186,10 +186,12 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
//determine best texture array atlas size by bruteforce fitting
while (atlas_size.x <= p_max_texture_size && atlas_size.y <= p_max_texture_size) {
- Vector<Vector2i> source_sizes = sizes;
+ Vector<Vector2i> source_sizes;
Vector<int> source_indices;
- source_indices.resize(source_sizes.size());
+ source_sizes.resize(sizes.size());
+ source_indices.resize(sizes.size());
for (int i = 0; i < source_indices.size(); i++) {
+ source_sizes.write[i] = sizes[i] + Vector2i(2, 2); // Add padding between lightmaps
source_indices.write[i] = i;
}
Vector<Vector3i> atlas_offsets;
@@ -207,7 +209,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
if (ofs.z > 0) {
//valid
ofs.z = slices;
- atlas_offsets.write[sidx] = ofs;
+ atlas_offsets.write[sidx] = ofs + Vector3i(1, 1, 0); // Center lightmap in the reserved oversized region
} else {
new_indices.push_back(sidx);
new_sources.push_back(source_sizes[i]);
@@ -272,7 +274,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
return BAKE_OK;
}
-void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
+void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
HashMap<Vertex, uint32_t, VertexHash> vertex_map;
//fill triangles array and vertex array
@@ -482,14 +484,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
img->save_png("res://grid_layer_" + itos(1000 + i).substr(1, 3) + ".png");
}
#endif
- if (p_step_function) {
- p_step_function(0.45, TTR("Generating Signed Distance Field"), p_bake_userdata, true);
- }
-
- //generate SDF for raytracing
- Vector<uint32_t> euclidean_pos = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), false);
- Vector<uint32_t> euclidean_neg = Geometry3D::generate_edf(solid, Vector3i(grid_size, grid_size, grid_size), true);
- Vector<int8_t> sdf8 = Geometry3D::generate_sdf8(euclidean_pos, euclidean_neg);
/*****************************/
/*** CREATE GPU STRUCTURES ***/
@@ -551,10 +545,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
tf.format = RD::DATA_FORMAT_R32G32_UINT;
texdata.write[0] = grid_indices.to_byte_array();
grid_texture = rd->texture_create(tf, RD::TextureView(), texdata);
- //sdf
- tf.format = RD::DATA_FORMAT_R8_SNORM;
- texdata.write[0] = sdf8.to_byte_array();
- grid_texture_sdf = rd->texture_create(tf, RD::TextureView(), texdata);
}
}
@@ -755,8 +745,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
light_environment_tex = rd->texture_create(tfp, RD::TextureView(), tdata);
#ifdef DEBUG_TEXTURES
- panorama_tex->convert(Image::FORMAT_RGB8);
- panorama_tex->save_png("res://0_panorama.png");
+ panorama_tex->save_exr("res://0_panorama.exr", false);
#endif
}
}
@@ -770,7 +759,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RID lights_buffer;
RID triangle_cell_indices_buffer;
RID grid_texture;
- RID grid_texture_sdf;
RID seams_buffer;
RID probe_positions_buffer;
@@ -783,11 +771,10 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
rd->free(lights_buffer); \
rd->free(triangle_cell_indices_buffer); \
rd->free(grid_texture); \
- rd->free(grid_texture_sdf); \
rd->free(seams_buffer); \
rd->free(probe_positions_buffer);
- _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, grid_texture_sdf, seams_buffer, p_step_function, p_bake_userdata);
+ _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata);
if (p_step_function) {
p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true);
@@ -883,27 +870,20 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 9;
- u.ids.push_back(grid_texture_sdf);
- base_uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 10;
u.ids.push_back(albedo_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 11;
+ u.binding = 10;
u.ids.push_back(emission_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 12;
+ u.binding = 11;
u.ids.push_back(sampler);
base_uniforms.push_back(u);
}
@@ -937,13 +917,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAF, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://1_position_" + itos(i) + ".png");
+ img->save_exr("res://1_position_" + itos(i) + ".exr", false);
s = rd->texture_get_data(normal_tex, i);
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://1_normal_" + itos(i) + ".png");
+ img->save_exr("res://1_normal_" + itos(i) + ".exr", false);
}
#endif
@@ -966,27 +944,27 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
ERR_FAIL_COND_V(err != OK, BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES);
- //unoccluder
+ // Unoccluder
RID compute_shader_unocclude = rd->shader_create_from_bytecode(compute_shader->get_bytecode("unocclude"));
ERR_FAIL_COND_V(compute_shader_unocclude.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen
RID compute_shader_unocclude_pipeline = rd->compute_pipeline_create(compute_shader_unocclude);
- //direct light
+ // Direct light
RID compute_shader_primary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("primary"));
ERR_FAIL_COND_V(compute_shader_primary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); // internal check, should not happen
RID compute_shader_primary_pipeline = rd->compute_pipeline_create(compute_shader_primary);
- //indirect light
+ // Indirect light
RID compute_shader_secondary = rd->shader_create_from_bytecode(compute_shader->get_bytecode("secondary"));
ERR_FAIL_COND_V(compute_shader_secondary.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_secondary_pipeline = rd->compute_pipeline_create(compute_shader_secondary);
- //dilate
+ // Dilate
RID compute_shader_dilate = rd->shader_create_from_bytecode(compute_shader->get_bytecode("dilate"));
ERR_FAIL_COND_V(compute_shader_dilate.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_dilate_pipeline = rd->compute_pipeline_create(compute_shader_dilate);
- //dilate
+ // Light probes
RID compute_shader_light_probes = rd->shader_create_from_bytecode(compute_shader->get_bytecode("light_probes"));
ERR_FAIL_COND_V(compute_shader_light_probes.is_null(), BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES); //internal check, should not happen
RID compute_shader_light_probes_pipeline = rd->compute_pipeline_create(compute_shader_light_probes);
@@ -1153,8 +1131,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://2_light_primary_" + itos(i) + ".png");
+ img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false);
}
#endif
@@ -1212,7 +1189,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 6;
- u.ids.push_back(light_environment_tex); //reuse unocclude tex
+ u.ids.push_back(light_environment_tex);
uniforms.push_back(u);
}
}
@@ -1298,7 +1275,15 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
}
}
}
+
+ if (b == 0) {
+ // This disables the environment for subsequent bounces
+ push_constant.environment_xform[3] = -99.0f;
+ }
}
+
+ // Restore the correct environment transform
+ push_constant.environment_xform[3] = 0.0f;
}
/* LIGHPROBES */
@@ -1449,8 +1434,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://4_light_secondary_" + itos(i) + ".png");
+ img->save_exr("res://4_light_secondary_" + itos(i) + ".exr", false);
}
#endif
@@ -1582,6 +1566,11 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
clear_colors.push_back(Color(0, 0, 0, 1));
for (int i = 0; i < atlas_slices; i++) {
int subslices = (p_bake_sh ? 4 : 1);
+
+ if (slice_seam_count[i] == 0) {
+ continue;
+ }
+
for (int k = 0; k < subslices; k++) {
RasterSeamsPushConstant seams_push_constant;
seams_push_constant.slice = uint32_t(i * subslices + k);
@@ -1654,8 +1643,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img;
img.instance();
img->create(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
- img->convert(Image::FORMAT_RGBA8);
- img->save_png("res://5_blendseams" + itos(i) + ".png");
+ img->save_exr("res://5_blendseams" + itos(i) + ".exr", false);
}
#endif
if (p_step_function) {
@@ -1682,7 +1670,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Ref<Image> img2;
img2.instance();
img2->create(probe_values.size(), 1, false, Image::FORMAT_RGBAF, probe_data);
- img2->save_png("res://6_lightprobes.png");
+ img2->save_exr("res://6_lightprobes.exr", false);
}
#endif
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index f2a826a447..7ab7f34464 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -231,7 +231,7 @@ class LightmapperRD : public Lightmapper {
Vector<Color> probe_values;
BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata);
- void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &grid_texture_sdf, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
+ void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
public:
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index f8a0cd16de..1581639036 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -84,9 +84,8 @@ layout(set = 0, binding = 7, std430) restrict readonly buffer Probes {
probe_positions;
layout(set = 0, binding = 8) uniform utexture3D grid;
-layout(set = 0, binding = 9) uniform texture3D grid_sdf;
-layout(set = 0, binding = 10) uniform texture2DArray albedo_tex;
-layout(set = 0, binding = 11) uniform texture2DArray emission_tex;
+layout(set = 0, binding = 9) uniform texture2DArray albedo_tex;
+layout(set = 0, binding = 10) uniform texture2DArray emission_tex;
-layout(set = 0, binding = 12) uniform sampler linear_sampler;
+layout(set = 0, binding = 11) uniform sampler linear_sampler;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 3dd96893fb..9ca40535f9 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -96,15 +96,22 @@ params;
bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, vec3 p2, out float r_distance, out vec3 r_barycentric) {
const vec3 e0 = p1 - p0;
const vec3 e1 = p0 - p2;
- vec3 triangleNormal = cross(e1, e0);
+ vec3 triangle_normal = cross(e1, e0);
- const vec3 e2 = (1.0 / dot(triangleNormal, dir)) * (p0 - from);
+ float n_dot_dir = dot(triangle_normal, dir);
+
+ if (abs(n_dot_dir) < 0.01) {
+ return false;
+ }
+
+ const vec3 e2 = (p0 - from) / n_dot_dir;
const vec3 i = cross(dir, e2);
r_barycentric.y = dot(i, e1);
r_barycentric.z = dot(i, e0);
r_barycentric.x = 1.0 - (r_barycentric.z + r_barycentric.y);
- r_distance = dot(triangleNormal, e2);
+ r_distance = dot(triangle_normal, e2);
+
return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0)));
}
@@ -307,8 +314,6 @@ void main() {
continue;
}
- d /= lights.data[i].range;
-
attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation);
if (lights.data[i].type == LIGHT_TYPE_SPOT) {
@@ -410,7 +415,7 @@ void main() {
uint tidx;
vec3 barycentric;
- vec3 light;
+ vec3 light = vec3(0.0);
if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
//hit a triangle
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
@@ -419,8 +424,8 @@ void main() {
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
- } else {
- //did not hit a triangle, reach out for the sky
+ } else if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
+ // Did not hit a triangle, reach out for the sky
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
vec2 st = vec2(
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 342ded6ea1..d77d946a77 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -87,7 +87,7 @@ void PacketPeerMbedDTLS::_cleanup() {
int PacketPeerMbedDTLS::_set_cookie() {
// Setup DTLS session cookie for this client
uint8_t client_id[18];
- IP_Address addr = base->get_packet_address();
+ IPAddress addr = base->get_packet_address();
uint16_t port = base->get_packet_port();
memcpy(client_id, addr.get_ipv6(), 16);
memcpy(&client_id[16], (uint8_t *)&port, 2);
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 68e9df5263..57120bff26 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -3,84 +3,101 @@
Import("env")
Import("env_modules")
-embree_src = [
- "common/sys/sysinfo.cpp",
- "common/sys/alloc.cpp",
- "common/sys/filename.cpp",
- "common/sys/library.cpp",
- "common/sys/thread.cpp",
- "common/sys/string.cpp",
- "common/sys/regression.cpp",
- "common/sys/mutex.cpp",
- "common/sys/condition.cpp",
- "common/sys/barrier.cpp",
- "common/math/constants.cpp",
- "common/simd/sse.cpp",
- "common/lexers/stringstream.cpp",
- "common/lexers/tokenstream.cpp",
- "common/tasking/taskschedulerinternal.cpp",
- "common/algorithms/parallel_for.cpp",
- "common/algorithms/parallel_reduce.cpp",
- "common/algorithms/parallel_prefix_sum.cpp",
- "common/algorithms/parallel_for_for.cpp",
- "common/algorithms/parallel_for_for_prefix_sum.cpp",
- "common/algorithms/parallel_partition.cpp",
- "common/algorithms/parallel_sort.cpp",
- "common/algorithms/parallel_set.cpp",
- "common/algorithms/parallel_map.cpp",
- "common/algorithms/parallel_filter.cpp",
- "kernels/common/device.cpp",
- "kernels/common/stat.cpp",
- "kernels/common/acceln.cpp",
- "kernels/common/accelset.cpp",
- "kernels/common/state.cpp",
- "kernels/common/rtcore.cpp",
- "kernels/common/rtcore_builder.cpp",
- "kernels/common/scene.cpp",
- "kernels/common/alloc.cpp",
- "kernels/common/geometry.cpp",
- "kernels/common/scene_triangle_mesh.cpp",
- "kernels/geometry/primitive4.cpp",
- "kernels/builders/primrefgen.cpp",
- "kernels/bvh/bvh.cpp",
- "kernels/bvh/bvh_statistics.cpp",
- "kernels/bvh/bvh4_factory.cpp",
- "kernels/bvh/bvh8_factory.cpp",
- "kernels/bvh/bvh_collider.cpp",
- "kernels/bvh/bvh_rotate.cpp",
- "kernels/bvh/bvh_refit.cpp",
- "kernels/bvh/bvh_builder.cpp",
- "kernels/bvh/bvh_builder_morton.cpp",
- "kernels/bvh/bvh_builder_sah.cpp",
- "kernels/bvh/bvh_builder_sah_spatial.cpp",
- "kernels/bvh/bvh_builder_sah_mb.cpp",
- "kernels/bvh/bvh_builder_twolevel.cpp",
- "kernels/bvh/bvh_intersector1_bvh4.cpp",
-]
-
-embree_dir = "#thirdparty/embree-aarch64/"
-
-env_embree = env_modules.Clone()
-embree_sources = [embree_dir + file for file in embree_src]
-env_embree.Prepend(CPPPATH=[embree_dir, embree_dir + "include"])
-env_embree.Append(CPPFLAGS=["-DEMBREE_TARGET_SSE2", "-DEMBREE_LOWEST_ISA", "-DTASKING_INTERNAL", "-DNDEBUG"])
-
-if not env_embree.msvc:
- env_embree.Append(CPPFLAGS=["-msse2", "-mxsave"])
+env_raycast = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+if env["builtin_embree"]:
+ thirdparty_dir = "#thirdparty/embree-aarch64/"
+
+ embree_src = [
+ "common/sys/sysinfo.cpp",
+ "common/sys/alloc.cpp",
+ "common/sys/filename.cpp",
+ "common/sys/library.cpp",
+ "common/sys/thread.cpp",
+ "common/sys/string.cpp",
+ "common/sys/regression.cpp",
+ "common/sys/mutex.cpp",
+ "common/sys/condition.cpp",
+ "common/sys/barrier.cpp",
+ "common/math/constants.cpp",
+ "common/simd/sse.cpp",
+ "common/lexers/stringstream.cpp",
+ "common/lexers/tokenstream.cpp",
+ "common/tasking/taskschedulerinternal.cpp",
+ "common/algorithms/parallel_for.cpp",
+ "common/algorithms/parallel_reduce.cpp",
+ "common/algorithms/parallel_prefix_sum.cpp",
+ "common/algorithms/parallel_for_for.cpp",
+ "common/algorithms/parallel_for_for_prefix_sum.cpp",
+ "common/algorithms/parallel_partition.cpp",
+ "common/algorithms/parallel_sort.cpp",
+ "common/algorithms/parallel_set.cpp",
+ "common/algorithms/parallel_map.cpp",
+ "common/algorithms/parallel_filter.cpp",
+ "kernels/common/device.cpp",
+ "kernels/common/stat.cpp",
+ "kernels/common/acceln.cpp",
+ "kernels/common/accelset.cpp",
+ "kernels/common/state.cpp",
+ "kernels/common/rtcore.cpp",
+ "kernels/common/rtcore_builder.cpp",
+ "kernels/common/scene.cpp",
+ "kernels/common/alloc.cpp",
+ "kernels/common/geometry.cpp",
+ "kernels/common/scene_triangle_mesh.cpp",
+ "kernels/geometry/primitive4.cpp",
+ "kernels/builders/primrefgen.cpp",
+ "kernels/bvh/bvh.cpp",
+ "kernels/bvh/bvh_statistics.cpp",
+ "kernels/bvh/bvh4_factory.cpp",
+ "kernels/bvh/bvh8_factory.cpp",
+ "kernels/bvh/bvh_collider.cpp",
+ "kernels/bvh/bvh_rotate.cpp",
+ "kernels/bvh/bvh_refit.cpp",
+ "kernels/bvh/bvh_builder.cpp",
+ "kernels/bvh/bvh_builder_morton.cpp",
+ "kernels/bvh/bvh_builder_sah.cpp",
+ "kernels/bvh/bvh_builder_sah_spatial.cpp",
+ "kernels/bvh/bvh_builder_sah_mb.cpp",
+ "kernels/bvh/bvh_builder_twolevel.cpp",
+ "kernels/bvh/bvh_intersector1_bvh4.cpp",
+ ]
+
+ thirdparty_sources = [thirdparty_dir + file for file in embree_src]
+
+ env_raycast.Prepend(CPPPATH=[thirdparty_dir, thirdparty_dir + "include"])
+ env_raycast.Append(CPPDEFINES=["EMBREE_TARGET_SSE2", "EMBREE_LOWEST_ISA", "TASKING_INTERNAL", "NDEBUG"])
+
+ if not env.msvc:
+ if env["arch"] in ["x86", "x86_64"]:
+ env_raycast.Append(CPPFLAGS=["-msse2", "-mxsave"])
+
+ if env["platform"] == "windows":
+ env_raycast.Append(CPPFLAGS=["-mstackrealign"])
+
if env["platform"] == "windows":
- env_embree.Append(CPPFLAGS=["-mstackrealign"])
+ if env.msvc:
+ env.Append(LINKFLAGS=["psapi.lib"])
+ env_raycast.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
+ else:
+ env.Append(LIBS=["psapi"])
-if env["platform"] == "windows":
- if env.msvc:
- env.Append(LINKFLAGS=["psapi.lib"])
- env_embree.Append(CPPFLAGS=["-D__SSE2__", "-D__SSE__"])
- else:
- env.Append(LIBS=["psapi"])
+ env_thirdparty = env_raycast.Clone()
+ env_thirdparty.disable_warnings()
+ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
+ env.modules_sources += thirdparty_obj
-env_embree.disable_warnings()
-env_embree.add_source_files(env.modules_sources, embree_sources)
-env_raycast = env_modules.Clone()
-env_raycast.Prepend(CPPPATH=[embree_dir, embree_dir + "include", embree_dir + "common"])
+# Godot source files
+
+module_obj = []
+
+env_raycast.add_source_files(module_obj, "*.cpp")
+env.modules_sources += module_obj
-env_raycast.add_source_files(env.modules_sources, "*.cpp")
+# Needed to force rebuilding the module files when the thirdparty library is updated.
+env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp
index 9039622d3d..56bdb5900b 100644
--- a/modules/raycast/lightmap_raycaster.cpp
+++ b/modules/raycast/lightmap_raycaster.cpp
@@ -32,14 +32,8 @@
#include "lightmap_raycaster.h"
-// From Embree.
-#include <math/vec2.h>
-#include <math/vec3.h>
-
#include <pmmintrin.h>
-using namespace embree;
-
LightmapRaycaster *LightmapRaycasterEmbree::create_embree_raycaster() {
return memnew(LightmapRaycasterEmbree);
}
@@ -127,25 +121,24 @@ void LightmapRaycasterEmbree::add_mesh(const Vector<Vector3> &p_vertices, const
ERR_FAIL_COND(vertex_count % 3 != 0);
ERR_FAIL_COND(vertex_count != p_uv2s.size());
+ ERR_FAIL_COND(!p_normals.is_empty() && vertex_count != p_normals.size());
- Vec3fa *embree_vertices = (Vec3fa *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vec3fa), vertex_count);
- Vec2fa *embree_light_uvs = (Vec2fa *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vec2fa), vertex_count);
- uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
+ Vector3 *embree_vertices = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
+ memcpy(embree_vertices, p_vertices.ptr(), sizeof(Vector3) * vertex_count);
- Vec3fa *embree_normals = nullptr;
- if (!p_normals.is_empty()) {
- embree_normals = (Vec3fa *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vec3fa), vertex_count);
- }
+ Vector2 *embree_light_uvs = (Vector2 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 0, RTC_FORMAT_FLOAT2, sizeof(Vector2), vertex_count);
+ memcpy(embree_light_uvs, p_uv2s.ptr(), sizeof(Vector2) * vertex_count);
+ uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
for (int i = 0; i < vertex_count; i++) {
- embree_vertices[i] = Vec3fa(p_vertices[i].x, p_vertices[i].y, p_vertices[i].z);
- embree_light_uvs[i] = Vec2fa(p_uv2s[i].x, p_uv2s[i].y);
- if (embree_normals != nullptr) {
- embree_normals[i] = Vec3fa(p_normals[i].x, p_normals[i].y, p_normals[i].z);
- }
embree_triangles[i] = i;
}
+ if (!p_normals.is_empty()) {
+ Vector3 *embree_normals = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX_ATTRIBUTE, 1, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
+ memcpy(embree_normals, p_normals.ptr(), sizeof(Vector3) * vertex_count);
+ }
+
rtcCommitGeometry(embree_mesh);
rtcSetGeometryIntersectFilterFunction(embree_mesh, filter_function);
rtcSetGeometryUserData(embree_mesh, this);
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index f747763248..6a2fb0f666 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -169,7 +169,7 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
{ 0 }, // R
{ 1, 0 }, // GR
{ 2, 1, 0 }, // BGR
- { 2, 1, 0, 3 } // BGRA
+ { 3, 2, 1, 0 } // ABGR
};
int channel_count = get_channel_count(format);
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 7ca14fbca8..3b24de433c 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -723,7 +723,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
case VisualScriptBuiltinFunc::MATH_POSMOD: {
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- *r_return = Math::posmod((int)*p_inputs[0], (int)*p_inputs[1]);
+ *r_return = Math::posmod((int64_t)*p_inputs[0], (int64_t)*p_inputs[1]);
} break;
case VisualScriptBuiltinFunc::MATH_FLOOR: {
VALIDATE_ARG_NUM(0);
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 02ec9ccd06..dc400982e8 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -740,21 +740,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
Color c = sbf->get_border_color();
Color ic = c;
- c.a = 1;
- if (EditorSettings::get_singleton()->get("interface/theme/use_graph_node_headers")) {
- Color mono_color;
- if (((c.r + c.g + c.b) / 3) < 0.7) {
- mono_color = Color(1.0, 1.0, 1.0);
- ic = Color(0.0, 0.0, 0.0, 0.7);
- } else {
- mono_color = Color(0.0, 0.0, 0.0);
- ic = Color(1.0, 1.0, 1.0, 0.7);
- }
- mono_color.a = 0.85;
- c = mono_color;
- }
gnode->add_theme_color_override("title_color", c);
- c.a = 0.7;
+ c.a = 1;
gnode->add_theme_color_override("close_color", c);
gnode->add_theme_color_override("resizer_color", ic);
gnode->add_theme_style_override("frame", sbf);
@@ -1875,7 +1862,7 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseButton> btn = p_event;
- if (btn.is_valid() && btn->is_doubleclick()) {
+ if (btn.is_valid() && btn->is_double_click()) {
TreeItem *ti = members->get_selected();
if (ti && ti->get_parent() == members->get_root()->get_children()) { // to check if it's a function
_center_on_node(script->get_function_node_id(ti->get_metadata(0)));
@@ -3623,32 +3610,33 @@ void VisualScriptEditor::_notification(int p_what) {
bool dark_theme = tm->get_constant("dark_theme", "Editor");
- List<Pair<String, Color>> colors;
if (dark_theme) {
- colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96)));
- colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51)));
- colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81)));
- colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87)));
- colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96)));
- colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69)));
+ node_colors["flow_control"] = Color(0.96, 0.96, 0.96);
+ node_colors["functions"] = Color(0.96, 0.52, 0.51);
+ node_colors["data"] = Color(0.5, 0.96, 0.81);
+ node_colors["operators"] = Color(0.67, 0.59, 0.87);
+ node_colors["custom"] = Color(0.5, 0.73, 0.96);
+ node_colors["constants"] = Color(0.96, 0.5, 0.69);
} else {
- colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26)));
- colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38)));
- colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51)));
- colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82)));
- colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95)));
- colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49)));
+ node_colors["flow_control"] = Color(0.26, 0.26, 0.26);
+ node_colors["functions"] = Color(0.95, 0.4, 0.38);
+ node_colors["data"] = Color(0.07, 0.73, 0.51);
+ node_colors["operators"] = Color(0.51, 0.4, 0.82);
+ node_colors["custom"] = Color(0.31, 0.63, 0.95);
+ node_colors["constants"] = Color(0.94, 0.18, 0.49);
}
- for (List<Pair<String, Color>>::Element *E = colors.front(); E; E = E->next()) {
- Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
+ for (Map<StringName, Color>::Element *E = node_colors.front(); E; E = E->next()) {
+ const Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
+
if (!sb.is_null()) {
Ref<StyleBoxFlat> frame_style = sb->duplicate();
- Color c = sb->get_border_color();
- Color cn = E->get().second;
- cn.a = c.a;
- frame_style->set_border_color(cn);
- node_styles[E->get().first] = frame_style;
+ // Adjust the border color to be close to the GraphNode's background color.
+ // This keeps the node's title area from being too distracting.
+ Color color = dark_theme ? E->get().darkened(0.75) : E->get().lightened(0.75);
+ color.a = 0.9;
+ frame_style->set_border_color(color);
+ node_styles[E->key()] = frame_style;
}
}
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index bb6f194286..fc9a2df60f 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -135,6 +135,7 @@ class VisualScriptEditor : public ScriptEditorBase {
Vector<Pair<Variant::Type, String>> args;
};
+ Map<StringName, Color> node_colors;
HashMap<StringName, Ref<StyleBox>> node_styles;
void _update_graph_connections();
diff --git a/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index 25b6d6ef0e..626498e1ae 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -121,8 +121,8 @@ void EMWSClient::disconnect_from_host(int p_code, String p_reason) {
_peer->close(p_code, p_reason);
}
-IP_Address EMWSClient::get_connected_host() const {
- ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export.");
+IPAddress EMWSClient::get_connected_host() const {
+ ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export.");
}
uint16_t EMWSClient::get_connected_port() const {
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index 2ab7dc83d0..ca2d7ed986 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -56,7 +56,7 @@ public:
Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IP_Address get_connected_host() const;
+ IPAddress get_connected_host() const;
uint16_t get_connected_port() const;
virtual ConnectionStatus get_connection_status() const;
int get_max_packet_size() const;
diff --git a/modules/websocket/emws_peer.cpp b/modules/websocket/emws_peer.cpp
index 5e75e10d68..1ad3bdc825 100644
--- a/modules/websocket/emws_peer.cpp
+++ b/modules/websocket/emws_peer.cpp
@@ -93,8 +93,8 @@ void EMWSPeer::close(int p_code, String p_reason) {
peer_sock = -1;
};
-IP_Address EMWSPeer::get_connected_host() const {
- ERR_FAIL_V_MSG(IP_Address(), "Not supported in HTML5 export.");
+IPAddress EMWSPeer::get_connected_host() const {
+ ERR_FAIL_V_MSG(IPAddress(), "Not supported in HTML5 export.");
};
uint16_t EMWSPeer::get_connected_port() const {
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index abe5bf2bdb..73e701720b 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -73,7 +73,7 @@ public:
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
- virtual IP_Address get_connected_host() const;
+ virtual IPAddress get_connected_host() const;
virtual uint16_t get_connected_port() const;
virtual WriteMode get_write_mode() const;
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index a35d84f372..4a4f09a943 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -58,8 +58,8 @@ Vector<String> EMWSServer::get_protocols() const {
return out;
}
-IP_Address EMWSServer::get_peer_address(int p_peer_id) const {
- return IP_Address();
+IPAddress EMWSServer::get_peer_address(int p_peer_id) const {
+ return IPAddress();
}
int EMWSServer::get_peer_port(int p_peer_id) const {
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
index 4179b20ffe..e7285ccb86 100644
--- a/modules/websocket/emws_server.h
+++ b/modules/websocket/emws_server.h
@@ -47,7 +47,7 @@ public:
bool is_listening() const;
bool has_peer(int p_id) const;
Ref<WebSocketPeer> get_peer(int p_id) const;
- IP_Address get_peer_address(int p_peer_id) const;
+ IPAddress get_peer_address(int p_peer_id) const;
int get_peer_port(int p_peer_id) const;
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
int get_max_packet_size() const;
diff --git a/modules/websocket/websocket_client.h b/modules/websocket/websocket_client.h
index 0225c9b3d3..c7f17f1ffb 100644
--- a/modules/websocket/websocket_client.h
+++ b/modules/websocket/websocket_client.h
@@ -57,7 +57,7 @@ public:
virtual Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) = 0;
virtual void disconnect_from_host(int p_code = 1000, String p_reason = "") = 0;
- virtual IP_Address get_connected_host() const = 0;
+ virtual IPAddress get_connected_host() const = 0;
virtual uint16_t get_connected_port() const = 0;
virtual bool is_server() const override;
diff --git a/modules/websocket/websocket_peer.h b/modules/websocket/websocket_peer.h
index 2ba83637f9..e9bb20f21f 100644
--- a/modules/websocket/websocket_peer.h
+++ b/modules/websocket/websocket_peer.h
@@ -55,7 +55,7 @@ public:
virtual void close(int p_code = 1000, String p_reason = "") = 0;
virtual bool is_connected_to_host() const = 0;
- virtual IP_Address get_connected_host() const = 0;
+ virtual IPAddress get_connected_host() const = 0;
virtual uint16_t get_connected_port() const = 0;
virtual bool was_string_packet() const = 0;
virtual void set_no_delay(bool p_enabled) = 0;
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index f57e8d959c..7cf68b835c 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -34,7 +34,7 @@ GDCINULL(WebSocketServer);
WebSocketServer::WebSocketServer() {
_peer_id = 1;
- bind_ip = IP_Address("*");
+ bind_ip = IPAddress("*");
}
WebSocketServer::~WebSocketServer() {
@@ -71,11 +71,11 @@ void WebSocketServer::_bind_methods() {
ADD_SIGNAL(MethodInfo("data_received", PropertyInfo(Variant::INT, "id")));
}
-IP_Address WebSocketServer::get_bind_ip() const {
+IPAddress WebSocketServer::get_bind_ip() const {
return bind_ip;
}
-void WebSocketServer::set_bind_ip(const IP_Address &p_bind_ip) {
+void WebSocketServer::set_bind_ip(const IPAddress &p_bind_ip) {
ERR_FAIL_COND(is_listening());
ERR_FAIL_COND(!p_bind_ip.is_valid() && !p_bind_ip.is_wildcard());
bind_ip = p_bind_ip;
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
index 3fbd5e3b95..10da51fce5 100644
--- a/modules/websocket/websocket_server.h
+++ b/modules/websocket/websocket_server.h
@@ -40,7 +40,7 @@ class WebSocketServer : public WebSocketMultiplayerPeer {
GDCLASS(WebSocketServer, WebSocketMultiplayerPeer);
GDCICLASS(WebSocketServer);
- IP_Address bind_ip;
+ IPAddress bind_ip;
protected:
static void _bind_methods();
@@ -57,7 +57,7 @@ public:
virtual bool is_server() const override;
ConnectionStatus get_connection_status() const override;
- virtual IP_Address get_peer_address(int p_peer_id) const = 0;
+ virtual IPAddress get_peer_address(int p_peer_id) const = 0;
virtual int get_peer_port(int p_peer_id) const = 0;
virtual void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") = 0;
@@ -66,8 +66,8 @@ public:
void _on_disconnect(int32_t p_peer_id, bool p_was_clean);
void _on_close_request(int32_t p_peer_id, int p_code, String p_reason);
- IP_Address get_bind_ip() const;
- void set_bind_ip(const IP_Address &p_bind_ip);
+ IPAddress get_bind_ip() const;
+ void set_bind_ip(const IPAddress &p_bind_ip);
Ref<CryptoKey> get_private_key() const;
void set_private_key(Ref<CryptoKey> p_key);
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index a075ae3982..111d2178d6 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -160,7 +160,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
ERR_FAIL_COND_V(_connection.is_valid(), ERR_ALREADY_IN_USE);
_peer = Ref<WSLPeer>(memnew(WSLPeer));
- IP_Address addr;
+ IPAddress addr;
if (!p_host.is_valid_ip_address()) {
addr = IP::get_singleton()->resolve_hostname(p_host);
@@ -316,8 +316,8 @@ void WSLClient::disconnect_from_host(int p_code, String p_reason) {
_resp_pos = 0;
}
-IP_Address WSLClient::get_connected_host() const {
- ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IP_Address());
+IPAddress WSLClient::get_connected_host() const {
+ ERR_FAIL_COND_V(!_peer->is_connected_to_host(), IPAddress());
return _peer->get_connected_host();
}
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index e7c91ed333..849639ee8b 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -75,7 +75,7 @@ public:
int get_max_packet_size() const;
Ref<WebSocketPeer> get_peer(int p_peer_id) const;
void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IP_Address get_connected_host() const;
+ IPAddress get_connected_host() const;
uint16_t get_connected_port() const;
virtual ConnectionStatus get_connection_status() const;
virtual void poll();
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index dbbf86d0da..1dbadfed74 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -305,8 +305,8 @@ void WSLPeer::close(int p_code, String p_reason) {
_packet_buffer.resize(0);
}
-IP_Address WSLPeer::get_connected_host() const {
- ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IP_Address());
+IPAddress WSLPeer::get_connected_host() const {
+ ERR_FAIL_COND_V(!is_connected_to_host() || _data->tcp.is_null(), IPAddress());
return _data->tcp->get_connected_host();
}
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index 5e6a7e8554..f1ea98d384 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -90,7 +90,7 @@ public:
virtual void close_now();
virtual void close(int p_code = 1000, String p_reason = "");
virtual bool is_connected_to_host() const;
- virtual IP_Address get_connected_host() const;
+ virtual IPAddress get_connected_host() const;
virtual uint16_t get_connected_port() const;
virtual WriteMode get_write_mode() const;
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index 437eb2061b..dc5b23c31e 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -272,8 +272,8 @@ Ref<WebSocketPeer> WSLServer::get_peer(int p_id) const {
return _peer_map[p_id];
}
-IP_Address WSLServer::get_peer_address(int p_peer_id) const {
- ERR_FAIL_COND_V(!has_peer(p_peer_id), IP_Address());
+IPAddress WSLServer::get_peer_address(int p_peer_id) const {
+ ERR_FAIL_COND_V(!has_peer(p_peer_id), IPAddress());
return _peer_map[p_peer_id]->get_connected_host();
}
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 75669e12ee..c2cf9df58b 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -73,7 +73,7 @@ private:
int _out_pkt_size = DEF_PKT_SHIFT;
List<Ref<PendingPeer>> _pending;
- Ref<TCP_Server> _server;
+ Ref<TCPServer> _server;
Vector<String> _protocols;
public:
@@ -84,7 +84,7 @@ public:
int get_max_packet_size() const;
bool has_peer(int p_id) const;
Ref<WebSocketPeer> get_peer(int p_id) const;
- IP_Address get_peer_address(int p_peer_id) const;
+ IPAddress get_peer_address(int p_peer_id) const;
int get_peer_port(int p_peer_id) const;
void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
virtual void poll();
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index e1f9521a48..8913ef1b65 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -29,26 +29,19 @@
/*************************************************************************/
#include "register_types.h"
-
-#include "core/error/error_macros.h"
-
#include "core/crypto/crypto_core.h"
-
#include "thirdparty/xatlas/xatlas.h"
-#include <stdio.h>
-#include <stdlib.h>
+extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y);
-extern bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
-
-bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uvs, int **r_vertices, int *r_vertex_count, int **r_indices, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache) {
+bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) {
CryptoCore::MD5Context ctx;
ctx.start();
ctx.update((unsigned char *)&p_texel_size, sizeof(float));
ctx.update((unsigned char *)p_indices, sizeof(int) * p_index_count);
- ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count);
- ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count);
+ ctx.update((unsigned char *)p_vertices, sizeof(float) * p_vertex_count * 3);
+ ctx.update((unsigned char *)p_normals, sizeof(float) * p_vertex_count * 3);
unsigned char hash[16];
ctx.finish(hash);
@@ -56,38 +49,37 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
bool cached = false;
unsigned int cache_idx = 0;
- if (r_used_cache && r_cache_size) {
- //Check if hash is in cache data
+ *r_mesh_cache = nullptr;
+ *r_mesh_cache_size = 0;
- int *cache_data = r_cache_data;
+ if (p_cache_data) {
+ //Check if hash is in cache data
+ int *cache_data = (int *)p_cache_data;
int n_entries = cache_data[0];
- unsigned int r_idx = 1;
+ unsigned int read_idx = 1;
for (int i = 0; i < n_entries; ++i) {
- if (memcmp(&cache_data[r_idx], hash, 16) == 0) {
+ if (memcmp(&cache_data[read_idx], hash, 16) == 0) {
cached = true;
- cache_idx = r_idx;
+ cache_idx = read_idx;
break;
}
- r_idx += 4; // hash
- r_idx += 2; // size hint
+ read_idx += 4; // hash
+ read_idx += 2; // size hint
- int vertex_count = cache_data[r_idx];
- r_idx += 1; // vertex count
- r_idx += vertex_count; // vertex
- r_idx += vertex_count * 2; // uvs
+ int vertex_count = cache_data[read_idx];
+ read_idx += 1; // vertex count
+ read_idx += vertex_count; // vertex
+ read_idx += vertex_count * 2; // uvs
- int index_count = cache_data[r_idx];
- r_idx += 1; // index count
- r_idx += index_count; // indices
+ int index_count = cache_data[read_idx];
+ read_idx += 1; // index count
+ read_idx += index_count; // indices
}
}
- if (r_used_cache && cached) {
- int *cache_data = r_cache_data;
-
- // Return cache data pointer to the caller
- r_cache_data = &cache_data[cache_idx];
+ if (cached) {
+ int *cache_data = (int *)p_cache_data;
cache_idx += 4;
@@ -99,96 +91,92 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
// Load vertices
*r_vertex_count = cache_data[cache_idx];
cache_idx++;
- *r_vertices = &cache_data[cache_idx];
+ *r_vertex = &cache_data[cache_idx];
cache_idx += *r_vertex_count;
// Load UVs
- *r_uvs = (float *)&cache_data[cache_idx];
+ *r_uv = (float *)&cache_data[cache_idx];
cache_idx += *r_vertex_count * 2;
// Load indices
*r_index_count = cache_data[cache_idx];
cache_idx++;
- *r_indices = &cache_data[cache_idx];
-
- // Return cache data size to the caller
- r_cache_size = sizeof(int) * (4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count); // hash + size hint + vertex_count + vertices + uvs + index_count + indices
- r_used_cache = true;
- return true;
- }
-
- //set up input mesh
- xatlas::MeshDecl input_mesh;
- input_mesh.indexData = p_indices;
- input_mesh.indexCount = p_index_count;
- input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
-
- input_mesh.vertexCount = p_vertex_count;
- input_mesh.vertexPositionData = p_vertices;
- input_mesh.vertexPositionStride = sizeof(float) * 3;
- input_mesh.vertexNormalData = p_normals;
- input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
- input_mesh.vertexUvData = nullptr;
- input_mesh.vertexUvStride = 0;
-
- xatlas::ChartOptions chart_options;
- xatlas::PackOptions pack_options;
-
- pack_options.maxChartSize = 4096;
- pack_options.blockAlign = true;
- pack_options.padding = 1;
- pack_options.texelsPerUnit = 1.0 / p_texel_size;
+ *r_index = &cache_data[cache_idx];
+ } else {
+ // set up input mesh
+ xatlas::MeshDecl input_mesh;
+ input_mesh.indexData = p_indices;
+ input_mesh.indexCount = p_index_count;
+ input_mesh.indexFormat = xatlas::IndexFormat::UInt32;
+
+ input_mesh.vertexCount = p_vertex_count;
+ input_mesh.vertexPositionData = p_vertices;
+ input_mesh.vertexPositionStride = sizeof(float) * 3;
+ input_mesh.vertexNormalData = p_normals;
+ input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
+ input_mesh.vertexUvData = NULL;
+ input_mesh.vertexUvStride = 0;
+
+ xatlas::ChartOptions chart_options;
+ chart_options.fixWinding = true;
+
+ xatlas::PackOptions pack_options;
+ pack_options.padding = 1;
+ pack_options.maxChartSize = 4094; // Lightmap atlassing needs 2 for padding between meshes, so 4096-2
+ pack_options.blockAlign = true;
+ pack_options.texelsPerUnit = 1.0 / p_texel_size;
+
+ xatlas::Atlas *atlas = xatlas::Create();
+
+ xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
+ ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
+
+ xatlas::Generate(atlas, chart_options, pack_options);
+
+ *r_size_hint_x = atlas->width;
+ *r_size_hint_y = atlas->height;
+
+ float w = *r_size_hint_x;
+ float h = *r_size_hint_y;
+
+ if (w == 0 || h == 0) {
+ xatlas::Destroy(atlas);
+ return false; //could not bake because there is no area
+ }
- xatlas::Atlas *atlas = xatlas::Create();
- printf("Adding mesh..\n");
- xatlas::AddMeshError err = xatlas::AddMesh(atlas, input_mesh, 1);
- ERR_FAIL_COND_V_MSG(err != xatlas::AddMeshError::Success, false, xatlas::StringForEnum(err));
+ const xatlas::Mesh &output = atlas->meshes[0];
+
+ *r_vertex = (int *)memalloc(sizeof(int) * output.vertexCount);
+ ERR_FAIL_NULL_V_MSG(*r_vertex, false, "Out of memory.");
+ *r_uv = (float *)memalloc(sizeof(float) * output.vertexCount * 2);
+ ERR_FAIL_NULL_V_MSG(*r_uv, false, "Out of memory.");
+ *r_index = (int *)memalloc(sizeof(int) * output.indexCount);
+ ERR_FAIL_NULL_V_MSG(*r_index, false, "Out of memory.");
+
+ float max_x = 0;
+ float max_y = 0;
+ for (uint32_t i = 0; i < output.vertexCount; i++) {
+ (*r_vertex)[i] = output.vertexArray[i].xref;
+ (*r_uv)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
+ (*r_uv)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
+ max_x = MAX(max_x, output.vertexArray[i].uv[0]);
+ max_y = MAX(max_y, output.vertexArray[i].uv[1]);
+ }
- printf("Generate..\n");
- xatlas::Generate(atlas, chart_options, pack_options);
+ *r_vertex_count = output.vertexCount;
- *r_size_hint_x = atlas->width;
- *r_size_hint_y = atlas->height;
+ for (uint32_t i = 0; i < output.indexCount; i++) {
+ (*r_index)[i] = output.indexArray[i];
+ }
- float w = *r_size_hint_x;
- float h = *r_size_hint_y;
+ *r_index_count = output.indexCount;
- if (w == 0 || h == 0) {
xatlas::Destroy(atlas);
- return false; //could not bake because there is no area
- }
-
- const xatlas::Mesh &output = atlas->meshes[0];
-
- *r_vertices = (int *)malloc(sizeof(int) * output.vertexCount);
- ERR_FAIL_NULL_V_MSG(*r_vertices, false, "Out of memory.");
- *r_uvs = (float *)malloc(sizeof(float) * output.vertexCount * 2);
- ERR_FAIL_NULL_V_MSG(*r_uvs, false, "Out of memory.");
- *r_indices = (int *)malloc(sizeof(int) * output.indexCount);
- ERR_FAIL_NULL_V_MSG(*r_indices, false, "Out of memory.");
-
- float max_x = 0.0;
- float max_y = 0.0;
- for (uint32_t i = 0; i < output.vertexCount; i++) {
- (*r_vertices)[i] = output.vertexArray[i].xref;
- (*r_uvs)[i * 2 + 0] = output.vertexArray[i].uv[0] / w;
- (*r_uvs)[i * 2 + 1] = output.vertexArray[i].uv[1] / h;
- max_x = MAX(max_x, output.vertexArray[i].uv[0]);
- max_y = MAX(max_y, output.vertexArray[i].uv[1]);
}
- printf("Final texture size: %f,%f - max %f,%f\n", w, h, max_x, max_y);
- *r_vertex_count = output.vertexCount;
+ if (*r_use_cache) {
+ // Build cache data for current mesh
- for (uint32_t i = 0; i < output.indexCount; i++) {
- (*r_indices)[i] = output.indexArray[i];
- }
-
- *r_index_count = output.indexCount;
-
- xatlas::Destroy(atlas);
-
- if (r_used_cache) {
unsigned int new_cache_size = 4 + 2 + 1 + *r_vertex_count + (*r_vertex_count * 2) + 1 + *r_index_count; // hash + size hint + vertex_count + vertices + uvs + index_count + indices
new_cache_size *= sizeof(int);
int *new_cache_data = (int *)memalloc(new_cache_size);
@@ -208,11 +196,11 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
new_cache_idx++;
// vertices
- memcpy(&new_cache_data[new_cache_idx], *r_vertices, sizeof(int) * *r_vertex_count);
+ memcpy(&new_cache_data[new_cache_idx], *r_vertex, sizeof(int) * (*r_vertex_count));
new_cache_idx += *r_vertex_count;
// uvs
- memcpy(&new_cache_data[new_cache_idx], *r_uvs, sizeof(float) * *r_vertex_count * 2);
+ memcpy(&new_cache_data[new_cache_idx], *r_uv, sizeof(float) * (*r_vertex_count) * 2);
new_cache_idx += *r_vertex_count * 2;
// index count
@@ -220,15 +208,15 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
new_cache_idx++;
// indices
- memcpy(&new_cache_data[new_cache_idx], *r_indices, sizeof(int) * *r_index_count);
- new_cache_idx += *r_index_count;
+ memcpy(&new_cache_data[new_cache_idx], *r_index, sizeof(int) * (*r_index_count));
// Return cache data to the caller
- r_cache_data = new_cache_data;
- r_cache_size = new_cache_size;
- r_used_cache = false;
+ *r_mesh_cache = (uint8_t *)new_cache_data;
+ *r_mesh_cache_size = new_cache_size;
}
+ *r_use_cache = cached; // Return whether cache was used.
+
return true;
}
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index dd001baba9..51cea39a43 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -778,7 +778,7 @@ void DisplayServerAndroid::process_double_tap(int event_android_button_mask, Poi
ev->set_pressed(event_button_mask != 0);
ev->set_button_index(_button_index_from_mask(event_button_mask));
ev->set_button_mask(event_button_mask);
- ev->set_doubleclick(true);
+ ev->set_double_click(true);
Input::get_singleton()->accumulate_input_event(ev);
}
diff --git a/platform/android/net_socket_android.cpp b/platform/android/net_socket_android.cpp
index ddc2368793..dbd1870ee6 100644
--- a/platform/android/net_socket_android.cpp
+++ b/platform/android/net_socket_android.cpp
@@ -103,7 +103,7 @@ Error NetSocketAndroid::set_broadcasting_enabled(bool p_enabled) {
return OK;
}
-Error NetSocketAndroid::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketAndroid::join_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
Error err = NetSocketPosix::join_multicast_group(p_multi_address, p_if_name);
if (err != OK)
return err;
@@ -115,7 +115,7 @@ Error NetSocketAndroid::join_multicast_group(const IP_Address &p_multi_address,
return OK;
}
-Error NetSocketAndroid::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) {
+Error NetSocketAndroid::leave_multicast_group(const IPAddress &p_multi_address, String p_if_name) {
Error err = NetSocketPosix::leave_multicast_group(p_multi_address, p_if_name);
if (err != OK)
return err;
diff --git a/platform/android/net_socket_android.h b/platform/android/net_socket_android.h
index cc2a68ac49..60090c26bb 100644
--- a/platform/android/net_socket_android.h
+++ b/platform/android/net_socket_android.h
@@ -67,8 +67,8 @@ public:
virtual void close();
virtual Error set_broadcasting_enabled(bool p_enabled);
- virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name);
- virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name);
+ virtual Error join_multicast_group(const IPAddress &p_multi_address, String p_if_name);
+ virtual Error leave_multicast_group(const IPAddress &p_multi_address, String p_if_name);
NetSocketAndroid() {}
~NetSocketAndroid();
diff --git a/platform/iphone/display_server_iphone.h b/platform/iphone/display_server_iphone.h
index 31a44723a5..7bf1557873 100644
--- a/platform/iphone/display_server_iphone.h
+++ b/platform/iphone/display_server_iphone.h
@@ -99,7 +99,7 @@ public:
// MARK: Touches
- void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
+ void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click);
void touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y);
void touches_cancelled(int p_idx);
diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm
index b590ce065c..a852bea207 100644
--- a/platform/iphone/display_server_iphone.mm
+++ b/platform/iphone/display_server_iphone.mm
@@ -222,7 +222,7 @@ void DisplayServerIPhone::_window_callback(const Callable &p_callable, const Var
// MARK: Touches
-void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick) {
+void DisplayServerIPhone::touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_double_click) {
if (!GLOBAL_DEF("debug/disable_touch", false)) {
Ref<InputEventScreenTouch> ev;
ev.instance();
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index 0031650360..234e42376d 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -215,14 +215,14 @@ EM_BOOL DisplayServerJavaScript::mouse_button_callback(int p_event_type, const E
display->last_click_ms = 0;
display->last_click_pos = Point2(-100, -100);
display->last_click_button_index = -1;
- ev->set_doubleclick(true);
+ ev->set_double_click(true);
}
} else {
display->last_click_button_index = ev->get_button_index();
}
- if (!ev->is_doubleclick()) {
+ if (!ev->is_double_click()) {
display->last_click_ms += diff;
display->last_click_pos = ev->get_position();
}
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 14e279b45b..951d86d09e 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -41,7 +41,7 @@
class EditorHTTPServer : public Reference {
private:
- Ref<TCP_Server> server;
+ Ref<TCPServer> server;
Map<String, String> mimes;
Ref<StreamPeerTCP> tcp;
Ref<StreamPeerSSL> ssl;
@@ -100,7 +100,7 @@ public:
_clear_client();
}
- Error listen(int p_port, IP_Address p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
+ Error listen(int p_port, IPAddress p_address, bool p_use_ssl, String p_ssl_key, String p_ssl_cert) {
use_ssl = p_use_ssl;
if (use_ssl) {
Ref<Crypto> crypto = Crypto::create();
@@ -919,7 +919,7 @@ Error EditorExportPlatformJavaScript::run(const Ref<EditorExportPreset> &p_prese
const uint16_t bind_port = EDITOR_GET("export/web/http_port");
// Resolve host if needed.
const String bind_host = EDITOR_GET("export/web/http_host");
- IP_Address bind_ip;
+ IPAddress bind_ip;
if (bind_host.is_valid_ip_address()) {
bind_ip = bind_host;
} else {
diff --git a/platform/javascript/http_client.h.inc b/platform/javascript/http_client.h.inc
index 842a93fcba..6544d41c98 100644
--- a/platform/javascript/http_client.h.inc
+++ b/platform/javascript/http_client.h.inc
@@ -34,7 +34,8 @@ Error make_request(Method p_method, const String &p_url, const Vector<String> &p
static void _parse_headers(int p_len, const char **p_headers, void *p_ref);
int js_id = 0;
-int read_limit = 4096;
+// 64 KiB by default (favors fast download speeds at the cost of memory usage).
+int read_limit = 65536;
Status status = STATUS_DISCONNECTED;
String host;
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index adbbcaac31..1876960c57 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -325,6 +325,10 @@ def configure(env):
if not env["builtin_pcre2"]:
env.ParseConfig("pkg-config libpcre2-32 --cflags --libs")
+ if not env["builtin_embree"]:
+ # No pkgconfig file so far, hardcode expected lib name.
+ env.Append(LIBS=["embree3"])
+
## Flags
if os.system("pkg-config --exists alsa") == 0: # 0 means found
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 8dc1b41702..12f030bd58 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -3162,14 +3162,14 @@ void DisplayServerX11::process_events() {
last_click_ms = 0;
last_click_pos = Point2i(-100, -100);
last_click_button_index = -1;
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
}
} else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) {
last_click_button_index = mb->get_button_index();
}
- if (!mb->is_doubleclick()) {
+ if (!mb->is_double_click()) {
last_click_ms += diff;
last_click_pos = Point2i(event.xbutton.x, event.xbutton.y);
}
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 61bb26c2a8..473ae95036 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -830,7 +830,7 @@ static void _mouseDownEvent(DisplayServer::WindowID window_id, NSEvent *event, i
mb->set_global_position(pos);
mb->set_button_mask(DS_OSX->last_button_state);
if (index == MOUSE_BUTTON_LEFT && pressed) {
- mb->set_doubleclick([event clickCount] == 2);
+ mb->set_double_click([event clickCount] == 2);
}
Input::get_singleton()->accumulate_input_event(mb);
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 33992069f9..2314a392cc 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -147,7 +147,7 @@ void OS_UWP::initialize_core() {
ticks_start = 0;
ticks_start = get_ticks_usec();
- IP_Unix::make_default();
+ IPUnix::make_default();
cursor_shape = CURSOR_ARROW;
}
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 8789e6dfb4..4b859da340 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2412,17 +2412,17 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_LBUTTONDBLCLK: {
mb->set_pressed(true);
mb->set_button_index(1);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
case WM_RBUTTONDBLCLK: {
mb->set_pressed(true);
mb->set_button_index(2);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
case WM_MBUTTONDBLCLK: {
mb->set_pressed(true);
mb->set_button_index(3);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
case WM_MOUSEWHEEL: {
mb->set_pressed(true);
@@ -2470,7 +2470,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mb->set_button_index(MOUSE_BUTTON_XBUTTON1);
else
mb->set_button_index(MOUSE_BUTTON_XBUTTON2);
- mb->set_doubleclick(true);
+ mb->set_double_click(true);
} break;
default: {
return 0;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 1e9cdd241d..f517190a89 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -204,7 +204,7 @@ void OS_Windows::initialize() {
current_pi.pi.hProcess = GetCurrentProcess();
process_map->insert(GetCurrentProcessId(), current_pi);
- IP_Unix::make_default();
+ IPUnix::make_default();
main_loop = nullptr;
}
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 4565543ec3..532a795b7c 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -1526,6 +1526,12 @@ Vector2 TileMap::map_to_world(const Vector2 &p_pos, bool p_ignore_ofs) const {
Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
Vector2 ret = get_cell_transform().affine_inverse().xform(p_pos);
+ // Account for precision errors on the border (GH-23250).
+ // 0.00005 is 5*CMP_EPSILON, results would start being unpredictable if
+ // cell size is > 15,000, but we can hardly have more precision anyway with
+ // floating point.
+ ret += Vector2(0.00005, 0.00005);
+
switch (half_offset) {
case HALF_OFFSET_X: {
if (int(floor(ret.y)) & 1) {
@@ -1552,11 +1558,6 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const {
}
}
- // Account for precision errors on the border (GH-23250).
- // 0.00005 is 5*CMP_EPSILON, results would start being unpredictable if
- // cell size is > 15,000, but we can hardly have more precision anyway with
- // floating point.
- ret += Vector2(0.00005, 0.00005);
return ret.floor();
}
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index e72709e847..ebefb2938f 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -107,7 +107,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> mb = p_event;
//Show color picker on double click.
- if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_doubleclick() && mb->is_pressed()) {
+ if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_double_click() && mb->is_pressed()) {
grabbed = _get_point_from_pos(mb->get_position().x);
_show_color_picker();
accept_event();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 86d070f9b1..4fddb4b661 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -600,7 +600,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
}
} else {
- if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
+ if (!mb->is_double_click() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
defer_select_single = i;
return;
}
@@ -622,7 +622,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
- } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
+ } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_double_click()) {
emit_signal("item_activated", i);
}
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 1aff5d5390..eb836b3bf7 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -260,15 +260,15 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} else {
if (selecting_enabled) {
- if (!b->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
// Triple-click select all.
selection.enabled = true;
selection.begin = 0;
selection.end = text.length();
- selection.doubleclick = true;
+ selection.double_click = true;
selection.last_dblclk = 0;
caret_column = selection.begin;
- } else if (b->is_doubleclick()) {
+ } else if (b->is_double_click()) {
// Double-click select word.
Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
for (int i = 0; i < words.size(); i++) {
@@ -276,7 +276,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
selection.enabled = true;
selection.begin = words[i].x;
selection.end = words[i].y;
- selection.doubleclick = true;
+ selection.double_click = true;
selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
caret_column = selection.end;
break;
@@ -308,11 +308,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- if ((!selection.creating) && (!selection.doubleclick)) {
+ if ((!selection.creating) && (!selection.double_click)) {
deselect();
}
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
show_virtual_keyboard();
}
@@ -1532,7 +1532,7 @@ void LineEdit::deselect() {
selection.start_column = 0;
selection.enabled = false;
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
update();
}
@@ -1659,7 +1659,7 @@ void LineEdit::select(int p_from, int p_to) {
selection.begin = p_from;
selection.end = p_to;
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
update();
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index f4f0ff0629..12fec2f98b 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -134,7 +134,7 @@ private:
int start_column = 0;
bool enabled = false;
bool creating = false;
- bool doubleclick = false;
+ bool double_click = false;
bool drag_attempt = false;
uint64_t last_dblclk = 0;
} selection;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index c763ae6bd6..e8a908c30e 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1482,7 +1482,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
if (b->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (b->is_pressed() && !b->is_doubleclick()) {
+ if (b->is_pressed() && !b->is_double_click()) {
scroll_updated = false;
ItemFrame *c_frame = nullptr;
int c_line = 0;
@@ -1514,8 +1514,8 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
}
}
}
- } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
- //doubleclick: select word
+ } else if (b->is_pressed() && b->is_double_click() && selection.enabled) {
+ //double_click: select word
ItemFrame *c_frame = nullptr;
int c_line = 0;
@@ -1549,7 +1549,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
} else if (!b->is_pressed()) {
selection.click_item = nullptr;
- if (!b->is_doubleclick() && !scroll_updated) {
+ if (!b->is_double_click() && !scroll_updated) {
Item *c_item = nullptr;
bool outside = true;
@@ -2612,6 +2612,14 @@ void RichTextLabel::pop() {
current = current->parent;
}
+// Creates a new line without adding an ItemNewline to the previous line.
+// Useful when wanting to calling remove_line and add a new line immediately after.
+void RichTextLabel::increment_line_count() {
+ _validate_line_caches(main);
+ current_frame->lines.resize(current_frame->lines.size() + 1);
+ _invalidate_current_line(current_frame);
+}
+
void RichTextLabel::clear() {
main->_clear_children();
current = main;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index e3e457d1f2..afc88e070a 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -483,6 +483,8 @@ public:
void push_cell();
void pop();
+ void increment_line_count();
+
void clear();
void set_offset(int p_pixel);
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 73c6371658..67dcf458b0 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -299,7 +299,7 @@ void ScrollContainer::_update_dimensions() {
child_max_size.x = MAX(child_max_size.x, minsize.x);
child_max_size.y = MAX(child_max_size.y, minsize.y);
- Rect2 r = Rect2(-scroll, minsize);
+ Rect2 r = Rect2(-Size2(get_h_scroll(), get_v_scroll()), minsize);
if (!scroll_h || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) {
r.position.x = 0;
if (c->get_h_size_flags() & SIZE_EXPAND) {
@@ -434,40 +434,16 @@ void ScrollContainer::update_scrollbars() {
Size2 min = child_max_size;
- bool hide_scroll_v = !scroll_v || min.height <= size.height;
- bool hide_scroll_h = !scroll_h || min.width <= size.width;
-
- v_scroll->set_max(min.height);
- if (hide_scroll_v) {
- v_scroll->set_page(size.height);
- v_scroll->hide();
- scroll.y = 0;
- } else {
- v_scroll->show();
- if (hide_scroll_h) {
- v_scroll->set_page(size.height);
- } else {
- v_scroll->set_page(size.height - hmin.height);
- }
-
- scroll.y = v_scroll->get_value();
- }
+ bool hide_scroll_h = !scroll_h || min.width <= size.width || !h_scroll_visible;
+ bool hide_scroll_v = !scroll_v || min.height <= size.height || !v_scroll_visible;
h_scroll->set_max(min.width);
- if (hide_scroll_h) {
- h_scroll->set_page(size.width);
- h_scroll->hide();
- scroll.x = 0;
- } else {
- h_scroll->show();
- if (hide_scroll_v) {
- h_scroll->set_page(size.width);
- } else {
- h_scroll->set_page(size.width - vmin.width);
- }
+ h_scroll->set_page(size.width - (hide_scroll_v ? 0 : vmin.width));
+ h_scroll->set_visible(!hide_scroll_h);
- scroll.x = h_scroll->get_value();
- }
+ v_scroll->set_max(min.height);
+ v_scroll->set_page(size.height - (hide_scroll_h ? 0 : hmin.height));
+ v_scroll->set_visible(!hide_scroll_v);
// Avoid scrollbar overlapping.
h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, hide_scroll_v ? 0 : -vmin.width);
@@ -475,13 +451,28 @@ void ScrollContainer::update_scrollbars() {
}
void ScrollContainer::_scroll_moved(float) {
- scroll.x = h_scroll->get_value();
- scroll.y = v_scroll->get_value();
queue_sort();
-
update();
};
+void ScrollContainer::set_h_scroll(int p_pos) {
+ h_scroll->set_value(p_pos);
+ _cancel_drag();
+}
+
+int ScrollContainer::get_h_scroll() const {
+ return h_scroll->get_value();
+}
+
+void ScrollContainer::set_v_scroll(int p_pos) {
+ v_scroll->set_value(p_pos);
+ _cancel_drag();
+}
+
+int ScrollContainer::get_v_scroll() const {
+ return v_scroll->get_value();
+}
+
void ScrollContainer::set_enable_h_scroll(bool p_enable) {
if (scroll_h == p_enable) {
return;
@@ -510,22 +501,30 @@ bool ScrollContainer::is_v_scroll_enabled() const {
return scroll_v;
}
-int ScrollContainer::get_v_scroll() const {
- return v_scroll->get_value();
+void ScrollContainer::set_h_scroll_visible(bool p_visible) {
+ if (h_scroll_visible == p_visible) {
+ return;
+ }
+
+ h_scroll_visible = p_visible;
+ update_scrollbars();
}
-void ScrollContainer::set_v_scroll(int p_pos) {
- v_scroll->set_value(p_pos);
- _cancel_drag();
+bool ScrollContainer::is_h_scroll_visible() const {
+ return h_scroll_visible;
}
-int ScrollContainer::get_h_scroll() const {
- return h_scroll->get_value();
+void ScrollContainer::set_v_scroll_visible(bool p_visible) {
+ if (v_scroll_visible == p_visible) {
+ return;
+ }
+
+ v_scroll_visible = p_visible;
+ update_scrollbars();
}
-void ScrollContainer::set_h_scroll(int p_pos) {
- h_scroll->set_value(p_pos);
- _cancel_drag();
+bool ScrollContainer::is_v_scroll_visible() const {
+ return v_scroll_visible;
}
int ScrollContainer::get_deadzone() const {
@@ -581,17 +580,29 @@ VScrollBar *ScrollContainer::get_v_scrollbar() {
void ScrollContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &ScrollContainer::_gui_input);
- ClassDB::bind_method(D_METHOD("set_enable_h_scroll", "enable"), &ScrollContainer::set_enable_h_scroll);
- ClassDB::bind_method(D_METHOD("is_h_scroll_enabled"), &ScrollContainer::is_h_scroll_enabled);
- ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
- ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
+
ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
+
ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);
ClassDB::bind_method(D_METHOD("get_v_scroll"), &ScrollContainer::get_v_scroll);
+
+ ClassDB::bind_method(D_METHOD("set_enable_h_scroll", "enable"), &ScrollContainer::set_enable_h_scroll);
+ ClassDB::bind_method(D_METHOD("is_h_scroll_enabled"), &ScrollContainer::is_h_scroll_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
+ ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_h_scroll_visible", "visible"), &ScrollContainer::set_h_scroll_visible);
+ ClassDB::bind_method(D_METHOD("is_h_scroll_visible"), &ScrollContainer::is_h_scroll_visible);
+
+ ClassDB::bind_method(D_METHOD("set_v_scroll_visible", "visible"), &ScrollContainer::set_v_scroll_visible);
+ ClassDB::bind_method(D_METHOD("is_v_scroll_visible"), &ScrollContainer::is_v_scroll_visible);
+
ClassDB::bind_method(D_METHOD("set_deadzone", "deadzone"), &ScrollContainer::set_deadzone);
ClassDB::bind_method(D_METHOD("get_deadzone"), &ScrollContainer::get_deadzone);
+
ClassDB::bind_method(D_METHOD("set_follow_focus", "enabled"), &ScrollContainer::set_follow_focus);
ClassDB::bind_method(D_METHOD("is_following_focus"), &ScrollContainer::is_following_focus);
@@ -604,10 +615,12 @@ void ScrollContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_focus"), "set_follow_focus", "is_following_focus");
ADD_GROUP("Scroll", "scroll_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_visible"), "set_h_scroll_visible", "is_h_scroll_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_visible"), "set_v_scroll_visible", "is_v_scroll_visible");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone");
GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index e7d73bab0a..f61df70b85 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -42,7 +42,6 @@ class ScrollContainer : public Container {
VScrollBar *v_scroll;
Size2 child_max_size;
- Size2 scroll;
void update_scrollbars();
@@ -50,16 +49,17 @@ class ScrollContainer : public Container {
Vector2 drag_accum;
Vector2 drag_from;
Vector2 last_drag_accum;
- float last_drag_time = 0.0;
- float time_since_motion = 0.0;
+ float time_since_motion = 0.0f;
bool drag_touching = false;
bool drag_touching_deaccel = false;
- bool click_handled = false;
bool beyond_deadzone = false;
bool scroll_h = true;
bool scroll_v = true;
+ bool h_scroll_visible = true;
+ bool v_scroll_visible = true;
+
int deadzone = 0;
bool follow_focus = false;
@@ -80,11 +80,11 @@ protected:
void _ensure_focused_visible(Control *p_node);
public:
- int get_v_scroll() const;
- void set_v_scroll(int p_pos);
-
- int get_h_scroll() const;
void set_h_scroll(int p_pos);
+ int get_h_scroll() const;
+
+ void set_v_scroll(int p_pos);
+ int get_v_scroll() const;
void set_enable_h_scroll(bool p_enable);
bool is_h_scroll_enabled() const;
@@ -92,6 +92,12 @@ public:
void set_enable_v_scroll(bool p_enable);
bool is_v_scroll_enabled() const;
+ void set_h_scroll_visible(bool p_visible);
+ bool is_h_scroll_visible() const;
+
+ void set_v_scroll_visible(bool p_visible);
+ bool is_v_scroll_visible() const;
+
int get_deadzone() const;
void set_deadzone(int p_deadzone);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 4f508423b3..ded912591f 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -2054,6 +2054,7 @@ void TextEdit::indent_selected_lines_left() {
if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
+ String first_line_text = get_line(start_line);
String last_line_text = get_line(end_line);
for (int i = start_line; i <= end_line; i++) {
@@ -2078,10 +2079,17 @@ void TextEdit::indent_selected_lines_left() {
}
}
- // Fix selection and cursor being off by one on the last line.
- if (is_selection_active() && last_line_text != get_line(end_line)) {
- select(selection.from_line, selection.from_column - removed_characters,
- selection.to_line, initial_selection_end_column - removed_characters);
+ if (is_selection_active()) {
+ // Fix selection being off by one on the first line.
+ if (first_line_text != get_line(start_line)) {
+ select(selection.from_line, selection.from_column - removed_characters,
+ selection.to_line, initial_selection_end_column);
+ }
+ // Fix selection being off by one on the last line.
+ if (last_line_text != get_line(end_line)) {
+ select(selection.from_line, selection.from_column,
+ selection.to_line, initial_selection_end_column - removed_characters);
+ }
}
cursor_set_column(initial_cursor_column - removed_characters, false);
end_complex_operation();
@@ -2895,7 +2903,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
completion_current = completion_options[completion_index];
update();
- if (mb->is_doubleclick()) {
+ if (mb->is_double_click()) {
_confirm_completion();
}
}
@@ -3018,12 +3026,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
selection.selecting_column = col;
}
- if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
+ if (!mb->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) {
// Triple-click select line.
selection.selecting_mode = SelectionMode::SELECTION_MODE_LINE;
_update_selection_mode_line();
last_dblclk = 0;
- } else if (mb->is_doubleclick() && text[cursor.line].length()) {
+ } else if (mb->is_double_click() && text[cursor.line].length()) {
// Double-click select word.
selection.selecting_mode = SelectionMode::SELECTION_MODE_WORD;
_update_selection_mode_word();
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 73fd9dbcd7..d10ce584b7 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -1388,7 +1388,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
- if ((select_mode == SELECT_ROW && selected_item == p_item) || p_item->cells[i].selected) {
+ if ((select_mode == SELECT_ROW && selected_item == p_item) || p_item->cells[i].selected || !p_item->has_meta("__focus_rect")) {
Rect2i r(cell_rect.position, cell_rect.size);
p_item->set_meta("__focus_rect", Rect2(r.position, r.size));
@@ -1672,7 +1672,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
float line_width = 1.0;
#ifdef TOOLS_ENABLED
- line_width *= EDSCALE;
+ line_width *= Math::round(EDSCALE);
#endif
Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
@@ -1866,7 +1866,7 @@ void Tree::_range_click_timeout() {
}
}
-int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod) {
+int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod) {
int item_h = compute_item_height(p_item) + cache.vseparation;
bool skip = (p_item == root && hide_root);
@@ -1963,7 +1963,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
if (p_button == MOUSE_BUTTON_LEFT || (p_button == MOUSE_BUTTON_RIGHT && allow_rmb_select)) {
/* process selection */
- if (p_doubleclick && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check
+ if (p_double_click && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check
propagate_mouse_activated = true;
@@ -2167,7 +2167,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
TreeItem *c = p_item->children;
while (c) {
- int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_doubleclick, c, p_button, p_mod);
+ int child_h = propagate_mouse_event(new_pos, x_ofs, y_ofs, p_double_click, c, p_button, p_mod);
if (child_h < 0) {
return -1; // break, stop propagating, no need to anymore
@@ -2846,7 +2846,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
propagate_mouse_activated = false;
blocked++;
- propagate_mouse_event(pos + cache.offset, 0, 0, b->is_doubleclick(), root, b->get_button_index(), b);
+ propagate_mouse_event(pos + cache.offset, 0, 0, b->is_double_click(), root, b->get_button_index(), b);
blocked--;
if (pressing_for_editor) {
@@ -3013,6 +3013,10 @@ bool Tree::edit_selected() {
return false;
}
+bool Tree::is_editing() {
+ return popup_editor->is_visible();
+}
+
Size2 Tree::get_internal_min_size() const {
Size2i size = cache.bg->get_offset();
if (root) {
@@ -4262,7 +4266,7 @@ void Tree::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_custom_button_pressed"));
ADD_SIGNAL(MethodInfo("item_double_clicked"));
ADD_SIGNAL(MethodInfo("item_collapsed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem")));
- //ADD_SIGNAL( MethodInfo("item_doubleclicked" ) );
+ //ADD_SIGNAL( MethodInfo("item_double_clicked" ) );
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::OBJECT, "item", PROPERTY_HINT_RESOURCE_TYPE, "TreeItem"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("custom_popup_edited", PropertyInfo(Variant::BOOL, "arrow_clicked")));
ADD_SIGNAL(MethodInfo("item_activated"));
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index d1407e24d4..6d36f0df7f 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -390,7 +390,7 @@ private:
void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color);
int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item);
void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false);
- int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod);
+ int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_double_click, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod);
void _text_editor_enter(String p_text);
void _text_editor_modal_close();
void value_editor_changed(double p_value);
@@ -604,6 +604,7 @@ public:
int get_item_offset(TreeItem *p_item) const;
Rect2 get_item_rect(TreeItem *p_item, int p_column = -1) const;
bool edit_selected();
+ bool is_editing();
// First item that starts with the text, from the current focused item down and wraps around.
TreeItem *search_item_text(const String &p_find, int *r_col = nullptr, bool p_selectable = false);
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 55529517f1..fa98a10a26 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -1210,7 +1210,7 @@ void CanvasItem::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_light_mask", "get_light_mask");
ADD_GROUP("Texture", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Inherit,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Inherit,Disabled,Enabled,Mirror"), "set_texture_repeat", "get_texture_repeat");
ADD_GROUP("Material", "");
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 90f556cf1b..b94a818b06 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1840,6 +1840,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = nullptr;
Point2 mpos = mb->get_position();
+ gui.last_mouse_pos = mpos;
if (mb->is_pressed()) {
Size2 pos = mpos;
if (gui.mouse_focus_mask) {
@@ -3607,7 +3608,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
ADD_GROUP("Audio Listener", "audio_listener_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_2d"), "set_as_audio_listener_2d", "is_audio_listener_2d");
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index e8157c7165..86c7bda2b3 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -2519,7 +2519,7 @@ void BaseMaterial3D::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "uv2_world_triplanar"), "set_flag", "get_flag", FLAG_UV2_USE_WORLD_TRIPLANAR);
ADD_GROUP("Sampling", "texture_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapNearest,MipmapLinear,MipmapNearestAniso,MipmapLinearAniso"), "set_texture_filter", "get_texture_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Aniso.,Linear Mipmap Aniso."), "set_texture_filter", "get_texture_filter");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "texture_repeat"), "set_flag", "get_flag", FLAG_USE_TEXTURE_REPEAT);
ADD_GROUP("Shadows", "");
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index d31dbc877b..33ad15b938 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -1401,7 +1401,7 @@ void ArrayMesh::regen_normal_maps() {
}
//dirty hack
-bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y, int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache);
+bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_vertices, const float *p_normals, int p_vertex_count, const int *p_indices, int p_index_count, const uint8_t *p_cache_data, bool *r_use_cache, uint8_t **r_mesh_cache, int *r_mesh_cache_size, float **r_uv, int **r_vertex, int *r_vertex_count, int **r_index, int *r_index_count, int *r_size_hint_x, int *r_size_hint_y) = NULL;
struct ArrayMeshLightmapSurface {
Ref<Material> material;
@@ -1411,28 +1411,28 @@ struct ArrayMeshLightmapSurface {
};
Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) {
- int *cache_data = nullptr;
- unsigned int cache_size = 0;
- bool use_cache = false; // Don't use cache
- return lightmap_unwrap_cached(cache_data, cache_size, use_cache, p_base_transform, p_texel_size);
+ Vector<uint8_t> null_cache;
+ return lightmap_unwrap_cached(p_base_transform, p_texel_size, null_cache, null_cache, false);
}
-Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform, float p_texel_size) {
+Error ArrayMesh::lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
- Vector<float> vertices;
- Vector<float> normals;
- Vector<int> indices;
- Vector<float> uv;
- Vector<Pair<int, int>> uv_indices;
+ LocalVector<float> vertices;
+ LocalVector<float> normals;
+ LocalVector<int> indices;
+ LocalVector<float> uv;
+ LocalVector<Pair<int, int>> uv_indices;
Vector<ArrayMeshLightmapSurface> lightmap_surfaces;
// Keep only the scale
- Transform transform = p_base_transform;
- transform.origin = Vector3();
- transform.looking_at(Vector3(1, 0, 0), Vector3(0, 1, 0));
+ Basis basis = p_base_transform.get_basis();
+ Vector3 scale = Vector3(basis.get_axis(0).length(), basis.get_axis(1).length(), basis.get_axis(2).length());
+
+ Transform transform;
+ transform.scale(scale);
Basis normal_basis = transform.basis.inverse().transposed();
@@ -1446,14 +1446,12 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
Array arrays = surface_get_arrays(i);
s.material = surface_get_material(i);
- SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices);
+ SurfaceTool::create_vertex_array_from_triangle_arrays(arrays, s.vertices, &s.format);
- Vector<Vector3> rvertices = arrays[Mesh::ARRAY_VERTEX];
+ PackedVector3Array rvertices = arrays[Mesh::ARRAY_VERTEX];
int vc = rvertices.size();
- const Vector3 *r = rvertices.ptr();
- Vector<Vector3> rnormals = arrays[Mesh::ARRAY_NORMAL];
- const Vector3 *rn = rnormals.ptr();
+ PackedVector3Array rnormals = arrays[Mesh::ARRAY_NORMAL];
int vertex_ofs = vertices.size() / 3;
@@ -1462,24 +1460,29 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
uv_indices.resize(vertex_ofs + vc);
for (int j = 0; j < vc; j++) {
- Vector3 v = transform.xform(r[j]);
- Vector3 n = normal_basis.xform(rn[j]).normalized();
-
- vertices.write[(j + vertex_ofs) * 3 + 0] = v.x;
- vertices.write[(j + vertex_ofs) * 3 + 1] = v.y;
- vertices.write[(j + vertex_ofs) * 3 + 2] = v.z;
- normals.write[(j + vertex_ofs) * 3 + 0] = n.x;
- normals.write[(j + vertex_ofs) * 3 + 1] = n.y;
- normals.write[(j + vertex_ofs) * 3 + 2] = n.z;
- uv_indices.write[j + vertex_ofs] = Pair<int, int>(i, j);
+ Vector3 v = transform.xform(rvertices[j]);
+ Vector3 n = normal_basis.xform(rnormals[j]).normalized();
+
+ vertices[(j + vertex_ofs) * 3 + 0] = v.x;
+ vertices[(j + vertex_ofs) * 3 + 1] = v.y;
+ vertices[(j + vertex_ofs) * 3 + 2] = v.z;
+ normals[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals[(j + vertex_ofs) * 3 + 2] = n.z;
+ uv_indices[j + vertex_ofs] = Pair<int, int>(i, j);
}
- Vector<int> rindices = arrays[Mesh::ARRAY_INDEX];
+ PackedInt32Array rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size();
+ float eps = 1.19209290e-7F; // Taken from xatlas.h
if (ic == 0) {
for (int j = 0; j < vc / 3; j++) {
- if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[j * 3 + 0]);
+ Vector3 p1 = transform.xform(rvertices[j * 3 + 1]);
+ Vector3 p2 = transform.xform(rvertices[j * 3 + 2]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
@@ -1489,15 +1492,18 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
}
} else {
- const int *ri = rindices.ptr();
-
for (int j = 0; j < ic / 3; j++) {
- if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate()) {
+ Vector3 p0 = transform.xform(rvertices[rindices[j * 3 + 0]]);
+ Vector3 p1 = transform.xform(rvertices[rindices[j * 3 + 1]]);
+ Vector3 p2 = transform.xform(rvertices[rindices[j * 3 + 2]]);
+
+ if ((p0 - p1).length_squared() < eps || (p1 - p2).length_squared() < eps || (p2 - p0).length_squared() < eps) {
continue;
}
- indices.push_back(vertex_ofs + ri[j * 3 + 0]);
- indices.push_back(vertex_ofs + ri[j * 3 + 1]);
- indices.push_back(vertex_ofs + ri[j * 3 + 2]);
+
+ indices.push_back(vertex_ofs + rindices[j * 3 + 0]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 1]);
+ indices.push_back(vertex_ofs + rindices[j * 3 + 2]);
}
}
@@ -1506,6 +1512,9 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
//unwrap
+ bool use_cache = p_generate_cache; // Used to request cache generation and to know if cache was used
+ uint8_t *gen_cache;
+ int gen_cache_size;
float *gen_uvs;
int *gen_vertices;
int *gen_indices;
@@ -1514,17 +1523,16 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
int size_x;
int size_y;
- bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y, r_cache_data, r_cache_size, r_used_cache);
+ bool ok = array_mesh_lightmap_unwrap_callback(p_texel_size, vertices.ptr(), normals.ptr(), vertices.size() / 3, indices.ptr(), indices.size(), p_src_cache.ptr(), &use_cache, &gen_cache, &gen_cache_size, &gen_uvs, &gen_vertices, &gen_vertex_count, &gen_indices, &gen_index_count, &size_x, &size_y);
if (!ok) {
return ERR_CANT_CREATE;
}
- //remove surfaces
clear_surfaces();
//create surfacetools for each surface..
- Vector<Ref<SurfaceTool>> surfaces_tools;
+ LocalVector<Ref<SurfaceTool>> surfaces_tools;
for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st;
@@ -1535,11 +1543,12 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
}
print_verbose("Mesh: Gen indices: " + itos(gen_index_count));
+
//go through all indices
for (int i = 0; i < gen_index_count; i += 3) {
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], uv_indices.size(), ERR_BUG);
- ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 0]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 1]], (int)uv_indices.size(), ERR_BUG);
+ ERR_FAIL_INDEX_V(gen_vertices[gen_indices[i + 2]], (int)uv_indices.size(), ERR_BUG);
ERR_FAIL_COND_V(uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 1]]].first || uv_indices[gen_vertices[gen_indices[i + 0]]].first != uv_indices[gen_vertices[gen_indices[i + 2]]].first, ERR_BUG);
@@ -1549,48 +1558,53 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach
SurfaceTool::Vertex v = lightmap_surfaces[surface].vertices[uv_indices[gen_vertices[gen_indices[i + j]]].second];
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_COLOR) {
- surfaces_tools.write[surface]->set_color(v.color);
+ surfaces_tools[surface]->set_color(v.color);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TEX_UV) {
- surfaces_tools.write[surface]->set_uv(v.uv);
+ surfaces_tools[surface]->set_uv(v.uv);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_NORMAL) {
- surfaces_tools.write[surface]->set_normal(v.normal);
+ surfaces_tools[surface]->set_normal(v.normal);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_TANGENT) {
Plane t;
t.normal = v.tangent;
t.d = v.binormal.dot(v.normal.cross(v.tangent)) < 0 ? -1 : 1;
- surfaces_tools.write[surface]->set_tangent(t);
+ surfaces_tools[surface]->set_tangent(t);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_BONES) {
- surfaces_tools.write[surface]->set_bones(v.bones);
+ surfaces_tools[surface]->set_bones(v.bones);
}
if (lightmap_surfaces[surface].format & ARRAY_FORMAT_WEIGHTS) {
- surfaces_tools.write[surface]->set_weights(v.weights);
+ surfaces_tools[surface]->set_weights(v.weights);
}
Vector2 uv2(gen_uvs[gen_indices[i + j] * 2 + 0], gen_uvs[gen_indices[i + j] * 2 + 1]);
- surfaces_tools.write[surface]->set_uv2(uv2);
+ surfaces_tools[surface]->set_uv2(uv2);
- surfaces_tools.write[surface]->add_vertex(v.vertex);
+ surfaces_tools[surface]->add_vertex(v.vertex);
}
}
//generate surfaces
-
- for (int i = 0; i < surfaces_tools.size(); i++) {
- surfaces_tools.write[i]->index();
- surfaces_tools.write[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), lightmap_surfaces[i].format);
+ for (unsigned int i = 0; i < surfaces_tools.size(); i++) {
+ surfaces_tools[i]->index();
+ surfaces_tools[i]->commit(Ref<ArrayMesh>((ArrayMesh *)this), lightmap_surfaces[i].format);
}
set_lightmap_size_hint(Size2(size_x, size_y));
- if (!r_used_cache) {
- //free stuff
- ::free(gen_vertices);
- ::free(gen_indices);
- ::free(gen_uvs);
+ if (gen_cache_size > 0) {
+ r_dst_cache.resize(gen_cache_size);
+ memcpy(r_dst_cache.ptrw(), gen_cache, gen_cache_size);
+ memfree(gen_cache);
+ }
+
+ if (!use_cache) {
+ // Cache was not used, free the buffers
+ memfree(gen_vertices);
+ memfree(gen_indices);
+ memfree(gen_uvs);
}
return OK;
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 13019c691d..aa830d7b50 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -263,7 +263,7 @@ public:
void regen_normal_maps();
Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05);
- Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform = Transform(), float p_texel_size = 0.05);
+ Error lightmap_unwrap_cached(const Transform &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache, bool p_generate_cache = true);
virtual void reload_from_file() override;
diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp
index d65b0c8927..31df35aa51 100644
--- a/scene/resources/physics_material.cpp
+++ b/scene/resources/physics_material.cpp
@@ -43,9 +43,9 @@ void PhysicsMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_absorbent", "absorbent"), &PhysicsMaterial::set_absorbent);
ClassDB::bind_method(D_METHOD("is_absorbent"), &PhysicsMaterial::is_absorbent);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "friction", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rough"), "set_rough", "is_rough");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_bounce", "get_bounce");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "absorbent"), "set_absorbent", "is_absorbent");
}
diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp
index 5761a405ce..cb44e059a3 100644
--- a/scene/resources/shape_3d.cpp
+++ b/scene/resources/shape_3d.cpp
@@ -102,6 +102,8 @@ void Shape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_margin", "margin"), &Shape3D::set_margin);
ClassDB::bind_method(D_METHOD("get_margin"), &Shape3D::get_margin);
+ ClassDB::bind_method(D_METHOD("get_debug_mesh"), &Shape3D::get_debug_mesh);
+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin");
}
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 21ad57e344..eb9fc0e800 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -40,31 +40,48 @@ bool AreaPair2DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
if (result != colliding) {
- if (result) {
- if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->add_area(area);
- }
- if (area->has_monitor_callback()) {
- area->add_body_to_query(body, body_shape, area_shape);
- }
-
- } else {
- if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->remove_area(area);
- }
- if (area->has_monitor_callback()) {
- area->remove_body_from_query(body, body_shape, area_shape);
- }
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ process_collision = true;
+ } else if (area->has_monitor_callback()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool AreaPair2DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ body->add_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->add_body_to_query(body, body_shape, area_shape);
+ }
+ } else {
+ if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) {
+ body->remove_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void AreaPair2DSW::solve(real_t p_step) {
+ // Nothing to do.
}
AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape) {
@@ -72,7 +89,6 @@ AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area,
area = p_area;
body_shape = p_body_shape;
area_shape = p_area_shape;
- colliding = false;
body->add_constraint(this, 0);
area->add_constraint(this);
if (p_body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) { //need to be active to process pair
@@ -103,33 +119,48 @@ bool Area2Pair2DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
if (result != colliding) {
- if (result) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- area_b->add_area_to_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->add_area_to_query(area_b, shape_b, shape_a);
- }
-
- } else {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ process_collision = true;
+ } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool Area2Pair2DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ area_b->add_area_to_query(area_a, shape_a, shape_b);
+ }
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ area_a->add_area_to_query(area_b, shape_b, shape_a);
+ }
+ } else {
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+ }
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void Area2Pair2DSW::solve(real_t p_step) {
+ // Nothing to do.
}
Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b) {
@@ -137,7 +168,6 @@ Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area
area_b = p_area_b;
shape_a = p_shape_a;
shape_b = p_shape_b;
- colliding = false;
area_a->add_constraint(this);
area_b->add_constraint(this);
}
diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h
index 4015aad5d1..4632a307d9 100644
--- a/servers/physics_2d/area_pair_2d_sw.h
+++ b/servers/physics_2d/area_pair_2d_sw.h
@@ -36,30 +36,34 @@
#include "constraint_2d_sw.h"
class AreaPair2DSW : public Constraint2DSW {
- Body2DSW *body;
- Area2DSW *area;
- int body_shape;
- int area_shape;
- bool colliding;
+ Body2DSW *body = nullptr;
+ Area2DSW *area = nullptr;
+ int body_shape = 0;
+ int area_shape = 0;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape);
~AreaPair2DSW();
};
class Area2Pair2DSW : public Constraint2DSW {
- Area2DSW *area_a;
- Area2DSW *area_b;
- int shape_a;
- int shape_b;
- bool colliding;
+ Area2DSW *area_a = nullptr;
+ Area2DSW *area_b = nullptr;
+ int shape_a = 0;
+ int shape_b = 0;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b);
~Area2Pair2DSW();
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 9306fea70c..f78a487e27 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -104,31 +104,17 @@ void Body2DSW::set_active(bool p_active) {
}
active = p_active;
- if (!p_active) {
- if (get_space()) {
- get_space()->body_remove_from_active_list(&active_list);
- }
- } else {
+
+ if (active) {
if (mode == PhysicsServer2D::BODY_MODE_STATIC) {
- return; //static bodies can't become active
- }
- if (get_space()) {
+ // Static bodies can't be active.
+ active = false;
+ } else if (get_space()) {
get_space()->body_add_to_active_list(&active_list);
}
-
- //still_time=0;
- }
- /*
- if (!space)
- return;
-
- for(int i=0;i<get_shape_count();i++) {
- Shape &s=shapes[i];
- if (s.bpid>0) {
- get_space()->get_broadphase()->set_active(s.bpid,active);
- }
+ } else if (get_space()) {
+ get_space()->body_remove_from_active_list(&active_list);
}
-*/
}
void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) {
@@ -370,13 +356,6 @@ void Body2DSW::set_space(Space2DSW *p_space) {
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
- /*
- _update_queries();
- if (is_active()) {
- active=false;
- set_active(true);
- }
- */
}
first_integration = false;
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index da70ac7d4b..ff31825b83 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -87,10 +87,13 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto
int least_deep = -1;
real_t min_depth = 1e10;
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i <= contact_count; i++) {
Contact &c = (i == contact_count) ? contact : contacts[i];
- Vector2 global_A = A->get_transform().basis_xform(c.local_A);
- Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B;
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
Vector2 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
@@ -124,6 +127,9 @@ void BodyPair2DSW::_validate_contacts() {
real_t max_separation = space->get_contact_max_separation();
real_t max_separation2 = max_separation * max_separation;
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
@@ -134,8 +140,8 @@ void BodyPair2DSW::_validate_contacts() {
} else {
c.reused = false;
- Vector2 global_A = A->get_transform().basis_xform(c.local_A);
- Vector2 global_B = B->get_transform().basis_xform(c.local_B) + offset_B;
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
Vector2 axis = global_A - global_B;
real_t depth = axis.dot(c.normal);
@@ -220,14 +226,16 @@ real_t combine_friction(Body2DSW *A, Body2DSW *B) {
}
bool BodyPair2DSW::setup(real_t p_step) {
- //cannot collide
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
- bool report_contacts_only = false;
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ report_contacts_only = false;
+ if (!dynamic_A && !dynamic_B) {
if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
report_contacts_only = true;
} else {
@@ -246,12 +254,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
_validate_contacts();
- Vector2 offset_A = A->get_transform().get_origin();
+ const Vector2 &offset_A = A->get_transform().get_origin();
Transform2D xform_Au = A->get_transform().untranslated();
Transform2D xform_A = xform_Au * A->get_shape_transform(shape_A);
Transform2D xform_Bu = B->get_transform();
- xform_Bu.elements[2] -= A->get_transform().get_origin();
+ xform_Bu.elements[2] -= offset_A;
Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B);
Shape2DSW *shape_A_ptr = A->get_shape(shape_A);
@@ -272,13 +280,13 @@ bool BodyPair2DSW::setup(real_t p_step) {
if (!collided) {
//test ccd (currently just a raycast)
- if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ if (A->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && dynamic_A) {
if (_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B)) {
collided = true;
}
}
- if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ if (B->get_continuous_collision_detection_mode() == PhysicsServer2D::CCD_MODE_CAST_RAY && dynamic_B) {
if (_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A, true)) {
collided = true;
}
@@ -338,9 +346,21 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
+ return true;
+}
+
+bool BodyPair2DSW::pre_solve(real_t p_step) {
+ if (!collided || oneway_disabled) {
+ return false;
+ }
+
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = 0.3;
+
+ Shape2DSW *shape_A_ptr = A->get_shape(shape_A);
+ Shape2DSW *shape_B_ptr = B->get_shape(shape_B);
+
if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) {
if (shape_A_ptr->get_custom_bias() == 0) {
bias = shape_B_ptr->get_custom_bias();
@@ -351,21 +371,23 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
}
- cc = 0;
-
real_t inv_dt = 1.0 / p_step;
bool do_process = false;
+ const Vector2 &offset_A = A->get_transform().get_origin();
+ const Transform2D &transform_A = A->get_transform();
+ const Transform2D &transform_B = B->get_transform();
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
-
c.active = false;
- Vector2 global_A = xform_Au.xform(c.local_A);
- Vector2 global_B = xform_Bu.xform(c.local_B);
+ Vector2 global_A = transform_A.basis_xform(c.local_A);
+ Vector2 global_B = transform_B.basis_xform(c.local_B) + offset_B;
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector2 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
if (depth <= 0 || !c.reused) {
continue;
@@ -396,8 +418,6 @@ bool BodyPair2DSW::setup(real_t p_step) {
continue;
}
- c.active = true;
-
// Precompute normal mass, tangent mass, and bias.
real_t rnA = c.rA.dot(c.normal);
real_t rnB = c.rB.dot(c.normal);
@@ -421,8 +441,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
// Apply normal + friction impulse
Vector2 P = c.acc_normal_impulse * c.normal + c.acc_tangent_impulse * tangent;
- A->apply_impulse(-P, c.rA);
- B->apply_impulse(P, c.rB);
+ if (dynamic_A) {
+ A->apply_impulse(-P, c.rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(P, c.rB);
+ }
}
#endif
@@ -434,6 +458,7 @@ bool BodyPair2DSW::setup(real_t p_step) {
c.bounce = c.bounce * dv.dot(c.normal);
}
+ c.active = true;
do_process = true;
}
@@ -441,13 +466,12 @@ bool BodyPair2DSW::setup(real_t p_step) {
}
void BodyPair2DSW::solve(real_t p_step) {
- if (!collided) {
+ if (!collided || oneway_disabled) {
return;
}
for (int i = 0; i < contact_count; ++i) {
Contact &c = contacts[i];
- cc++;
if (!c.active) {
continue;
@@ -474,8 +498,12 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(-jb, c.rA);
- B->apply_bias_impulse(jb, c.rB);
+ if (dynamic_A) {
+ A->apply_bias_impulse(-jb, c.rA);
+ }
+ if (dynamic_B) {
+ B->apply_bias_impulse(jb, c.rB);
+ }
real_t jn = -(c.bounce + vn) * c.mass_normal;
real_t jnOld = c.acc_normal_impulse;
@@ -490,8 +518,12 @@ void BodyPair2DSW::solve(real_t p_step) {
Vector2 j = c.normal * (c.acc_normal_impulse - jnOld) + tangent * (c.acc_tangent_impulse - jtOld);
- A->apply_impulse(-j, c.rA);
- B->apply_impulse(j, c.rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, c.rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, c.rB);
+ }
}
}
@@ -504,9 +536,6 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh
space = A->get_space();
A->add_constraint(this, 0);
B->add_constraint(this, 1);
- contact_count = 0;
- collided = false;
- oneway_disabled = false;
}
BodyPair2DSW::~BodyPair2DSW() {
diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h
index 31ab9b9017..4b42b44c92 100644
--- a/servers/physics_2d/body_pair_2d_sw.h
+++ b/servers/physics_2d/body_pair_2d_sw.h
@@ -44,13 +44,16 @@ class BodyPair2DSW : public Constraint2DSW {
Body2DSW *B;
};
- Body2DSW *_arr[2];
+ Body2DSW *_arr[2] = { nullptr, nullptr };
};
- int shape_A;
- int shape_B;
+ int shape_A = 0;
+ int shape_B = 0;
- Space2DSW *space;
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
+ Space2DSW *space = nullptr;
struct Contact {
Vector2 position;
@@ -73,10 +76,10 @@ class BodyPair2DSW : public Constraint2DSW {
Vector2 sep_axis;
Contact contacts[MAX_CONTACTS];
- int contact_count;
- bool collided;
- bool oneway_disabled;
- int cc;
+ int contact_count = 0;
+ bool collided = false;
+ bool oneway_disabled = false;
+ bool report_contacts_only = false;
bool _test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result = false);
void _validate_contacts();
@@ -84,8 +87,9 @@ class BodyPair2DSW : public Constraint2DSW {
_FORCE_INLINE_ void _contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B);
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B);
~BodyPair2DSW();
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index 2db3961f41..c395e59694 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -143,8 +143,8 @@ public:
return shapes[p_index].metadata;
}
- _FORCE_INLINE_ Transform2D get_transform() const { return transform; }
- _FORCE_INLINE_ Transform2D get_inv_transform() const { return inv_transform; }
+ _FORCE_INLINE_ const Transform2D &get_transform() const { return transform; }
+ _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; }
_FORCE_INLINE_ Space2DSW *get_space() const { return space; }
void set_shape_as_disabled(int p_idx, bool p_disabled);
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index b724deb48e..5e8dfbe570 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/constraint_2d_sw.h
@@ -63,6 +63,7 @@ public:
_FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
virtual bool setup(real_t p_step) = 0;
+ virtual bool pre_solve(real_t p_step) = 0;
virtual void solve(real_t p_step) = 0;
virtual ~Constraint2DSW() {}
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index 20d4b9aa1a..eaec582f9b 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -97,7 +97,10 @@ normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vecto
}
bool PinJoint2DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -148,12 +151,6 @@ bool PinJoint2DSW::setup(real_t p_step) {
bias = delta * -(get_bias() == 0 ? space->get_constraint_bias() : get_bias()) * (1.0 / p_step);
- // apply accumulated impulse
- A->apply_impulse(-P, rA);
- if (B) {
- B->apply_impulse(P, rB);
- }
-
return true;
}
@@ -161,6 +158,18 @@ inline Vector2 custom_cross(const Vector2 &p_vec, real_t p_other) {
return Vector2(p_other * p_vec.y, -p_other * p_vec.x);
}
+bool PinJoint2DSW::pre_solve(real_t p_step) {
+ // Apply accumulated impulse.
+ if (dynamic_A) {
+ A->apply_impulse(-P, rA);
+ }
+ if (B && dynamic_B) {
+ B->apply_impulse(P, rB);
+ }
+
+ return true;
+}
+
void PinJoint2DSW::solve(real_t p_step) {
// compute relative velocity
Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity());
@@ -174,8 +183,10 @@ void PinJoint2DSW::solve(real_t p_step) {
Vector2 impulse = M.basis_xform(bias - rel_vel - Vector2(softness, softness) * P);
- A->apply_impulse(-impulse, rA);
- if (B) {
+ if (dynamic_A) {
+ A->apply_impulse(-impulse, rA);
+ }
+ if (B && dynamic_B) {
B->apply_impulse(impulse, rB);
}
@@ -262,14 +273,19 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) {
}
bool GrooveJoint2DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
+ Space2DSW *space = A->get_space();
+ ERR_FAIL_COND_V(!space, false);
+
// calculate endpoints in worldspace
Vector2 ta = A->get_transform().xform(A_groove_1);
Vector2 tb = A->get_transform().xform(A_groove_2);
- Space2DSW *space = A->get_space();
// calculate axis
Vector2 n = -(tb - ta).orthogonal().normalized();
@@ -308,14 +324,22 @@ bool GrooveJoint2DSW::setup(real_t p_step) {
real_t _b = get_bias();
gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).clamped(get_max_bias());
- // apply accumulated impulse
- A->apply_impulse(-jn_acc, rA);
- B->apply_impulse(jn_acc, rB);
-
correct = true;
return true;
}
+bool GrooveJoint2DSW::pre_solve(real_t p_step) {
+ // Apply accumulated impulse.
+ if (dynamic_A) {
+ A->apply_impulse(-jn_acc, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(jn_acc, rB);
+ }
+
+ return true;
+}
+
void GrooveJoint2DSW::solve(real_t p_step) {
// compute impulse
Vector2 vr = relative_velocity(A, B, rA, rB);
@@ -328,8 +352,12 @@ void GrooveJoint2DSW::solve(real_t p_step) {
j = jn_acc - jOld;
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
}
GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b) :
@@ -351,7 +379,10 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_
//////////////////////////////////////////////
bool DampedSpringJoint2DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer2D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -373,12 +404,21 @@ bool DampedSpringJoint2DSW::setup(real_t p_step) {
target_vrn = 0.0f;
v_coef = 1.0f - Math::exp(-damping * (p_step)*k);
- // apply spring force
+ // Calculate spring force.
real_t f_spring = (rest_length - dist) * stiffness;
- Vector2 j = n * f_spring * (p_step);
+ j = n * f_spring * (p_step);
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ return true;
+}
+
+bool DampedSpringJoint2DSW::pre_solve(real_t p_step) {
+ // Apply spring force.
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
return true;
}
@@ -393,8 +433,12 @@ void DampedSpringJoint2DSW::solve(real_t p_step) {
target_vrn = vrn + v_damp;
Vector2 j = n * v_damp * n_mass;
- A->apply_impulse(-j, rA);
- B->apply_impulse(j, rB);
+ if (dynamic_A) {
+ A->apply_impulse(-j, rA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, rB);
+ }
}
void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) {
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h
index 628de972ae..ccc5c585a0 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/joints_2d_sw.h
@@ -39,6 +39,10 @@ class Joint2DSW : public Constraint2DSW {
real_t bias;
real_t max_bias;
+protected:
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
public:
_FORCE_INLINE_ void set_max_force(real_t p_force) { max_force = p_force; }
_FORCE_INLINE_ real_t get_max_force() const { return max_force; }
@@ -49,8 +53,9 @@ public:
_FORCE_INLINE_ void set_max_bias(real_t p_bias) { max_bias = p_bias; }
_FORCE_INLINE_ real_t get_max_bias() const { return max_bias; }
- virtual bool setup(real_t p_step) { return false; }
- virtual void solve(real_t p_step) {}
+ virtual bool setup(real_t p_step) override { return false; }
+ virtual bool pre_solve(real_t p_step) override { return false; }
+ virtual void solve(real_t p_step) override {}
void copy_settings_from(Joint2DSW *p_joint);
@@ -90,10 +95,11 @@ class PinJoint2DSW : public Joint2DSW {
real_t softness;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_PIN; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_PIN; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer2D::PinJointParam p_param) const;
@@ -126,10 +132,11 @@ class GrooveJoint2DSW : public Joint2DSW {
bool correct;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_GROOVE; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b);
};
@@ -153,15 +160,17 @@ class DampedSpringJoint2DSW : public Joint2DSW {
Vector2 rA, rB;
Vector2 n;
+ Vector2 j;
real_t n_mass;
real_t target_vrn;
real_t v_coef;
public:
- virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
+ virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value);
real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const;
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index 406d750776..b8cb4cddc5 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -29,45 +29,59 @@
/*************************************************************************/
#include "step_2d_sw.h"
+
#include "core/os/os.h"
#define BODY_ISLAND_COUNT_RESERVE 128
#define BODY_ISLAND_SIZE_RESERVE 512
#define ISLAND_COUNT_RESERVE 128
#define ISLAND_SIZE_RESERVE 512
+#define CONSTRAINT_COUNT_RESERVE 1024
void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body_island.push_back(p_body);
- // Faster with reversed iterations.
- for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().back(); E; E = E->prev()) {
- Constraint2DSW *c = (Constraint2DSW *)E->get().first;
- if (c->get_island_step() == _step) {
- continue; //already processed
+ if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) {
+ // Only dynamic bodies are tested for activation.
+ p_body_island.push_back(p_body);
+ }
+
+ for (const List<Pair<Constraint2DSW *, int>>::Element *E = p_body->get_constraint_list().front(); E; E = E->next()) {
+ Constraint2DSW *constraint = (Constraint2DSW *)E->get().first;
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
}
- c->set_island_step(_step);
- p_constraint_island.push_back(c);
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+ all_constraints.push_back(constraint);
- for (int i = 0; i < c->get_body_count(); i++) {
+ for (int i = 0; i < constraint->get_body_count(); i++) {
if (i == E->get().second) {
continue;
}
- Body2DSW *b = c->get_body_ptr()[i];
- if (b->get_island_step() == _step || b->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; //no go
+ Body2DSW *other_body = constraint->get_body_ptr()[i];
+ if (other_body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (other_body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
}
- _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
+ _populate_island(other_body, p_body_island, p_constraint_island);
}
}
}
-void Step2DSW::_setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta) {
+void Step2DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) {
+ Constraint2DSW *constraint = all_constraints[p_constraint_index];
+ constraint->setup(delta);
+}
+
+void Step2DSW::_pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const {
uint32_t constraint_count = p_constraint_island.size();
uint32_t valid_constraint_count = 0;
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
Constraint2DSW *constraint = p_constraint_island[constraint_index];
- if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ if (p_constraint_island[constraint_index]->pre_solve(delta)) {
// Keep this constraint for solving.
p_constraint_island[valid_constraint_count++] = constraint;
}
@@ -75,27 +89,25 @@ void Step2DSW::_setup_island(LocalVector<Constraint2DSW *> &p_constraint_island,
p_constraint_island.resize(valid_constraint_count);
}
-void Step2DSW::_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
- for (int i = 0; i < p_iterations; i++) {
- uint32_t constraint_count = p_constraint_island.size();
+void Step2DSW::_solve_island(uint32_t p_island_index, void *p_userdata) const {
+ const LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[p_island_index];
+
+ for (int i = 0; i < iterations; i++) {
+ uint32_t constraint_count = constraint_island.size();
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
- p_constraint_island[constraint_index]->solve(p_delta);
+ constraint_island[constraint_index]->solve(delta);
}
}
}
-void Step2DSW::_check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta) {
+void Step2DSW::_check_suspend(LocalVector<Body2DSW *> &p_body_island) const {
bool can_sleep = true;
uint32_t body_count = p_body_island.size();
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body2DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
- if (!body->sleep_test(p_delta)) {
+ if (!body->sleep_test(delta)) {
can_sleep = false;
}
}
@@ -104,10 +116,6 @@ void Step2DSW::_check_suspend(const LocalVector<Body2DSW *> &p_body_island, real
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body2DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer2D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
bool active = body->is_active();
if (active == can_sleep) {
@@ -121,6 +129,9 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
p_space->setup(); //update inertias, etc
+ iterations = p_iterations;
+ delta = p_delta;
+
const SelfList<Body2DSW>::List *body_list = &p_space->get_active_body_list();
/* INTEGRATE FORCES */
@@ -145,12 +156,39 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* GENERATE CONSTRAINT ISLANDS */
+ /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */
+
+ uint32_t island_count = 0;
+
+ const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
+
+ while (aml.first()) {
+ for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
+ Constraint2DSW *constraint = E->get();
+ if (constraint->get_island_step() == _step) {
+ continue;
+ }
+ constraint->set_island_step(_step);
+
+ // Each constraint can be on a separate island for areas as there's no solving phase.
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+
+ all_constraints.push_back(constraint);
+ constraint_island.push_back(constraint);
+ }
+ p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */
b = body_list->first();
uint32_t body_island_count = 0;
- uint32_t island_count = 0;
while (b) {
Body2DSW *body = b->self();
@@ -174,7 +212,9 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
_populate_island(body, body_island, constraint_island);
- body_islands.push_back(body_island);
+ if (body_island.is_empty()) {
+ --body_island_count;
+ }
if (constraint_island.is_empty()) {
--island_count;
@@ -185,37 +225,16 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
p_space->set_island_count((int)island_count);
- const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list();
-
- while (aml.first()) {
- for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
- Constraint2DSW *c = E->get();
- if (c->get_island_step() == _step) {
- continue;
- }
- c->set_island_step(_step);
- ++island_count;
- if (constraint_islands.size() < island_count) {
- constraint_islands.resize(island_count);
- }
- LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1];
- constraint_island.clear();
- constraint_island.push_back(c);
- }
- p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here
- }
-
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
profile_begtime = profile_endtime;
}
- /* SETUP CONSTRAINT ISLANDS */
+ /* SETUP CONSTRAINTS / PROCESS COLLISIONS */
- for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- _setup_island(constraint_islands[island_index], p_delta);
- }
+ uint32_t total_contraint_count = all_constraints.size();
+ work_pool.do_work(total_contraint_count, this, &Step2DSW::_setup_contraint, nullptr);
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
@@ -223,10 +242,21 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* SOLVE CONSTRAINT ISLANDS */
+ /* PRE-SOLVE CONSTRAINT ISLANDS */
+ // Warning: This doesn't run on threads, because it involves thread-unsafe processing.
for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- _solve_island(constraint_islands[island_index], p_iterations, p_delta);
+ _pre_solve_island(constraint_islands[island_index]);
+ }
+
+ /* SOLVE CONSTRAINT ISLANDS */
+
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ if (island_count > 1) {
+ work_pool.do_work(island_count, this, &Step2DSW::_solve_island, nullptr);
+ } else if (island_count > 0) {
+ _solve_island(0);
}
{ //profile
@@ -247,7 +277,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
- _check_suspend(body_islands[island_index], p_delta);
+ _check_suspend(body_islands[island_index]);
}
{ //profile
@@ -256,6 +286,8 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) {
//profile_begtime=profile_endtime;
}
+ all_constraints.clear();
+
p_space->update();
p_space->unlock();
_step++;
@@ -266,4 +298,11 @@ Step2DSW::Step2DSW() {
body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
constraint_islands.reserve(ISLAND_COUNT_RESERVE);
+ all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);
+
+ work_pool.init();
+}
+
+Step2DSW::~Step2DSW() {
+ work_pool.finish();
}
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h
index 5af4a36f52..c51fd73a79 100644
--- a/servers/physics_2d/step_2d_sw.h
+++ b/servers/physics_2d/step_2d_sw.h
@@ -34,21 +34,30 @@
#include "space_2d_sw.h"
#include "core/templates/local_vector.h"
+#include "core/templates/thread_work_pool.h"
class Step2DSW {
uint64_t _step;
+ int iterations = 0;
+ real_t delta = 0.0;
+
+ ThreadWorkPool work_pool;
+
LocalVector<LocalVector<Body2DSW *>> body_islands;
LocalVector<LocalVector<Constraint2DSW *>> constraint_islands;
+ LocalVector<Constraint2DSW *> all_constraints;
void _populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island);
- void _setup_island(LocalVector<Constraint2DSW *> &p_constraint_island, real_t p_delta);
- void _solve_island(LocalVector<Constraint2DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
- void _check_suspend(const LocalVector<Body2DSW *> &p_body_island, real_t p_delta);
+ void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr);
+ void _pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const;
+ void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr) const;
+ void _check_suspend(LocalVector<Body2DSW *> &p_body_island) const;
public:
void step(Space2DSW *p_space, real_t p_delta, int p_iterations);
Step2DSW();
+ ~Step2DSW();
};
#endif // STEP_2D_SW_H
diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/area_pair_3d_sw.cpp
index 4de5f1ba47..2073df7dee 100644
--- a/servers/physics_3d/area_pair_3d_sw.cpp
+++ b/servers/physics_3d/area_pair_3d_sw.cpp
@@ -40,31 +40,48 @@ bool AreaPair3DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
if (result != colliding) {
- if (result) {
- if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->add_area(area);
- }
- if (area->has_monitor_callback()) {
- area->add_body_to_query(body, body_shape, area_shape);
- }
-
- } else {
- if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
- body->remove_area(area);
- }
- if (area->has_monitor_callback()) {
- area->remove_body_from_query(body, body_shape, area_shape);
- }
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ process_collision = true;
+ } else if (area->has_monitor_callback()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool AreaPair3DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ body->add_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->add_body_to_query(body, body_shape, area_shape);
+ }
+ } else {
+ if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {
+ body->remove_area(area);
+ }
+
+ if (area->has_monitor_callback()) {
+ area->remove_body_from_query(body, body_shape, area_shape);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void AreaPair3DSW::solve(real_t p_step) {
+ // Nothing to do.
}
AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape) {
@@ -72,7 +89,6 @@ AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area,
area = p_area;
body_shape = p_body_shape;
area_shape = p_area_shape;
- colliding = false;
body->add_constraint(this, 0);
area->add_constraint(this);
if (p_body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
@@ -103,33 +119,48 @@ bool Area2Pair3DSW::setup(real_t p_step) {
result = true;
}
+ process_collision = false;
if (result != colliding) {
- if (result) {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- area_b->add_area_to_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->add_area_to_query(area_b, shape_b, shape_a);
- }
-
- } else {
- if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
- area_b->remove_area_from_query(area_a, shape_a, shape_b);
- }
-
- if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
- area_a->remove_area_from_query(area_b, shape_b, shape_a);
- }
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ process_collision = true;
+ } else if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ process_collision = true;
}
colliding = result;
}
- return false; //never do any post solving
+ return process_collision;
+}
+
+bool Area2Pair3DSW::pre_solve(real_t p_step) {
+ if (!process_collision) {
+ return false;
+ }
+
+ if (colliding) {
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ area_b->add_area_to_query(area_a, shape_a, shape_b);
+ }
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ area_a->add_area_to_query(area_b, shape_b, shape_a);
+ }
+ } else {
+ if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) {
+ area_b->remove_area_from_query(area_a, shape_a, shape_b);
+ }
+
+ if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) {
+ area_a->remove_area_from_query(area_b, shape_b, shape_a);
+ }
+ }
+
+ return false; // Never do any post solving.
}
void Area2Pair3DSW::solve(real_t p_step) {
+ // Nothing to do.
}
Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b) {
@@ -137,7 +168,6 @@ Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area
area_b = p_area_b;
shape_a = p_shape_a;
shape_b = p_shape_b;
- colliding = false;
area_a->add_constraint(this);
area_b->add_constraint(this);
}
diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/area_pair_3d_sw.h
index fbdaa25cbb..596d893082 100644
--- a/servers/physics_3d/area_pair_3d_sw.h
+++ b/servers/physics_3d/area_pair_3d_sw.h
@@ -40,11 +40,13 @@ class AreaPair3DSW : public Constraint3DSW {
Area3DSW *area;
int body_shape;
int area_shape;
- bool colliding;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape);
~AreaPair3DSW();
@@ -55,11 +57,13 @@ class Area2Pair3DSW : public Constraint3DSW {
Area3DSW *area_b;
int shape_a;
int shape_b;
- bool colliding;
+ bool colliding = false;
+ bool process_collision = false;
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b);
~Area2Pair3DSW();
diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/body_3d_sw.cpp
index d54345821d..4357c474e4 100644
--- a/servers/physics_3d/body_3d_sw.cpp
+++ b/servers/physics_3d/body_3d_sw.cpp
@@ -145,31 +145,17 @@ void Body3DSW::set_active(bool p_active) {
}
active = p_active;
- if (!p_active) {
- if (get_space()) {
- get_space()->body_remove_from_active_list(&active_list);
- }
- } else {
+
+ if (active) {
if (mode == PhysicsServer3D::BODY_MODE_STATIC) {
- return; //static bodies can't become active
- }
- if (get_space()) {
+ // Static bodies can't be active.
+ active = false;
+ } else if (get_space()) {
get_space()->body_add_to_active_list(&active_list);
}
-
- //still_time=0;
+ } else if (get_space()) {
+ get_space()->body_remove_from_active_list(&active_list);
}
- /*
- if (!space)
- return;
-
- for(int i=0;i<get_shape_count();i++) {
- Shape &s=shapes[i];
- if (s.bpid>0) {
- get_space()->get_broadphase()->set_active(s.bpid,active);
- }
- }
-*/
}
void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) {
@@ -392,13 +378,6 @@ void Body3DSW::set_space(Space3DSW *p_space) {
if (active) {
get_space()->body_add_to_active_list(&active_list);
}
- /*
- _update_queries();
- if (is_active()) {
- active=false;
- set_active(true);
- }
- */
}
first_integration = true;
diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/body_pair_3d_sw.cpp
index 28c854466f..cdb3da665e 100644
--- a/servers/physics_3d/body_pair_3d_sw.cpp
+++ b/servers/physics_3d/body_pair_3d_sw.cpp
@@ -212,14 +212,16 @@ real_t combine_friction(Body3DSW *A, Body3DSW *B) {
}
bool BodyPair3DSW::setup(real_t p_step) {
- //cannot collide
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
if (!A->test_collision_mask(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) {
collided = false;
return false;
}
- bool report_contacts_only = false;
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ report_contacts_only = false;
+ if (!dynamic_A && !dynamic_B) {
if ((A->get_max_contacts_reported() > 0) || (B->get_max_contacts_reported() > 0)) {
report_contacts_only = true;
} else {
@@ -237,7 +239,7 @@ bool BodyPair3DSW::setup(real_t p_step) {
validate_contacts();
- Vector3 offset_A = A->get_transform().get_origin();
+ const Vector3 &offset_A = A->get_transform().get_origin();
Transform xform_Au = Transform(A->get_transform().basis, Vector3());
Transform xform_A = xform_Au * A->get_shape_transform(shape_A);
@@ -248,27 +250,37 @@ bool BodyPair3DSW::setup(real_t p_step) {
Shape3DSW *shape_A_ptr = A->get_shape(shape_A);
Shape3DSW *shape_B_ptr = B->get_shape(shape_B);
- bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
- this->collided = collided;
+ collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
if (!collided) {
//test ccd (currently just a raycast)
- if (A->is_continuous_collision_detection_enabled() && A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC && B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ if (A->is_continuous_collision_detection_enabled() && dynamic_A && !dynamic_B) {
_test_ccd(p_step, A, shape_A, xform_A, B, shape_B, xform_B);
}
- if (B->is_continuous_collision_detection_enabled() && B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC && A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ if (B->is_continuous_collision_detection_enabled() && dynamic_B && !dynamic_A) {
_test_ccd(p_step, B, shape_B, xform_B, A, shape_A, xform_A);
}
return false;
}
+ return true;
+}
+
+bool BodyPair3DSW::pre_solve(real_t p_step) {
+ if (!collided) {
+ return false;
+ }
+
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = (real_t)0.3;
+ Shape3DSW *shape_A_ptr = A->get_shape(shape_A);
+ Shape3DSW *shape_B_ptr = B->get_shape(shape_B);
+
if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) {
if (shape_A_ptr->get_custom_bias() == 0) {
bias = shape_B_ptr->get_custom_bias();
@@ -283,22 +295,26 @@ bool BodyPair3DSW::setup(real_t p_step) {
bool do_process = false;
+ const Basis &basis_A = A->get_transform().basis;
+ const Basis &basis_B = B->get_transform().basis;
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
c.active = false;
- Vector3 global_A = xform_Au.xform(c.local_A);
- Vector3 global_B = xform_Bu.xform(c.local_B);
+ Vector3 global_A = basis_A.xform(c.local_A);
+ Vector3 global_B = basis_B.xform(c.local_B) + offset_B;
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
if (depth <= 0) {
continue;
}
#ifdef DEBUG_ENABLED
-
if (space->is_debugging_contacts()) {
+ const Vector3 &offset_A = A->get_transform().get_origin();
space->add_debug_contact(global_A + offset_A);
space->add_debug_contact(global_B + offset_A);
}
@@ -338,8 +354,12 @@ bool BodyPair3DSW::setup(real_t p_step) {
c.depth = depth;
Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
- A->apply_impulse(-j_vec, c.rA + A->get_center_of_mass());
- B->apply_impulse(j_vec, c.rB + B->get_center_of_mass());
+ if (dynamic_A) {
+ A->apply_impulse(-j_vec, c.rA + A->get_center_of_mass());
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j_vec, c.rB + B->get_center_of_mass());
+ }
c.acc_bias_impulse = 0;
c.acc_bias_impulse_center_of_mass = 0;
@@ -361,6 +381,8 @@ void BodyPair3DSW::solve(real_t p_step) {
return;
}
+ const real_t max_bias_av = MAX_BIAS_ROTATION / p_step;
+
for (int i = 0; i < contact_count; i++) {
Contact &c = contacts[i];
if (!c.active) {
@@ -384,8 +406,12 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
- B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
+ if (dynamic_A) {
+ A->apply_bias_impulse(-jb, c.rA + A->get_center_of_mass(), max_bias_av);
+ }
+ if (dynamic_B) {
+ B->apply_bias_impulse(jb, c.rB + B->get_center_of_mass(), max_bias_av);
+ }
crbA = A->get_biased_angular_velocity().cross(c.rA);
crbB = B->get_biased_angular_velocity().cross(c.rB);
@@ -400,8 +426,12 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
- A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f);
- B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f);
+ if (dynamic_A) {
+ A->apply_bias_impulse(-jb_com, A->get_center_of_mass(), 0.0f);
+ }
+ if (dynamic_B) {
+ B->apply_bias_impulse(jb_com, B->get_center_of_mass(), 0.0f);
+ }
}
c.active = true;
@@ -421,8 +451,12 @@ void BodyPair3DSW::solve(real_t p_step) {
Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
- A->apply_impulse(-j, c.rA + A->get_center_of_mass());
- B->apply_impulse(j, c.rB + B->get_center_of_mass());
+ if (dynamic_A) {
+ A->apply_impulse(-j, c.rA + A->get_center_of_mass());
+ }
+ if (dynamic_B) {
+ B->apply_impulse(j, c.rB + B->get_center_of_mass());
+ }
c.active = true;
}
@@ -464,8 +498,12 @@ void BodyPair3DSW::solve(real_t p_step) {
jt = c.acc_tangent_impulse - jtOld;
- A->apply_impulse(-jt, c.rA + A->get_center_of_mass());
- B->apply_impulse(jt, c.rB + B->get_center_of_mass());
+ if (dynamic_A) {
+ A->apply_impulse(-jt, c.rA + A->get_center_of_mass());
+ }
+ if (dynamic_B) {
+ B->apply_impulse(jt, c.rB + B->get_center_of_mass());
+ }
c.active = true;
}
@@ -481,8 +519,6 @@ BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_sh
space = A->get_space();
A->add_constraint(this, 0);
B->add_constraint(this, 1);
- contact_count = 0;
- collided = false;
}
BodyPair3DSW::~BodyPair3DSW() {
@@ -564,6 +600,8 @@ void BodySoftBodyPair3DSW::validate_contacts() {
}
bool BodySoftBodyPair3DSW::setup(real_t p_step) {
+ body_dynamic = (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
if (!body->test_collision_mask(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) {
collided = false;
return false;
@@ -585,12 +623,22 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
Shape3DSW *shape_A_ptr = body->get_shape(body_shape);
Shape3DSW *shape_B_ptr = soft_body->get_shape(0);
- bool collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
- this->collided = collided;
+ collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis);
+
+ return collided;
+}
+
+bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) {
+ if (!collided) {
+ return false;
+ }
real_t max_penetration = space->get_contact_max_allowed_penetration();
real_t bias = (real_t)0.3;
+
+ Shape3DSW *shape_A_ptr = body->get_shape(body_shape);
+
if (shape_A_ptr->get_custom_bias()) {
bias = shape_A_ptr->get_custom_bias();
}
@@ -599,6 +647,8 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
bool do_process = false;
+ const Transform &transform_A = body->get_transform();
+
uint32_t contact_count = contacts.size();
for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
Contact &c = contacts[contact_index];
@@ -609,10 +659,10 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
continue;
}
- Vector3 global_A = xform_Au.xform(c.local_A);
+ Vector3 global_A = transform_A.xform(c.local_A);
Vector3 global_B = soft_body->get_node_position(c.index_B) + c.local_B;
-
- real_t depth = c.normal.dot(global_A - global_B);
+ Vector3 axis = global_A - global_B;
+ real_t depth = axis.dot(c.normal);
if (depth <= 0) {
continue;
@@ -629,7 +679,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
}
#endif
- c.rA = global_A - xform_Au.origin - body->get_center_of_mass();
+ c.rA = global_A - transform_A.origin - body->get_center_of_mass();
c.rB = global_B;
if (body->can_report_contacts()) {
@@ -637,7 +687,7 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
body->add_contact(global_A, -c.normal, depth, body_shape, global_B, 0, soft_body->get_instance_id(), soft_body->get_self(), crA);
}
- if (body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ if (body_dynamic) {
body->set_active(true);
}
@@ -651,7 +701,9 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) {
c.depth = depth;
Vector3 j_vec = c.normal * c.acc_normal_impulse + c.acc_tangent_impulse;
- body->apply_impulse(-j_vec, c.rA + body->get_center_of_mass());
+ if (body_dynamic) {
+ body->apply_impulse(-j_vec, c.rA + body->get_center_of_mass());
+ }
soft_body->apply_node_impulse(c.index_B, j_vec);
c.acc_bias_impulse = 0;
c.acc_bias_impulse_center_of_mass = 0;
@@ -675,6 +727,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
return;
}
+ const real_t max_bias_av = MAX_BIAS_ROTATION / p_step;
+
uint32_t contact_count = contacts.size();
for (uint32_t contact_index = 0; contact_index < contact_count; ++contact_index) {
Contact &c = contacts[contact_index];
@@ -697,7 +751,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
Vector3 jb = c.normal * (c.acc_bias_impulse - jbnOld);
- body->apply_bias_impulse(-jb, c.rA + body->get_center_of_mass(), MAX_BIAS_ROTATION / p_step);
+ if (body_dynamic) {
+ body->apply_bias_impulse(-jb, c.rA + body->get_center_of_mass(), max_bias_av);
+ }
soft_body->apply_node_bias_impulse(c.index_B, jb);
crbA = body->get_biased_angular_velocity().cross(c.rA);
@@ -712,7 +768,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
Vector3 jb_com = c.normal * (c.acc_bias_impulse_center_of_mass - jbnOld_com);
- body->apply_bias_impulse(-jb_com, body->get_center_of_mass(), 0.0f);
+ if (body_dynamic) {
+ body->apply_bias_impulse(-jb_com, body->get_center_of_mass(), 0.0f);
+ }
soft_body->apply_node_bias_impulse(c.index_B, jb_com);
}
@@ -732,7 +790,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
Vector3 j = c.normal * (c.acc_normal_impulse - jnOld);
- body->apply_impulse(-j, c.rA + body->get_center_of_mass());
+ if (body_dynamic) {
+ body->apply_impulse(-j, c.rA + body->get_center_of_mass());
+ }
soft_body->apply_node_impulse(c.index_B, j);
c.active = true;
@@ -773,7 +833,9 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
jt = c.acc_tangent_impulse - jtOld;
- body->apply_impulse(-jt, c.rA + body->get_center_of_mass());
+ if (body_dynamic) {
+ body->apply_impulse(-jt, c.rA + body->get_center_of_mass());
+ }
soft_body->apply_node_impulse(c.index_B, jt);
c.active = true;
@@ -781,7 +843,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) {
}
}
-BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) {
+BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) :
+ BodyContact3DSW(&body, 1) {
body = p_A;
soft_body = p_B;
body_shape = p_shape_A;
diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/body_pair_3d_sw.h
index 74dddfa6aa..3f425ba2d7 100644
--- a/servers/physics_3d/body_pair_3d_sw.h
+++ b/servers/physics_3d/body_pair_3d_sw.h
@@ -57,9 +57,9 @@ protected:
};
Vector3 sep_axis;
- bool collided;
+ bool collided = false;
- Space3DSW *space;
+ Space3DSW *space = nullptr;
BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) :
Constraint3DSW(p_body_ptr, p_body_count) {
@@ -77,16 +77,21 @@ class BodyPair3DSW : public BodyContact3DSW {
Body3DSW *B;
};
- Body3DSW *_arr[2];
+ Body3DSW *_arr[2] = { nullptr, nullptr };
};
- int shape_A;
- int shape_B;
+ int shape_A = 0;
+ int shape_B = 0;
+
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
+ bool report_contacts_only = false;
Vector3 offset_B; //use local A coordinates to avoid numerical issues on collision detection
Contact contacts[MAX_CONTACTS];
- int contact_count;
+ int contact_count = 0;
static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata);
@@ -96,18 +101,21 @@ class BodyPair3DSW : public BodyContact3DSW {
bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform &p_xform_B);
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B);
~BodyPair3DSW();
};
class BodySoftBodyPair3DSW : public BodyContact3DSW {
- Body3DSW *body;
- SoftBody3DSW *soft_body;
+ Body3DSW *body = nullptr;
+ SoftBody3DSW *soft_body = nullptr;
- int body_shape;
+ int body_shape = 0;
+
+ bool body_dynamic = false;
LocalVector<Contact> contacts;
@@ -118,8 +126,12 @@ class BodySoftBodyPair3DSW : public BodyContact3DSW {
void validate_contacts();
public:
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual bool pre_solve(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
+
+ virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const override { return soft_body; }
+ virtual int get_soft_body_count() const override { return 1; }
BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B);
~BodySoftBodyPair3DSW();
diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/constraint_3d_sw.h
index 16a31e167d..7b44726ef5 100644
--- a/servers/physics_3d/constraint_3d_sw.h
+++ b/servers/physics_3d/constraint_3d_sw.h
@@ -31,7 +31,8 @@
#ifndef CONSTRAINT_SW_H
#define CONSTRAINT_SW_H
-#include "body_3d_sw.h"
+class Body3DSW;
+class SoftBody3DSW;
class Constraint3DSW {
Body3DSW **_body_ptr;
@@ -61,6 +62,9 @@ public:
_FORCE_INLINE_ Body3DSW **get_body_ptr() const { return _body_ptr; }
_FORCE_INLINE_ int get_body_count() const { return _body_count; }
+ virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const { return nullptr; }
+ virtual int get_soft_body_count() const { return 0; }
+
_FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
@@ -68,6 +72,7 @@ public:
_FORCE_INLINE_ bool is_disabled_collisions_between_bodies() const { return disabled_collisions_between_bodies; }
virtual bool setup(real_t p_step) = 0;
+ virtual bool pre_solve(real_t p_step) = 0;
virtual void solve(real_t p_step) = 0;
virtual ~Constraint3DSW() {}
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
index 167f797bfe..e9efddf165 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp
@@ -109,7 +109,10 @@ ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Trans
}
bool ConeTwistJoint3DSW::setup(real_t p_timestep) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -265,8 +268,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) {
real_t impulse = depth * tau / p_timestep * jacDiagABInv - rel_vel * jacDiagABInv;
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
- B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ }
}
}
@@ -287,8 +294,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) {
Vector3 impulse = m_swingAxis * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
}
// solve twist limit
@@ -303,8 +314,12 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) {
Vector3 impulse = m_twistAxis * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
}
}
}
diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
index 4e4d4e7f0c..b871ea50db 100644
--- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
+++ b/servers/physics_3d/joints/cone_twist_joint_3d_sw.h
@@ -102,10 +102,10 @@ public:
bool m_solveSwingLimit;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; }
- virtual bool setup(real_t p_timestep);
- virtual void solve(real_t p_timestep);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &rbAFrame, const Transform &rbBFrame);
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
index a86e8b4e76..7c504764a7 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp
@@ -82,7 +82,7 @@ int G6DOFRotationalLimitMotor3DSW::testLimitValue(real_t test_value) {
real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits(
real_t timeStep, Vector3 &axis, real_t jacDiagABInv,
- Body3DSW *body0, Body3DSW *body1) {
+ Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic) {
if (!needApplyTorques()) {
return 0.0f;
}
@@ -138,8 +138,10 @@ real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits(
Vector3 motorImp = clippedMotorImpulse * axis;
- body0->apply_torque_impulse(motorImp);
- if (body1) {
+ if (p_body0_dynamic) {
+ body0->apply_torque_impulse(motorImp);
+ }
+ if (body1 && p_body1_dynamic) {
body1->apply_torque_impulse(-motorImp);
}
@@ -154,6 +156,7 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis(
real_t jacDiagABInv,
Body3DSW *body1, const Vector3 &pointInA,
Body3DSW *body2, const Vector3 &pointInB,
+ bool p_body1_dynamic, bool p_body2_dynamic,
int limit_index,
const Vector3 &axis_normal_on_a,
const Vector3 &anchorPos) {
@@ -205,8 +208,12 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis(
normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
Vector3 impulse_vector = axis_normal_on_a * normalImpulse;
- body1->apply_impulse(impulse_vector, rel_pos1);
- body2->apply_impulse(-impulse_vector, rel_pos2);
+ if (p_body1_dynamic) {
+ body1->apply_impulse(impulse_vector, rel_pos1);
+ }
+ if (p_body2_dynamic) {
+ body2->apply_impulse(-impulse_vector, rel_pos2);
+ }
return normalImpulse;
}
@@ -303,7 +310,10 @@ bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) {
}
bool Generic6DOFJoint3DSW::setup(real_t p_timestep) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -384,6 +394,7 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) {
jacDiagABInv,
A, pointInA,
B, pointInB,
+ dynamic_A, dynamic_B,
i, linear_axis, m_AnchorPos);
}
}
@@ -398,7 +409,7 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) {
angularJacDiagABInv = real_t(1.) / m_jacAng[i].getDiagonal();
- m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B);
+ m_angularLimits[i].solveAngularLimits(m_timeStep, angular_axis, angularJacDiagABInv, A, B, dynamic_A, dynamic_B);
}
}
}
diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
index d61a033231..8af76cefc2 100644
--- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
+++ b/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h
@@ -120,7 +120,7 @@ public:
int testLimitValue(real_t test_value);
//! apply the correction impulses for two bodies
- real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1);
+ real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic);
};
class G6DOFTranslationalLimitMotor3DSW {
@@ -166,6 +166,7 @@ public:
real_t jacDiagABInv,
Body3DSW *body1, const Vector3 &pointInA,
Body3DSW *body2, const Vector3 &pointInB,
+ bool p_body1_dynamic, bool p_body2_dynamic,
int limit_index,
const Vector3 &axis_normal_on_a,
const Vector3 &anchorPos);
@@ -234,10 +235,10 @@ protected:
public:
Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &frameInA, const Transform &frameInB, bool useLinearReferenceFrameA);
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_6DOF; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_6DOF; }
- virtual bool setup(real_t p_timestep);
- virtual void solve(real_t p_timestep);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
//! Calcs global transform of the offsets
/*!
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
index 90b82f4680..bb8858c28a 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.cpp
@@ -155,7 +155,10 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo
}
bool HingeJoint3DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -279,8 +282,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
real_t impulse = depth * tau / p_step * jacDiagABInv - rel_vel * jacDiagABInv;
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
- B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ }
}
}
@@ -322,8 +329,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
angularError *= (real_t(1.) / denom2) * relaxation;
}
- A->apply_torque_impulse(-velrelOrthog + angularError);
- B->apply_torque_impulse(velrelOrthog - angularError);
+ if (dynamic_A) {
+ A->apply_torque_impulse(-velrelOrthog + angularError);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(velrelOrthog - angularError);
+ }
// solve limit
if (m_solveLimit) {
@@ -337,8 +348,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
impulseMag = m_accLimitImpulse - temp;
Vector3 impulse = axisA * impulseMag * m_limitSign;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
}
}
@@ -359,8 +374,12 @@ void HingeJoint3DSW::solve(real_t p_step) {
clippedMotorImpulse = clippedMotorImpulse < -m_maxMotorImpulse ? -m_maxMotorImpulse : clippedMotorImpulse;
Vector3 motorImp = clippedMotorImpulse * axisA;
- A->apply_torque_impulse(motorImp + angularLimit);
- B->apply_torque_impulse(-motorImp - angularLimit);
+ if (dynamic_A) {
+ A->apply_torque_impulse(motorImp + angularLimit);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-motorImp - angularLimit);
+ }
}
}
}
diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/hinge_joint_3d_sw.h
index b6117aa0bc..2100f5de44 100644
--- a/servers/physics_3d/joints/hinge_joint_3d_sw.h
+++ b/servers/physics_3d/joints/hinge_joint_3d_sw.h
@@ -96,10 +96,10 @@ class HingeJoint3DSW : public Joint3DSW {
real_t m_appliedImpulse;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_HINGE; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_HINGE; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
real_t get_hinge_angle();
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
index 75d87992d1..8eb84d1c2f 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.cpp
@@ -50,7 +50,10 @@ subject to the following restrictions:
#include "pin_joint_3d_sw.h"
bool PinJoint3DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -123,8 +126,12 @@ void PinJoint3DSW::solve(real_t p_step) {
m_appliedImpulse += impulse;
Vector3 impulse_vector = normal * impulse;
- A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
- B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, pivotAInW - A->get_transform().origin);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, pivotBInW - B->get_transform().origin);
+ }
normal[i] = 0;
}
diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/pin_joint_3d_sw.h
index 1875983527..3d91452850 100644
--- a/servers/physics_3d/joints/pin_joint_3d_sw.h
+++ b/servers/physics_3d/joints/pin_joint_3d_sw.h
@@ -74,10 +74,10 @@ class PinJoint3DSW : public Joint3DSW {
Vector3 m_pivotInB;
public:
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_PIN; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_PIN; }
- virtual bool setup(real_t p_step);
- virtual void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
void set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer3D::PinJointParam p_param) const;
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
index 2e1ee8e770..8bd1951311 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.cpp
@@ -127,7 +127,10 @@ SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform &
//-----------------------------------------------------------------------------
bool SliderJoint3DSW::setup(real_t p_step) {
- if ((A->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC) && (B->get_mode() <= PhysicsServer3D::BODY_MODE_KINEMATIC)) {
+ dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+ dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC);
+
+ if (!dynamic_A && !dynamic_B) {
return false;
}
@@ -200,8 +203,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
// calcutate and apply impulse
real_t normalImpulse = softness * (restitution * depth / p_step - damping * rel_vel) * m_jacLinDiagABInv[i];
Vector3 impulse_vector = normal * normalImpulse;
- A->apply_impulse(impulse_vector, m_relPosA);
- B->apply_impulse(-impulse_vector, m_relPosB);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, m_relPosA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, m_relPosB);
+ }
if (m_poweredLinMotor && (!i)) { // apply linear motor
if (m_accumulatedLinMotorImpulse < m_maxLinMotorForce) {
real_t desiredMotorVel = m_targetLinMotorVelocity;
@@ -221,8 +228,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
m_accumulatedLinMotorImpulse = new_acc;
// apply clamped impulse
impulse_vector = normal * normalImpulse;
- A->apply_impulse(impulse_vector, m_relPosA);
- B->apply_impulse(-impulse_vector, m_relPosB);
+ if (dynamic_A) {
+ A->apply_impulse(impulse_vector, m_relPosA);
+ }
+ if (dynamic_B) {
+ B->apply_impulse(-impulse_vector, m_relPosB);
+ }
}
}
}
@@ -256,8 +267,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
angularError *= (real_t(1.) / denom2) * m_restitutionOrthoAng * m_softnessOrthoAng;
}
// apply impulse
- A->apply_torque_impulse(-velrelOrthog + angularError);
- B->apply_torque_impulse(velrelOrthog - angularError);
+ if (dynamic_A) {
+ A->apply_torque_impulse(-velrelOrthog + angularError);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(velrelOrthog - angularError);
+ }
real_t impulseMag;
//solve angular limits
if (m_solveAngLim) {
@@ -268,8 +283,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
impulseMag *= m_kAngle * m_softnessDirAng;
}
Vector3 impulse = axisA * impulseMag;
- A->apply_torque_impulse(impulse);
- B->apply_torque_impulse(-impulse);
+ if (dynamic_A) {
+ A->apply_torque_impulse(impulse);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-impulse);
+ }
//apply angular motor
if (m_poweredAngMotor) {
if (m_accumulatedAngMotorImpulse < m_maxAngMotorForce) {
@@ -294,8 +313,12 @@ void SliderJoint3DSW::solve(real_t p_step) {
m_accumulatedAngMotorImpulse = new_acc;
// apply clamped impulse
Vector3 motorImp = angImpulse * axisA;
- A->apply_torque_impulse(motorImp);
- B->apply_torque_impulse(-motorImp);
+ if (dynamic_A) {
+ A->apply_torque_impulse(motorImp);
+ }
+ if (dynamic_B) {
+ B->apply_torque_impulse(-motorImp);
+ }
}
}
} // SliderJointSW::solveConstraint()
diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/slider_joint_3d_sw.h
index f52f6ace27..ef5891d0f9 100644
--- a/servers/physics_3d/joints/slider_joint_3d_sw.h
+++ b/servers/physics_3d/joints/slider_joint_3d_sw.h
@@ -240,10 +240,10 @@ public:
void set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value);
real_t get_param(PhysicsServer3D::SliderJointParam p_param) const;
- bool setup(real_t p_step);
- void solve(real_t p_step);
+ virtual bool setup(real_t p_step) override;
+ virtual void solve(real_t p_step) override;
- virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_SLIDER; }
+ virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_SLIDER; }
};
#endif // SLIDER_JOINT_SW_H
diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/joints_3d_sw.h
index 225a71aca9..e2514674ea 100644
--- a/servers/physics_3d/joints_3d_sw.h
+++ b/servers/physics_3d/joints_3d_sw.h
@@ -35,9 +35,14 @@
#include "constraint_3d_sw.h"
class Joint3DSW : public Constraint3DSW {
+protected:
+ bool dynamic_A = false;
+ bool dynamic_B = false;
+
public:
- virtual bool setup(real_t p_step) { return false; }
- virtual void solve(real_t p_step) {}
+ virtual bool setup(real_t p_step) override { return false; }
+ virtual bool pre_solve(real_t p_step) override { return true; }
+ virtual void solve(real_t p_step) override {}
void copy_settings_from(Joint3DSW *p_joint) {
set_self(p_joint->get_self());
diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/soft_body_3d_sw.h
index 6c0451ff45..98e554218b 100644
--- a/servers/physics_3d/soft_body_3d_sw.h
+++ b/servers/physics_3d/soft_body_3d_sw.h
@@ -106,6 +106,8 @@ class SoftBody3DSW : public CollisionObject3DSW {
VSet<RID> exceptions;
+ uint64_t island_step = 0;
+
public:
SoftBody3DSW();
@@ -124,6 +126,9 @@ public:
_FORCE_INLINE_ bool has_exception(const RID &p_exception) const { return exceptions.has(p_exception); }
_FORCE_INLINE_ const VSet<RID> &get_exceptions() const { return exceptions; }
+ _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; }
+ _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; }
+
virtual void set_space(Space3DSW *p_space);
void set_mesh(const Ref<Mesh> &p_mesh);
diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/step_3d_sw.cpp
index 06f3227eab..ba18bac611 100644
--- a/servers/physics_3d/step_3d_sw.cpp
+++ b/servers/physics_3d/step_3d_sw.cpp
@@ -37,39 +37,90 @@
#define BODY_ISLAND_SIZE_RESERVE 512
#define ISLAND_COUNT_RESERVE 128
#define ISLAND_SIZE_RESERVE 512
+#define CONSTRAINT_COUNT_RESERVE 1024
void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) {
p_body->set_island_step(_step);
- p_body_island.push_back(p_body);
- // Faster with reversed iterations.
- for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().back(); E; E = E->prev()) {
- Constraint3DSW *c = (Constraint3DSW *)E->key();
- if (c->get_island_step() == _step) {
- continue; //already processed
+ if (p_body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {
+ // Only dynamic bodies are tested for activation.
+ p_body_island.push_back(p_body);
+ }
+
+ for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) {
+ Constraint3DSW *constraint = (Constraint3DSW *)E->key();
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
}
- c->set_island_step(_step);
- p_constraint_island.push_back(c);
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+
+ all_constraints.push_back(constraint);
- for (int i = 0; i < c->get_body_count(); i++) {
+ // Find connected rigid bodies.
+ for (int i = 0; i < constraint->get_body_count(); i++) {
if (i == E->get()) {
continue;
}
- Body3DSW *b = c->get_body_ptr()[i];
- if (b->get_island_step() == _step || b->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || b->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- continue; //no go
+ Body3DSW *other_body = constraint->get_body_ptr()[i];
+ if (other_body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (other_body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
+ }
+ _populate_island(other_body, p_body_island, p_constraint_island);
+ }
+
+ // Find connected soft bodies.
+ for (int i = 0; i < constraint->get_soft_body_count(); i++) {
+ SoftBody3DSW *soft_body = constraint->get_soft_body_ptr(i);
+ if (soft_body->get_island_step() == _step) {
+ continue; // Already processed.
}
- _populate_island(c->get_body_ptr()[i], p_body_island, p_constraint_island);
+ _populate_island_soft_body(soft_body, p_body_island, p_constraint_island);
}
}
}
-void Step3DSW::_setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta) {
+void Step3DSW::_populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) {
+ p_soft_body->set_island_step(_step);
+
+ for (Set<Constraint3DSW *>::Element *E = p_soft_body->get_constraints().front(); E; E = E->next()) {
+ Constraint3DSW *constraint = (Constraint3DSW *)E->get();
+ if (constraint->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ constraint->set_island_step(_step);
+ p_constraint_island.push_back(constraint);
+
+ all_constraints.push_back(constraint);
+
+ // Find connected rigid bodies.
+ for (int i = 0; i < constraint->get_body_count(); i++) {
+ Body3DSW *body = constraint->get_body_ptr()[i];
+ if (body->get_island_step() == _step) {
+ continue; // Already processed.
+ }
+ if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) {
+ continue; // Static bodies don't connect islands.
+ }
+ _populate_island(body, p_body_island, p_constraint_island);
+ }
+ }
+}
+
+void Step3DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) {
+ Constraint3DSW *constraint = all_constraints[p_constraint_index];
+ constraint->setup(delta);
+}
+
+void Step3DSW::_pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const {
uint32_t constraint_count = p_constraint_island.size();
uint32_t valid_constraint_count = 0;
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
Constraint3DSW *constraint = p_constraint_island[constraint_index];
- if (p_constraint_island[constraint_index]->setup(p_delta)) {
+ if (p_constraint_island[constraint_index]->pre_solve(delta)) {
// Keep this constraint for solving.
p_constraint_island[valid_constraint_count++] = constraint;
}
@@ -77,15 +128,17 @@ void Step3DSW::_setup_island(LocalVector<Constraint3DSW *> &p_constraint_island,
p_constraint_island.resize(valid_constraint_count);
}
-void Step3DSW::_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta) {
+void Step3DSW::_solve_island(uint32_t p_island_index, void *p_userdata) {
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[p_island_index];
+
int current_priority = 1;
- uint32_t constraint_count = p_constraint_island.size();
+ uint32_t constraint_count = constraint_island.size();
while (constraint_count > 0) {
- for (int i = 0; i < p_iterations; i++) {
+ for (int i = 0; i < iterations; i++) {
// Go through all iterations.
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
- p_constraint_island[constraint_index]->solve(p_delta);
+ constraint_island[constraint_index]->solve(delta);
}
}
@@ -93,28 +146,24 @@ void Step3DSW::_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island,
uint32_t priority_constraint_count = 0;
++current_priority;
for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {
- Constraint3DSW *constraint = p_constraint_island[constraint_index];
+ Constraint3DSW *constraint = constraint_island[constraint_index];
if (constraint->get_priority() >= current_priority) {
// Keep this constraint for the next iteration.
- p_constraint_island[priority_constraint_count++] = constraint;
+ constraint_island[priority_constraint_count++] = constraint;
}
}
constraint_count = priority_constraint_count;
}
}
-void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta) {
+void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island) const {
bool can_sleep = true;
uint32_t body_count = p_body_island.size();
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body3DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
- if (!body->sleep_test(p_delta)) {
+ if (!body->sleep_test(delta)) {
can_sleep = false;
}
}
@@ -123,10 +172,6 @@ void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island, real
for (uint32_t body_index = 0; body_index < body_count; ++body_index) {
Body3DSW *body = p_body_island[body_index];
- if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC || body->get_mode() == PhysicsServer3D::BODY_MODE_KINEMATIC) {
- continue; // Ignore for static.
- }
-
bool active = body->is_active();
if (active == can_sleep) {
@@ -140,6 +185,9 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
p_space->setup(); //update inertias, etc
+ iterations = p_iterations;
+ delta = p_delta;
+
const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list();
const SelfList<SoftBody3DSW>::List *soft_body_list = &p_space->get_active_soft_body_list();
@@ -175,12 +223,39 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* GENERATE CONSTRAINT ISLANDS */
+ /* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */
+
+ uint32_t island_count = 0;
+
+ const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list();
+
+ while (aml.first()) {
+ for (const Set<Constraint3DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
+ Constraint3DSW *constraint = E->get();
+ if (constraint->get_island_step() == _step) {
+ continue;
+ }
+ constraint->set_island_step(_step);
+
+ // Each constraint can be on a separate island for areas as there's no solving phase.
+ ++island_count;
+ if (constraint_islands.size() < island_count) {
+ constraint_islands.resize(island_count);
+ }
+ LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
+ constraint_island.clear();
+
+ all_constraints.push_back(constraint);
+ constraint_island.push_back(constraint);
+ }
+ p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
+ }
+
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */
b = body_list->first();
uint32_t body_island_count = 0;
- uint32_t island_count = 0;
while (b) {
Body3DSW *body = b->self();
@@ -204,7 +279,9 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
_populate_island(body, body_island, constraint_island);
- body_islands.push_back(body_island);
+ if (body_island.is_empty()) {
+ --body_island_count;
+ }
if (constraint_island.is_empty()) {
--island_count;
@@ -213,58 +290,54 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
b = b->next();
}
- p_space->set_island_count((int)island_count);
+ /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE SOFT BODIES */
- const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list();
+ sb = soft_body_list->first();
+ while (sb) {
+ SoftBody3DSW *soft_body = sb->self();
- while (aml.first()) {
- for (const Set<Constraint3DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) {
- Constraint3DSW *c = E->get();
- if (c->get_island_step() == _step) {
- continue;
+ if (soft_body->get_island_step() != _step) {
+ ++body_island_count;
+ if (body_islands.size() < body_island_count) {
+ body_islands.resize(body_island_count);
}
- c->set_island_step(_step);
+ LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1];
+ body_island.clear();
+ body_island.reserve(BODY_ISLAND_SIZE_RESERVE);
+
++island_count;
if (constraint_islands.size() < island_count) {
constraint_islands.resize(island_count);
}
LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
constraint_island.clear();
- constraint_island.push_back(c);
- }
- p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here
- }
+ constraint_island.reserve(ISLAND_SIZE_RESERVE);
- sb = soft_body_list->first();
- while (sb) {
- for (const Set<Constraint3DSW *>::Element *E = sb->self()->get_constraints().front(); E; E = E->next()) {
- Constraint3DSW *c = E->get();
- if (c->get_island_step() == _step) {
- continue;
+ _populate_island_soft_body(soft_body, body_island, constraint_island);
+
+ if (body_island.is_empty()) {
+ --body_island_count;
}
- c->set_island_step(_step);
- ++island_count;
- if (constraint_islands.size() < island_count) {
- constraint_islands.resize(island_count);
+
+ if (constraint_island.is_empty()) {
+ --island_count;
}
- LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1];
- constraint_island.clear();
- constraint_island.push_back(c);
}
sb = sb->next();
}
+ p_space->set_island_count((int)island_count);
+
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);
profile_begtime = profile_endtime;
}
- /* SETUP CONSTRAINT ISLANDS */
+ /* SETUP CONSTRAINTS / PROCESS COLLISIONS */
- for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- _setup_island(constraint_islands[island_index], p_delta);
- }
+ uint32_t total_contraint_count = all_constraints.size();
+ work_pool.do_work(total_contraint_count, this, &Step3DSW::_setup_contraint, nullptr);
{ //profile
profile_endtime = OS::get_singleton()->get_ticks_usec();
@@ -272,12 +345,21 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
- /* SOLVE CONSTRAINT ISLANDS */
+ /* PRE-SOLVE CONSTRAINT ISLANDS */
+ // Warning: This doesn't run on threads, because it involves thread-unsafe processing.
for (uint32_t island_index = 0; island_index < island_count; ++island_index) {
- // Warning: _solve_island modifies the constraint islands for optimization purpose,
- // their content is not reliable after these calls and shouldn't be used anymore.
- _solve_island(constraint_islands[island_index], p_iterations, p_delta);
+ _pre_solve_island(constraint_islands[island_index]);
+ }
+
+ /* SOLVE CONSTRAINT ISLANDS */
+
+ // Warning: _solve_island modifies the constraint islands for optimization purpose,
+ // their content is not reliable after these calls and shouldn't be used anymore.
+ if (island_count > 1) {
+ work_pool.do_work(island_count, this, &Step3DSW::_solve_island, nullptr);
+ } else if (island_count > 0) {
+ _solve_island(0);
}
{ //profile
@@ -298,7 +380,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
/* SLEEP / WAKE UP ISLANDS */
for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {
- _check_suspend(body_islands[island_index], p_delta);
+ _check_suspend(body_islands[island_index]);
}
/* UPDATE SOFT BODY CONSTRAINTS */
@@ -315,6 +397,8 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) {
profile_begtime = profile_endtime;
}
+ all_constraints.clear();
+
p_space->update();
p_space->unlock();
_step++;
@@ -325,4 +409,11 @@ Step3DSW::Step3DSW() {
body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);
constraint_islands.reserve(ISLAND_COUNT_RESERVE);
+ all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);
+
+ work_pool.init();
+}
+
+Step3DSW::~Step3DSW() {
+ work_pool.finish();
}
diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/step_3d_sw.h
index f406c35c3a..9c60004b24 100644
--- a/servers/physics_3d/step_3d_sw.h
+++ b/servers/physics_3d/step_3d_sw.h
@@ -34,21 +34,31 @@
#include "space_3d_sw.h"
#include "core/templates/local_vector.h"
+#include "core/templates/thread_work_pool.h"
class Step3DSW {
uint64_t _step;
+ int iterations = 0;
+ real_t delta = 0.0;
+
+ ThreadWorkPool work_pool;
+
LocalVector<LocalVector<Body3DSW *>> body_islands;
LocalVector<LocalVector<Constraint3DSW *>> constraint_islands;
+ LocalVector<Constraint3DSW *> all_constraints;
void _populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island);
- void _setup_island(LocalVector<Constraint3DSW *> &p_constraint_island, real_t p_delta);
- void _solve_island(LocalVector<Constraint3DSW *> &p_constraint_island, int p_iterations, real_t p_delta);
- void _check_suspend(const LocalVector<Body3DSW *> &p_body_island, real_t p_delta);
+ void _populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island);
+ void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr);
+ void _pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const;
+ void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr);
+ void _check_suspend(const LocalVector<Body3DSW *> &p_body_island) const;
public:
void step(Space3DSW *p_space, real_t p_delta, int p_iterations);
Step3DSW();
+ ~Step3DSW();
};
#endif // STEP__SW_H
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index ff57aa94ce..aadb7bac19 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1698,6 +1698,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //first wireframe, for pseudo conservative
}
render_list_params.uv_offset = Vector2();
+ render_list_params.force_wireframe = false;
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); //second regular triangles
RD::get_singleton()->draw_list_end();
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index b2aaa50421..041476adf3 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1272,42 +1272,12 @@ void RenderForwardMobile::_fill_instance_data(RenderListType p_render_list, uint
rl->element_info.resize(p_offset + element_total);
- uint32_t repeats = 0;
- GeometryInstanceSurfaceDataCache *prev_surface = nullptr;
for (uint32_t i = 0; i < element_total; i++) {
GeometryInstanceSurfaceDataCache *surface = rl->elements[i + p_offset];
- GeometryInstanceForwardMobile *inst = surface->owner;
-
- bool cant_repeat = inst->flags_cache & INSTANCE_DATA_FLAG_MULTIMESH || inst->mesh_instance.is_valid();
-
- if (prev_surface != nullptr && !cant_repeat && prev_surface->sort.sort_key1 == surface->sort.sort_key1 && prev_surface->sort.sort_key2 == surface->sort.sort_key2) {
- //this element is the same as the previous one, count repeats to draw it using instancing
- repeats++;
- } else {
- if (repeats > 0) {
- for (uint32_t j = 1; j <= repeats; j++) {
- rl->element_info[p_offset + i - j].repeat = j;
- }
- }
- repeats = 1;
- }
-
RenderElementInfo &element_info = rl->element_info[p_offset + i];
element_info.lod_index = surface->lod_index;
element_info.uses_lightmap = surface->sort.uses_lightmap;
-
- if (cant_repeat) {
- prev_surface = nullptr;
- } else {
- prev_surface = surface;
- }
- }
-
- if (repeats > 0) {
- for (uint32_t j = 1; j <= repeats; j++) {
- rl->element_info[p_offset + element_total - j].repeat = j;
- }
}
}
@@ -1523,13 +1493,12 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(GeometryInstanceForwardMobile::PushConstant));
- uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat;
+ uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : 1;
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_USES_PARTICLE_TRAILS) {
instance_count /= surf->owner->trail_steps;
}
RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count);
- i += element_info.repeat - 1; //skip equal elements
}
}
@@ -1872,7 +1841,7 @@ void RenderForwardMobile::_geometry_instance_add_surface_with_material(GeometryI
sdcache->sort.material_id_low = p_material_id & 0x0000FFFF;
sdcache->sort.material_id_hi = p_material_id >> 16;
sdcache->sort.shader_id = p_shader_id;
- sdcache->sort.geometry_id = p_mesh.get_local_index(); //only meshes can repeat anyway
+ sdcache->sort.geometry_id = p_mesh.get_local_index();
// sdcache->sort.uses_forward_gi = ginstance->can_sdfgi;
sdcache->sort.priority = p_material->priority;
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index d356d88335..232ad0066b 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -363,10 +363,9 @@ protected:
};
struct RenderElementInfo {
- uint32_t repeat : 22;
uint32_t uses_lightmap : 1;
uint32_t lod_index : 8;
- uint32_t reserved : 1; // was uses_forward_gi but we don't use that here
+ uint32_t reserved : 23;
};
template <PassMode p_pass_mode>
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 2d4cd11f37..d7a5d1211c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -2554,6 +2554,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.soft_shadow_scale = storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_BLUR);
light_data.softshadow_angle = angular_diameter;
+ light_data.bake_mode = storage->light_get_bake_mode(base);
if (angular_diameter <= 0.0) {
light_data.soft_shadow_scale *= directional_shadow_quality_radius_get(); // Only use quality radius for PCF
@@ -2621,6 +2622,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
light_data.color[1] = linear_col.g * energy;
light_data.color[2] = linear_col.b * energy;
light_data.specular_amount = storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0;
+ light_data.bake_mode = storage->light_get_bake_mode(base);
float radius = MAX(0.001, storage->light_get_param(base, RS::LIGHT_PARAM_RANGE));
light_data.inv_radius = 1.0 / radius;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index b289eda58f..7600d6823e 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -497,7 +497,7 @@ private:
float soft_shadow_scale;
uint32_t mask;
float shadow_volumetric_fog_fade;
- uint32_t pad;
+ uint32_t bake_mode;
float projector_rect[4];
};
@@ -514,7 +514,8 @@ private:
uint32_t shadow_enabled;
float fade_from;
float fade_to;
- uint32_t pad[3];
+ uint32_t pad[2];
+ uint32_t bake_mode;
float shadow_volumetric_fog_fade;
float shadow_bias[4];
float shadow_normal_bias[4];
diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
index 46b571a5f5..2fce258cff 100644
--- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl
@@ -1,3 +1,6 @@
+#define LIGHT_BAKE_DISABLED 0
+#define LIGHT_BAKE_DYNAMIC 1
+#define LIGHT_BAKE_STATIC 2
struct LightData { //this structure needs to be as packed as possible
vec3 position;
@@ -23,7 +26,7 @@ struct LightData { //this structure needs to be as packed as possible
float soft_shadow_scale; // scales the shadow kernel for blurrier shadows
uint mask;
float shadow_volumetric_fog_fade;
- uint pad;
+ uint bake_mode;
vec4 projector_rect; //projector rect in srgb decal atlas
};
@@ -60,7 +63,8 @@ struct DirectionalLightData {
bool shadow_enabled;
float fade_from;
float fade_to;
- uvec3 pad;
+ uvec2 pad;
+ uint bake_mode;
float shadow_volumetric_fog_fade;
vec4 shadow_bias;
vec4 shadow_normal_bias;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 0bb16a8b29..1d67a3f1df 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -1227,6 +1227,10 @@ void main() {
continue; //not masked
}
+ if (directional_lights.data[i].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
float shadow = 1.0;
#ifdef USE_SOFT_SHADOWS
@@ -1676,6 +1680,10 @@ void main() {
continue; //not masked
}
+ if (omni_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
float shadow = light_process_omni_shadow(light_index, vertex, view);
shadow = blur_shadow(shadow);
@@ -1749,6 +1757,10 @@ void main() {
continue; //not masked
}
+ if (spot_lights.data[light_index].bake_mode == LIGHT_BAKE_STATIC && bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) {
+ continue; // Statically baked light and object uses lightmap, skip
+ }
+
float shadow = light_process_spot_shadow(light_index, vertex, view);
shadow = blur_shadow(shadow);
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index aee4d8712a..fcea8e4ffc 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -2394,7 +2394,7 @@ void RendererSceneCull::_frustum_cull(CullData &cull_data, FrustumCullResult &cu
cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid));
} else if (base_type == RS::INSTANCE_LIGHTMAP) {
- cull_result.gi_probes.push_back(RID::from_uint64(idata.instance_data_rid));
+ cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid));
} else if (((1 << base_type) & RS::INSTANCE_GEOMETRY_MASK) && !(idata.flags & InstanceData::FLAG_CAST_SHADOWS_ONLY)) {
bool keep = true;
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 2de0549e8d..d86c44a206 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -93,10 +93,14 @@ public:
DeviceFamily device_family = DEVICE_UNKNOWN;
uint32_t version_major = 1.0;
uint32_t version_minor = 0.0;
+
// subgroup capabilities
uint32_t subgroup_size = 0;
uint32_t subgroup_in_shaders = 0; // Set flags using SHADER_STAGE_VERTEX_BIT, SHADER_STAGE_FRAGMENT_BIT, etc.
uint32_t subgroup_operations = 0; // Set flags, using SubgroupOperations
+
+ // features
+ bool supports_multiview = false; // If true this device supports multiview options
};
typedef Vector<uint8_t> (*ShaderCompileFunction)(ShaderStage p_stage, const String &p_source_code, ShaderLanguage p_language, String *r_error, const Capabilities *p_capabilities);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 3605dec1be..a9154603ee 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -472,8 +472,8 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint
const Vector2 *src = array.ptr();
for (int i = 0; i < p_vertex_array_len; i++) {
- uint16_t uv[2] = { Math::make_half_float(src[i].x), Math::make_half_float(src[i].y) };
- memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 2);
+ float uv[2] = { src[i].x, src[i].y };
+ memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], uv, 2 * 4);
}
} break;
case RS::ARRAY_CUSTOM0:
diff --git a/tests/test_string.h b/tests/test_string.h
index 94d14517ae..486c17dbbd 100644
--- a/tests/test_string.h
+++ b/tests/test_string.h
@@ -860,10 +860,10 @@ TEST_CASE("[String] match") {
}
TEST_CASE("[String] IPVX address to string") {
- IP_Address ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
- IP_Address ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
- IP_Address ip2("fe80::52e5:49ff:fe93:1baf");
- IP_Address ip3("::ffff:192.168.0.1");
+ IPAddress ip0("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+ IPAddress ip(0x0123, 0x4567, 0x89ab, 0xcdef, true);
+ IPAddress ip2("fe80::52e5:49ff:fe93:1baf");
+ IPAddress ip3("::ffff:192.168.0.1");
String ip4 = "192.168.0.1";
CHECK(ip4.is_valid_ip_address());
diff --git a/thirdparty/enet/godot.cpp b/thirdparty/enet/godot.cpp
index 189de6cc1f..fd7968204b 100644
--- a/thirdparty/enet/godot.cpp
+++ b/thirdparty/enet/godot.cpp
@@ -45,10 +45,10 @@
/// Abstract ENet interface for UDP/DTLS.
class ENetGodotSocket {
public:
- virtual Error bind(IP_Address p_ip, uint16_t p_port) = 0;
- virtual Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) = 0;
- virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
- virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
+ virtual Error bind(IPAddress p_ip, uint16_t p_port) = 0;
+ virtual Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) = 0;
+ virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) = 0;
+ virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) = 0;
virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
virtual void close() = 0;
virtual void set_refuse_new_connections(bool p_enable) {} /* Only used by dtls server */
@@ -65,7 +65,7 @@ class ENetUDP : public ENetGodotSocket {
private:
Ref<NetSocket> sock;
- IP_Address local_address;
+ IPAddress local_address;
bool bound = false;
public:
@@ -79,21 +79,21 @@ public:
sock->close();
}
- Error bind(IP_Address p_ip, uint16_t p_port) {
+ Error bind(IPAddress p_ip, uint16_t p_port) {
local_address = p_ip;
bound = true;
return sock->bind(p_ip, p_port);
}
- Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+ Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) {
return sock->get_socket_address(r_ip, r_port);
}
- Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+ Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
return sock->sendto(p_buffer, p_len, r_sent, p_ip, p_port);
}
- Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) {
Error err = sock->poll(NetSocket::POLL_TYPE_IN, 0);
if (err != OK) {
return err;
@@ -157,7 +157,7 @@ class ENetDTLSClient : public ENetGodotSocket {
bool verify = false;
String for_hostname;
Ref<X509Certificate> cert;
- IP_Address local_address;
+ IPAddress local_address;
public:
ENetDTLSClient(ENetUDP *p_base, Ref<X509Certificate> p_cert, bool p_verify, String p_for_hostname) {
@@ -178,12 +178,12 @@ public:
close();
}
- Error bind(IP_Address p_ip, uint16_t p_port) {
+ Error bind(IPAddress p_ip, uint16_t p_port) {
local_address = p_ip;
return udp->bind(p_port, p_ip);
}
- Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+ Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) {
if (!udp->is_bound()) {
return ERR_UNCONFIGURED;
}
@@ -192,7 +192,7 @@ public:
return OK;
}
- Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+ Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
if (!connected) {
udp->connect_to_host(p_ip, p_port);
dtls->connect_to_peer(udp, verify, for_hostname, cert);
@@ -208,7 +208,7 @@ public:
return dtls->put_packet(p_buffer, p_len);
}
- Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) {
dtls->poll();
if (dtls->get_status() == PacketPeerDTLS::STATUS_HANDSHAKING) {
return ERR_BUSY;
@@ -250,7 +250,7 @@ class ENetDTLSServer : public ENetGodotSocket {
Ref<UDPServer> udp_server;
Map<String, Ref<PacketPeerDTLS>> peers;
int last_service = 0;
- IP_Address local_address;
+ IPAddress local_address;
public:
ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
@@ -273,12 +273,12 @@ public:
udp_server->set_max_pending_connections(p_refuse ? 0 : 16);
}
- Error bind(IP_Address p_ip, uint16_t p_port) {
+ Error bind(IPAddress p_ip, uint16_t p_port) {
local_address = p_ip;
return udp_server->listen(p_port, p_ip);
}
- Error get_socket_address(IP_Address *r_ip, uint16_t *r_port) {
+ Error get_socket_address(IPAddress *r_ip, uint16_t *r_port) {
if (!udp_server->is_listening()) {
return ERR_UNCONFIGURED;
}
@@ -287,7 +287,7 @@ public:
return OK;
}
- Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
+ Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IPAddress p_ip, uint16_t p_port) {
String key = String(p_ip) + ":" + itos(p_port);
ERR_FAIL_COND_V(!peers.has(key), ERR_UNAVAILABLE);
Ref<PacketPeerDTLS> peer = peers[key];
@@ -302,12 +302,12 @@ public:
return err;
}
- Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
+ Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IPAddress &r_ip, uint16_t &r_port) {
udp_server->poll();
// TODO limits? Maybe we can better enforce allowed connections!
if (udp_server->is_connection_available()) {
Ref<PacketPeerUDP> udp = udp_server->take_connection();
- IP_Address peer_ip = udp->get_packet_address();
+ IPAddress peer_ip = udp->get_packet_address();
int peer_port = udp->get_packet_port();
Ref<PacketPeerDTLS> peer = server->take_connection(udp);
PacketPeerDTLS::Status status = peer->get_status();
@@ -397,7 +397,7 @@ void enet_time_set(enet_uint32 newTimeBase) {
}
int enet_address_set_host(ENetAddress *address, const char *name) {
- IP_Address ip = IP::get_singleton()->resolve_hostname(name);
+ IPAddress ip = IP::get_singleton()->resolve_hostname(name);
ERR_FAIL_COND_V(!ip.is_valid(), -1);
enet_address_set_ip(address, ip.get_ipv6(), 16);
@@ -442,9 +442,9 @@ void enet_host_refuse_new_connections(ENetHost *host, int p_refuse) {
}
int enet_socket_bind(ENetSocket socket, const ENetAddress *address) {
- IP_Address ip;
+ IPAddress ip;
if (address->wildcard) {
- ip = IP_Address("*");
+ ip = IPAddress("*");
} else {
ip.set_ipv6(address->host);
}
@@ -466,7 +466,7 @@ int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBu
ERR_FAIL_COND_V(address == nullptr, -1);
ENetGodotSocket *sock = (ENetGodotSocket *)socket;
- IP_Address dest;
+ IPAddress dest;
Error err;
size_t i = 0;
@@ -508,7 +508,7 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
ENetGodotSocket *sock = (ENetGodotSocket *)socket;
int read;
- IP_Address ip;
+ IPAddress ip;
Error err = sock->recvfrom((uint8_t *)buffers[0].data, buffers[0].dataLength, read, ip, address->port);
if (err == ERR_BUSY) {
@@ -525,7 +525,7 @@ int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buf
}
int enet_socket_get_address (ENetSocket socket, ENetAddress * address) {
- IP_Address ip;
+ IPAddress ip;
uint16_t port;
ENetGodotSocket *sock = (ENetGodotSocket *)socket;
diff --git a/thirdparty/oidn/core/transfer_function.cpp b/thirdparty/oidn/core/transfer_function.cpp
index 487f0a9f75..ce5deca56b 100644
--- a/thirdparty/oidn/core/transfer_function.cpp
+++ b/thirdparty/oidn/core/transfer_function.cpp
@@ -24,10 +24,6 @@ namespace oidn {
float AutoexposureNode::autoexposure(const Image& color)
{
assert(color.format == Format::Float3);
-// -- GODOT start --
-// We don't want to mess with TTB and we don't use autoexposure, so we disable this code
-#if 0
-// -- GODOT end --
constexpr float key = 0.18f;
constexpr float eps = 1e-8f;
@@ -42,61 +38,66 @@ namespace oidn {
// Compute the average log luminance of the downsampled image
using Sum = std::pair<float, int>;
- Sum sum =
- tbb::parallel_reduce(
- tbb::blocked_range2d<int>(0, HK, 0, WK),
- Sum(0.f, 0),
- [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
+ // -- GODOT start --
+ // Sum sum =
+ // tbb::parallel_reduce(
+ // tbb::blocked_range2d<int>(0, HK, 0, WK),
+ // Sum(0.f, 0),
+ // [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
+ // {
+ // // Iterate over blocks
+ // for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+ // {
+ // for (int j = r.cols().begin(); j != r.cols().end(); ++j)
+ // {
+
+ Sum sum = Sum(0.0f, 0);
+
+ for (int i = 0; i != HK; ++i)
+ {
+ for (int j = 0; j != WK; ++j)
+ {
+ // Compute the average luminance in the current block
+ const int beginH = int(ptrdiff_t(i) * H / HK);
+ const int beginW = int(ptrdiff_t(j) * W / WK);
+ const int endH = int(ptrdiff_t(i+1) * H / HK);
+ const int endW = int(ptrdiff_t(j+1) * W / WK);
+
+ float L = 0.f;
+
+ for (int h = beginH; h < endH; ++h)
{
- // Iterate over blocks
- for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+ for (int w = beginW; w < endW; ++w)
{
- for (int j = r.cols().begin(); j != r.cols().end(); ++j)
- {
- // Compute the average luminance in the current block
- const int beginH = int(ptrdiff_t(i) * H / HK);
- const int beginW = int(ptrdiff_t(j) * W / WK);
- const int endH = int(ptrdiff_t(i+1) * H / HK);
- const int endW = int(ptrdiff_t(j+1) * W / WK);
-
- float L = 0.f;
-
- for (int h = beginH; h < endH; ++h)
- {
- for (int w = beginW; w < endW; ++w)
- {
- const float* rgb = (const float*)color.get(h, w);
-
- const float r = maxSafe(rgb[0], 0.f);
- const float g = maxSafe(rgb[1], 0.f);
- const float b = maxSafe(rgb[2], 0.f);
-
- L += luminance(r, g, b);
- }
- }
-
- L /= (endH - beginH) * (endW - beginW);
-
- // Accumulate the log luminance
- if (L > eps)
- {
- sum.first += log2(L);
- sum.second++;
- }
- }
+ const float* rgb = (const float*)color.get(h, w);
+
+ const float r = maxSafe(rgb[0], 0.f);
+ const float g = maxSafe(rgb[1], 0.f);
+ const float b = maxSafe(rgb[2], 0.f);
+
+ L += luminance(r, g, b);
}
+ }
- return sum;
- },
- [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
- tbb::static_partitioner()
- );
+ L /= (endH - beginH) * (endW - beginW);
+
+ // Accumulate the log luminance
+ if (L > eps)
+ {
+ sum.first += log2(L);
+ sum.second++;
+ }
+ }
+ }
+
+ // return sum;
+ // },
+ // [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
+ // tbb::static_partitioner()
+ // );
+ // -- GODOT end --
return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f;
-// -- GODOT start --
-#endif
- return 1.0;
-// -- GODOT end --
}
} // namespace oidn
diff --git a/thirdparty/oidn/patches/godot-changes-c58c5216.patch b/thirdparty/oidn/patches/godot-changes-c58c5216.patch
index 6a54703064..c01f00187b 100644
--- a/thirdparty/oidn/patches/godot-changes-c58c5216.patch
+++ b/thirdparty/oidn/patches/godot-changes-c58c5216.patch
@@ -280,28 +280,58 @@ index 8c2de09..ed8328c 100644
namespace oidn {
diff --git a/core/transfer_function.cpp b/core/transfer_function.cpp
-index 601f814..487f0a9 100644
+index 601f814..ce5deca 100644
--- a/core/transfer_function.cpp
+++ b/core/transfer_function.cpp
-@@ -24,6 +24,10 @@ namespace oidn {
- float AutoexposureNode::autoexposure(const Image& color)
- {
- assert(color.format == Format::Float3);
-+// -- GODOT start --
-+// We don't want to mess with TTB and we don't use autoexposure, so we disable this code
-+#if 0
-+// -- GODOT end --
+@@ -38,16 +38,24 @@ namespace oidn {
+ // Compute the average log luminance of the downsampled image
+ using Sum = std::pair<float, int>;
+
+- Sum sum =
+- tbb::parallel_reduce(
+- tbb::blocked_range2d<int>(0, HK, 0, WK),
+- Sum(0.f, 0),
+- [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
++ // -- GODOT start --
++ // Sum sum =
++ // tbb::parallel_reduce(
++ // tbb::blocked_range2d<int>(0, HK, 0, WK),
++ // Sum(0.f, 0),
++ // [&](const tbb::blocked_range2d<int>& r, Sum sum) -> Sum
++ // {
++ // // Iterate over blocks
++ // for (int i = r.rows().begin(); i != r.rows().end(); ++i)
++ // {
++ // for (int j = r.cols().begin(); j != r.cols().end(); ++j)
++ // {
++
++ Sum sum = Sum(0.0f, 0);
++
++ for (int i = 0; i != HK; ++i)
+ {
+- // Iterate over blocks
+- for (int i = r.rows().begin(); i != r.rows().end(); ++i)
+- {
+- for (int j = r.cols().begin(); j != r.cols().end(); ++j)
++ for (int j = 0; j != WK; ++j)
+ {
+ // Compute the average luminance in the current block
+ const int beginH = int(ptrdiff_t(i) * H / HK);
+@@ -82,11 +90,12 @@ namespace oidn {
+ }
+ }
- constexpr float key = 0.18f;
- constexpr float eps = 1e-8f;
-@@ -89,6 +93,10 @@ namespace oidn {
- );
+- return sum;
+- },
+- [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
+- tbb::static_partitioner()
+- );
++ // return sum;
++ // },
++ // [](Sum a, Sum b) -> Sum { return Sum(a.first+b.first, a.second+b.second); },
++ // tbb::static_partitioner()
++ // );
++ // -- GODOT end --
return (sum.second > 0) ? (key / exp2(sum.first / float(sum.second))) : 1.f;
-+// -- GODOT start --
-+#endif
-+ return 1.0;
-+// -- GODOT end --
}
-
- } // namespace oidn