summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/variant/variant_call.cpp4
-rw-r--r--doc/classes/Area3D.xml3
-rw-r--r--doc/classes/CameraServer.xml2
-rw-r--r--doc/classes/CharacterBody2D.xml6
-rw-r--r--doc/classes/CharacterBody3D.xml3
-rw-r--r--doc/classes/MeshInstance3D.xml6
-rw-r--r--doc/classes/Node.xml3
-rw-r--r--doc/classes/PhysicsServer3D.xml2
-rw-r--r--doc/classes/SkinReference.xml9
-rw-r--r--doc/classes/SoftBody3D.xml1
-rw-r--r--doc/classes/Vector2.xml8
-rw-r--r--doc/classes/Vector3.xml8
-rw-r--r--drivers/gles3/storage/light_storage.h23
-rw-r--r--editor/editor_data.cpp3
-rw-r--r--editor/editor_help.cpp4
-rw-r--r--editor/editor_layouts_dialog.cpp8
-rw-r--r--editor/editor_node.cpp8
-rw-r--r--editor/filesystem_dock.cpp14
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--misc/extension_api_validation/4.2-stable.expected7
-rw-r--r--modules/openxr/openxr_api.cpp11
-rw-r--r--scene/3d/mesh_instance_3d.cpp5
-rw-r--r--scene/3d/mesh_instance_3d.h2
-rw-r--r--scene/gui/rich_text_label.cpp12
-rw-r--r--scene/main/node.cpp51
-rw-r--r--scene/main/node.h7
-rw-r--r--servers/rendering/dummy/storage/light_storage.h1
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h23
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp3
-rw-r--r--servers/rendering/renderer_scene_cull.cpp14
-rw-r--r--servers/rendering/shader_language.cpp6
-rw-r--r--servers/rendering/storage/light_storage.h1
-rw-r--r--tests/core/io/test_ip.h (renamed from scene/main/node.compat.inc)26
-rw-r--r--tests/scene/test_camera_2d.h318
-rw-r--r--tests/test_main.cpp2
35 files changed, 511 insertions, 94 deletions
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index ba7c44e405..d0d940c47d 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1799,7 +1799,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector2, dot, sarray("with"), varray());
bind_method(Vector2, slide, sarray("n"), varray());
bind_method(Vector2, bounce, sarray("n"), varray());
- bind_method(Vector2, reflect, sarray("n"), varray());
+ bind_method(Vector2, reflect, sarray("line"), varray());
bind_method(Vector2, cross, sarray("with"), varray());
bind_method(Vector2, abs, sarray(), varray());
bind_method(Vector2, sign, sarray(), varray());
@@ -1896,7 +1896,7 @@ static void _register_variant_builtin_methods() {
bind_method(Vector3, project, sarray("b"), varray());
bind_method(Vector3, slide, sarray("n"), varray());
bind_method(Vector3, bounce, sarray("n"), varray());
- bind_method(Vector3, reflect, sarray("n"), varray());
+ bind_method(Vector3, reflect, sarray("direction"), varray());
bind_method(Vector3, sign, sarray(), varray());
bind_method(Vector3, octahedron_encode, sarray(), varray());
bind_static_method(Vector3, octahedron_decode, sarray("uv"), varray());
diff --git a/doc/classes/Area3D.xml b/doc/classes/Area3D.xml
index 4ee16d499d..8eedd3cdf2 100644
--- a/doc/classes/Area3D.xml
+++ b/doc/classes/Area3D.xml
@@ -124,12 +124,15 @@
</member>
<member name="wind_attenuation_factor" type="float" setter="set_wind_attenuation_factor" getter="get_wind_attenuation_factor" default="0.0">
The exponential rate at which wind force decreases with distance from its origin.
+ [b]Note:[/b] This wind force only applies to [SoftBody3D] nodes. Other physics bodies are currently not affected by wind.
</member>
<member name="wind_force_magnitude" type="float" setter="set_wind_force_magnitude" getter="get_wind_force_magnitude" default="0.0">
The magnitude of area-specific wind force.
+ [b]Note:[/b] This wind force only applies to [SoftBody3D] nodes. Other physics bodies are currently not affected by wind.
</member>
<member name="wind_source_path" type="NodePath" setter="set_wind_source_path" getter="get_wind_source_path" default="NodePath(&quot;&quot;)">
The [Node3D] which is used to specify the direction and origin of an area-specific wind force. The direction is opposite to the z-axis of the [Node3D]'s local transform, and its origin is the origin of the [Node3D]'s local transform.
+ [b]Note:[/b] This wind force only applies to [SoftBody3D] nodes. Other physics bodies are currently not affected by wind.
</member>
</members>
<signals>
diff --git a/doc/classes/CameraServer.xml b/doc/classes/CameraServer.xml
index 983bd6cd91..020b5d887b 100644
--- a/doc/classes/CameraServer.xml
+++ b/doc/classes/CameraServer.xml
@@ -6,7 +6,7 @@
<description>
The [CameraServer] keeps track of different cameras accessible in Godot. These are external cameras such as webcams or the cameras on your phone.
It is notably used to provide AR modules with a video feed from the camera.
- [b]Note:[/b] This class is currently only implemented on macOS and iOS. On other platforms, no [CameraFeed]s will be available.
+ [b]Note:[/b] This class is currently only implemented on macOS and iOS. To get a [CameraFeed] on iOS, the camera plugin from [url=https://github.com/godotengine/godot-ios-plugins]godot-ios-plugins[/url] is required. On other platforms, no [CameraFeed]s will be available.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CharacterBody2D.xml b/doc/classes/CharacterBody2D.xml
index df409cb3c4..ede4d63cfc 100644
--- a/doc/classes/CharacterBody2D.xml
+++ b/doc/classes/CharacterBody2D.xml
@@ -30,7 +30,8 @@
<method name="get_floor_normal" qualifiers="const">
<return type="Vector2" />
<description>
- Returns the surface normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ Returns the collision normal of the floor at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_floor] returns [code]true[/code].
+ [b]Warning:[/b] The collision normal is not always the same as the surface normal.
</description>
</method>
<method name="get_last_motion" qualifiers="const">
@@ -94,7 +95,8 @@
<method name="get_wall_normal" qualifiers="const">
<return type="Vector2" />
<description>
- Returns the surface normal of the wall at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_wall] returns [code]true[/code].
+ Returns the collision normal of the wall at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_wall] returns [code]true[/code].
+ [b]Warning:[/b] The collision normal is not always the same as the surface normal.
</description>
</method>
<method name="is_on_ceiling" qualifiers="const">
diff --git a/doc/classes/CharacterBody3D.xml b/doc/classes/CharacterBody3D.xml
index 498149b9c0..474adfc6ff 100644
--- a/doc/classes/CharacterBody3D.xml
+++ b/doc/classes/CharacterBody3D.xml
@@ -87,7 +87,8 @@
<method name="get_wall_normal" qualifiers="const">
<return type="Vector3" />
<description>
- Returns the surface normal of the wall at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_wall] returns [code]true[/code].
+ Returns the collision normal of the wall at the last collision point. Only valid after calling [method move_and_slide] and when [method is_on_wall] returns [code]true[/code].
+ [b]Warning:[/b] The collision normal is not always the same as the surface normal.
</description>
</method>
<method name="is_on_ceiling" qualifiers="const">
diff --git a/doc/classes/MeshInstance3D.xml b/doc/classes/MeshInstance3D.xml
index f56b03bdc4..e5187cf7a1 100644
--- a/doc/classes/MeshInstance3D.xml
+++ b/doc/classes/MeshInstance3D.xml
@@ -70,6 +70,12 @@
Returns the value of the blend shape at the given [param blend_shape_idx]. Returns [code]0.0[/code] and produces an error if [member mesh] is [code]null[/code] or doesn't have a blend shape at that index.
</description>
</method>
+ <method name="get_skin_reference" qualifiers="const">
+ <return type="SkinReference" />
+ <description>
+ Returns the internal [SkinReference] containing the skeleton's [RID] attached to this RID. See also [method Resource.get_rid], [method SkinReference.get_skeleton], and [method RenderingServer.instance_attach_skeleton].
+ </description>
+ </method>
<method name="get_surface_override_material" qualifiers="const">
<return type="Material" />
<param index="0" name="surface" type="int" />
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index d9138b059c..aea4082dbe 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -795,9 +795,8 @@
<return type="void" />
<param index="0" name="node" type="Node" />
<param index="1" name="keep_groups" type="bool" default="false" />
- <param index="2" name="keep_children" type="bool" default="true" />
<description>
- Replaces this node by the given [param node]. If [param keep_children] is [code]true[/code] all children of this node are moved to [param node].
+ Replaces this node by the given [param node]. All children of this node are moved to [param node].
If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in (see [method add_to_group]).
[b]Warning:[/b] The replaced node is removed from the tree, but it is [b]not[/b] deleted. To prevent memory leaks, store a reference to the node in a variable, or use [method Object.free].
</description>
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index 7dcb185834..4a4a1ad025 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -1628,7 +1628,7 @@
Constant to set/get the priority (order of processing) of an area.
</constant>
<constant name="AREA_PARAM_WIND_FORCE_MAGNITUDE" value="10" enum="AreaParameter">
- Constant to set/get the magnitude of area-specific wind force.
+ Constant to set/get the magnitude of area-specific wind force. This wind force only applies to [SoftBody3D] nodes. Other physics bodies are currently not affected by wind.
</constant>
<constant name="AREA_PARAM_WIND_SOURCE" value="11" enum="AreaParameter">
Constant to set/get the 3D vector that specifies the origin from which an area-specific wind blows.
diff --git a/doc/classes/SkinReference.xml b/doc/classes/SkinReference.xml
index 466dbe2500..cb0c44cefa 100644
--- a/doc/classes/SkinReference.xml
+++ b/doc/classes/SkinReference.xml
@@ -1,8 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SkinReference" inherits="RefCounted" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A reference-counted holder object for a skeleton RID used in the [RenderingServer].
</brief_description>
<description>
+ An internal object containing a mapping from a [Skin] used within the context of a particular [MeshInstance3D] to refer to the skeleton's [RID] in the RenderingServer.
+ See also [method MeshInstance3D.get_skin_reference] and [method RenderingServer.instance_attach_skeleton].
+ Note that despite the similar naming, the skeleton RID used in the [RenderingServer] does not have a direct one-to-one correspondence to a [Skeleton3D] node.
+ In particular, a [Skeleton3D] node with no [MeshInstance3D] children may be unknown to the [RenderingServer].
+ On the other hand, a [Skeleton3D] with multiple [MeshInstance3D] nodes which each have different [member MeshInstance3D.skin] objects may have multiple SkinReference instances (and hence, multiple skeleton [RID]s).
</description>
<tutorials>
</tutorials>
@@ -10,11 +16,14 @@
<method name="get_skeleton" qualifiers="const">
<return type="RID" />
<description>
+ Returns the [RID] owned by this SkinReference, as returned by [method RenderingServer.skeleton_create].
</description>
</method>
<method name="get_skin" qualifiers="const">
<return type="Skin" />
<description>
+ Returns the [Skin] connected to this SkinReference. In the case of [MeshInstance3D] with no [member MeshInstance3D.skin] assigned, this will reference an internal default [Skin] owned by that [MeshInstance3D].
+ Note that a single [Skin] may have more than one [SkinReference] in the case that it is shared by meshes across multiple [Skeleton3D] nodes.
</description>
</method>
</methods>
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index a4d80a7c3e..195196b78c 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
A deformable 3D physics mesh. Used to create elastic or deformable objects such as cloth, rubber, or other flexible materials.
+ Additionally, [SoftBody3D] is subject to wind forces defined in [Area3D] (see [member Area3D.wind_source_path], [member Area3D.wind_force_magnitude], and [member Area3D.wind_attenuation_factor]).
[b]Note:[/b] There are many known bugs in [SoftBody3D]. Therefore, it's not recommended to use them for things that can affect gameplay (such as trampolines).
</description>
<tutorials>
diff --git a/doc/classes/Vector2.xml b/doc/classes/Vector2.xml
index 0b39743a72..7b166a4fb0 100644
--- a/doc/classes/Vector2.xml
+++ b/doc/classes/Vector2.xml
@@ -110,7 +110,8 @@
<return type="Vector2" />
<param index="0" name="n" type="Vector2" />
<description>
- Returns a new vector "bounced off" from a plane defined by the given normal.
+ Returns the vector "bounced off" from a line defined by the given normal [param n] perpendicular to the line.
+ [b]Note:[/b] [method bounce] performs the operation that most engines and frameworks call [code skip-lint]reflect()[/code].
</description>
</method>
<method name="ceil" qualifiers="const">
@@ -321,9 +322,10 @@
</method>
<method name="reflect" qualifiers="const">
<return type="Vector2" />
- <param index="0" name="n" type="Vector2" />
+ <param index="0" name="line" type="Vector2" />
<description>
- Returns the result of reflecting the vector from a line defined by the given direction vector [param n].
+ Returns the result of reflecting the vector from a line defined by the given direction vector [param line].
+ [b]Note:[/b] [method reflect] differs from what other engines and frameworks call [code skip-lint]reflect()[/code]. In other engines, [code skip-lint]reflect()[/code] takes a normal direction which is a direction perpendicular to the line. In Godot, you specify the direction of the line directly. See also [method bounce] which does what most engines call [code skip-lint]reflect()[/code].
</description>
</method>
<method name="rotated" qualifiers="const">
diff --git a/doc/classes/Vector3.xml b/doc/classes/Vector3.xml
index af1383fe22..031d91af78 100644
--- a/doc/classes/Vector3.xml
+++ b/doc/classes/Vector3.xml
@@ -86,7 +86,8 @@
<return type="Vector3" />
<param index="0" name="n" type="Vector3" />
<description>
- Returns the vector "bounced off" from a plane defined by the given normal.
+ Returns the vector "bounced off" from a plane defined by the given normal [param n].
+ [b]Note:[/b] [method bounce] performs the operation that most engines and frameworks call [code skip-lint]reflect()[/code].
</description>
</method>
<method name="ceil" qualifiers="const">
@@ -306,9 +307,10 @@
</method>
<method name="reflect" qualifiers="const">
<return type="Vector3" />
- <param index="0" name="n" type="Vector3" />
+ <param index="0" name="direction" type="Vector3" />
<description>
- Returns the result of reflecting the vector from a plane defined by the given normal [param n].
+ Returns the result of reflecting the vector from a plane defined by the given direction vector [param direction].
+ [b]Note:[/b] [method reflect] differs from what other engines and frameworks call [code skip-lint]reflect()[/code]. In other engines, [code skip-lint]reflect()[/code] takes a normal direction which is a direction perpendicular to the plane. In Godot, you specify a direction parallel to the plane. See also [method bounce] which does what most engines call [code skip-lint]reflect()[/code].
</description>
</method>
<method name="rotated" qualifiers="const">
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index 8107a3ad4d..b6e64c9492 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -441,6 +441,29 @@ public:
virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
virtual void light_instance_mark_visible(RID p_light_instance) override;
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override {
+ const LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_NULL_V(light_instance, false);
+ const Light *light = light_owner.get_or_null(light_instance->light);
+ ERR_FAIL_NULL_V(light, false);
+
+ if (!light->shadow) {
+ return false;
+ }
+
+ if (!light->distance_fade) {
+ return true;
+ }
+
+ real_t distance = p_position.distance_to(light_instance->transform.origin);
+
+ if (distance > light->distance_fade_shadow + light->distance_fade_length) {
+ return false;
+ }
+
+ return true;
+ }
+
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->light;
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index 72225fd454..bdc6504417 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -722,8 +722,7 @@ bool EditorData::check_and_update_scene(int p_idx) {
new_scene->set_scene_file_path(edited_scene[p_idx].root->get_scene_file_path());
Node *old_root = edited_scene[p_idx].root;
- edited_scene.write[p_idx].root = new_scene;
- old_root->replace_by(new_scene, false, false);
+ EditorNode::get_singleton()->set_edited_scene(new_scene);
memdelete(old_root);
edited_scene.write[p_idx].selection = new_selection;
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index cd498ce089..b3fc87e2c8 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -3562,8 +3562,11 @@ void EditorHelpHighlighter::reset_cache() {
}
EditorHelpHighlighter::EditorHelpHighlighter() {
+ const Color text_color = EDITOR_GET("text_editor/theme/highlighting/text_color");
+
#ifdef MODULE_GDSCRIPT_ENABLED
TextEdit *gdscript_text_edit = memnew(TextEdit);
+ gdscript_text_edit->add_theme_color_override("font_color", text_color);
Ref<GDScript> gdscript;
gdscript.instantiate();
@@ -3580,6 +3583,7 @@ EditorHelpHighlighter::EditorHelpHighlighter() {
#ifdef MODULE_MONO_ENABLED
TextEdit *csharp_text_edit = memnew(TextEdit);
+ csharp_text_edit->add_theme_color_override("font_color", text_color);
// See GH-89610.
//Ref<CSharpScript> csharp;
diff --git a/editor/editor_layouts_dialog.cpp b/editor/editor_layouts_dialog.cpp
index db6fa2c035..52047c569d 100644
--- a/editor/editor_layouts_dialog.cpp
+++ b/editor/editor_layouts_dialog.cpp
@@ -31,8 +31,6 @@
#include "editor_layouts_dialog.h"
#include "core/io/config_file.h"
-#include "core/object/class_db.h"
-#include "core/os/keyboard.h"
#include "editor/editor_settings.h"
#include "editor/themes/editor_scale.h"
#include "scene/gui/item_list.h"
@@ -60,7 +58,7 @@ void EditorLayoutsDialog::_update_ok_disable_state() {
if (layout_names->is_anything_selected()) {
get_ok_button()->set_disabled(false);
} else {
- get_ok_button()->set_disabled(!name->is_visible() || name->get_text().is_empty());
+ get_ok_button()->set_disabled(!name->is_visible() || name->get_text().strip_edges().is_empty());
}
}
@@ -80,8 +78,8 @@ void EditorLayoutsDialog::ok_pressed() {
for (int i = 0; i < selected_items.size(); ++i) {
emit_signal(SNAME("name_confirmed"), layout_names->get_item_text(selected_items[i]));
}
- } else if (name->is_visible() && !name->get_text().is_empty()) {
- emit_signal(SNAME("name_confirmed"), name->get_text());
+ } else if (name->is_visible() && !name->get_text().strip_edges().is_empty()) {
+ emit_signal(SNAME("name_confirmed"), name->get_text().strip_edges());
}
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 0e6c814b44..26ba43cac5 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -2136,10 +2136,6 @@ void EditorNode::_dialog_action(String p_file) {
} break;
case SETTINGS_LAYOUT_DELETE: {
- if (p_file.is_empty()) {
- return;
- }
-
Ref<ConfigFile> config;
config.instantiate();
Error err = config->load(EditorSettings::get_singleton()->get_editor_layouts_config());
@@ -3674,9 +3670,7 @@ void EditorNode::set_edited_scene(Node *p_scene) {
if (old_edited_scene_root->get_parent() == scene_root) {
scene_root->remove_child(old_edited_scene_root);
}
- if (old_edited_scene_root->is_connected("replacing_by", callable_mp(this, &EditorNode::set_edited_scene))) {
- old_edited_scene_root->disconnect(SNAME("replacing_by"), callable_mp(this, &EditorNode::set_edited_scene));
- }
+ old_edited_scene_root->disconnect(SNAME("replacing_by"), callable_mp(this, &EditorNode::set_edited_scene));
}
get_editor_data().set_edited_scene_root(p_scene);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 2087c8cee6..3b6ce8d396 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2531,6 +2531,14 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
}
} break;
+ case FILE_COPY_ABSOLUTE_PATH: {
+ if (!p_selected.is_empty()) {
+ const String &fpath = p_selected[0];
+ const String absolute_path = ProjectSettings::get_singleton()->globalize_path(fpath);
+ DisplayServer::get_singleton()->clipboard_set(absolute_path);
+ }
+ } break;
+
case FILE_COPY_UID: {
if (!p_selected.is_empty()) {
ResourceUID::ID uid = ResourceLoader::get_resource_uid(p_selected[0]);
@@ -3193,6 +3201,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, const Vect
if (p_paths.size() == 1) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionCopy")), ED_GET_SHORTCUT("filesystem_dock/copy_path"), FILE_COPY_PATH);
+ p_popup->add_shortcut(ED_GET_SHORTCUT("filesystem_dock/copy_absolute_path"), FILE_COPY_ABSOLUTE_PATH);
if (ResourceLoader::get_resource_uid(p_paths[0]) != ResourceUID::INVALID_ID) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Instance")), ED_GET_SHORTCUT("filesystem_dock/copy_uid"), FILE_COPY_UID);
}
@@ -3481,6 +3490,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
_tree_rmb_option(FILE_DUPLICATE);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_path", p_event)) {
_tree_rmb_option(FILE_COPY_PATH);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/copy_absolute_path", p_event)) {
+ _tree_rmb_option(FILE_COPY_ABSOLUTE_PATH);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_uid", p_event)) {
_tree_rmb_option(FILE_COPY_UID);
} else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
@@ -3553,6 +3564,8 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
_file_list_rmb_option(FILE_DUPLICATE);
} else if (ED_IS_SHORTCUT("filesystem_dock/copy_path", p_event)) {
_file_list_rmb_option(FILE_COPY_PATH);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/copy_absolute_path", p_event)) {
+ _file_list_rmb_option(FILE_COPY_ABSOLUTE_PATH);
} else if (ED_IS_SHORTCUT("filesystem_dock/delete", p_event)) {
_file_list_rmb_option(FILE_REMOVE);
} else if (ED_IS_SHORTCUT("filesystem_dock/rename", p_event)) {
@@ -3856,6 +3869,7 @@ FileSystemDock::FileSystemDock() {
// `KeyModifierMask::CMD_OR_CTRL | Key::C` conflicts with other editor shortcuts.
ED_SHORTCUT("filesystem_dock/copy_path", TTR("Copy Path"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::C);
+ ED_SHORTCUT("filesystem_dock/copy_absolute_path", TTR("Copy Absolute Path"));
ED_SHORTCUT("filesystem_dock/copy_uid", TTR("Copy UID"));
ED_SHORTCUT("filesystem_dock/duplicate", TTR("Duplicate..."), KeyModifierMask::CMD_OR_CTRL | Key::D);
ED_SHORTCUT("filesystem_dock/delete", TTR("Delete"), Key::KEY_DELETE);
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index b950075928..c9fe3a8baf 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -129,6 +129,7 @@ private:
FILE_OPEN_EXTERNAL,
FILE_OPEN_IN_TERMINAL,
FILE_COPY_PATH,
+ FILE_COPY_ABSOLUTE_PATH,
FILE_COPY_UID,
FOLDER_EXPAND_ALL,
FOLDER_COLLAPSE_ALL,
diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected
index bb10b422dc..9cd732813e 100644
--- a/misc/extension_api_validation/4.2-stable.expected
+++ b/misc/extension_api_validation/4.2-stable.expected
@@ -241,13 +241,6 @@ Validate extension JSON: Error: Field 'classes/AcceptDialog/methods/remove_butto
Changed argument type to the more specific one actually expected by the method. Compatibility method registered.
-GH-89992
---------
-Validate extension JSON: Error: Field 'classes/Node/methods/replace_by/arguments': size changed value in new API, from 2 to 3.
-
-Added optional argument to prevent children to be reparented during replace_by. Compatibility method registered.
-
-
GH-88047
--------
Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3.
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 5438f5020c..1fe402341b 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -1204,10 +1204,12 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
depth_views[i].subImage.imageRect.offset.y = 0;
depth_views[i].subImage.imageRect.extent.width = main_swapchain_size.width;
depth_views[i].subImage.imageRect.extent.height = main_swapchain_size.height;
+ // OpenXR spec says that: minDepth < maxDepth.
depth_views[i].minDepth = 0.0;
depth_views[i].maxDepth = 1.0;
- depth_views[i].nearZ = 0.01; // Near and far Z will be set to the correct values in fill_projection_matrix
- depth_views[i].farZ = 100.0;
+ // But we can reverse near and far for reverse-Z.
+ depth_views[i].nearZ = 100.0; // Near and far Z will be set to the correct values in fill_projection_matrix
+ depth_views[i].farZ = 0.01;
}
};
@@ -1802,8 +1804,9 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z
// if we're using depth views, make sure we update our near and far there...
if (depth_views != nullptr) {
for (uint32_t i = 0; i < view_count; i++) {
- depth_views[i].nearZ = p_z_near;
- depth_views[i].farZ = p_z_far;
+ // As we are using reverse-Z these need to be flipped.
+ depth_views[i].nearZ = p_z_far;
+ depth_views[i].farZ = p_z_near;
}
}
diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp
index 8635240655..616fb18d53 100644
--- a/scene/3d/mesh_instance_3d.cpp
+++ b/scene/3d/mesh_instance_3d.cpp
@@ -204,6 +204,10 @@ Ref<Skin> MeshInstance3D::get_skin() const {
return skin;
}
+Ref<SkinReference> MeshInstance3D::get_skin_reference() const {
+ return skin_ref;
+}
+
void MeshInstance3D::set_skeleton_path(const NodePath &p_skeleton) {
skeleton_path = p_skeleton;
if (!is_inside_tree()) {
@@ -518,6 +522,7 @@ void MeshInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance3D::get_skeleton_path);
ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance3D::set_skin);
ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance3D::get_skin);
+ ClassDB::bind_method(D_METHOD("get_skin_reference"), &MeshInstance3D::get_skin_reference);
ClassDB::bind_method(D_METHOD("get_surface_override_material_count"), &MeshInstance3D::get_surface_override_material_count);
ClassDB::bind_method(D_METHOD("set_surface_override_material", "surface", "material"), &MeshInstance3D::set_surface_override_material);
diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h
index add6bfe15e..d6ae1291d3 100644
--- a/scene/3d/mesh_instance_3d.h
+++ b/scene/3d/mesh_instance_3d.h
@@ -75,6 +75,8 @@ public:
void set_skeleton_path(const NodePath &p_skeleton);
NodePath get_skeleton_path();
+ Ref<SkinReference> get_skin_reference() const;
+
int get_blend_shape_count() const;
int find_blend_shape_by_name(const StringName &p_name);
float get_blend_shape_value(int p_blend_shape) const;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 1baf71dd07..f8bbedde09 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -835,10 +835,13 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
// Draw dropcap.
int dc_lines = l.text_buf->get_dropcap_lines();
float h_off = l.text_buf->get_dropcap_size().x;
- if (l.dc_ol_size > 0) {
- l.text_buf->draw_dropcap_outline(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_ol_size, l.dc_ol_color);
+ bool skip_dc = (trim_chars && l.char_offset > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs));
+ if (!skip_dc) {
+ if (l.dc_ol_size > 0) {
+ l.text_buf->draw_dropcap_outline(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_ol_size, l.dc_ol_color);
+ }
+ l.text_buf->draw_dropcap(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color);
}
- l.text_buf->draw_dropcap(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color);
int line_count = 0;
Size2 ctrl_size = get_size();
@@ -894,7 +897,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} break;
}
- if (!prefix.is_empty() && line == 0) {
+ bool skip_prefix = (visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING && l.char_offset == visible_characters) || (trim_chars && l.char_offset > visible_characters) || (trim_glyphs_ltr && (r_processed_glyphs >= visible_glyphs)) || (trim_glyphs_rtl && (r_processed_glyphs < total_glyphs - visible_glyphs));
+ if (!prefix.is_empty() && line == 0 && !skip_prefix) {
Ref<Font> font = theme_cache.normal_font;
int font_size = theme_cache.normal_font_size;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index beb2583b61..5c5049759f 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "node.h"
-#include "node.compat.inc"
#include "core/config/project_settings.h"
#include "core/core_string_names.h"
@@ -3006,7 +3005,7 @@ static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) {
}
}
-void Node::replace_by(Node *p_node, bool p_keep_groups, bool p_keep_children) {
+void Node::replace_by(Node *p_node, bool p_keep_groups) {
ERR_THREAD_GUARD
ERR_FAIL_NULL(p_node);
ERR_FAIL_COND(p_node->data.parent);
@@ -3027,13 +3026,13 @@ void Node::replace_by(Node *p_node, bool p_keep_groups, bool p_keep_children) {
_replace_connections_target(p_node);
if (data.owner) {
- if (p_keep_children) {
- for (int i = 0; i < get_child_count(); i++) {
- find_owned_by(data.owner, get_child(i), &owned_by_owner);
- }
+ for (int i = 0; i < get_child_count(); i++) {
+ find_owned_by(data.owner, get_child(i), &owned_by_owner);
}
+
_clean_up_owner();
}
+
Node *parent = data.parent;
int index_in_parent = get_index(false);
@@ -3045,33 +3044,31 @@ void Node::replace_by(Node *p_node, bool p_keep_groups, bool p_keep_children) {
emit_signal(SNAME("replacing_by"), p_node);
- if (p_keep_children) {
- while (get_child_count()) {
- Node *child = get_child(0);
- remove_child(child);
- if (!child->is_owned_by_parent()) {
- // add the custom children to the p_node
- Node *child_owner = child->get_owner() == this ? p_node : child->get_owner();
- child->set_owner(nullptr);
- p_node->add_child(child);
- child->set_owner(child_owner);
- }
+ while (get_child_count()) {
+ Node *child = get_child(0);
+ remove_child(child);
+ if (!child->is_owned_by_parent()) {
+ // add the custom children to the p_node
+ Node *child_owner = child->get_owner() == this ? p_node : child->get_owner();
+ child->set_owner(nullptr);
+ p_node->add_child(child);
+ child->set_owner(child_owner);
}
+ }
- for (Node *E : owned) {
- if (E->data.owner != p_node) {
- E->set_owner(p_node);
- }
+ p_node->set_owner(owner);
+ for (Node *E : owned) {
+ if (E->data.owner != p_node) {
+ E->set_owner(p_node);
}
+ }
- for (Node *E : owned_by_owner) {
- if (E->data.owner != owner) {
- E->set_owner(owner);
- }
+ for (Node *E : owned_by_owner) {
+ if (E->data.owner != owner) {
+ E->set_owner(owner);
}
}
- p_node->set_owner(owner);
p_node->set_scene_file_path(get_scene_file_path());
}
@@ -3598,7 +3595,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_tween"), &Node::create_tween);
ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANTIATION | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS));
- ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups", "keep_children"), &Node::replace_by, DEFVAL(false), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder);
ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder);
diff --git a/scene/main/node.h b/scene/main/node.h
index 99def10338..f49eeec9cd 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -310,11 +310,6 @@ private:
Variant _call_thread_safe_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
protected:
-#ifndef DISABLE_DEPRECATED
- void _replace_by_bind_compat_89992(Node *p_node, bool p_keep_data = false);
- static void _bind_compatibility_methods();
-#endif // DISABLE_DEPRECATED
-
void _block() { data.blocked++; }
void _unblock() { data.blocked--; }
@@ -634,7 +629,7 @@ public:
return binds;
}
- void replace_by(Node *p_node, bool p_keep_groups = false, bool p_keep_children = true);
+ void replace_by(Node *p_node, bool p_keep_data = false);
void set_process_mode(ProcessMode p_mode);
ProcessMode get_process_mode() const;
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index a76305cdaa..0a9602b603 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -91,6 +91,7 @@ public:
void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
void light_instance_mark_visible(RID p_light_instance) override {}
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override { return false; }
/* PROBE API */
virtual RID reflection_probe_allocate() override { return RID(); }
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index b3d6bf5254..f152cc5dae 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -590,6 +590,29 @@ public:
virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
virtual void light_instance_mark_visible(RID p_light_instance) override;
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override {
+ const LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_NULL_V(light_instance, false);
+ const Light *light = light_owner.get_or_null(light_instance->light);
+ ERR_FAIL_NULL_V(light, false);
+
+ if (!light->shadow) {
+ return false;
+ }
+
+ if (!light->distance_fade) {
+ return true;
+ }
+
+ real_t distance = p_position.distance_to(light_instance->transform.origin);
+
+ if (distance > light->distance_fade_shadow + light->distance_fade_length) {
+ return false;
+ }
+
+ return true;
+ }
+
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->light;
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index c5d74d395f..b7934cb3de 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -130,9 +130,10 @@ void RenderSceneBuffersRD::cleanup() {
named_textures.clear();
// Clear weight_buffer / blur textures.
- for (const WeightBuffers &weight_buffer : weight_buffers) {
+ for (WeightBuffers &weight_buffer : weight_buffers) {
if (weight_buffer.weight.is_valid()) {
RD::get_singleton()->free(weight_buffer.weight);
+ weight_buffer.weight = RID();
}
}
}
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index b33de9d6f4..96c0479ac3 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -1029,7 +1029,6 @@ inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
Instance *instance = instance_owner.get_or_null(p_instance);
ERR_FAIL_NULL(instance);
- ERR_FAIL_COND(!is_geometry_instance(instance->base_type));
if (p_aabb != AABB()) {
// Set custom AABB
@@ -3029,6 +3028,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
light_culler->prepare_camera(p_camera_data->main_transform, p_camera_data->main_projection);
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
+ Vector3 camera_position = p_camera_data->main_transform.origin;
ERR_FAIL_COND(p_render_buffers.is_null());
@@ -3038,7 +3038,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
if (p_reflection_probe.is_null()) {
//no rendering code here, this is only to set up what needs to be done, request regions, etc.
- scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
+ scene_render->sdfgi_update(p_render_buffers, p_environment, camera_position); //update conditions for SDFGI (whether its used or not)
}
RENDER_TIMESTAMP("Update Visibility Dependencies");
@@ -3051,7 +3051,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
VisibilityCullData visibility_cull_data;
visibility_cull_data.scenario = scenario;
visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport];
- visibility_cull_data.camera_position = p_camera_data->main_transform.origin;
+ visibility_cull_data.camera_position = camera_position;
for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0
visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i);
@@ -3220,16 +3220,20 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
}
- // Positional Shadowss
+ // Positional Shadows
for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) {
Instance *ins = scene_cull_result.lights[i];
- if (!p_shadow_atlas.is_valid() || !RSG::light_storage->light_has_shadow(ins->base)) {
+ if (!p_shadow_atlas.is_valid()) {
continue;
}
InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
+ if (!RSG::light_storage->light_instance_is_shadow_visible_at_position(light->instance, camera_position)) {
+ continue;
+ }
+
float coverage = 0.f;
{ //compute coverage
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index fef1a205d6..8fbad346a4 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -8361,7 +8361,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
}
}
#endif // DEBUG_ENABLED
- if (String(shader_type_identifier) != "spatial") {
+ if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") {
_set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
@@ -8848,7 +8848,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
_set_error(RTR("'hint_normal_roughness_texture' is only available when using the Forward+ backend."));
return ERR_PARSE_ERROR;
}
- if (String(shader_type_identifier) != "spatial") {
+ if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") {
_set_error(vformat(RTR("'hint_normal_roughness_texture' is not supported in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
@@ -8857,7 +8857,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE;
--texture_uniforms;
--texture_binding;
- if (String(shader_type_identifier) != "spatial") {
+ if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") {
_set_error(vformat(RTR("'hint_depth_texture' is not supported in '%s' shaders."), shader_type_identifier));
return ERR_PARSE_ERROR;
}
diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h
index d439598f3d..6a0adfa596 100644
--- a/servers/rendering/storage/light_storage.h
+++ b/servers/rendering/storage/light_storage.h
@@ -98,6 +98,7 @@ public:
virtual bool light_instances_can_render_shadow_cube() const {
return true;
}
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light, const Vector3 &p_position) const = 0;
/* PROBE API */
diff --git a/scene/main/node.compat.inc b/tests/core/io/test_ip.h
index 69ece1a40d..7b5583faa0 100644
--- a/scene/main/node.compat.inc
+++ b/tests/core/io/test_ip.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* node.compat.inc */
+/* test_ip.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,14 +28,24 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef DISABLE_DEPRECATED
+#ifndef TEST_IP_H
+#define TEST_IP_H
-void Node::_replace_by_bind_compat_89992(Node *p_node, bool p_keep_data) {
- replace_by(p_node, p_keep_data, true);
-}
+#include "core/io/ip.h"
+
+#include "tests/test_macros.h"
-void Node::_bind_compatibility_methods() {
- ClassDB::bind_compatibility_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::_replace_by_bind_compat_89992, DEFVAL(false));
+namespace TestIP {
+
+TEST_CASE("[IP] resolve_hostname") {
+ for (int x = 0; x < 1000; x++) {
+ IPAddress IPV4 = IP::get_singleton()->resolve_hostname("localhost", IP::TYPE_IPV4);
+ CHECK("127.0.0.1" == String(IPV4));
+ IPAddress IPV6 = IP::get_singleton()->resolve_hostname("localhost", IP::TYPE_IPV6);
+ CHECK("0:0:0:0:0:0:0:1" == String(IPV6));
+ }
}
-#endif
+} // namespace TestIP
+
+#endif // TEST_IP_H
diff --git a/tests/scene/test_camera_2d.h b/tests/scene/test_camera_2d.h
new file mode 100644
index 0000000000..f03a4aed53
--- /dev/null
+++ b/tests/scene/test_camera_2d.h
@@ -0,0 +1,318 @@
+/**************************************************************************/
+/* test_camera_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef TEST_CAMERA_2D_H
+#define TEST_CAMERA_2D_H
+
+#include "scene/2d/camera_2d.h"
+#include "scene/main/viewport.h"
+#include "scene/main/window.h"
+#include "tests/test_macros.h"
+
+namespace TestCamera2D {
+
+TEST_CASE("[SceneTree][Camera2D] Getters and setters") {
+ Camera2D *test_camera = memnew(Camera2D);
+
+ SUBCASE("AnchorMode") {
+ test_camera->set_anchor_mode(Camera2D::AnchorMode::ANCHOR_MODE_FIXED_TOP_LEFT);
+ CHECK(test_camera->get_anchor_mode() == Camera2D::AnchorMode::ANCHOR_MODE_FIXED_TOP_LEFT);
+ test_camera->set_anchor_mode(Camera2D::AnchorMode::ANCHOR_MODE_DRAG_CENTER);
+ CHECK(test_camera->get_anchor_mode() == Camera2D::AnchorMode::ANCHOR_MODE_DRAG_CENTER);
+ }
+
+ SUBCASE("ProcessCallback") {
+ test_camera->set_process_callback(Camera2D::Camera2DProcessCallback::CAMERA2D_PROCESS_PHYSICS);
+ CHECK(test_camera->get_process_callback() == Camera2D::Camera2DProcessCallback::CAMERA2D_PROCESS_PHYSICS);
+ test_camera->set_process_callback(Camera2D::Camera2DProcessCallback::CAMERA2D_PROCESS_IDLE);
+ CHECK(test_camera->get_process_callback() == Camera2D::Camera2DProcessCallback::CAMERA2D_PROCESS_IDLE);
+ }
+
+ SUBCASE("Drag") {
+ constexpr float drag_left_margin = 0.8f;
+ constexpr float drag_top_margin = 0.8f;
+ constexpr float drag_right_margin = 0.8f;
+ constexpr float drag_bottom_margin = 0.8f;
+ constexpr float drag_horizontal_offset1 = 0.5f;
+ constexpr float drag_horizontal_offset2 = -0.5f;
+ constexpr float drag_vertical_offset1 = 0.5f;
+ constexpr float drag_vertical_offset2 = -0.5f;
+ test_camera->set_drag_margin(SIDE_LEFT, drag_left_margin);
+ CHECK(test_camera->get_drag_margin(SIDE_LEFT) == drag_left_margin);
+ test_camera->set_drag_margin(SIDE_TOP, drag_top_margin);
+ CHECK(test_camera->get_drag_margin(SIDE_TOP) == drag_top_margin);
+ test_camera->set_drag_margin(SIDE_RIGHT, drag_right_margin);
+ CHECK(test_camera->get_drag_margin(SIDE_RIGHT) == drag_right_margin);
+ test_camera->set_drag_margin(SIDE_BOTTOM, drag_bottom_margin);
+ CHECK(test_camera->get_drag_margin(SIDE_BOTTOM) == drag_bottom_margin);
+ test_camera->set_drag_horizontal_enabled(true);
+ CHECK(test_camera->is_drag_horizontal_enabled());
+ test_camera->set_drag_horizontal_enabled(false);
+ CHECK_FALSE(test_camera->is_drag_horizontal_enabled());
+ test_camera->set_drag_horizontal_offset(drag_horizontal_offset1);
+ CHECK(test_camera->get_drag_horizontal_offset() == drag_horizontal_offset1);
+ test_camera->set_drag_horizontal_offset(drag_horizontal_offset2);
+ CHECK(test_camera->get_drag_horizontal_offset() == drag_horizontal_offset2);
+ test_camera->set_drag_vertical_enabled(true);
+ CHECK(test_camera->is_drag_vertical_enabled());
+ test_camera->set_drag_vertical_enabled(false);
+ CHECK_FALSE(test_camera->is_drag_vertical_enabled());
+ test_camera->set_drag_vertical_offset(drag_vertical_offset1);
+ CHECK(test_camera->get_drag_vertical_offset() == drag_vertical_offset1);
+ test_camera->set_drag_vertical_offset(drag_vertical_offset2);
+ CHECK(test_camera->get_drag_vertical_offset() == drag_vertical_offset2);
+ }
+
+ SUBCASE("Drawing") {
+ test_camera->set_margin_drawing_enabled(true);
+ CHECK(test_camera->is_margin_drawing_enabled());
+ test_camera->set_margin_drawing_enabled(false);
+ CHECK_FALSE(test_camera->is_margin_drawing_enabled());
+ test_camera->set_limit_drawing_enabled(true);
+ CHECK(test_camera->is_limit_drawing_enabled());
+ test_camera->set_limit_drawing_enabled(false);
+ CHECK_FALSE(test_camera->is_limit_drawing_enabled());
+ test_camera->set_screen_drawing_enabled(true);
+ CHECK(test_camera->is_screen_drawing_enabled());
+ test_camera->set_screen_drawing_enabled(false);
+ CHECK_FALSE(test_camera->is_screen_drawing_enabled());
+ }
+
+ SUBCASE("Enabled") {
+ test_camera->set_enabled(true);
+ CHECK(test_camera->is_enabled());
+ test_camera->set_enabled(false);
+ CHECK_FALSE(test_camera->is_enabled());
+ }
+
+ SUBCASE("Rotation") {
+ constexpr float rotation_smoothing_speed = 20.0f;
+ test_camera->set_ignore_rotation(true);
+ CHECK(test_camera->is_ignoring_rotation());
+ test_camera->set_ignore_rotation(false);
+ CHECK_FALSE(test_camera->is_ignoring_rotation());
+ test_camera->set_rotation_smoothing_enabled(true);
+ CHECK(test_camera->is_rotation_smoothing_enabled());
+ test_camera->set_rotation_smoothing_speed(rotation_smoothing_speed);
+ CHECK(test_camera->get_rotation_smoothing_speed() == rotation_smoothing_speed);
+ }
+
+ SUBCASE("Zoom") {
+ const Vector2 zoom = Vector2(4, 4);
+ test_camera->set_zoom(zoom);
+ CHECK(test_camera->get_zoom() == zoom);
+ }
+
+ SUBCASE("Offset") {
+ const Vector2 offset = Vector2(100, 100);
+ test_camera->set_offset(offset);
+ CHECK(test_camera->get_offset() == offset);
+ }
+
+ SUBCASE("Limit") {
+ constexpr int limit_left = 100;
+ constexpr int limit_top = 100;
+ constexpr int limit_right = 100;
+ constexpr int limit_bottom = 100;
+ test_camera->set_limit_smoothing_enabled(true);
+ CHECK(test_camera->is_limit_smoothing_enabled());
+ test_camera->set_limit_smoothing_enabled(false);
+ CHECK_FALSE(test_camera->is_limit_smoothing_enabled());
+ test_camera->set_limit(SIDE_LEFT, limit_left);
+ CHECK(test_camera->get_limit(SIDE_LEFT) == limit_left);
+ test_camera->set_limit(SIDE_TOP, limit_top);
+ CHECK(test_camera->get_limit(SIDE_TOP) == limit_top);
+ test_camera->set_limit(SIDE_RIGHT, limit_right);
+ CHECK(test_camera->get_limit(SIDE_RIGHT) == limit_right);
+ test_camera->set_limit(SIDE_BOTTOM, limit_bottom);
+ CHECK(test_camera->get_limit(SIDE_BOTTOM) == limit_bottom);
+ }
+
+ SUBCASE("Position") {
+ constexpr float smoothing_speed = 20.0f;
+ test_camera->set_position_smoothing_enabled(true);
+ CHECK(test_camera->is_position_smoothing_enabled());
+ test_camera->set_position_smoothing_speed(smoothing_speed);
+ CHECK(test_camera->get_position_smoothing_speed() == smoothing_speed);
+ }
+
+ memdelete(test_camera);
+}
+
+TEST_CASE("[SceneTree][Camera2D] Camera positioning") {
+ SubViewport *mock_viewport = memnew(SubViewport);
+ Camera2D *test_camera = memnew(Camera2D);
+
+ mock_viewport->set_size(Vector2(400, 200));
+ SceneTree::get_singleton()->get_root()->add_child(mock_viewport);
+ mock_viewport->add_child(test_camera);
+
+ SUBCASE("Anchor mode") {
+ test_camera->set_anchor_mode(Camera2D::ANCHOR_MODE_DRAG_CENTER);
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(0, 0)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+
+ test_camera->set_anchor_mode(Camera2D::ANCHOR_MODE_FIXED_TOP_LEFT);
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(200, 100)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+ }
+
+ SUBCASE("Offset") {
+ test_camera->set_offset(Vector2(100, 100));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(100, 100)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+
+ test_camera->set_offset(Vector2(-100, 300));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(-100, 300)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+
+ test_camera->set_offset(Vector2(0, 0));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(0, 0)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+ }
+
+ SUBCASE("Limits") {
+ test_camera->set_limit(SIDE_LEFT, 100);
+ test_camera->set_limit(SIDE_TOP, 50);
+
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(300, 150)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+
+ test_camera->set_limit(SIDE_LEFT, 0);
+ test_camera->set_limit(SIDE_TOP, 0);
+
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(200, 100)));
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+ }
+
+ SUBCASE("Drag") {
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(0, 0)));
+
+ // horizontal
+ test_camera->set_drag_horizontal_enabled(true);
+ test_camera->set_drag_margin(SIDE_RIGHT, 0.5);
+
+ test_camera->set_position(Vector2(100, 100));
+ test_camera->force_update_scroll();
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 100)));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(0, 100)));
+ test_camera->set_position(Vector2(101, 101));
+ test_camera->force_update_scroll();
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(1, 101)));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(1, 101)));
+
+ // test align
+ test_camera->set_position(Vector2(0, 0));
+ test_camera->align();
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(0, 0)));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(0, 0)));
+
+ // vertical
+ test_camera->set_drag_vertical_enabled(true);
+ test_camera->set_drag_horizontal_enabled(false);
+ test_camera->set_drag_margin(SIDE_TOP, 0.3);
+
+ test_camera->set_position(Vector2(200, -20));
+ test_camera->force_update_scroll();
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(200, 0)));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(200, 0)));
+ test_camera->set_position(Vector2(250, -55));
+ test_camera->force_update_scroll();
+ CHECK(test_camera->get_camera_position().is_equal_approx(Vector2(250, -25)));
+ CHECK(test_camera->get_camera_screen_center().is_equal_approx(Vector2(250, -25)));
+ }
+
+ memdelete(test_camera);
+ memdelete(mock_viewport);
+}
+
+TEST_CASE("[SceneTree][Camera2D] Transforms") {
+ SubViewport *mock_viewport = memnew(SubViewport);
+ Camera2D *test_camera = memnew(Camera2D);
+
+ mock_viewport->set_size(Vector2(400, 200));
+ SceneTree::get_singleton()->get_root()->add_child(mock_viewport);
+ mock_viewport->add_child(test_camera);
+
+ SUBCASE("Default camera") {
+ Transform2D xform = mock_viewport->get_canvas_transform();
+ // x,y are basis vectors, origin = screen center
+ Transform2D test_xform = Transform2D(Vector2(1, 0), Vector2(0, 1), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+ }
+
+ SUBCASE("Zoom") {
+ test_camera->set_zoom(Vector2(0.5, 2));
+ Transform2D xform = mock_viewport->get_canvas_transform();
+ Transform2D test_xform = Transform2D(Vector2(0.5, 0), Vector2(0, 2), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+
+ test_camera->set_zoom(Vector2(10, 10));
+ xform = mock_viewport->get_canvas_transform();
+ test_xform = Transform2D(Vector2(10, 0), Vector2(0, 10), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+
+ test_camera->set_zoom(Vector2(1, 1));
+ xform = mock_viewport->get_canvas_transform();
+ test_xform = Transform2D(Vector2(1, 0), Vector2(0, 1), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+ }
+
+ SUBCASE("Rotation") {
+ test_camera->set_rotation(Math_PI / 2);
+ Transform2D xform = mock_viewport->get_canvas_transform();
+ Transform2D test_xform = Transform2D(Vector2(1, 0), Vector2(0, 1), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+
+ test_camera->set_ignore_rotation(false);
+ xform = mock_viewport->get_canvas_transform();
+ test_xform = Transform2D(Vector2(0, -1), Vector2(1, 0), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+
+ test_camera->set_rotation(-1 * Math_PI);
+ test_camera->force_update_scroll();
+ xform = mock_viewport->get_canvas_transform();
+ test_xform = Transform2D(Vector2(-1, 0), Vector2(0, -1), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+
+ test_camera->set_rotation(0);
+ test_camera->force_update_scroll();
+ xform = mock_viewport->get_canvas_transform();
+ test_xform = Transform2D(Vector2(1, 0), Vector2(0, 1), Vector2(200, 100));
+ CHECK(xform.is_equal_approx(test_xform));
+ }
+
+ memdelete(test_camera);
+ memdelete(mock_viewport);
+}
+
+} // namespace TestCamera2D
+
+#endif // TEST_CAMERA_2D_H
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 24eb84127b..4a389f4284 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -44,6 +44,7 @@
#include "tests/core/io/test_file_access.h"
#include "tests/core/io/test_http_client.h"
#include "tests/core/io/test_image.h"
+#include "tests/core/io/test_ip.h"
#include "tests/core/io/test_json.h"
#include "tests/core/io/test_marshalls.h"
#include "tests/core/io/test_pck_packer.h"
@@ -101,6 +102,7 @@
#include "tests/scene/test_arraymesh.h"
#include "tests/scene/test_audio_stream_wav.h"
#include "tests/scene/test_bit_map.h"
+#include "tests/scene/test_camera_2d.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_color_picker.h"
#include "tests/scene/test_control.h"